├── .gitignore ├── README.md ├── appveyor.yml ├── binding.gyp ├── examples ├── raw.js └── simple.js ├── index.js ├── package.json └── src ├── XInputFunctions.cc ├── XInputFunctions.h └── XInputWrap.cc /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | node_modules/ 3 | test.js 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > Node.js xinput wrapper. Access xinput based controllers 2 | 3 | [![Build status](https://ci.appveyor.com/api/projects/status/1nxo39ety9q5itfs?svg=true)](https://ci.appveyor.com/project/thraaawn/xinputjs) 4 | 5 | xinput.js wraps the xinput game controller API. Besides allowing raw access to the xinput device, it also provides a small wrapper class which emits events based on controller input. 6 | 7 | ## Contents 8 | 9 | - [Requirements](#requirements) 10 | - [Building](#building) 11 | - [Examples](#examples) 12 | - [License](#license) 13 | 14 | ## Requirements 15 | 16 | [xinput](https://en.wikipedia.org/wiki/DirectInput#XInput) is only available on Windows. Please ensure you have the [required dependencies](https://github.com/nodejs/node-gyp#installation) as well as Visual Studio installed. 17 | 18 | ## Building 19 | 20 | node-gyp is required to build xinput.js. 21 | 22 | Install node-gyp using npm: 23 | 24 | ``` 25 | npm install -g node-gyp 26 | ``` 27 | 28 | Then configure and build: 29 | 30 | ``` 31 | node-gyp configure 32 | node-gyp build 33 | ``` 34 | 35 | ## Examples 36 | 37 | ### Simple 38 | ```JavaScript 39 | var xinput = require('../'); 40 | 41 | [0, 1, 2, 3] 42 | .filter(n => xinput.IsConnected(n)) 43 | .map(n => xinput.WrapController(n, { 44 | interval: 20, 45 | deadzone: { 46 | x: 0.20, 47 | y: 0.15 48 | }, 49 | holdtime: 500 50 | })) 51 | .forEach(gamepad => { 52 | var n = gamepad.deviceNumber; 53 | 54 | gamepad.addListener("button-long", (button, elapsed) => { 55 | console.log("[%d] Hold button %s for %dms", n, button, elapsed); 56 | /* After holding the button for a while -> 57 | [1] Button buttons.a changed: true 58 | [1] Hold button buttons.a for 501ms 59 | [1] Button buttons.a changed: false 60 | */ 61 | }); 62 | 63 | gamepad.addListener("button-short", (button, elapsed) => { 64 | console.log("[%d] Pressed button %s for %dms", n, button, elapsed); 65 | /* After tapping the button for a short moment -> 66 | [1] Button control.start changed: true 67 | [1] Button control.start changed: false 68 | [1] Pressed button control.start for 101ms 69 | */ 70 | }); 71 | 72 | gamepad.addListener("button-changed", (button, state) => { 73 | console.log("[%d] Button %s changed: %s", n, button, state); 74 | /* Find example output in both listeners above */ 75 | }); 76 | 77 | gamepad.addListener("analog-input", (input, data) => { 78 | console.log("[%d] Holding %s at:", n, input, data); 79 | /* Moving the left stick to the left -> 80 | [1] Holding leftstick at: { x: -0.04042176580095827, y: 0 } 81 | [1] Holding leftstick at: { x: -0.17329172643208102, y: 0 } 82 | [1] Holding leftstick at: { x: -0.532532731101413, y: 0 } 83 | [1] Holding leftstick at: { x: -0.8130359813226723, y: 0 } 84 | [1] Holding leftstick at: { x: -0.9705114902188178, y: 0 } 85 | [1] Holding leftstick at: { x: -1, y: 0 } 86 | */ 87 | 88 | /* Holding both triggers for a short moment -> 89 | [1] Holding trigger at: { left: 0.2235294133424759, right: 0 } 90 | [1] Holding trigger at: { left: 0.658823549747467, right: 0.16078431904315948 } 91 | [1] Holding trigger at: { left: 1, right: 0.5098039507865906 } 92 | [1] Holding trigger at: { left: 1, right: 0.9960784316062927 } 93 | [1] Holding trigger at: { left: 1, right: 1 } 94 | [1] Holding trigger at: { left: 1, right: 1 } 95 | [1] Holding trigger at: { left: 1, right: 1 } 96 | [1] Holding trigger at: { left: 1, right: 1 } 97 | [1] Holding trigger at: { left: 1, right: 0.9960784316062927 } 98 | [1] Holding trigger at: { left: 0.4313725531101227, right: 0.37254902720451355 } 99 | */ 100 | }); 101 | 102 | gamepad.addListener("connection-changed", (isConnected) => { 103 | console.log("[%d] Connection state changed: %s", n, isConnected ? "Connected!" : "Disconnected!"); 104 | /* Pulling out the batteries + plugging them back in -> 105 | [1] Connection state changed: Disconnected! 106 | [1] Connection state changed: Connected! 107 | */ 108 | }); 109 | }); 110 | ``` 111 | 112 | ### Raw 113 | ```JavaScript 114 | var xinput = require('../'); 115 | 116 | // Test all controllers 0-3 117 | [0, 1, 2, 3].forEach(controllerNum => { 118 | console.log("Controller %d connected:", controllerNum, xinput.IsConnected(controllerNum)); 119 | // -> Connected: true 120 | 121 | if(xinput.IsConnected(controllerNum)) { 122 | // Dump the current state 123 | console.log("Controller %d state:", controllerNum, xinput.GetState(controllerNum)); 124 | /* -> { 125 | // Digital inputs 126 | buttons: { a: false, b: false, x: false, y: false }, 127 | dpad: { left: false, right: false, up: false, down: false }, 128 | shoulder: { left: false, right: false }, 129 | thumb: { left: false, right: false }, 130 | control: { back: false, start: false }, 131 | 132 | // Analog inputs 133 | trigger: { left: 0, right: 0 }, 134 | leftstick: { x: -1679, y: 1514 }, 135 | rightstick: { x: -296, y: -3893 } 136 | } */ 137 | 138 | // Vibrate and stop after 1s 139 | xinput.Vibrate(controllerNum, 0.5, 0.5); 140 | setTimeout(() => xinput.Vibrate(controllerNum, 0.0, 0.0), 1000); 141 | } 142 | }); 143 | ``` 144 | 145 | ## License 146 | 147 | MIT -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # http://www.appveyor.com/docs/appveyor-yml 2 | 3 | # Test against these versions of Io.js and Node.js. 4 | environment: 5 | matrix: 6 | # node.js 7 | - nodejs_version: "0.10" 8 | - nodejs_version: "0" #Latest 0.x.x build. 9 | - nodejs_version: "3" #Latest io.js build. 10 | - nodejs_version: "4.2.4" #LTS 11 | - nodejs_version: "Stable" 12 | 13 | # Install scripts. (runs after repo cloning) 14 | install: 15 | # Get the latest stable version of Node.js or io.js 16 | - ps: Install-Product node $env:nodejs_version 17 | - npm install 18 | 19 | test_script: 20 | # Output useful info for debugging. 21 | - node --version 22 | - npm --version 23 | 24 | build: off 25 | 26 | version: "{build}" -------------------------------------------------------------------------------- /binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "xinput", 5 | "sources": [ 6 | "src/XInputWrap.cc", 7 | "src/XInputFunctions.cc" 8 | ], 9 | "include_dirs": [ 10 | " { 5 | console.log("Controller %d connected:", controllerNum, xinput.IsConnected(controllerNum)); 6 | // -> Connected: true 7 | 8 | if(xinput.IsConnected(controllerNum)) { 9 | // Dump the current state 10 | console.log("Controller %d state:", controllerNum, xinput.GetState(controllerNum)); 11 | /* -> { 12 | // Digital inputs 13 | buttons: { a: false, b: false, x: false, y: false }, 14 | dpad: { left: false, right: false, up: false, down: false }, 15 | shoulder: { left: false, right: false }, 16 | thumb: { left: false, right: false }, 17 | control: { back: false, start: false }, 18 | 19 | // Analog inputs 20 | trigger: { left: 0, right: 0 }, 21 | leftstick: { x: -1679, y: 1514 }, 22 | rightstick: { x: -296, y: -3893 } 23 | } */ 24 | 25 | // Vibrate and stop after 1s 26 | xinput.Vibrate(controllerNum, 0.5, 0.5); 27 | setTimeout(() => xinput.Vibrate(controllerNum, 0.0, 0.0), 1000); 28 | } 29 | }); -------------------------------------------------------------------------------- /examples/simple.js: -------------------------------------------------------------------------------- 1 | var xinput = require('../'); 2 | 3 | [0, 1, 2, 3] 4 | .filter(n => xinput.IsConnected(n)) 5 | .map(n => xinput.WrapController(n, { 6 | interval: 20, 7 | deadzone: { 8 | x: 0.20, 9 | y: 0.15 10 | }, 11 | holdtime: 500 12 | })) 13 | .forEach(gamepad => { 14 | var n = gamepad.deviceNumber; 15 | 16 | gamepad.addListener("button-long", (button, elapsed) => { 17 | console.log("[%d] Hold button %s for %dms", n, button, elapsed); 18 | /* After holding the button for a while -> 19 | [1] Button buttons.a changed: true 20 | [1] Hold button buttons.a for 501ms 21 | [1] Button buttons.a changed: false 22 | */ 23 | }); 24 | 25 | gamepad.addListener("button-short", (button, elapsed) => { 26 | console.log("[%d] Pressed button %s for %dms", n, button, elapsed); 27 | /* After tapping the button for a short moment -> 28 | [1] Button control.start changed: true 29 | [1] Button control.start changed: false 30 | [1] Pressed button control.start for 101ms 31 | */ 32 | }); 33 | 34 | gamepad.addListener("button-changed", (button, state) => { 35 | console.log("[%d] Button %s changed: %s", n, button, state); 36 | /* Find example output in both listeners above */ 37 | }); 38 | 39 | gamepad.addListener("analog-input", (input, data) => { 40 | console.log("[%d] Holding %s at:", n, input, data); 41 | /* Moving the left stick to the left -> 42 | [1] Holding leftstick at: { x: -0.04042176580095827, y: 0 } 43 | [1] Holding leftstick at: { x: -0.17329172643208102, y: 0 } 44 | [1] Holding leftstick at: { x: -0.532532731101413, y: 0 } 45 | [1] Holding leftstick at: { x: -0.8130359813226723, y: 0 } 46 | [1] Holding leftstick at: { x: -0.9705114902188178, y: 0 } 47 | [1] Holding leftstick at: { x: -1, y: 0 } 48 | */ 49 | 50 | /* Holding both triggers for a short moment -> 51 | [1] Holding trigger at: { left: 0.2235294133424759, right: 0 } 52 | [1] Holding trigger at: { left: 0.658823549747467, right: 0.16078431904315948 } 53 | [1] Holding trigger at: { left: 1, right: 0.5098039507865906 } 54 | [1] Holding trigger at: { left: 1, right: 0.9960784316062927 } 55 | [1] Holding trigger at: { left: 1, right: 1 } 56 | [1] Holding trigger at: { left: 1, right: 1 } 57 | [1] Holding trigger at: { left: 1, right: 1 } 58 | [1] Holding trigger at: { left: 1, right: 1 } 59 | [1] Holding trigger at: { left: 1, right: 0.9960784316062927 } 60 | [1] Holding trigger at: { left: 0.4313725531101227, right: 0.37254902720451355 } 61 | */ 62 | }); 63 | 64 | gamepad.addListener("connection-changed", (isConnected) => { 65 | console.log("[%d] Connection state changed: %s", n, isConnected ? "Connected!" : "Disconnected!"); 66 | /* Pulling out the batteries + plugging them back in -> 67 | [1] Connection state changed: Disconnected! 68 | [1] Connection state changed: Connected! 69 | */ 70 | }); 71 | }); -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var xinput = require('bindings')('xinput'); 4 | 5 | const EventEmitter = require('events'); 6 | class XInputDevice extends EventEmitter { 7 | constructor(deviceNumber, options) { 8 | super(); 9 | 10 | this.options = { 11 | interval: 20, 12 | deadzone: { 13 | x: 0.20, 14 | y: 0.15 15 | }, 16 | holdtime: 500 17 | }; 18 | 19 | if(options) { 20 | Object.keys(options).forEach(option => this.setOption(option, options[option])); 21 | } 22 | 23 | this.deviceNumber = deviceNumber; 24 | this.connected = xinput.IsConnected(this.deviceNumber); 25 | this.state = xinput.GetState(this.deviceNumber); 26 | 27 | this._previousState = this.state; 28 | this._digitalStates = ['buttons', 'dpad', 'shoulder', 'thumb', 'control']; 29 | this._analogStates = ['trigger', 'leftstick', 'rightstick']; 30 | this._holdTimes = {}; 31 | this._holdTimers = {}; 32 | 33 | this.initLoop(); 34 | } 35 | 36 | setOption(key, value) { 37 | this.options[key] = value; 38 | } 39 | 40 | stopLoop() { 41 | if(this.eventLoop == null) { 42 | return; 43 | } 44 | 45 | clearInterval(this.eventLoop); 46 | } 47 | 48 | initLoop() { 49 | this.stopLoop(); 50 | this.eventLoop = setInterval(this._update.bind(this), this.options.interval); 51 | } 52 | 53 | getNormalizedState(section, button) { 54 | return this._normalize(section, button, this.state[section][button]); 55 | } 56 | 57 | _normalize(section, button, val) { 58 | if(section == "leftstick" || section == "rightstick") { 59 | let normed = Math.max(-1, val / 32767); 60 | let zoned = (Math.abs(normed) < this.options.deadzone[button] ? 0 : (Math.abs(normed) - this.options.deadzone[button]) * (normed / Math.abs(normed))); 61 | 62 | if (this.options.deadzone[button] > 0) zoned /= 1 - this.options.deadzone[button]; 63 | 64 | return zoned; 65 | } 66 | 67 | return val; 68 | } 69 | 70 | _onConnectedChanged(isConnected) { 71 | this.emit("connection-changed", isConnected); 72 | this.emit("connection-" + isConnected ? "established" : "closed"); 73 | } 74 | 75 | _onInputChanged(section, button, state) { 76 | let key = `${section}.${button}`; 77 | this.emit("_input-changed", key, state); 78 | 79 | if(this._digitalStates.indexOf(section) != -1) { 80 | this.emit("button-changed", key, state); 81 | 82 | if(state) { 83 | this._holdTimes[key] = new Date().getTime(); 84 | this._holdTimers[key] = setTimeout((() => { 85 | let now = new Date().getTime(); 86 | let timePressed = this._holdTimes[key] || now; 87 | let elapsed = now - timePressed; 88 | 89 | this.emit("button-long", key, elapsed); 90 | }).bind(this), this.options.holdtime); 91 | } else { 92 | let now = new Date().getTime(); 93 | let timePressed = this._holdTimes[key] || now; 94 | let elapsed = now - timePressed; 95 | 96 | clearTimeout(this._holdTimers[key]); 97 | 98 | if(elapsed < this.options.holdtime) { 99 | this.emit("button-short", key, elapsed); 100 | } 101 | } 102 | } 103 | } 104 | 105 | _update() { 106 | let state = xinput.GetState(this.deviceNumber); 107 | let connected = xinput.IsConnected(this.deviceNumber); 108 | 109 | this.state = state; 110 | 111 | if(this.connected != connected) { 112 | this._onConnectedChanged(connected); 113 | this.connected = connected; 114 | } 115 | 116 | Object.keys(state).forEach(section => { 117 | Object.keys(state[section]).forEach(button => { 118 | let value = this._normalize(section, button, state[section][button]); 119 | let previous = this._normalize(section, button, this._previousState[section][button]); 120 | 121 | if(previous != value) { 122 | this._onInputChanged(section, button, value); 123 | } 124 | }); 125 | }); 126 | 127 | this._analogStates.forEach(section => { 128 | let hasInput = false; 129 | let values = {}; 130 | 131 | Object.keys(state[section]).forEach(button => { 132 | let value = this._normalize(section, button, state[section][button]); 133 | if(value != 0) { 134 | hasInput = true; 135 | } 136 | values[button] = value; 137 | }); 138 | 139 | if(hasInput) { 140 | this.emit("analog-input", section, values); 141 | } 142 | }); 143 | 144 | this._previousState = state; 145 | } 146 | } 147 | 148 | xinput.WrapController = function(deviceNumber, options) { 149 | return new XInputDevice(deviceNumber, options); 150 | }; 151 | 152 | module.exports = xinput; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "xinput.js", 3 | "version": "1.0.0", 4 | "description": "xinput wrapper. Access xinput based controllers.", 5 | "main": "index.js", 6 | "scripts": { 7 | "configure": "node-gyp configure", 8 | "build": "node-gyp build" 9 | }, 10 | "author": "davenonymous", 11 | "license": "MIT", 12 | "dependencies": { 13 | "bindings": "^1.2.1", 14 | "nan": "^2.2.0" 15 | }, 16 | "os": [ 17 | "win32" 18 | ], 19 | "gypfile": true, 20 | "repository": { 21 | "type": "git", 22 | "url": "https://github.com/thraaawn/xinputjs.git" 23 | }, 24 | "keywords": [ 25 | "gamepad", 26 | "joystick", 27 | "xinput" 28 | ], 29 | "bugs": { 30 | "url": "https://github.com/thraaawn/xinputjs/issues" 31 | }, 32 | "homepage": "https://github.com/thraaawn/xinputjs" 33 | } 34 | -------------------------------------------------------------------------------- /src/XInputFunctions.cc: -------------------------------------------------------------------------------- 1 | #include "XInputFunctions.h" 2 | #include 3 | 4 | NAN_METHOD(Vibrate) { 5 | //DEPRECATION FIX 6 | v8::Isolate* isolate = info.GetIsolate(); 7 | v8::Local context = isolate->GetCurrentContext(); 8 | 9 | XINPUT_VIBRATION vibration; 10 | ZeroMemory(&vibration, sizeof(XINPUT_VIBRATION)); 11 | 12 | double left = info[1]->IsUndefined() ? 0 : Nan::To(info[1]).FromJust(); 13 | double right = info[2]->IsUndefined() ? 0 : Nan::To(info[2]).FromJust(); 14 | 15 | vibration.wLeftMotorSpeed = (WORD)(65535 * left); 16 | vibration.wRightMotorSpeed = (WORD)(65535 * right); 17 | 18 | // TODO: Verify parameters 19 | XInputSetState((WORD)info[0]->IntegerValue(context).FromJust(), &vibration); 20 | } 21 | 22 | NAN_METHOD(IsConnected) { 23 | //DEPRECATION FIX 24 | v8::Isolate* isolate = info.GetIsolate(); 25 | v8::Local context = isolate->GetCurrentContext(); 26 | 27 | XINPUT_STATE controllerState; 28 | ZeroMemory(&controllerState, sizeof(XINPUT_STATE)); 29 | 30 | // TODO: Verify parameters 31 | DWORD result = XInputGetState((WORD)info[0]->IntegerValue(context).FromJust(), &controllerState); 32 | if(result == ERROR_SUCCESS) { 33 | info.GetReturnValue().Set(true); 34 | } else { 35 | info.GetReturnValue().Set(false); 36 | } 37 | } 38 | 39 | NAN_METHOD(GetState) { 40 | //DEPRECATION FIX 41 | v8::Isolate* isolate = info.GetIsolate(); 42 | v8::Local context = isolate->GetCurrentContext(); 43 | 44 | XINPUT_STATE controllerState; 45 | ZeroMemory(&controllerState, sizeof(XINPUT_STATE)); 46 | 47 | // TODO: Verify parameters 48 | DWORD result = XInputGetState((WORD)info[0]->IntegerValue(context).FromJust(), &controllerState); 49 | 50 | 51 | v8::Local objButtons = Nan::New(); 52 | objButtons->Set(context, Nan::New("a").ToLocalChecked(), Nan::New((controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_A) != 0)); 53 | objButtons->Set(context, Nan::New("b").ToLocalChecked(), Nan::New((controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_B) != 0)); 54 | objButtons->Set(context, Nan::New("x").ToLocalChecked(), Nan::New((controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_X) != 0)); 55 | objButtons->Set(context, Nan::New("y").ToLocalChecked(), Nan::New((controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_Y) != 0)); 56 | 57 | v8::Local objDPad = Nan::New(); 58 | objDPad->Set(context, Nan::New("left").ToLocalChecked(), Nan::New((controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) != 0)); 59 | objDPad->Set(context, Nan::New("right").ToLocalChecked(), Nan::New((controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) != 0)); 60 | objDPad->Set(context, Nan::New("up").ToLocalChecked(), Nan::New((controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP) != 0)); 61 | objDPad->Set(context, Nan::New("down").ToLocalChecked(), Nan::New((controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) != 0)); 62 | 63 | v8::Local objShoulder = Nan::New(); 64 | objShoulder->Set(context, Nan::New("left").ToLocalChecked(), Nan::New((controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER) != 0)); 65 | objShoulder->Set(context, Nan::New("right").ToLocalChecked(), Nan::New((controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER) != 0)); 66 | 67 | v8::Local objThumb = Nan::New(); 68 | objThumb->Set(context, Nan::New("left").ToLocalChecked(), Nan::New((controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB) != 0)); 69 | objThumb->Set(context, Nan::New("right").ToLocalChecked(), Nan::New((controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB) != 0)); 70 | 71 | v8::Local objControl = Nan::New(); 72 | objControl->Set(context, Nan::New("back").ToLocalChecked(), Nan::New((controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_BACK) != 0)); 73 | objControl->Set(context, Nan::New("start").ToLocalChecked(), Nan::New((controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_START) != 0)); 74 | 75 | 76 | v8::Local objTrigger = Nan::New(); 77 | objTrigger->Set(context, Nan::New("left").ToLocalChecked(), Nan::New((float)controllerState.Gamepad.bLeftTrigger / 255)); 78 | objTrigger->Set(context, Nan::New("right").ToLocalChecked(), Nan::New((float)controllerState.Gamepad.bRightTrigger / 255)); 79 | 80 | 81 | v8::Local objLeftStick = Nan::New(); 82 | objLeftStick->Set(context, Nan::New("x").ToLocalChecked(), Nan::New(controllerState.Gamepad.sThumbLX)); 83 | objLeftStick->Set(context, Nan::New("y").ToLocalChecked(), Nan::New(controllerState.Gamepad.sThumbLY)); 84 | 85 | v8::Local objRightStick = Nan::New(); 86 | objRightStick->Set(context, Nan::New("x").ToLocalChecked(), Nan::New(controllerState.Gamepad.sThumbRX)); 87 | objRightStick->Set(context, Nan::New("y").ToLocalChecked(), Nan::New(controllerState.Gamepad.sThumbRY)); 88 | 89 | 90 | v8::Local obj = Nan::New(); 91 | // Digital, i.e. buttons 92 | obj->Set(context, Nan::New("buttons").ToLocalChecked(), objButtons); 93 | obj->Set(context, Nan::New("dpad").ToLocalChecked(), objDPad); 94 | obj->Set(context, Nan::New("shoulder").ToLocalChecked(), objShoulder); 95 | obj->Set(context, Nan::New("thumb").ToLocalChecked(), objThumb); 96 | obj->Set(context, Nan::New("control").ToLocalChecked(), objControl); 97 | 98 | // Analog, i.e. sticks and triggers 99 | obj->Set(context, Nan::New("trigger").ToLocalChecked(), objTrigger); 100 | obj->Set(context, Nan::New("leftstick").ToLocalChecked(), objLeftStick); 101 | obj->Set(context, Nan::New("rightstick").ToLocalChecked(), objRightStick); 102 | 103 | 104 | 105 | info.GetReturnValue().Set(obj); 106 | } 107 | -------------------------------------------------------------------------------- /src/XInputFunctions.h: -------------------------------------------------------------------------------- 1 | #ifndef NATIVE_EXTENSION_XINPUT 2 | #define NATIVE_EXTENSION_XINPUT 3 | 4 | #include 5 | 6 | NAN_METHOD(IsConnected); 7 | NAN_METHOD(GetState); 8 | NAN_METHOD(Vibrate); 9 | 10 | #endif -------------------------------------------------------------------------------- /src/XInputWrap.cc: -------------------------------------------------------------------------------- 1 | #include "XInputFunctions.h" 2 | 3 | using v8::FunctionTemplate; 4 | 5 | NAN_MODULE_INIT(InitAll) { 6 | Nan::Set(target, Nan::New("IsConnected").ToLocalChecked(), Nan::GetFunction(Nan::New(IsConnected)).ToLocalChecked()); 7 | Nan::Set(target, Nan::New("GetState").ToLocalChecked(), Nan::GetFunction(Nan::New(GetState)).ToLocalChecked()); 8 | Nan::Set(target, Nan::New("Vibrate").ToLocalChecked(), Nan::GetFunction(Nan::New(Vibrate)).ToLocalChecked()); 9 | } 10 | 11 | NODE_MODULE(NativeExtension, InitAll); --------------------------------------------------------------------------------