Access native XInput functions as well as some helpers based around them.
This lib hooks directly to the system's dll (xinput1_4.dll, xinput1_3.dll or xinput9_1_0.dll).
It aims to implement and expose XInput functions as close as possible to the document.
π "Hidden" XInput functions such as XInputGetCapabilitiesEx()
are exposed as well.
Vibration via helper function
import { rumble } from "xinput-ffi";
//Rumble 1st XInput gamepad
await rumble();
//Now with 100% force
await rumble({force: 100});
//low-frequency rumble motor(left) at 50%
//and high-frequency rumble motor (right) at 25%
await rumble({force: [50,25]});
XInput function
import * as XInput from "xinput-ffi";
const capabilities = await XInput.getCapabilities({translate: true});
console.log(capabilities);
/* Output:
{
type: 'XINPUT_DEVTYPE_GAMEPAD',
subType: 'XINPUT_DEVSUBTYPE_GAMEPAD',
flags: [ 'XINPUT_CAPS_VOICE_SUPPORTED', 'XINPUT_CAPS_PMD_SUPPORTED' ],
gamepad: {
wButtons: [
'XINPUT_GAMEPAD_DPAD_UP',
'XINPUT_GAMEPAD_DPAD_DOWN',
//etc...
],
bLeftTrigger: 255,
bRightTrigger: 255,
sThumbLX: -64,
sThumbLY: -64,
sThumbRX: -64,
sThumbRY: -64
},
vibration: { wLeftMotorSpeed: 255, wRightMotorSpeed: 255 }
}
*/
"Hidden" XInput function
import * as XInput from "xinput-ffi";
const state = await XInput.getStateEx();
console.log(state);
/*Output:
{
dwPacketNumber: 6510,
gamepad: {
wButtons: [ 'XINPUT_GAMEPAD_GUIDE' ],
bLeftTrigger: 0,
bRightTrigger: 0,
sThumbLX: -1024,
sThumbLY: 767,
sThumbRX: 257,
sThumbRY: 767
}
}
*/
Miscellaneous
import * as XInput from "xinput-ffi";
//Check connected status for all controller
console.log(await XInput.listConnected());
// [true,false,false,false] Only 1st gamepad is connected
//Identify connected XInput devices
console.log (await XInput.identify({XInputOnly: true}));
/* Output:
[
{
name: 'Xbox360 Controller',
manufacturer: 'Microsoft Corp.',
vendorID: 1118,
productID: 654,
xinput: true,
interfaces: [ 'USB', 'HID' ],
guid: [
'{745a17a0-74d3-11d0-b6fe-00a0c90f57da}',
'{d61ca365-5af4-4486-998b-9db4734c6ca3}'
]
}
]
*/
Simple XInput menu navigation
Here is an example of a simple XInput menu navigation system using the high level XInput implementation found in this module (helper).
- main process
let gamepad;
mainWin.once("ready-to-show", async() => {
const { XInputGamepad } = await import("xinput-ffi");
gamepad = new XInputGamepad();
//send input to renderer
gamepad.on("input", (buttons)=>{
setImmediate(() => {
mainWin.webContents.send("onGamepadInput", buttons);
});
});
gamepad.poll(); //gamepad event loop
mainWin.show();
mainWin.focus();
});
//gain/loose focus
mainWin.on("blur", () => {
gamepad?.pause();
});
mainWin.on("focus", () => {
gamepad?.resume();
});
//clean up
mainWin.on("close", () => {
gamepad?.stop();
gamepad = null; //deref
});
mainWin.on("closed", () => {
mainWin = null; //deref
});
mainWin.loadFile(path/to/file);
- contextBridge (preload)
contextBridge.exposeInMainWorld("ipcRenderer", {
onGamepadInput: (callback) => ipcRenderer.on("onGamepadInput", callback)
});
- renderer
window.ipcRenderer.onGamepadInput((event, input) => {
switch(input[0]){
case "XINPUT_GAMEPAD_DPAD_UP":
//do something
break;
default:
console.log(input);
}
});
npm install xinput-ffi
Previous version(s) are CommonJS (CJS) with an ESM wrapper.
Summary:
- constants
- XInput function
- Helper functions
- Identify device | VID/PID
- High level implementation of XInput
XInput controller constants for convenience.
import { constants } from "xinput-ffi";
console.log(constants.XUSER_MAX_COUNT); //4
π‘ Also available under its own namespace.
import { XUSER_MAX_COUNT } from "xinput-ffi/constants";
console.log(XUSER_MAX_COUNT); //4
- βοΈ XInputEnable
- β XInputGetAudioDeviceIds > deprecated: doesn't work on modern Windows system.
- βοΈ XInputGetBatteryInformation
- βοΈ XInputGetCapabilities
- β XInputGetDSoundAudioDeviceGuids > deprecated: doesn't work on modern Windows system.
- βοΈ XInputGetKeystroke
- βοΈ XInputGetState
- βοΈ XInputSetState
"Hidden" and undocumented functions
π Reverse Engineer's log
- βοΈ XInputGetStateEx
- βοΈ XInputWaitForGuideButton
- βοΈ XInputCancelGuideButtonWait
- βοΈ XInputPowerOffController
β οΈ XInputGetBaseBusInformation > Not working with all gamepad.- βοΈ XInputGetCapabilitiesEx
NB: Depending on which XInput dll version you are using (1_4, 1_3, 9_1_0) some functions won't be available.
Enable/Disable all XInput gamepads.
This function is meant to be called when an application gains or loses focus.
NB:
- Stop any rumble currently playing when set to false.
- This may trigger
ERR_DEVICE_NOT_CONNECTED
for set/getState(Ex) when set to false and there was no prior input ever.
π XInputEnable
Retrieves the battery type and charge status of a wireless controller.
βοΈ options:
- dwUserIndex?: number (0)
Index of the user's controller. Can be a value from 0 to 3.
- devType?: number (0)
Specifies which device associated with this controller should be queried.
0: GAMEPAD or 1: HEADSET
- translate?: boolean (true)
When a value is known it will be 'translated' to its string equivalent value otherwise its integer value.
If you want the raw data only set it to false.
π‘ If option
is a number it will be used as dwUserIndex.
Returns an object like a π XINPUT_BATTERY_INFORMATION structure.
Example
await getBatteryInformation();
await getBatteryInformation(0);
await getBatteryInformation({dwUserIndex: 0});
//output
{
batteryType: 'BATTERY_TYPE_WIRED',
batteryLevel: 'BATTERY_LEVEL_FULL'
}
If you want raw data output
await getBatteryInformation({translate: false});
//output
{
batteryType: 1,
batteryLevel: 3
}
π XInputGetBatteryInformation
Retrieves the capabilities and features of the specified controller.
βοΈ options:
- dwUserIndex?: number (0)
Index of the user's controller. Can be a value from 0 to 3.
- dwFlags?: number (1)
Input flags that identify the controller type.
If this value is 0, then the capabilities of all controllers connected to the system are returned.
Currently, only 1: XINPUT_FLAG_GAMEPAD is supported.
- translate?: boolean (true)
When a value is known it will be 'translated' to its string equivalent value otherwise its integer value.
If you want the raw data only set it to false.
π‘ If option
is a number it will be used as dwUserIndex.
Returns an object like a π XINPUT_CAPABILITIES structure.
Example
await getCapabilities();
await getCapabilities(0);
await getCapabilities({dwUserIndex: 0});
//Output
{
type: 'XINPUT_DEVTYPE_GAMEPAD',
subType: 'XINPUT_DEVSUBTYPE_GAMEPAD',
flags: [ 'XINPUT_CAPS_VOICE_SUPPORTED', 'XINPUT_CAPS_PMD_SUPPORTED' ],
gamepad: {
wButtons: [
'XINPUT_GAMEPAD_DPAD_UP',
'XINPUT_GAMEPAD_DPAD_DOWN',
'XINPUT_GAMEPAD_DPAD_LEFT',
'XINPUT_GAMEPAD_DPAD_RIGHT',
'XINPUT_GAMEPAD_START',
'XINPUT_GAMEPAD_BACK',
'XINPUT_GAMEPAD_LEFT_THUMB',
'XINPUT_GAMEPAD_RIGHT_THUMB',
'XINPUT_GAMEPAD_LEFT_SHOULDER',
'XINPUT_GAMEPAD_RIGHT_SHOULDER',
'XINPUT_GAMEPAD_A',
'XINPUT_GAMEPAD_B',
'XINPUT_GAMEPAD_X',
'XINPUT_GAMEPAD_Y'
],
bLeftTrigger: 255,
bRightTrigger: 255,
sThumbLX: -64,
sThumbLY: -64,
sThumbRX: -64,
sThumbRY: -64
},
vibration: { wLeftMotorSpeed: 255, wRightMotorSpeed: 255 }
}
If you want raw data output
await getCapabilities({translate: false});
//output
{
type: 1,
subType: 1,
flags: 12,
gamepad: {
wButtons: 65535,
bLeftTrigger: 255,
bRightTrigger: 255,
sThumbLX: -64,
sThumbLY: -64,
sThumbRX: -64,
sThumbRY: -64
},
vibration: { wLeftMotorSpeed: 255, wRightMotorSpeed: 255 }
}
Retrieves a gamepad input event.
To be honest, this isn't really useful since the chatpad feature wasn't implemented on Windows.
βοΈ options:
- dwUserIndex?: number (0)
Index of the user's controller. Can be a value from 0 to 3.
- translate?: boolean (true)
When a value is known it will be 'translated' to its string equivalent value otherwise its integer value.
If you want the raw data only set it to false.
π‘ If option
is a number it will be used as dwUserIndex.
Returns an object like a π XINPUT_KEYSTROKE structure.
Example
await getKeystroke();
await getKeystroke(0);
await getKeystroke({dwUserIndex: 0});
//Output
{
virtualKey: 'VK_PAD_A',
unicode: 0,
flags: [ 'XINPUT_KEYSTROKE_KEYDOWN' ],
userIndex: 0,
hidCode: 0
}
If you want raw data output
await getKeystroke({translate: false});
//output
{
virtualKey: 22528,
unicode: 0,
flags: 1,
userIndex: 0,
hidCode: 0
}
π XInputGetKeystroke
Retrieves the current state of the specified controller.
βοΈ options:
- dwUserIndex?: number (0)
Index of the user's controller. Can be a value from 0 to 3.
- translate?: boolean (true)
When a value is known it will be 'translated' to its string equivalent value otherwise its integer value.
If you want the raw data only set it to false.
π‘ If option
is a number it will be used as dwUserIndex.
Returns an object like a π XINPUT_STATE structure.
Example
await getState();
await getState(0);
await getState({dwUserIndex: 0});
//Output
{
dwPacketNumber: 18165,
gamepad: {
wButtons: ['XINPUT_GAMEPAD_A'],
bLeftTrigger: 0,
bRightTrigger: 0,
sThumbLX: 128,
sThumbLY: 641,
sThumbRX: -1156,
sThumbRY: -129
}
}
If you want raw data output
await getState({translate: false});
//output
{
dwPacketNumber: 322850,
gamepad: {
wButtons: 4096,
bLeftTrigger: 0,
bRightTrigger: 0,
sThumbLX: 257,
sThumbLY: 767,
sThumbRX: 773,
sThumbRY: 1279
}
}
π‘ Thumbsticks: as explained by Microsoft you should implement dead zone correctly.
This is done for you in getButtonsDown()
π XInputGetState
Sends data to a connected controller. This function is used to activate the vibration function of a controller.
βοΈ options:
- dwUserIndex?: number (0)
Index of the user's controller. Can be a value from 0 to 3.
- usePercent?: boolean (true)
XInputSetState
valid values are in the range 0 to 65535.
Zero signifies no motor use; 65535 signifies 100 percent motor use.
lowFrequency
and highFrequency
are in % (0-100) for convenience when you set this to true.
π‘ If option
is a number it will be used as dwUserIndex.
NB:
- You need to keep the event-loop alive otherwise the vibration will terminate with your program.
- You need to reset the state to 0 for both frequency before using setState again.
Both are done for you with rumble()
π XInputSetState
The same as XInputGetState
, adding the "Guide" button (0x0400).
βοΈ options:
- dwUserIndex?: number (0)
Index of the user's controller. Can be a value from 0 to 3.
- translate?: boolean (true)
When a value is known it will be 'translated' to its string equivalent value otherwise its integer value.
If you want the raw data only set it to false.
π‘ If option
is a number it will be used as dwUserIndex.
Returns an object like a π XINPUT_STATE structure.
Example
await getStateEx();
await getStateEx(0);
await getStateEx({dwUserIndex: 0});
//Output
{
dwPacketNumber: 18165,
gamepad: {
wButtons: ['XINPUT_GAMEPAD_GUIDE'],
bLeftTrigger: 0,
bRightTrigger: 0,
sThumbLX: 128,
sThumbLY: 641,
sThumbRX: -1156,
sThumbRY: -129
}
}
If you want raw data output
await getStateEx({translate: false});
//output
{
dwPacketNumber: 322850,
gamepad: {
wButtons: 1024,
bLeftTrigger: 0,
bRightTrigger: 0,
sThumbLX: 257,
sThumbLY: 767,
sThumbRX: 773,
sThumbRY: 1279
}
}
Wait until Guide button is pressed.
βοΈ options:
- dwUserIndex?: number (0)
Index of the user's controller. Can be a value from 0 to 3.
- dwFlags?: number (0)
Wait behavior:
0: Blocking 1: Async
It's not clear on how to get the async option to report.
π‘ If option
is a number it will be used as dwUserIndex.
If XInputWaitForGuideButton
was activated in async mode, this will stop it.
βοΈ options:
- dwUserIndex?: number (0)
Index of the user's controller. Can be a value from 0 to 3.
π‘ If option
is a number it will be used as dwUserIndex.
Power off a controller.
βοΈ options:
- dwUserIndex?: number (0)
Index of the user's controller. Can be a value from 0 to 3.
π‘ If option
is a number it will be used as dwUserIndex.
ERROR_DEVICE_NOT_CONNECTED
, even if connected.
βοΈ options:
- dwBusIndex?: number (0)
Bus index. Can be a value from 0 to 16.
π‘ If option
is a number it will be used as dwBusIndex?.
Returns an object like the following structure:
struct XINPUT_BASE_BUS_INFORMATION
{
WORD VendorId, //unknown
WORD ProductId, //unknown
WORD InputId, //unknown
WORD Field_6, //unknown
DWORD Field_8, //unknown
BYTE Field_C, //unknown
BYTE Field_D, //unknown
BYTE Field_E, //unknown
BYTE Field_F //unknown
}
The same as XInputGetCapabilities
but with added properties such as vendorID and productID.
βοΈ options:
- dwUserIndex?: number (0)
Index of the user's controller. Can be a value from 0 to 3.
- translate?: boolean (true)
When a value is known it will be 'translated' to its string equivalent value otherwise its integer value.
If you want the raw data only set it to false.
π‘ If option
is a number it will be used as dwUserIndex.
Returns an object similar to π XINPUT_CAPABILITIES structure.
See below for details.
Example
await getCapabilitiesEx();
await getCapabilitiesEx(0);
await getCapabilitiesEx({dwUserIndex: 0});
//Output
{
capabilities: {
type: 'XINPUT_DEVTYPE_GAMEPAD',
dubType: 'XINPUT_DEVSUBTYPE_GAMEPAD',
flags: [ 'XINPUT_CAPS_VOICE_SUPPORTED', 'XINPUT_CAPS_PMD_SUPPORTED' ],
gamepad: {
wButtons: [
'XINPUT_GAMEPAD_DPAD_UP',
'XINPUT_GAMEPAD_DPAD_DOWN',
'XINPUT_GAMEPAD_DPAD_LEFT',
'XINPUT_GAMEPAD_DPAD_RIGHT',
'XINPUT_GAMEPAD_START',
'XINPUT_GAMEPAD_BACK',
'XINPUT_GAMEPAD_LEFT_THUMB',
'XINPUT_GAMEPAD_RIGHT_THUMB',
'XINPUT_GAMEPAD_LEFT_SHOULDER',
'XINPUT_GAMEPAD_RIGHT_SHOULDER',
'XINPUT_GAMEPAD_A',
'XINPUT_GAMEPAD_B',
'XINPUT_GAMEPAD_X',
'XINPUT_GAMEPAD_Y'
],
bLeftTrigger: 255,
bRightTrigger: 255,
sThumbLX: -64,
sThumbLY: -64,
sThumbRX: -64,
sThumbRY: -64
},
vibration: { wLeftMotorSpeed: 255, wRightMotorSpeed: 255 }
},
vendorId: 'Microsoft Corp.',
productId: 'Xbox360 Controller',
productVersion: 276,
}
If you want raw data output
await getCapabilitiesEx({translate: false});
//output
{
capabilities: {
type: 1,
dubType: 1,
flags: 12,
gamepad: {
wButtons: 62463,
bLeftTrigger: 255,
bRightTrigger: 255,
sThumbLX: -64,
sThumbLY: -64,
sThumbRX: -64,
sThumbRY: -64
},
vibration: {
wLeftMotorSpeed: 255,
wRightMotorSpeed: 255
}
},
vendorId: 1118,
productId: 654,
productVersion: 276,
}
The following are sugar/helper functions based upon the previous XInput functions.
Whether the specified controller is connected or not.
Returns true/false.
Returns an array of connected status for all controller.
eg: [true,false,false,false] => Only 1st gamepad is connected
Normalize getState()/getStateEx()
information for convenience:
ThumbStick position, magnitude, direction (taking the deadzone into account).
Trigger state and force (taking threshold into account).
Which buttons are pressed if any.
βοΈ options:
- gamepad?: number (0)
Index of the user's controller. Can be a value from 0 to 3.
- deadzone?: number | number[] ( [7849,8689] )
Thumbstick deadzone(s):
Either an integer (both thumbstick with the same value) or an array of 2 integer: [left,right]
- directionThreshold?: number (0.2)
float [0.0,1.0] to handle cardinal direction.
Set it to 0
so direction[]
only reports "UP RIGHT", "UP LEFT", "DOWN LEFT", "DOWN RIGHT".
Otherwise "RIGHT", "LEFT", "UP", "DOWN" will be added to the above using threshold to
differentiate the 2 axes by using range of [-threshold,threshold].
π‘ If you just want "RIGHT", "LEFT", "UP" and "DOWN" the easiest way is to set this to 0.8
with the default deadzone.
Alternatively play with this value and/or deadzone to decide on a thresold and ignore when direction[]
has a length of 2.
- triggerThreshold?: number (30)
Trigger activation threshold. Range [0,255].
=> Returns an object where:
- int packetNumber : dwPacketNumber; This value is increased every time the state of the controller has changed.
- []string buttons : list of currently pressed buttons
- trigger.left/right :
- boolean active : is the trigger pressed down ? (below triggerThreshold will not set active to true)
- int force : by how much ? [0,255]
- thumb.left/right :
- float x: normalized (deadzone) x axis [0.0,1.0]. 0 is centered. Negative values is left. Positive values is right.
- float y: normalized (deadzone) y axis [0.0,1.0]. 0 is centered. Negative values is down. Positive values is up.
- float magnitude: normalized (deadzone) magnitude [0.0,1.0] (by how far is the thumbstick from the center ? 1 is fully pushed).
- []string direction: Human readable direction of the thumbstick. eg: ["UP", "RIGHT"]. See directionThreshold above for details.
{
packetNumber: 132309,
buttons: [ 'XINPUT_GAMEPAD_A' ],
trigger: {
left: { active: true, force: 255 },
right: { active: false, force: 0 }
},
thumb: {
left: {
x: -0.6960457056589758,
y: 0.717997476063599,
magnitude: 1,
direction: [ 'UP', 'LEFT' ]
},
right: {
x: 0.039307955814283674,
y: 0.9992271436513833,
magnitude: 1,
direction: [ 'UP' ]
}
}
}
This function is used to activate the vibration function of a controller.
βοΈ options:
- gamepad?: number (0)
Index of the user's controller. Can be a value from 0 to 3.
- force?: number | number[] ([50,25])
Vibration force in % (0-100) to apply to the motors.
Either an integer (both motor with the same value) or an array of 2 integer: [left,right]
- duration?: number (2500)
Vibration duration in ms. Max: ~2500 ms.
- forceEnableGamepad?: boolean (false)
Use enable()
to force the activation of XInput gamepad before vibration.
- forceStateWhileRumble?: boolean (false)
Bruteforce -ly (spam) setState()
for the duration of the vibration. Use this when a 3rd party reset your state or whatever.
XInput doesn't provide VID/PID by design.
Even if with XInputGetCapabilitiesEx
you can get the vendorID and productID, it will most likely be a Xbox Controller (real one or through XInput emulation).
Use identify()
(see below) to query WMI _Win32_PNPEntity
to scan for known gamepads.
It won't tell you which is connected to which XInput slot tho.
List all known HID and USB connected devices by matching with entries in ./lib/util/HardwareID.js
βοΈ options:
- XInputOnly?: boolean (true)
Return only XInput gamepad.
=> Return an array of object where
- string name : device name
- string manufacturer : vendor name
- number vendorID : vendor id
- number productID : product id
- string[] interfaces : PNPentity interface(s) found; Available: HID and USB
- string[] guid: classguid(s) found
- boolean xinput: a XInput device or not
π‘ object are unique by their vid/pid
Output example with a DS4(wireless) and ds4windows(XInput wrapper):
import { identify } from "xinput-ffi";
await identify();
//Output
[
{
name: 'DualShock 4 (v2)',
manufacturer: 'Sony Corp.',
vendorID: 1356,
productID: 2508,
xinput: false,
interfaces: [ 'USB', 'HID' ],
guid: [
'{36fc9e60-c465-11cf-8056-444553540000}',
'{745a17a0-74d3-11d0-b6fe-00a0c90f57da}',
'{4d36e96c-e325-11ce-bfc1-08002be10318}'
]
},
{
name: 'DualShock 4 USB Wireless Adaptor',
manufacturer: 'Sony Corp.',
vendorID: 1356,
productID: 2976,
xinput: false,
interfaces: [ 'USB', 'HID' ],
guid: [
'{745a17a0-74d3-11d0-b6fe-00a0c90f57da}',
'{36fc9e60-c465-11cf-8056-444553540000}',
'{4d36e96c-e325-11ce-bfc1-08002be10318}'
]
},
{
name: 'Xbox360 Controller',
manufacturer: 'Microsoft Corp.',
vendorID: 1118,
productID: 654,
xinput: true,
interfaces: [ 'USB', 'HID' ],
guid: [
'{745a17a0-74d3-11d0-b6fe-00a0c90f57da}',
'{d61ca365-5af4-4486-998b-9db4734c6ca3}'
]
}
]
This is a high level implementation of XInput to get the gamepad's input on the fly in a human readable way. This serves as an example to demonstrate how to use the XInput functions and helpers based around them. The purpose of this class is to drive a simple navigation menu system with a XInput compatible controller (real XInput or through XInput emulation).
This leverages the new Node.js timersPromises setInterval() to keep the event loop alive and do the gamepad polling.
This class extends EventEmitter from node:events
Options
-
hz?: number (30)
This will determinate the polling rate. Usually 60hz (1000/60 = ~16ms) is used. If I'm not mistaken this is what the Chrome browser uses. But for our use case we don't need to poll that fast so it defaults to 30hz (~33ms). Increasing this value improves latency, but may cause a loss in performance due to more CPU time spent. The max accepted is 250hz (4ms).
-
multitap?: boolean (true)
Scan for all 4 XInput slots to find any Gamepad. Set to false to only poll XInput slot 0 and potentially reduce the number of FFI calls per gamepad tick (event loop).
-
joystickAsDPAD?: boolean (true)
Convert the left joystick analog axis to DPAD buttons. For our use case, driving a simple navigation menu, this is useful.
-
inputFeedback?: boolean (false)
Vibrate shortly and lightly on any button activation. This is just for fun and/or debug.
Events
input(buttons: string[])
List of activated buttons (human readable) of the first controller found.
A button is "activated" on press (button down) then release (button up).
π‘ NB: Triggers axis are converted into non standard XInput button name : GAMEPAD_LEFT_TRIGGER
and GAMEPAD_RIGHT_TRIGGER
(on/off behavior).
XInput Button names:
"XINPUT_GAMEPAD_DPAD_UP",
"XINPUT_GAMEPAD_DPAD_DOWN",
"XINPUT_GAMEPAD_DPAD_LEFT",
"XINPUT_GAMEPAD_DPAD_RIGHT",
"XINPUT_GAMEPAD_START",
"XINPUT_GAMEPAD_BACK",
"XINPUT_GAMEPAD_LEFT_THUMB",
"XINPUT_GAMEPAD_RIGHT_THUMB",
"XINPUT_GAMEPAD_LEFT_SHOULDER",
"XINPUT_GAMEPAD_RIGHT_SHOULDER",
"XINPUT_GAMEPAD_GUIDE",
"XINPUT_GAMEPAD_A",
"XINPUT_GAMEPAD_B",
"XINPUT_GAMEPAD_X",
"XINPUT_GAMEPAD_Y"
π‘ NB: XInput constants are available under the constants
namespace.
import { BUTTONS } from "xinput-ffi/constants";
//or
import { constants } from "xinput-ffi"
Example:
import { XInputGamepad } from "xinput-ffi";
const gamepad = new XInputGamepad({ hz: 60 });
gamepad.on("input", (buttons)=>{
setImmediate(() => {
console.log(buttons);
});
});
gamepad.poll();
Methods
Start the gamepad event loop. This will keep the Node.js event loop going.
β Will throw on unexpected error.
Stop the gamepad event loop.
NB: This method will remove every event listener.
This function is meant to be called when an application loses focus.
cf: XInputEnable
This function is meant to be called when an application gains focus.
cf: XInputEnable
Vibrate the first controller found. Shorthand to the helper fn rumble()
.
π‘ Expose only force
and duration
options of rumble()
.
β Will throw on error other than ERROR_DEVICE_NOT_CONNECTED
.