diff --git a/controller.js b/controller.js
new file mode 100644
index 0000000..456c0cb
--- /dev/null
+++ b/controller.js
@@ -0,0 +1,74 @@
+var dualShock = require('./dist/dualshock-controller/src/dualshock');
+
+
+var controller = dualShock({
+ config: "dualshock4-generic-driver"
+});
+controller.on('error', err => console.log(err));
+
+function setExtras(obj){
+ controller.setExtras(obj);
+}
+var connected = false;
+controller.on('connected', () => {
+ connected = true;
+});
+controller.on("disconnected", ()=>{
+ connected = false;
+})
+
+function isConnected(){
+ return connected;
+}
+//add event handlers:
+// controller.on('left:move', data => console.log('left Moved: ' + data.x + ' | ' + data.y));
+
+// controller.on('right:move', data => console.log('right Moved: ' + data.x + ' | ' + data.y));
+
+// controller.on('square:press', () => console.log('square press'));
+
+// controller.on('square:release', () => console.log('square release'));
+
+//sixasis motion events:
+//the object returned from each of the movement events is as follows:
+//{
+// direction : values can be: 1 for right, forward and up. 2 for left, backwards and down.
+// value : values will be from 0 to 120 for directions right, forward and up and from 0 to -120 for left, backwards and down.
+//}
+
+function on(event, handler){
+ controller.on(event, handler);
+}
+
+module.exports = {
+ on,
+ isConnected,
+ setExtras
+}
+// controller.on('touchpad:x1:active', () => console.log('touchpad one finger active'));
+
+// controller.on('touchpad:x2:active', () => console.log('touchpad two fingers active'));
+
+// controller.on('touchpad:x2:inactive', () => console.log('touchpad back to single finger'));
+
+// controller.on('touchpad:x1', data => console.log('touchpad x1:', data.x, data.y));
+
+// controller.on('touchpad:x2', data => console.log('touchpad x2:', data.x, data.y));
+
+
+// //right-left movement
+// controller.on('rightLeft:motion', data => console.log(data));
+
+// //forward-back movement
+// controller.on('forwardBackward:motion', data => console.log(data));
+
+// //up-down movement
+// controller.on('upDown:motion', data => console.log(data));
+
+// //controller status
+// //as of version 0.6.2 you can get the battery %, if the controller is connected and if the controller is charging
+// controller.on('battery:change', data => console.log(data));
+
+// controller.on('connection:change', data => console.log(data));
+
+// controller.on('charging:change', data => console.log(data));
diff --git a/dist/dualshock-controller/.editorconfig b/dist/dualshock-controller/.editorconfig
new file mode 100644
index 0000000..359c836
--- /dev/null
+++ b/dist/dualshock-controller/.editorconfig
@@ -0,0 +1,9 @@
+root = true
+
+[*]
+indent_style = space
+indent_size = 4
+charset = utf-8
+trim_trailing_whitespace = true
+end_of_line = lf
+insert_final_newline = true
diff --git a/dist/dualshock-controller/.gitignore b/dist/dualshock-controller/.gitignore
new file mode 100644
index 0000000..f568ada
--- /dev/null
+++ b/dist/dualshock-controller/.gitignore
@@ -0,0 +1,6 @@
+node_modules
+*.log
+coverage
+*.iml
+*.idea
+.DS_Store
diff --git a/dist/dualshock-controller/.travis.yml b/dist/dualshock-controller/.travis.yml
new file mode 100644
index 0000000..3765381
--- /dev/null
+++ b/dist/dualshock-controller/.travis.yml
@@ -0,0 +1,6 @@
+language: node_js
+node_js:
+ - "6.9.2"
+before_script:
+install: echo "node-hid installation will fail in travis. Overiding `npm install`"
+compiler: clang
diff --git a/dist/dualshock-controller/README.md b/dist/dualshock-controller/README.md
new file mode 100644
index 0000000..3c4f2c6
--- /dev/null
+++ b/dist/dualshock-controller/README.md
@@ -0,0 +1,194 @@
+node-dualshock-controller
+=========================
+[](https://travis-ci.org/rdepena/node-dualshock-controller) [](https://codeclimate.com/github/rdepena/node-dualshock-controller)
+
+`dualshock-controller` Eventing API layer over HID for the Sony DualShock 3 and DualShock 4 controllers
+
+## Installation:
+
+#### OSX/Windows:
+
+```bash
+npm install dualshock-controller
+```
+#### Linux:
+
+Review the [Linux support](#linux-support) section.
+
+## Using the DualShock library
+
+`Important: THE CONTROLLER WILL NOT SEND ANY DATA IF YOU DO NOT PRESS THE PS BUTTON.`
+
+Also, to use the touchpad, rumble and LED capabilities of the controller you
+must connect the controller to your computer using a micro-USB cable.
+
+~~~~ javascript
+var dualShock = require('dualshock-controller');
+
+//pass options to init the controller.
+var controller = dualShock(
+ {
+ //you can use a ds4 by uncommenting this line.
+ //config: "dualshock4-generic-driver",
+ //if the above configuration doesn't work for you,
+ //try uncommenting the following line instead.
+ //config: "dualshock4-alternate-driver"
+ //if using ds4 comment this line.
+ config: "dualShock3",
+ //smooths the output from the acelerometers (moving averages) defaults to true
+ accelerometerSmoothing: true,
+ //smooths the output from the analog sticks (moving averages) defaults to false
+ analogStickSmoothing: false
+ });
+
+//make sure you add an error event handler
+controller.on('error', err => console.log(err));
+
+//DualShock 4 control rumble and light settings for the controller
+controller.setExtras({
+ rumbleLeft: 0, // 0-255 (Rumble left intensity)
+ rumbleRight: 0, // 0-255 (Rumble right intensity)
+ red: 0, // 0-255 (Red intensity)
+ green: 75, // 0-255 (Blue intensity)
+ blue: 225, // 0-255 (Green intensity)
+ flashOn: 40, // 0-255 (Flash on time)
+ flashOff: 10 // 0-255 (Flash off time)
+});
+
+//DualShock 3 control rumble and light settings for the controller
+controller.setExtras({
+ rumbleLeft: 0, // 0-1 (Rumble left on/off)
+ rumbleRight: 0, // 0-255 (Rumble right intensity)
+ led: 2 // 2 | 4 | 8 | 16 (Leds 1-4 on/off, bitmasked)
+});
+
+//add event handlers:
+controller.on('left:move', data => console.log('left Moved: ' + data.x + ' | ' + data.y));
+
+controller.on('right:move', data => console.log('right Moved: ' + data.x + ' | ' + data.y));
+
+controller.on('connected', () => console.log('connected'));
+
+controller.on('square:press', ()=> console.log('square press'));
+
+controller.on('square:release', () => console.log('square release'));
+
+//sixasis motion events:
+//the object returned from each of the movement events is as follows:
+//{
+// direction : values can be: 1 for right, forward and up. 2 for left, backwards and down.
+// value : values will be from 0 to 120 for directions right, forward and up and from 0 to -120 for left, backwards and down.
+//}
+
+//DualShock 4 TouchPad
+//finger 1 is x1 finger 2 is x2
+controller.on('touchpad:x1:active', () => console.log('touchpad one finger active'));
+
+controller.on('touchpad:x2:active', () => console.log('touchpad two fingers active'));
+
+controller.on('touchpad:x2:inactive', () => console.log('touchpad back to single finger'));
+
+controller.on('touchpad:x1', data => console.log('touchpad x1:', data.x, data.y));
+
+controller.on('touchpad:x2', data => console.log('touchpad x2:', data.x, data.y));
+
+
+//right-left movement
+controller.on('rightLeft:motion', data => console.log(data));
+
+//forward-back movement
+controller.on('forwardBackward:motion', data => console.log(data));
+
+//up-down movement
+controller.on('upDown:motion', data => console.log(data));
+
+//controller status
+//as of version 0.6.2 you can get the battery %, if the controller is connected and if the controller is charging
+controller.on('battery:change', data => console.log(data));
+
+controller.on('connection:change', data => console.log(data));
+
+controller.on('charging:change', data => console.log(data));
+
+~~~~
+
+## Linux support:
+
+In order to provide Rumble/Gyro and LED support for all platforms the linux specific joystick implementation has been removed. This means you will need to:
+
+* [Install node-hid build requirements](#node-hid-build)
+* [Install node-hid with hidraw support](#node-hid-hidraw)
+* [create udev rules](#create-udev-rules)
+
+#### Install node-hid build requirements
+
+To build node-hid you will need to install:
+
+* libudev-dev
+* libusb-1.0-0
+* libusb-1.0-0-dev
+* build-essential
+* git
+* node-gyp
+* node-pre-gyp
+
+Using apt-get:
+
+```bash
+sudo apt-get install libudev-dev libusb-1.0-0 libusb-1.0-0-dev build-essential git
+```
+
+```bash
+npm install -g node-gyp node-pre-gyp
+```
+
+#### Install node-hid with hidraw support
+
+Once you have run the installation scripts above you can install the node-dualshock module, then replace the installed node-hid with hidraw support enabled node-hid:
+
+```bash
+npm install dualshock-controller
+```
+
+```bash
+npm install node-hid --driver=hidraw --build-from-source
+```
+
+#### Create udev rules
+
+You will need to create a udev rule to be able to access the hid stream as a non root user.
+
+Write the following file in `/etc/udev/rules.d/61-dualshock.rules`
+
+```
+SUBSYSTEM=="input", GROUP="input", MODE="0666"
+SUBSYSTEM=="usb", ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0268", MODE:="666", GROUP="plugdev"
+KERNEL=="hidraw*", SUBSYSTEM=="hidraw", MODE="0664", GROUP="plugdev"
+
+SUBSYSTEM=="input", GROUP="input", MODE="0666"
+SUBSYSTEM=="usb", ATTRS{idVendor}=="054c", ATTRS{idProduct}=="05c4", MODE:="666", GROUP="plugdev"
+KERNEL=="hidraw*", SUBSYSTEM=="hidraw", MODE="0664", GROUP="plugdev"
+```
+
+Reload the rules `sudo udevadm control --reload-rules`, then disconnect/connect the controller.
+
+The MIT License (MIT)
+
+Copyright (c) 2017 Ricardo de Pena
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/dist/dualshock-controller/controllerConfigurations/README.md b/dist/dualshock-controller/controllerConfigurations/README.md
new file mode 100644
index 0000000..195cc27
--- /dev/null
+++ b/dist/dualshock-controller/controllerConfigurations/README.md
@@ -0,0 +1,35 @@
+These json files are used to map the controller:
+=========================
+
+## To add a new controller:
+Use DeviceDiscoveryHelp.js in the examples folder, using node-hid you can obtain the values you need to create a controller.json file and leverage the library to wire it up.
+
+### To connect the right controller
+the vendorId and the productId need to be set to the right values, you can use node-hid to determine what these are.
+
+### Analogs are mapped as:
+~~~~ js
+"analogSticks" : [
+ {
+ "name" : "left",
+ "x" : 7,
+ "y" : 6
+ },
+ {
+ "name" : "right",
+ "x" : 9,
+ "y" : 8
+ }
+]
+
+### Buttons are usually grouped by a block but should be added as:
+
+~~~~ js
+"buttons" : [
+ {
+ "name": name of the button used for events,
+ "buttonBlock": int representing the button block,
+ "buttonValue": bit value,
+ "analogPin" : int representing the pin used for analog.
+ },
+]
diff --git a/dist/dualshock-controller/controllerConfigurations/dualShock3.json b/dist/dualshock-controller/controllerConfigurations/dualShock3.json
new file mode 100644
index 0000000..3d10283
--- /dev/null
+++ b/dist/dualshock-controller/controllerConfigurations/dualShock3.json
@@ -0,0 +1,244 @@
+{
+ "vendorId" : 1356,
+ "productId" : 616,
+ "analogSticks" : [
+ {
+ "name" : "left",
+ "x" : 6,
+ "y" : 7,
+ "joystickXNumber" : 0,
+ "joystickYNumber" : 1
+ },
+ {
+ "name" : "right",
+ "x" : 8,
+ "y" : 9,
+ "joystickXNumber" : 2,
+ "joystickYNumber" : 3
+ }
+ ],
+ "buttons" : [
+ {
+ "name": "l2",
+ "buttonBlock": 3,
+ "buttonValue": "0x01",
+ "analogPin" : 18,
+ "joystickNumber": 8
+ },
+ {
+ "name": "r2",
+ "buttonBlock": 3,
+ "buttonValue": "0x02",
+ "analogPin" : 19,
+ "joystickNumber" : 9
+ },
+ {
+ "name": "l1",
+ "buttonBlock": 3,
+ "buttonValue": "0x04",
+ "analogPin" : 20,
+ "joystickNumber" : 10
+ },
+ {
+ "name":"r1",
+ "buttonBlock": 3,
+ "buttonValue": "0x08",
+ "analogPin" : 21,
+ "joystickNumber" : 11
+ },
+ {
+ "name": "triangle",
+ "buttonBlock": 3,
+ "buttonValue": "0x10",
+ "analogPin" : 22,
+ "joystickNumber" : 12
+ },
+ {
+ "name": "circle",
+ "buttonBlock": 3,
+ "buttonValue": "0x20",
+ "analogPin" : 23,
+ "joystickNumber" : 13
+ },
+ {
+ "name": "x",
+ "buttonBlock": 3,
+ "buttonValue": "0x40",
+ "analogPin" : 24,
+ "joystickNumber" : 14
+ },
+ {
+ "name": "square",
+ "buttonBlock": 3,
+ "buttonValue": "0x80",
+ "analogPin": 25,
+ "joystickNumber" : 15
+ },
+ {
+ "name": "select",
+ "buttonBlock": 2,
+ "buttonValue": "0x1",
+ "joystickNumber" : 0
+ },
+ {
+ "name": "leftAnalogBump",
+ "buttonBlock": 2,
+ "buttonValue": "0x2",
+ "joystickNumber" : 1
+ },
+ {
+ "name": "rightAnalogBump",
+ "buttonBlock": 2,
+ "buttonValue": "0x4",
+ "joystickNumber" : 2
+ },
+ {
+ "name": "start",
+ "buttonBlock": 2,
+ "buttonValue": "0x08",
+ "joystickNumber" : 3
+ },
+ {
+ "name": "dpadUp",
+ "buttonBlock": 2,
+ "buttonValue": "0x10",
+ "analogPin": 14,
+ "joystickNumber" : 4
+ },
+ {
+ "name": "dpadRight",
+ "buttonBlock": 2,
+ "buttonValue": "0x20",
+ "analogPin": 15,
+ "joystickNumber" : 5
+ },
+ {
+ "name": "dpadDown",
+ "buttonBlock": 2,
+ "buttonValue" : "0x40",
+ "analogPin" : 16,
+ "joystickNumber" : 6
+ },
+ {
+ "name": "dpadLeft",
+ "buttonBlock": 2,
+ "buttonValue": "0x80",
+ "analogPin": 17,
+ "joystickNumber" : 7
+ },
+ {
+ "name": "psxButton",
+ "buttonBlock":4,
+ "buttonValue": "0x01",
+ "joystickNumber" : 16
+ }
+ ],
+ "motionInputs": [
+ {
+ "name" : "rightLeft",
+ "directionPin" : 41,
+ "valuePin" : 42
+ },
+ {
+ "name" : "forwardBackward",
+ "directionPin" : 43,
+ "valuePin" : 44
+ },
+ {
+ "name" : "upDown",
+ "directionPin" : 45,
+ "valuePin" : 46
+ },
+ {
+ "name" : "yaw",
+ "directionPin" : 47,
+ "valuePin" : 48
+ }
+ ],
+ "status": [
+ {
+ "name" : "charging",
+ "pin" : 29,
+ "states" : [
+ {
+ "value" : 0,
+ "state" : "Charging"
+ },
+ {
+ "value" : 2,
+ "state" : "Charging"
+ },
+ {
+ "value" : 3,
+ "state" : "Not Charging"
+ }
+ ]
+ },
+ {
+ "name" : "battery",
+ "pin" : 30,
+ "states" : [
+ {
+ "value" : 238,
+ "state" : "Charging"
+ },
+ {
+ "value" : 0,
+ "state" : "No charge"
+ },
+ {
+ "value" : 1,
+ "state" : "20%"
+ },
+ {
+ "value" : 2,
+ "state" : "40%"
+ },
+ {
+ "value" : 3,
+ "state" : "60%"
+ },
+ {
+ "value" : 4,
+ "state" : "80%"
+ },
+ {
+ "value" : 5,
+ "state" : "100%"
+ }
+ ]
+ },
+ {
+ "name" : "connection",
+ "pin" : 31,
+ "states" : [
+ {
+ "value" : 18,
+ "state" : "Usb"
+ },
+ {
+ "value" : 22,
+ "state" : "Bluetooth"
+ },
+ {
+ "value" : 20,
+ "state" : "Rumbling"
+ }
+ ]
+ }
+ ],
+ "output": {
+ "defaultBuffer":[
+ 1, 0, 254, 0, 254, 0, 0, 0, 0, 0, 0,
+ 255, 39, 16, 0, 50, 255, 39, 16, 0, 50, 255,
+ 39, 16, 0, 50, 255, 39, 16, 0, 50, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0
+ ],
+ "indexes": {
+ "rumbleLeft": 3,
+ "rumbleRight": 5,
+ "led": 10
+ }
+ }
+}
diff --git a/dist/dualshock-controller/controllerConfigurations/dualShock4-alternate-driver.json b/dist/dualshock-controller/controllerConfigurations/dualShock4-alternate-driver.json
new file mode 100644
index 0000000..bdc76e9
--- /dev/null
+++ b/dist/dualshock-controller/controllerConfigurations/dualShock4-alternate-driver.json
@@ -0,0 +1,177 @@
+{
+ "vendorId" : 1356,
+ "productId" : 2508,
+ "analogSticks" : [
+ {
+ "name" : "left",
+ "x" : 1,
+ "y" : 2
+ },
+ {
+ "name" : "right",
+ "x" : 3,
+ "y" : 4
+ }
+ ],
+ "buttons" : [
+ {
+ "name": "l2",
+ "buttonBlock": 6,
+ "buttonValue": "0x04",
+ "analogPin" : 8
+ },
+ {
+ "name": "r2",
+ "buttonBlock": 6,
+ "buttonValue": "0x08",
+ "analogPin" : 9
+ },
+ {
+ "name": "l1",
+ "buttonBlock": 6,
+ "buttonValue": "0x01"
+ },
+ {
+ "name": "r1",
+ "buttonBlock": 6,
+ "buttonValue": "0x02"
+ },
+ {
+ "name": "leftAnalogBump",
+ "buttonBlock": 6,
+ "buttonValue": "0x04"
+ },
+ {
+ "name": "rightAnalogBump",
+ "buttonBlock": 6,
+ "buttonValue": "0x08"
+ },
+ {
+ "name": "psxButton",
+ "buttonBlock": 7,
+ "buttonValue": "0x01"
+ },
+ {
+ "name": "touchPad",
+ "buttonBlock": 7,
+ "buttonValue": "0x02"
+ },
+ {
+ "name": "square",
+ "buttonBlock": 5,
+ "buttonValue": "0x10"
+ },
+ {
+ "name": "triangle",
+ "buttonBlock": 5,
+ "buttonValue": "0x80"
+ },
+ {
+ "name": "circle",
+ "buttonBlock": 5,
+ "buttonValue": "0x40"
+ },
+ {
+ "name": "x",
+ "buttonBlock": 5,
+ "buttonValue": "0x20"
+ },
+ {
+ "name": "dpadUp",
+ "buttonBlock": 5,
+ "buttonValue": "0x00",
+ "mask": "0xF"
+ },
+ {
+ "name": "dpadUpRight",
+ "buttonBlock": 5,
+ "buttonValue": "0x01",
+ "mask": "0xF"
+ },
+ {
+ "name": "dpadRight",
+ "buttonBlock": 5,
+ "buttonValue": "0x02",
+ "mask": "0xF"
+ },
+ {
+ "name": "dpadDownRight",
+ "buttonBlock": 5,
+ "buttonValue": "0x03",
+ "mask": "0xF"
+ },
+ {
+ "name": "dpadDown",
+ "buttonBlock": 5,
+ "buttonValue" : "0x04",
+ "mask": "0xF"
+ },
+ {
+ "name": "dpadDownLeft",
+ "buttonBlock": 5,
+ "buttonValue" : "0x05",
+ "mask": "0xF"
+ },
+ {
+ "name": "dpadLeft",
+ "buttonBlock": 5,
+ "buttonValue": "0x06",
+ "mask": "0xF"
+ },
+ {
+ "name": "dpadUpLeft",
+ "buttonBlock": 5,
+ "buttonValue": "0x07",
+ "mask": "0xF"
+ },
+ {
+ "name": "share",
+ "buttonBlock": 6,
+ "buttonValue": "0x10"
+ },
+ {
+ "name": "options",
+ "buttonBlock": 6,
+ "buttonValue": "0x20"
+ },
+ {
+ "name": "leftStick",
+ "buttonBlock": 6,
+ "buttonValue": "0x40"
+ },
+ {
+ "name": "rightStick",
+ "buttonBlock": 6,
+ "buttonValue": "0x80"
+ }
+ ],
+ "motionInputs" : [],
+ "status" : [],
+ "output": {
+ "defaultBuffer":[
+ 5,255,4,0,0,0,0,0,0,0,0
+ ],
+ "indexes": {
+ "rumbleLeft": 4,
+ "rumbleRight": 5,
+ "red": 6,
+ "green": 7,
+ "blue": 8,
+ "flashOn": 9,
+ "flashOff": 10
+ }
+ },
+ "touchPad": [{
+ "name":"x1",
+ "activePin": 35,
+ "dataPinA": 37,
+ "dataPinB": 36,
+ "dataPinC": 38
+ },{
+ "name": "x2",
+ "activePin": 39,
+ "dataPinA": 41,
+ "dataPinB": 40,
+ "dataPinC": 42
+ }]
+}
diff --git a/dist/dualshock-controller/controllerConfigurations/dualShock4-generic-driver.json b/dist/dualshock-controller/controllerConfigurations/dualShock4-generic-driver.json
new file mode 100644
index 0000000..5cdfda6
--- /dev/null
+++ b/dist/dualshock-controller/controllerConfigurations/dualShock4-generic-driver.json
@@ -0,0 +1,177 @@
+{
+ "vendorId" : 1356,
+ "productId" : 1476,
+ "analogSticks" : [
+ {
+ "name" : "left",
+ "x" : 1,
+ "y" : 2
+ },
+ {
+ "name" : "right",
+ "x" : 3,
+ "y" : 4
+ }
+ ],
+ "buttons" : [
+ {
+ "name": "l2",
+ "buttonBlock": 6,
+ "buttonValue": "0x04",
+ "analogPin" : 8
+ },
+ {
+ "name": "r2",
+ "buttonBlock": 6,
+ "buttonValue": "0x08",
+ "analogPin" : 9
+ },
+ {
+ "name": "l1",
+ "buttonBlock": 6,
+ "buttonValue": "0x01"
+ },
+ {
+ "name": "r1",
+ "buttonBlock": 6,
+ "buttonValue": "0x02"
+ },
+ {
+ "name": "leftAnalogBump",
+ "buttonBlock": 6,
+ "buttonValue": "0x04"
+ },
+ {
+ "name": "rightAnalogBump",
+ "buttonBlock": 6,
+ "buttonValue": "0x08"
+ },
+ {
+ "name": "psxButton",
+ "buttonBlock": 7,
+ "buttonValue": "0x01"
+ },
+ {
+ "name": "touchPad",
+ "buttonBlock": 7,
+ "buttonValue": "0x02"
+ },
+ {
+ "name": "square",
+ "buttonBlock": 5,
+ "buttonValue": "0x10"
+ },
+ {
+ "name": "triangle",
+ "buttonBlock": 5,
+ "buttonValue": "0x80"
+ },
+ {
+ "name": "circle",
+ "buttonBlock": 5,
+ "buttonValue": "0x40"
+ },
+ {
+ "name": "x",
+ "buttonBlock": 5,
+ "buttonValue": "0x20"
+ },
+ {
+ "name": "dpadUp",
+ "buttonBlock": 5,
+ "buttonValue": "0x00",
+ "mask": "0xF"
+ },
+ {
+ "name": "dpadUpRight",
+ "buttonBlock": 5,
+ "buttonValue": "0x01",
+ "mask": "0xF"
+ },
+ {
+ "name": "dpadRight",
+ "buttonBlock": 5,
+ "buttonValue": "0x02",
+ "mask": "0xF"
+ },
+ {
+ "name": "dpadDownRight",
+ "buttonBlock": 5,
+ "buttonValue": "0x03",
+ "mask": "0xF"
+ },
+ {
+ "name": "dpadDown",
+ "buttonBlock": 5,
+ "buttonValue" : "0x04",
+ "mask": "0xF"
+ },
+ {
+ "name": "dpadDownLeft",
+ "buttonBlock": 5,
+ "buttonValue" : "0x05",
+ "mask": "0xF"
+ },
+ {
+ "name": "dpadLeft",
+ "buttonBlock": 5,
+ "buttonValue": "0x06",
+ "mask": "0xF"
+ },
+ {
+ "name": "dpadUpLeft",
+ "buttonBlock": 5,
+ "buttonValue": "0x07",
+ "mask": "0xF"
+ },
+ {
+ "name": "share",
+ "buttonBlock": 6,
+ "buttonValue": "0x10"
+ },
+ {
+ "name": "options",
+ "buttonBlock": 6,
+ "buttonValue": "0x20"
+ },
+ {
+ "name": "leftStick",
+ "buttonBlock": 6,
+ "buttonValue": "0x40"
+ },
+ {
+ "name": "rightStick",
+ "buttonBlock": 6,
+ "buttonValue": "0x80"
+ }
+ ],
+ "motionInputs" : [],
+ "status" : [],
+ "output": {
+ "defaultBuffer":[
+ 5,255,4,0,0,0,0,0,0,0,0
+ ],
+ "indexes": {
+ "rumbleLeft": 4,
+ "rumbleRight": 5,
+ "red": 6,
+ "green": 7,
+ "blue": 8,
+ "flashOn": 9,
+ "flashOff": 10
+ }
+ },
+ "touchPad": [{
+ "name":"x1",
+ "activePin": 35,
+ "dataPinA": 37,
+ "dataPinB": 36,
+ "dataPinC": 38
+ },{
+ "name": "x2",
+ "activePin": 39,
+ "dataPinA": 41,
+ "dataPinB": 40,
+ "dataPinC": 42
+ }]
+}
diff --git a/dist/dualshock-controller/controllerConfigurations/dualShock4.json b/dist/dualshock-controller/controllerConfigurations/dualShock4.json
new file mode 100644
index 0000000..a3afc16
--- /dev/null
+++ b/dist/dualshock-controller/controllerConfigurations/dualShock4.json
@@ -0,0 +1,195 @@
+{
+ "vendorId" : 1356,
+ "productId" : 1476,
+ "analogSticks" : [
+ {
+ "name" : "left",
+ "x" : 1,
+ "y" : 2,
+ "joystickXNumber" : 0,
+ "joystickYNumber" : 1
+ },
+ {
+ "name" : "right",
+ "x" : 3,
+ "y" : 4,
+ "joystickXNumber" : 2,
+ "joystickYNumber" : 5
+ },
+ {
+ "name" : "l2Analog",
+ "x" : 100,
+ "joystickXNumber" : 3
+ },
+ {
+ "name" : "r2Analog",
+ "x" : 101,
+ "joystickXNumber" : 4
+ }
+ ],
+ "buttons" : [
+ {
+ "name": "l2",
+ "buttonBlock": 6,
+ "buttonValue": "0x04",
+ "analogPin" : 8,
+ "joystickNumber": 6
+ },
+ {
+ "name": "r2",
+ "buttonBlock": 6,
+ "buttonValue": "0x08",
+ "analogPin" : 9,
+ "joystickNumber": 7
+ },
+ {
+ "name": "l1",
+ "buttonBlock": 6,
+ "buttonValue": "0x01",
+ "joystickNumber": 4
+ },
+ {
+ "name": "r1",
+ "buttonBlock": 6,
+ "buttonValue": "0x02",
+ "joystickNumber": 5
+ },
+ {
+ "name": "psxButton",
+ "buttonBlock": 7,
+ "buttonValue": "0x01",
+ "joystickNumber": 12
+ },
+ {
+ "name": "touchPad",
+ "buttonBlock": 7,
+ "buttonValue": "0x02",
+ "joystickNumber": 13
+ },
+ {
+ "name": "square",
+ "buttonBlock": 5,
+ "buttonValue": "0x10",
+ "joystickNumber": 0
+ },
+ {
+ "name": "triangle",
+ "buttonBlock": 5,
+ "buttonValue": "0x80",
+ "joystickNumber": 3
+ },
+ {
+ "name": "circle",
+ "buttonBlock": 5,
+ "buttonValue": "0x40",
+ "joystickNumber": 2
+ },
+ {
+ "name": "x",
+ "buttonBlock": 5,
+ "buttonValue": "0x20",
+ "joystickNumber": 1
+ },
+ {
+ "name": "dpadUp",
+ "buttonBlock": 5,
+ "buttonValue": "0x00",
+ "mask": "0xF"
+ },
+ {
+ "name": "dpadUpRight",
+ "buttonBlock": 5,
+ "buttonValue": "0x01",
+ "mask": "0xF"
+ },
+ {
+ "name": "dpadRight",
+ "buttonBlock": 5,
+ "buttonValue": "0x02",
+ "mask": "0xF"
+ },
+ {
+ "name": "dpadDownRight",
+ "buttonBlock": 5,
+ "buttonValue": "0x03",
+ "mask": "0xF"
+ },
+ {
+ "name": "dpadDown",
+ "buttonBlock": 5,
+ "buttonValue" : "0x04",
+ "mask": "0xF"
+ },
+ {
+ "name": "dpadDownLeft",
+ "buttonBlock": 5,
+ "buttonValue" : "0x05",
+ "mask": "0xF"
+ },
+ {
+ "name": "dpadLeft",
+ "buttonBlock": 5,
+ "buttonValue": "0x06",
+ "mask": "0xF"
+ },
+ {
+ "name": "dpadUpLeft",
+ "buttonBlock": 5,
+ "buttonValue": "0x07",
+ "mask": "0xF"
+ },
+ {
+ "name": "share",
+ "buttonBlock": 6,
+ "buttonValue": "0x10",
+ "joystickNumber": 8
+ },
+ {
+ "name": "options",
+ "buttonBlock": 6,
+ "buttonValue": "0x20",
+ "joystickNumber": 9
+ },
+ {
+ "name": "leftStick",
+ "buttonBlock": 6,
+ "buttonValue": "0x40",
+ "joystickNumber": 10
+ },
+ {
+ "name": "rightStick",
+ "buttonBlock": 6,
+ "buttonValue": "0x80",
+ "joystickNumber": 11
+ }
+ ],
+ "motionInputs" : [],
+ "status" : [],
+ "output": {
+ "defaultBuffer":[
+ 5,255,4,0,0,0,0,0,0,0,0
+ ],
+ "indexes": {
+ "rumbleLeft": 4,
+ "rumbleRight": 5,
+ "red": 6,
+ "green": 7,
+ "blue": 8,
+ "flashOn": 9,
+ "flashOff": 10
+ }
+ },
+ "touchPad": [{
+ "name":"x1",
+ "activePin": 35,
+ "dataPinA": 37,
+ "dataPinB": 36,
+ "dataPinC": 38
+ },{
+ "name": "x2",
+ "activePin": 39,
+ "dataPinA": 41,
+ "dataPinB": 40,
+ "dataPinC": 42
+ }]
+}
diff --git a/dist/dualshock-controller/examples/README.md b/dist/dualshock-controller/examples/README.md
new file mode 100644
index 0000000..2f28345
--- /dev/null
+++ b/dist/dualshock-controller/examples/README.md
@@ -0,0 +1,8 @@
+Examples:
+=========================
+
+## Don't use this code as a starting point.
+I do things here that are not neccesary, you are better off looking at the readme in root as it has a cleaner implementation, this is here just so you can test it right away.
+
+If you'd like to see more examples for the DualShock 4, feel free to check out
+[ds-examples](https://github.com/itaisteinherz/ds-examples).
diff --git a/dist/dualshock-controller/examples/consolePrintControllerEvents.js b/dist/dualshock-controller/examples/consolePrintControllerEvents.js
new file mode 100644
index 0000000..45e3322
--- /dev/null
+++ b/dist/dualshock-controller/examples/consolePrintControllerEvents.js
@@ -0,0 +1,61 @@
+var printcontrollerEvents = function(controller, controllerConfiguration) {
+ 'use strict';
+ controller.on('left:move', function(data) {
+ console.log('left Moved');
+ console.log(data);
+ });
+ controller.on('right:move', function(data) {
+ console.log('right Moved');
+ console.log(data);
+ });
+ controller.on('connected', function() {
+ console.log('connected');
+ });
+
+ controller.on('error', function(data) {
+ console.log(data);
+ });
+
+ var pressed = function(data) {
+ console.log(data + ": press");
+ };
+ var released = function(data) {
+ console.log(data + ": release");
+ };
+ var analog = function(data) {
+ console.log(data + ": analog");
+ };
+ var hold = function(data) {
+ console.log(data + ": hold");
+ };
+ var motion = function(motionInput, data) {
+ console.log(motionInput);
+ console.log(data);
+ };
+ //subscribe to all the buttons:
+ for (var i = 0; i < controllerConfiguration.buttons.length; i++) {
+ controller.on(controllerConfiguration.buttons[i].name + ":press", pressed);
+ controller.on(controllerConfiguration.buttons[i].name + ":release", released);
+ controller.on(controllerConfiguration.buttons[i].name + ":analog", analog);
+ controller.on(controllerConfiguration.buttons[i].name + ":hold", hold);
+
+ }
+ //subscribe to all the status events:
+ if (controllerConfiguration.status && controllerConfiguration.status.length) {
+ for (i = 0; i < controllerConfiguration.status.length; i++) {
+ controller.on(controllerConfiguration.status[i].name + ":change", console.log);
+ }
+ }
+ //subscribe to the motion events.
+ controller.on('rightLeft' + ':motion', function(data) {
+ motion('rightLeft', data);
+ });
+ controller.on('forwardBackward' + ':motion', function(data) {
+ motion('forwardBackward', data);
+ });
+ controller.on('upDown' + ':motion', function(data) {
+ motion('upDown', data);
+ });
+};
+
+module.exports = printcontrollerEvents;
diff --git a/dist/dualshock-controller/examples/consolePrintDualShock3.js b/dist/dualshock-controller/examples/consolePrintDualShock3.js
new file mode 100644
index 0000000..078859a
--- /dev/null
+++ b/dist/dualshock-controller/examples/consolePrintDualShock3.js
@@ -0,0 +1,52 @@
+'use strict';
+var dualShock = require('./../src/dualshock.js');
+var dualShock3;
+
+//init the controller
+dualShock3 = dualShock({
+ analogStickSmoothing: false,
+ config: "dualShock3",
+ logging: true
+});
+
+// //for a client implementation we do not need this, this is only to test the inputs.
+var controllerConfiguration = require('./../controllerConfigurations/dualShock3');
+
+// //init the print events
+var consolePrintEvents = require('./consolePrintControllerEvents')(dualShock3, controllerConfiguration);
+
+dualShock3.on("dpadup:press", () => {
+ dualShock3.setExtras({
+ led: 2
+ });
+});
+
+dualShock3.on("dpadright:press", () => {
+ dualShock3.setExtras({
+ led: 4
+ });
+});
+
+dualShock3.on("dpaddown:press", () => {
+ dualShock3.setExtras({
+ led: 8
+ });
+});
+
+dualShock3.on("dpadleft:press", () => {
+ dualShock3.setExtras({
+ led: 16
+ });
+});
+
+dualShock3.on("r2:analog", (d) => {
+ dualShock3.setExtras({
+ rumbleRight: d
+ });
+});
+
+dualShock3.on("l2:press", (d) => {
+ dualShock3.setExtras({
+ rumbleLeft: 1
+ });
+});
diff --git a/dist/dualshock-controller/examples/consolePrintDualShock4.js b/dist/dualshock-controller/examples/consolePrintDualShock4.js
new file mode 100644
index 0000000..78ea7c4
--- /dev/null
+++ b/dist/dualshock-controller/examples/consolePrintDualShock4.js
@@ -0,0 +1,59 @@
+'use strict';
+var dualShock = require('./../src/dualshock.js');
+
+var dualShock4 = dualShock({
+ config: "dualShock4",
+ logging: true
+});
+
+//for a client implementation we do not need this, this is only to test the inputs.
+var controllerConfiguration = require('./../controllerConfigurations/dualShock4');
+
+//init the print events
+var consolePrintEvents = require('./consolePrintControllerEvents')(dualShock4, controllerConfiguration);
+
+dualShock4.on("dpadup:press", () => {
+ dualShock4.setExtras({
+ red: 255
+ });
+});
+
+dualShock4.on("dpadright:press", () => {
+ dualShock4.setExtras({
+ green: 255
+ });
+});
+
+dualShock4.on("dpaddown:press", () => {
+ dualShock4.setExtras({
+ blue: 255
+ });
+});
+
+dualShock4.on("dpadleft:press", () => {
+ dualShock4.setExtras({
+ red: 255,
+ green: 255,
+ blue: 255
+ });
+});
+
+dualShock4.on("x:press", (d) => {
+ dualShock4.setExtras({
+ red: 255,
+ flashOn: 50,
+ flashOff: 10
+ });
+});
+
+dualShock4.on("r2:analog", (d) => {
+ dualShock4.setExtras({
+ rumbleRight: d
+ });
+});
+
+dualShock4.on("l2:analog", (d) => {
+ dualShock4.setExtras({
+ rumbleLeft: d
+ });
+});
diff --git a/dist/dualshock-controller/examples/deviceDiscoveryHelp.js b/dist/dualshock-controller/examples/deviceDiscoveryHelp.js
new file mode 100644
index 0000000..e4d73a8
--- /dev/null
+++ b/dist/dualshock-controller/examples/deviceDiscoveryHelp.js
@@ -0,0 +1,12 @@
+var HID = require('node-hid');
+console.log(HID.devices());
+
+var controller = new HID.HID(1356, 616);
+
+controller.on('data', function(data) {
+ for (var i = 0; i < data.length; i++) {
+ if (i === 30) {
+ console.log(i + " " + data[i]);
+ }
+ }
+});
diff --git a/dist/dualshock-controller/examples/deviceDiscoveryHelpLinux.js b/dist/dualshock-controller/examples/deviceDiscoveryHelpLinux.js
new file mode 100644
index 0000000..bb143d9
--- /dev/null
+++ b/dist/dualshock-controller/examples/deviceDiscoveryHelpLinux.js
@@ -0,0 +1,6 @@
+var joystick = require('joystick'),
+ controller = new joystick(0, 256, 500);
+
+controller.on('button', console.log);
+
+controller.on('axis', console.log);
diff --git a/dist/dualshock-controller/gruntfile.js b/dist/dualshock-controller/gruntfile.js
new file mode 100644
index 0000000..60d5100
--- /dev/null
+++ b/dist/dualshock-controller/gruntfile.js
@@ -0,0 +1,67 @@
+const files = ['gruntfile.js',
+ 'src/*.js',
+ 'src/inputProcessors/*.js',
+ 'test/*.js',
+ 'examples/*.js'
+];
+module.exports = function(grunt) {
+ grunt.initConfig({
+ watch: {
+ files: files,
+ tasks: ['default']
+ },
+ jshint: {
+ files: files,
+ options: {
+ reporterOutput: "",
+ esnext: true,
+ node: true,
+ globals: {
+ describe: true,
+ it: true,
+ beforeEach: true
+ }
+ }
+ },
+ mochaTest: {
+ test: {
+ options: {
+ reporter: 'spec'
+ },
+ src: ['test/*.js']
+ }
+ },
+ jsbeautifier: {
+ files: files,
+ options: {
+ js: {
+ braceStyle: "collapse",
+ breakChainedMethods: false,
+ e4x: false,
+ evalCode: false,
+ indentChar: " ",
+ indentLevel: 0,
+ indentSize: 4,
+ indentWithTabs: false,
+ jslintHappy: false,
+ keepArrayIndentation: false,
+ keepFunctionIndentation: false,
+ maxPreserveNewlines: 10,
+ preserveNewlines: true,
+ spaceBeforeConditional: true,
+ spaceInParen: false,
+ unescapeStrings: false,
+ wrapLineLength: 0
+ }
+ }
+ }
+ });
+
+ grunt.loadNpmTasks('grunt-contrib-watch');
+ grunt.loadNpmTasks('grunt-contrib-jshint');
+ grunt.loadNpmTasks('grunt-mocha-test');
+ grunt.loadNpmTasks('grunt-jsbeautifier');
+
+ grunt.registerTask('test', ['jshint', 'mochaTest']);
+ grunt.registerTask('default', ['jshint', 'mochaTest', 'jsbeautifier']);
+};
diff --git a/dist/dualshock-controller/package.json b/dist/dualshock-controller/package.json
new file mode 100644
index 0000000..867b06d
--- /dev/null
+++ b/dist/dualshock-controller/package.json
@@ -0,0 +1,47 @@
+{
+ "name": "dualshock-controller",
+ "version": "1.1.1",
+ "description": "Eventing API layer over HID for the Sony DualShock 3 and DualShock 4 controllers ",
+ "main": "./src/dualshock.js",
+ "dependencies": {
+ "node-hid": "^0.5.0"
+ },
+ "devDependencies": {
+ "grunt": "^1.0.1",
+ "grunt-cli": "^1.2.0",
+ "grunt-contrib-jshint": "^1.1.0",
+ "grunt-contrib-watch": "^1.0.0",
+ "grunt-mocha-test": "^0.13.2",
+ "mocha": "^3.2.0",
+ "sinon": "^1.8",
+ "nyc": "^10.0.0",
+ "grunt-jsbeautifier": "^0.2.7",
+ "jshint": "^2.5.0",
+ "mockery": "^2.0.0"
+ },
+ "scripts": {
+ "test": "grunt test",
+ "coverage": "nyc npm test"
+ },
+ "engines": {
+ "node": ">=6.9.2"
+ },
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/rdepena/node-dualshock-controller.git"
+ },
+ "author": "ricardo de pena",
+ "license": "MIT",
+ "readmeFilename": "README.md",
+ "keywords": [
+ "ps3",
+ "controller",
+ "gamepad",
+ "dualshock",
+ "dualshock3",
+ "dualshock4",
+ "dual shock 3",
+ "dual shock 4",
+ "node-hid"
+ ]
+}
diff --git a/dist/dualshock-controller/src/HID.node b/dist/dualshock-controller/src/HID.node
new file mode 100644
index 0000000..1501c4f
Binary files /dev/null and b/dist/dualshock-controller/src/HID.node differ
diff --git a/dist/dualshock-controller/src/analogs.js b/dist/dualshock-controller/src/analogs.js
new file mode 100644
index 0000000..19b001e
--- /dev/null
+++ b/dist/dualshock-controller/src/analogs.js
@@ -0,0 +1,51 @@
+'use strict';
+// Module dependencies.
+var dsutilities = require('./utilities'),
+ Smoothing = require('./smoothing'),
+ config = require('./config');
+
+//Proccess Analog stick events.
+var Analogs = function(controller) {
+
+ var varianceThreshhold = 1,
+ smoothInput = config.getOptions().analogStickSmoothing,
+ outputSmoothing = new Smoothing(smoothInput),
+ analogSticks = config.getControllerConfig().analogSticks;
+
+ //Private methods
+ var processStick = function(analogStick, data) {
+ var currentValue = {
+ x: data[analogStick.x],
+ y: data[analogStick.y]
+ },
+ previousValue = {
+ x: outputSmoothing.readLastPosition(analogStick.name + 'x'),
+ y: outputSmoothing.readLastPosition(analogStick.name + 'y')
+ };
+
+ //we only raise an event if both
+ if (dsutilities.isWithinVariance(previousValue.x, currentValue.x, varianceThreshhold) ||
+ dsutilities.isWithinVariance(previousValue.y, currentValue.y, varianceThreshhold)) {
+
+ currentValue.x = outputSmoothing.smooth(analogStick.name + 'x', currentValue.x);
+ currentValue.y = outputSmoothing.smooth(analogStick.name + 'y', currentValue.y);
+
+ // Update and emit
+ if (controller[analogStick.name]) {
+ controller[analogStick.name].x = currentValue.x;
+ controller[analogStick.name].y = currentValue.y;
+ }
+ controller.emit(analogStick.name + ':move', currentValue);
+ }
+ };
+
+ // Public methods
+ //process all the analog events.
+ this.process = function(data) {
+ for (var i = 0; i < analogSticks.length; i++) {
+ processStick(analogSticks[i], data);
+ }
+ };
+};
+
+module.exports = Analogs;
diff --git a/dist/dualshock-controller/src/buttons.js b/dist/dualshock-controller/src/buttons.js
new file mode 100644
index 0000000..516938a
--- /dev/null
+++ b/dist/dualshock-controller/src/buttons.js
@@ -0,0 +1,104 @@
+'use strict';
+// Module dependencies.
+var config = require('./config'),
+ dsutilities = require('./utilities');
+
+//Proccess button events.
+var Buttons = function(controller) {
+
+ var buttons = config.getControllerConfig().buttons;
+
+ // convert strings to numbers, e.g. "0x01" to 0x01
+ // must be converted because JSON doesn't allow numbers with leading zeros
+ buttons.forEach(function(button) {
+ if (typeof button.buttonValue == "string") {
+ button.buttonValue = parseInt(button.buttonValue);
+ }
+
+ if (typeof button.mask == "string") {
+ button.mask = parseInt(button.mask);
+ } else if (!(button.mask instanceof Number)) {
+ button.mask = 0xFF;
+ }
+
+ //generate event name aliases:
+ button.eventPrefixes = dsutilities.generateEventPrefixAliases(button.name);
+ });
+
+
+ var buffer = {};
+
+ //Private methods
+ var emitEvent = function(button, eventText, data) {
+ button.eventPrefixes.forEach(function(eventPrefix) {
+ controller.emit(eventPrefix + eventText, data);
+ });
+ };
+ var processButton = function(button, data) {
+ //make sure the data contains a value for the specified block
+ //and bitwise operation for the button value
+
+ var block = data[button.buttonBlock] & button.mask;
+ var hit = (block & button.buttonValue) == button.buttonValue;
+ var value = 0;
+ var state = 0; // 0: up, 1: down, 2: hold
+
+ // special case for the dualshock 4's dpadUp button as it causes the
+ // lower 8 bits of it's block to be zeroed
+ if (!button.buttonValue) {
+ hit = !block;
+ }
+
+ // special case for dualshock 4's dpad - they are not bitmasked values as
+ // they cannot be pressed together - ie. up, left and upleft are three
+ // different values - upleft is not equal to up & left
+ if (button.buttonBlock == 5 && block < 0x08) {
+ hit = block == button.buttonValue;
+ }
+
+ if (hit) {
+ value = 1;
+
+ //if the button is in the released state.
+ if (!buffer[button.name]) {
+ state = 1;
+ buffer[button.name] = true;
+ emitEvent(button, ':press', button.name);
+ } else {
+ state = 2;
+ emitEvent(button, ':hold', button.name);
+ }
+
+ //send the analog data
+ if (button.analogPin && data[button.analogPin]) {
+ emitEvent(button, ':analog', data[button.analogPin]);
+ }
+
+ } else if (buffer[button.name]) {
+ //button was pressed and is not released
+ buffer[button.name] = false;
+
+ //button is no longer pressed, emit a analog 0 event.
+ if (button.analogPin) {
+ emitEvent(button, ':analog', 0);
+ }
+ //emit the released event.
+ emitEvent(button, ':release', button.name);
+ }
+
+ if (controller[button.name]) {
+ controller[button.name].value = value;
+ controller[button.name].state = state;
+ }
+ };
+
+ // Public methods
+ //process all the analog events.
+ this.process = function(data) {
+ for (var i = 0; i < buttons.length; i++) {
+ processButton(buttons[i], data);
+ }
+ };
+};
+
+module.exports = Buttons;
diff --git a/dist/dualshock-controller/src/config.js b/dist/dualshock-controller/src/config.js
new file mode 100644
index 0000000..1901dfe
--- /dev/null
+++ b/dist/dualshock-controller/src/config.js
@@ -0,0 +1,56 @@
+'use strict';
+// Module dependencies.
+// we will expose these objects via the manager.
+var options,
+ controllerConfig;
+
+//provides access to the current options and configs.
+var config = {
+ setOptions: function(opts) {
+ //no options were passed
+ options = opts || {};
+
+ // Defaults:
+ var defaultValues = {
+ config: "dualShock3",
+ accelerometerSmoothing: true,
+ analogStickSmoothing: false,
+ logging: false,
+ forceNodeHid: false,
+ linuxJoystickId: 0
+ };
+
+ for (var name in defaultValues) {
+ if (defaultValues.hasOwnProperty(name)) {
+ var target = options[name];
+ var orig = defaultValues[name];
+
+ if (!target) {
+ options[name] = orig;
+ }
+ }
+ }
+
+ var controllerConfiguration;
+ //use passed config or load from built-in configs
+ if (typeof options.config === "object") {
+ controllerConfiguration = options.config;
+ } else {
+ controllerConfiguration = require('./../controllerConfigurations/' + options.config);
+ }
+
+ //set the current controllerConfiguration
+ config.setControllerConfig(controllerConfiguration);
+ },
+ getOptions: function() {
+ return options;
+ },
+ setControllerConfig: function(config) {
+ controllerConfig = config;
+ },
+ getControllerConfig: function() {
+ return controllerConfig;
+ }
+};
+
+module.exports = config;
diff --git a/dist/dualshock-controller/src/controller.js b/dist/dualshock-controller/src/controller.js
new file mode 100644
index 0000000..f6760c3
--- /dev/null
+++ b/dist/dualshock-controller/src/controller.js
@@ -0,0 +1,167 @@
+// Module dependencies.
+const util = require('util'),
+ dsutilities = require('./utilities'),
+ Emitter = require('events').EventEmitter,
+ Gyro = require('./gyro'),
+ Analogs = require('./analogs'),
+ Buttons = require('./buttons'),
+ Status = require('./status'),
+ HID = require('./HID'),
+ config = require('./config'),
+ TouchPad = require('./touchpad');
+
+//generic controller object, it will need a controller Configuration with a buttons array passed into its connect function.
+const Controller = function() {
+ 'use strict';
+ Emitter.call(this);
+
+ const controllerConfig = config.getControllerConfig(),
+ options = config.getOptions(),
+ indexes = controllerConfig.output.indexes,
+ analogs = new Analogs(this),
+ buttons = new Buttons(this),
+ gyro = new Gyro(this),
+ status = new Status(this),
+ touchPad = new TouchPad(this);
+
+ let device = null;
+
+ [{
+ type: 'analogSticks',
+ properties: [{
+ name: 'x',
+ initialValue: 0
+ }, {
+ name: 'y',
+ initialValue: 0
+ }]
+ }, {
+ type: 'buttons',
+ properties: [{
+ name: 'state',
+ initialValue: 0
+ }, {
+ name: 'value',
+ initialValue: 0
+ }]
+ }, {
+ type: 'motionInputs',
+ properties: [{
+ name: 'value',
+ initialValue: 0
+ }, {
+ name: 'direction',
+ initialValue: 0
+ }]
+ }, {
+ type: 'status',
+ properties: [{
+ name: 'state',
+ initialValue: ''
+ }]
+ }].forEach(function(setup) {
+ const entities = controllerConfig[setup.type],
+ properties = setup.properties;
+
+ if (entities.length) {
+ entities.forEach(function(entity) {
+ this[entity.name] = properties.reduce(function(accum, property) {
+ return (accum[property.name] = property.initialValue, accum);
+ }, {});
+ }, this);
+ }
+ }, this);
+
+ //Private methods
+ //emit an error event or log it to the console.
+ const handleException = function(ex) {
+ //if exception was generated within our stream
+ if (this && this.emit) {
+ this.emit('error', ex);
+ } else {
+ dsutilities.warn(ex);
+ throw (ex);
+ }
+ };
+
+ //process data from HID connected device.
+ const processFrame = function(data) {
+ if (controllerConfig.motionInputs) {
+ gyro.process(data);
+ }
+ if (controllerConfig.analogSticks) {
+ analogs.process(data);
+ }
+ if (controllerConfig.buttons) {
+ buttons.process(data);
+ }
+ if (controllerConfig.status) {
+ status.process(data);
+ }
+ if (controllerConfig.touchPad) {
+ touchPad.process(data);
+ }
+ };
+
+ const isController = function(device) {
+ var vendor = (device.vendorId == controllerConfig.vendorId);
+ var product = (device.productId == controllerConfig.productId || device.productId == 2508);
+ return vendor && product;
+ };
+
+ // Public methods
+ this.connect = function() {
+ dsutilities.warn('connect method is deprecated, controller now connects upon declaration.');
+ };
+
+ this.disconnect = function() {
+ if (device && device.close) {
+ device.close();
+ }
+ this.emit('disconnecting');
+ dsutilities.warn('node dualshock disconnecting');
+ };
+
+ // Used to set controller rumble and light
+ this.setExtras = function(data) {
+
+ let buff = controllerConfig.output.defaultBuffer.slice();
+
+ Object.keys(data).forEach(k => {
+ buff[indexes[k]] = data[k];
+ });
+ device.write(buff);
+ };
+
+ //connect to the controller.
+ if (typeof options.device === 'undefined') {
+ dsutilities.warn('node dualshock connecting');
+ var devices = HID.devices();
+
+ const deviceMeta = devices
+ .filter(isController)[0];
+ if (deviceMeta) {
+ device = new HID.HID(deviceMeta.path);
+ console.log(device);
+ device.on('data', processFrame.bind(this));
+ device.on('error', handleException.bind(this));
+ } else {
+ handleException(new Error(`device with Vendor ID:${controllerConfig.vendorId} Product ID:${controllerConfig.productId} not found`));
+ }
+
+ } else {
+ // Allow user-specified device
+ device = options.device;
+ console.log("Custom device: ", device);
+ device.on('data', processFrame.bind(this));
+ device.on('error', handleException.bind(this));
+ }
+
+ //subscribe to the exit event:
+ process.on('exit', this.disconnect.bind(this));
+};
+
+//need to inherit from event emiter.
+util.inherits(Controller, Emitter);
+
+module.exports = Controller;
diff --git a/dist/dualshock-controller/src/dualshock.js b/dist/dualshock-controller/src/dualshock.js
new file mode 100644
index 0000000..48b9b22
--- /dev/null
+++ b/dist/dualshock-controller/src/dualshock.js
@@ -0,0 +1,22 @@
+// Module dependencies.
+var Controller = require('./controller'),
+ config = require('./config');
+
+// This is the app entry point.
+// options you can pass:
+// {
+// config : "File from controllerConfigurations" or a JS object containing configuration,
+// accelerometerSmoothing : true/false, this will activate motion/acelerometer output smoothing. true by default.
+// analogStickSmoothing : true/false, this will activate analog thumb stick smoothing
+// }
+var dualShock = function(options) {
+ 'use strict';
+
+ //set the current options
+ config.setOptions(options);
+
+ //returns the controller.
+ return new Controller();
+};
+
+module.exports = dualShock;
diff --git a/dist/dualshock-controller/src/gyro.js b/dist/dualshock-controller/src/gyro.js
new file mode 100644
index 0000000..9635c46
--- /dev/null
+++ b/dist/dualshock-controller/src/gyro.js
@@ -0,0 +1,72 @@
+'use strict';
+// Module dependencies.
+var dsutilities = require('./utilities'),
+ Smoothing = require('./smoothing'),
+ config = require('./config');
+
+//Proccess button events.
+var motionProcessor = function(controller) {
+
+ var varianceThreshhold = 1,
+ smoothInput = config.getOptions().accelerometerSmoothing,
+ outputSmoothing = new Smoothing(smoothInput),
+ motionInputs = config.getControllerConfig().motionInputs;
+
+ //generate event name aliases:
+ motionInputs.forEach(function(motionAxis) {
+ motionAxis.eventPrefixes = dsutilities.generateEventPrefixAliases(motionAxis.name);
+ });
+
+ //Private methods
+ //data corrections so that each dirrection has a 0 throug x value
+ var correctData = function(motionAxis, data) {
+ var value;
+ //ensuring that both directions start from 0 and move to -x or x;
+ if (data[motionAxis.directionPin] === 1) {
+ //we need the values to be from 0 to x.
+ value = 255 - data[motionAxis.valuePin];
+ } else if (data[motionAxis.directionPin] === 2) {
+ //going in the oposite direction, we need to values to be from 0 to -x;
+ value = data[motionAxis.valuePin] * -1;
+ }
+
+ //return an object with both value and dirrection.
+ return {
+ direction: data[motionAxis.directionPin],
+ value: value
+ };
+ };
+
+ //process the axis movement.
+ var processAxis = function(motionAxis, data) {
+ //every motion will have a dirrection and a value
+ var motionValue = correctData(motionAxis, data),
+ lastPosition = outputSmoothing.readLastPosition(motionAxis.name);
+
+ //check if the values are within variance
+ if (dsutilities.isWithinVariance(lastPosition, motionValue.value, varianceThreshhold)) {
+ motionValue.value = outputSmoothing.smooth(motionAxis.name, motionValue.value);
+
+ // Don't assign motionValue directly to controller[motionAxis.name],
+ // this will break the reference.
+ if (controller[motionAxis.name]) {
+ controller[motionAxis.name].value = motionValue.value;
+ controller[motionAxis.name].direction = motionValue.direction;
+ }
+
+ motionAxis.eventPrefixes.forEach(function(eventPrefix) {
+ controller.emit(eventPrefix + ':motion', motionValue);
+ });
+ }
+ };
+
+ // Public methods
+ //process all configured motion inputs.
+ this.process = function(data) {
+ for (var i = 0; i < motionInputs.length; i++) {
+ processAxis(motionInputs[i], data);
+ }
+ };
+};
+
+module.exports = motionProcessor;
diff --git a/dist/dualshock-controller/src/smoothing.js b/dist/dualshock-controller/src/smoothing.js
new file mode 100644
index 0000000..5a20160
--- /dev/null
+++ b/dist/dualshock-controller/src/smoothing.js
@@ -0,0 +1,50 @@
+// Module dependencies.
+
+//smooths data with moving average
+var outputSmoothing = function(smoothInput) {
+ 'use strict';
+
+ var buffer = {},
+ maxFrames = 5;
+
+ // Public methods
+ this.readLastPosition = function(motionAxisName) {
+ var axisBuffer = buffer[motionAxisName];
+ return axisBuffer ? axisBuffer[axisBuffer.length - 1] : null;
+ };
+
+ this.addToBuffer = function(motionAxisName, value) {
+ if (buffer[motionAxisName]) {
+ //add the current value to the buffer
+ buffer[motionAxisName].push(value);
+
+ //remove the head of the buffer
+ if (buffer[motionAxisName].length > maxFrames) {
+ buffer[motionAxisName].shift();
+ }
+ } else {
+ //create an array with the value.
+ buffer[motionAxisName] = [value];
+ }
+ };
+
+ //smooth using a moving average.
+ this.smooth = function(motionAxisName, value) {
+ this.addToBuffer(motionAxisName, value);
+ var axisBuffer = buffer[motionAxisName],
+ sum = 0,
+ smoothedVal = value;
+
+ if (smoothInput) {
+ for (var i = 0; i < axisBuffer.length; i++) {
+ sum += axisBuffer[i];
+ }
+ smoothedVal = Math.floor(sum / axisBuffer.length);
+ }
+
+ return smoothedVal;
+
+ };
+};
+
+module.exports = outputSmoothing;
diff --git a/dist/dualshock-controller/src/status.js b/dist/dualshock-controller/src/status.js
new file mode 100644
index 0000000..016e9da
--- /dev/null
+++ b/dist/dualshock-controller/src/status.js
@@ -0,0 +1,36 @@
+'use strict';
+// Module dependencies.
+
+var config = require('./config');
+
+//Proccess button events.
+var Status = function(controller) {
+
+ var buffer = {},
+ status = config.getControllerConfig().status;
+
+ var processControllerStatus = function(category, data) {
+ var state;
+ for (var i = 0; i < category.states.length; i++) {
+ if (data[category.pin] === category.states[i].value) {
+ state = category.states[i].state;
+ }
+ }
+
+ if (buffer[category.name] !== state) {
+ if (controller[category.name]) {
+ controller[category.name].state = state;
+ }
+ controller.emit(category.name + ':change', state);
+ }
+ buffer[category.name] = state;
+ };
+
+ this.process = function(data) {
+ for (var i = 0; i < status.length; i++) {
+ processControllerStatus(status[i], data);
+ }
+ };
+};
+
+module.exports = Status;
diff --git a/dist/dualshock-controller/src/touchpad.js b/dist/dualshock-controller/src/touchpad.js
new file mode 100644
index 0000000..af7674f
--- /dev/null
+++ b/dist/dualshock-controller/src/touchpad.js
@@ -0,0 +1,52 @@
+const config = require('./config');
+
+function genpBufferFromConf(tpAxis) {
+ return {
+ name: tpAxis.name,
+ active: false,
+ data: {
+ x: 0,
+ y: 0
+ }
+ };
+}
+
+module.exports = function TouchPad(controller) {
+ const touchPad = config.getControllerConfig().touchPad;
+ let pBuffer = {};
+
+ function processIsActive(buffer, tpAxis) {
+ const active = buffer[tpAxis.activePin] < 128;
+ const axisBuffer = pBuffer[tpAxis.name];
+ const evt = active ? 'active' : 'inactive';
+
+ if (active !== axisBuffer.active) {
+ controller.emit(`touchpad:${tpAxis.name}:${evt}`);
+ }
+
+ axisBuffer.active = active;
+ }
+
+ function processData(buffer, tpAxis) {
+ const axisBuffer = pBuffer[tpAxis.name];
+
+ if (axisBuffer.active) {
+ axisBuffer.data.x = ((buffer[tpAxis.dataPinA] & 15) << 8 | buffer[tpAxis.dataPinB]);
+ axisBuffer.data.y = buffer[tpAxis.dataPinC] << 4 | ((buffer[tpAxis.dataPinA] & 240) >> 4);
+ controller.emit(`touchpad:${tpAxis.name}`, axisBuffer.data);
+ }
+
+ }
+
+ this.process = function process(buffer) {
+ for (let i = 0; i < touchPad.length; i++) {
+ //if we have not built a pBuffer profile for this axis lets build it.
+ if (!pBuffer[touchPad[i].name]) {
+ pBuffer[touchPad[i].name] = genpBufferFromConf(touchPad[i]);
+ }
+
+ processIsActive(buffer, touchPad[i]);
+ processData(buffer, touchPad[i]);
+ }
+ };
+};
diff --git a/dist/dualshock-controller/src/utilities.js b/dist/dualshock-controller/src/utilities.js
new file mode 100644
index 0000000..089d063
--- /dev/null
+++ b/dist/dualshock-controller/src/utilities.js
@@ -0,0 +1,34 @@
+'use strict';
+// Module dependencies.
+
+var config = require('./config');
+
+var unique = function unique(x) {
+ var result = [];
+ for (var i = 0; i < x.length; i++) {
+ if ((result.indexOf(x[i]) < 0)) {
+ result.push(x[i]);
+ }
+ }
+ return result;
+};
+
+//provide a few utility functions.
+module.exports = {
+
+ //reduces noise from the controller
+ isWithinVariance: function(x, y, varianceThreshhold) {
+ return Math.abs(x - y) > varianceThreshhold;
+ },
+ warn: function(message) {
+ if (config.getOptions().logging) {
+ console.log(message);
+ }
+ },
+ generateEventPrefixAliases: function(eventPrefix) {
+ return unique([
+ eventPrefix,
+ eventPrefix.toLowerCase()
+ ]);
+ }
+};
diff --git a/dist/dualshock-controller/test/analog.tests.js b/dist/dualshock-controller/test/analog.tests.js
new file mode 100644
index 0000000..3291715
--- /dev/null
+++ b/dist/dualshock-controller/test/analog.tests.js
@@ -0,0 +1,84 @@
+// Module dependencies.
+var Analogs = require('../src/analogs'),
+ assert = require('assert'),
+ sinon = require('sinon'),
+ EventEmitter = require('events').EventEmitter,
+ config = require('../src/config');
+
+describe('the Analogs component', function() {
+ 'use strict';
+
+ var mockConfig = [{
+ "name": "analog",
+ "x": 0,
+ "y": 1
+ }],
+ instance = [{
+ name: 'process'
+ }],
+ dataA = [50, 65],
+ dataB = [0, 0],
+ analogs,
+ emitter,
+ spy;
+
+ beforeEach(function() {
+ emitter = new EventEmitter();
+ config.setOptions({
+ analogStickSmoothing: false
+ });
+ config.setControllerConfig({
+ analogSticks: mockConfig
+ });
+ analogs = new Analogs(emitter);
+ spy = new sinon.spy();
+ });
+
+ describe('object instance', function() {
+ it('should have the following shape', function() {
+ //make sure we find these functions.
+ instance.forEach(function(method) {
+ assert.equal(typeof analogs[method.name], 'function');
+ });
+ });
+ });
+
+ describe('move events', function() {
+ it('should invoke the move event', function() {
+ emitter.on('analog:move', spy);
+ analogs.process(dataA);
+
+ assert.equal(spy.called, true);
+ });
+ it('should not invoke the move event', function() {
+ emitter.on('analog:move', spy);
+ analogs.process(dataB);
+
+ assert.equal(spy.called, false);
+ });
+ it('should invoke the move event with zero', function() {
+ analogs.process(dataA);
+ emitter.on('analog:move', spy);
+ analogs.process(dataB);
+
+ assert.equal(spy.called, true);
+ });
+ });
+
+ describe('return values', function() {
+ it('should return the analog values', function() {
+ emitter.on('analog:move', spy);
+ analogs.process(dataA);
+ var expectedValue = {
+ x: 50,
+ y: 65
+ },
+ spyArgument = spy.args[0][0];
+
+ assert.equal(expectedValue.x, spyArgument.x);
+ assert.equal(expectedValue.y, spyArgument.y);
+ assert.equal(spy.called, true);
+ });
+ });
+
+});
diff --git a/dist/dualshock-controller/test/buttons.tests.js b/dist/dualshock-controller/test/buttons.tests.js
new file mode 100644
index 0000000..f7a8688
--- /dev/null
+++ b/dist/dualshock-controller/test/buttons.tests.js
@@ -0,0 +1,178 @@
+// Module dependencies.
+var Buttons = require('../src/buttons'),
+ assert = require('assert'),
+ sinon = require('sinon'),
+ EventEmitter = require('events').EventEmitter,
+ config = require('../src/config');
+
+describe('the Buttons component', function() {
+ 'use strict';
+
+ var mockConfig = [{
+ "name": "buttonName",
+ "buttonBlock": 0,
+ "buttonValue": "0x08",
+ "analogPin": 1
+ }, {
+ "name": "dpadUp",
+ "buttonBlock": 5,
+ "buttonValue": "0x00",
+ "mask": "0xF"
+ }, {
+ "name": "dpadDown",
+ "buttonBlock": 5,
+ "buttonValue": "0x01",
+ "mask": "0xF"
+ }],
+ instance = [{
+ name: 'process'
+ }],
+ dataA = [8, 170],
+ dataB = [0, 0],
+ buttons,
+ emitter,
+ spy,
+ spyLowerCaseEvents;
+
+ beforeEach(function() {
+ emitter = new EventEmitter();
+ config.setControllerConfig({
+ buttons: mockConfig
+ });
+ buttons = new Buttons(emitter);
+ spy = new sinon.spy();
+ spyLowerCaseEvents = new sinon.spy();
+
+ });
+
+ describe('object instance', function() {
+ it('should have the following shape', function() {
+ //make sure we find these functions.
+ instance.forEach(function(method) {
+ assert.equal(typeof buttons[method.name], 'function');
+ });
+ });
+ });
+
+ describe('press events', function() {
+ it('should envoke the buttonName:press', function() {
+ emitter.on('buttonName:press', spy);
+ emitter.on('buttonname:press', spyLowerCaseEvents);
+ buttons.process(dataA);
+
+ assert.equal(spy.called, true);
+ assert.equal(spyLowerCaseEvents.called, true);
+ });
+ it('should not envoke the buttonName:press', function() {
+ emitter.on('buttonName:release', spy);
+ emitter.on('buttonname:release', spyLowerCaseEvents);
+ buttons.process(dataB);
+
+ assert.equal(spy.called, false);
+ assert.equal(spyLowerCaseEvents.called, false);
+ });
+ });
+
+ describe('release events', function() {
+ it('should envoke the buttonName:release', function() {
+ emitter.on('buttonName:release', spy);
+ emitter.on('buttonname:release', spyLowerCaseEvents);
+ buttons.process(dataA);
+ buttons.process(dataB);
+
+ assert.equal(spy.called, true);
+ assert.equal(spyLowerCaseEvents.called, true);
+ });
+ it('should not envoke the buttonName:release', function() {
+ emitter.on('buttonName:release', spy);
+ emitter.on('buttonname:release', spyLowerCaseEvents);
+ buttons.process(dataA);
+
+ assert.equal(spy.called, false);
+ assert.equal(spyLowerCaseEvents.called, false);
+ });
+ });
+
+ describe('button hold', function() {
+ it('should raise the hold event', function() {
+ emitter.on('buttonName:hold', spy);
+ emitter.on('buttonname:hold', spyLowerCaseEvents);
+ buttons.process(dataA);
+ buttons.process(dataA);
+ assert.equal(spy.args[0][0], 'buttonName');
+ assert.equal(spy.called, true);
+ assert.equal(spyLowerCaseEvents.called, true);
+ });
+
+ it('should not raise the hold event', function() {
+ emitter.on('buttonName:hold', spy);
+ emitter.on('buttonname:hold', spyLowerCaseEvents);
+ buttons.process(dataB);
+ buttons.process(dataB);
+ assert.equal(spy.called, false);
+ assert.equal(spyLowerCaseEvents.called, false);
+ });
+ });
+
+ describe('button analog', function() {
+ it('should raise the analog event', function() {
+ emitter.on('buttonName:analog', spy);
+ emitter.on('buttonname:analog', spyLowerCaseEvents);
+ buttons.process(dataA);
+
+ assert.equal(spy.args[0][0], dataA[1]);
+ assert.equal(spy.called, true);
+ assert.equal(spyLowerCaseEvents.called, true);
+ });
+
+ it('should not raise the analog event', function() {
+ emitter.on('buttonName:analog', spy);
+ emitter.on('buttonname:analog', spyLowerCaseEvents);
+ buttons.process(dataB);
+
+ assert.equal(spy.called, false);
+ assert.equal(spyLowerCaseEvents.called, false);
+ });
+ });
+
+ describe('ps4 dpad up button', function() {
+ it('should emit the dpadUp:press event', function() {
+ emitter.on('dpadUp:press', spy);
+ emitter.on('dpadup:press', spyLowerCaseEvents);
+ buttons.process([0, 0, 0, 0, 0, 0]);
+
+ assert.equal(spy.called, true);
+ assert.equal(spyLowerCaseEvents.called, true);
+ });
+
+ it('should not emit the dpadDown:press event', function() {
+ emitter.on('dpadDown:press', spy);
+ emitter.on('dpaddown:press', spyLowerCaseEvents);
+ buttons.process([0, 0, 0, 0, 0, 0]);
+
+ assert.equal(spy.called, false);
+ assert.equal(spyLowerCaseEvents.called, false);
+ });
+ });
+
+ describe('ps4 dpad down button', function() {
+ it('should emit the dpadDown:press event', function() {
+ emitter.on('dpadDown:press', spy);
+ emitter.on('dpaddown:press', spyLowerCaseEvents);
+ buttons.process([0, 0, 0, 0, 0, parseInt("00001001", 2)]);
+
+ assert.equal(spy.called, true);
+ assert.equal(spyLowerCaseEvents.called, true);
+ });
+
+ it('should not emit the dpadUp:press event', function() {
+ emitter.on('dpadUp:press', spy);
+ emitter.on('dpadup:press', spyLowerCaseEvents);
+ buttons.process([0, 0, 0, 0, 0, parseInt("00001001", 2)]);
+
+ assert.equal(spy.called, false);
+ assert.equal(spyLowerCaseEvents.called, false);
+ });
+ });
+
+});
diff --git a/dist/dualshock-controller/test/config.tests.js b/dist/dualshock-controller/test/config.tests.js
new file mode 100644
index 0000000..8ca5e64
--- /dev/null
+++ b/dist/dualshock-controller/test/config.tests.js
@@ -0,0 +1,91 @@
+'use strict';
+
+var assert = require('assert');
+
+describe('The Config component', function() {
+ var mockConfig = {
+ vendorId: 1556,
+ productId: 616,
+ output: []
+ },
+ mockOptions = {
+ config: 'dualShock3',
+ accelerometerSmoothing: true,
+ logging: false
+ },
+ instance = [{
+ name: 'setOptions'
+ }, {
+ name: 'getOptions'
+ }, {
+ name: 'setControllerConfig'
+ }, {
+ name: 'getControllerConfig'
+ }],
+ defaultOptionsInstance = [{
+ name: 'config'
+ }, {
+ name: 'accelerometerSmoothing'
+ }, {
+ name: 'analogStickSmoothing'
+ }],
+ configA,
+ configB;
+
+ beforeEach(function() {
+ configA = require('../src/config');
+ configB = require('../src/config');
+ });
+
+
+ describe('object instance', function() {
+ it('should have the following shape', function() {
+ instance.forEach(function(method) {
+ assert.equal(typeof configA[method.name], 'function');
+ });
+ });
+ });
+
+ describe('option methods', function() {
+ it('should be able to save options', function() {
+ configA.setOptions(mockOptions);
+ assert.equal(configA.getOptions(), mockOptions);
+ });
+
+ it('should provide a single object accross instances', function() {
+ configA.setOptions(mockOptions);
+ assert.equal(configA.getOptions(), configB.getOptions());
+ });
+ });
+
+ describe('controllerConfig methods', function() {
+ it('should be able to save controllerConfig settings', function() {
+ configA.setControllerConfig(mockConfig);
+ //change the object
+ mockConfig.vendorId = 22;
+ assert.equal(configA.getControllerConfig(), mockConfig);
+ });
+
+ it('should provide a single object accross instances', function() {
+ configA.setControllerConfig(mockConfig);
+ assert.equal(configA.getControllerConfig(), configB.getControllerConfig());
+ });
+ });
+
+ describe('default values', function() {
+ beforeEach(function() {
+ configA.setOptions();
+ });
+ it('should apply default values', function() {
+ var ops = configA.getOptions();
+ defaultOptionsInstance.forEach(function(property) {
+ assert.notEqual(ops[property.name], void 0);
+ });
+ });
+ it('should load default config', function() {
+ var controllerConfig = configA.getControllerConfig();
+ assert.notEqual(controllerConfig, null);
+ assert.notEqual(controllerConfig, void 0);
+ });
+ });
+});
diff --git a/dist/dualshock-controller/test/dualshock.tests.js b/dist/dualshock-controller/test/dualshock.tests.js
new file mode 100644
index 0000000..17e85bd
--- /dev/null
+++ b/dist/dualshock-controller/test/dualshock.tests.js
@@ -0,0 +1,158 @@
+var assert = require('assert'),
+ Emitter = require('events').EventEmitter,
+ config = require('../src/config'),
+ mockery = require('mockery');
+
+function Device() {
+ Emitter.call(this);
+}
+
+Device.prototype = Object.create(Emitter.prototype, {
+ constructor: {
+ value: Device
+ },
+ close: {
+ value: function() {}
+ }
+});
+
+var config = {
+ analogSticks: [{
+ name: 'foo',
+ x: 0,
+ y: 1
+ }],
+ buttons: [{
+ name: 'bar',
+ buttonBlock: 0,
+ buttonValue: 0x08,
+ analogPin: 1
+ }],
+ motionInputs: [{
+ name: 'baz',
+ directionPin: 0,
+ valuePin: 1
+ }],
+ status: [{
+ name: 'quz',
+ pin: 5,
+ states: [{
+ value: 0,
+ state: 'Charging'
+ }, {
+ value: 2,
+ state: 'Charging'
+ }, {
+ value: 3,
+ state: '40%'
+ }]
+ }],
+ output: []
+};
+
+var analogs = config.analogSticks;
+var buttons = config.buttons;
+var motions = config.motionInputs;
+var status = config.status;
+
+describe('the DualShock component', function() {
+ //enable mockery and mock node-hid:
+ mockery.enable();
+ var nodeHidMock = {
+ HID: function(vendor, productId) {
+ return {
+ on: function() {
+ //could use this at some point. nothing atm.
+ }
+ };
+ }
+ };
+ //register mock node-hid.
+ mockery.registerMock('node-hid', nodeHidMock);
+
+ //once mockery is up we can require the dualshock module.
+ var DualShock = require('./../src/dualshock.js'),
+ controller, device;
+
+ before(function() {
+ device = new Device();
+ controller = DualShock({
+ config: config,
+ device: device
+ });
+ });
+
+ //disable mockery so it does not interfere with other tests.
+ after(function() {
+ mockery.deregisterMock('node-hid');
+ mockery.disable();
+ });
+
+ beforeEach(function() {
+ controller.removeAllListeners(Object.keys(controller._events));
+ });
+
+ describe('analog properties', function() {
+ analogs.forEach(function(analog) {
+ it(analog.name, function() {
+ assert.equal(controller[analog.name].x, 0);
+ assert.equal(controller[analog.name].y, 0);
+
+ device.emit('data', [100, 100]);
+
+ assert.equal(controller[analog.name].x, 100);
+ assert.equal(controller[analog.name].y, 100);
+ });
+ });
+ });
+
+ describe('button properties', function() {
+ buttons.forEach(function(button) {
+ it(button.name, function() {
+ assert.equal(controller[button.name].value, 0);
+ assert.equal(controller[button.name].state, 0);
+
+ device.emit('data', [8, 170]);
+
+ assert.equal(controller[button.name].value, 1);
+ assert.equal(controller[button.name].state, 1);
+
+ device.emit('data', [8, 170]);
+
+ assert.equal(controller[button.name].value, 1);
+ assert.equal(controller[button.name].state, 2);
+
+ device.emit('data', [0, 0]);
+
+ assert.equal(controller[button.name].value, 0);
+ assert.equal(controller[button.name].state, 0);
+ });
+ });
+ });
+
+ describe('motion properties', function() {
+ motions.forEach(function(motion) {
+ it(motion.name, function() {
+ assert.equal(controller[motion.name].value, 0);
+ assert.equal(controller[motion.name].direction, 0);
+
+ device.emit('data', [1, 233]);
+
+ assert.equal(controller[motion.name].value, 22);
+ assert.equal(controller[motion.name].direction, 1);
+ });
+ });
+ });
+
+ describe('status properties', function() {
+ status.forEach(function(stat) {
+ it(stat.name, function() {
+ device.emit('data', [0, 0, 0, 0, 1, 3]);
+ assert.equal(controller[stat.name].state, '40%');
+
+ device.emit('data', [0, 0, 0, 0, 1, 2]);
+ assert.equal(controller[stat.name].state, 'Charging');
+ });
+ });
+ });
+});
diff --git a/dist/dualshock-controller/test/gyro.tests.js b/dist/dualshock-controller/test/gyro.tests.js
new file mode 100644
index 0000000..a3037a8
--- /dev/null
+++ b/dist/dualshock-controller/test/gyro.tests.js
@@ -0,0 +1,78 @@
+// Module dependencies.
+var Gyro = require('../src/gyro'),
+ assert = require('assert'),
+ sinon = require('sinon'),
+ EventEmitter = require('events').EventEmitter,
+ config = require('../src/config');
+
+describe('the Gyro component', function() {
+ 'use strict';
+
+ var mockConfig = [{
+ name: "dirrection",
+ directionPin: 0,
+ valuePin: 1
+ }],
+ instance = [{
+ name: 'process'
+ }],
+ dataA = [1, 130],
+ dataB = [2, 130],
+ emitter,
+ spy,
+ gyro;
+
+ beforeEach(function() {
+ emitter = new EventEmitter();
+ spy = sinon.spy();
+ config.setOptions({
+ accelerometerSmoothing: false
+ });
+ config.setControllerConfig({
+ motionInputs: mockConfig
+ });
+ gyro = new Gyro(emitter);
+ });
+
+ describe('object instance', function() {
+
+ it('should have the following shape', function() {
+ //make sure we find these functions.
+ instance.forEach(function(method) {
+ assert.equal(typeof gyro[method.name], 'function');
+ });
+ });
+ });
+
+ describe('process()', function() {
+
+ it('should envoke the dirrection:motion event with positive values', function() {
+ emitter.on('dirrection:motion', spy);
+ gyro.process(dataA);
+ assert.equal(spy.called, true);
+ var expectedValue = {
+ direction: 1,
+ value: 125
+ },
+ spyArgument = spy.args[0][0];
+
+ assert.equal(spyArgument.direction, expectedValue.direction);
+ assert.equal(spyArgument.value, expectedValue.value);
+ });
+
+ it('should envoke the dirrection event with negative values.', function() {
+ emitter.on('dirrection:motion', spy);
+ gyro.process(dataB);
+ assert.equal(spy.called, true);
+ var expectedValue = {
+ direction: 2,
+ value: -130
+ },
+ spyArgument = spy.args[0][0];
+
+ assert.equal(spyArgument.direction, expectedValue.direction);
+ assert.equal(spyArgument.value, expectedValue.value);
+ });
+ });
+
+});
diff --git a/dist/dualshock-controller/test/smoothing.tests.js b/dist/dualshock-controller/test/smoothing.tests.js
new file mode 100644
index 0000000..2046e28
--- /dev/null
+++ b/dist/dualshock-controller/test/smoothing.tests.js
@@ -0,0 +1,71 @@
+// Module dependencies.
+var Smoothing = require('../src/smoothing'),
+ assert = require('assert');
+
+describe('the smoothing component', function() {
+ 'use strict';
+
+ var smoothing,
+ nonSmoothing,
+ //an instance should have the following functions.
+ instance = [{
+ name: 'readLastPosition'
+ }, {
+ name: 'addToBuffer'
+ }, {
+ name: 'smooth'
+ }];
+
+ beforeEach(function() {
+ smoothing = new Smoothing(true);
+ nonSmoothing = new Smoothing(false);
+ for (var i = 0; i < 5; i++) {
+ nonSmoothing.addToBuffer('testNonSmoothing', i);
+ smoothing.addToBuffer('one', i);
+ smoothing.addToBuffer('two', i + 1);
+ smoothing.addToBuffer('testSmoothing', i);
+ }
+ });
+
+ describe('object instance', function() {
+ it('should have the following shape', function() {
+ //make sure we find these functions.
+ instance.forEach(function(method) {
+ assert.equal(typeof smoothing[method.name], 'function');
+ });
+ });
+ });
+
+ describe('addToBuffer()', function() {
+ it('should add values to the buffer', function() {
+ smoothing.addToBuffer('one', 6);
+ smoothing.addToBuffer('two', 7);
+
+ assert.equal(smoothing.readLastPosition('one'), 6);
+ assert.equal(smoothing.readLastPosition('two'), 7);
+ });
+ });
+
+ describe('readLastPosition()', function() {
+ it('should handle buffers for different objects', function() {
+ assert.equal(smoothing.readLastPosition('one'), 4);
+ assert.equal(smoothing.readLastPosition('two'), 5);
+ });
+ });
+
+ describe('smooth()', function() {
+ it('should return expected values when smoothing', function() {
+ //with the data set smoothing of 6 should be 3.
+ assert.equal(smoothing.smooth('testSmoothing', 6), 3);
+ //with the data set smoothing of 8 should be 4.
+ assert.equal(smoothing.smooth('testSmoothing', 8), 4);
+ });
+
+ it('should return expected values when not smoothing', function() {
+ //with smoothing turned off 9 should return 9
+ assert.equal(nonSmoothing.smooth('testNonSmoothing', 9), 9);
+ //with smoothing turned off 6 should return 6
+ assert.equal(nonSmoothing.smooth('testNonSmoothing', 6), 6);
+ });
+ });
+});
diff --git a/dist/dualshock-controller/test/status.tests.js b/dist/dualshock-controller/test/status.tests.js
new file mode 100644
index 0000000..a394439
--- /dev/null
+++ b/dist/dualshock-controller/test/status.tests.js
@@ -0,0 +1,60 @@
+// Module dependencies.
+var Status = require('../src/status'),
+ assert = require('assert'),
+ sinon = require('sinon'),
+ EventEmitter = require('events').EventEmitter,
+ config = require('../src/config');
+
+describe('the status component', function() {
+ var mockConfig = [{
+ "name": "chargingState",
+ "pin": 0,
+ "states": [{
+ "value": 0,
+ "state": "Charging"
+ }, {
+ "value": 2,
+ "state": "Charging"
+ }, {
+ "value": 3,
+ "state": "40%"
+ }]
+ }],
+ dataA = [0, 0],
+ dataB = [0, 3],
+ instance = [{
+ name: 'process'
+ }],
+ status,
+ emitter,
+ spy;
+
+ beforeEach(function() {
+ emitter = new EventEmitter();
+ spy = sinon.spy();
+ config.setControllerConfig({
+ status: mockConfig
+ });
+ status = new Status(emitter, mockConfig);
+ });
+
+ describe('object instance', function() {
+ it('should have the following shape', function() {
+ //make sure we find these functions.
+ instance.forEach(function(method) {
+ assert.equal(typeof status[method.name], 'function');
+ });
+ });
+ });
+
+ describe('process()', function() {
+ it('process should return an object with the expected values', function() {
+ emitter.on('chargingState:change', spy);
+ status.process(dataA);
+ var spyArgument = spy.args[0][0];
+ assert.equal(typeof spyArgument, 'string');
+ assert.equal(spyArgument, 'Charging');
+ spyArgument = null;
+ });
+ });
+});
diff --git a/html/gamepad/ps4controller.js b/html/gamepad/ps4controller.js
new file mode 100644
index 0000000..6c53faf
--- /dev/null
+++ b/html/gamepad/ps4controller.js
@@ -0,0 +1,40 @@
+//Only to be used for PS4 (Dualshock 4) controllers
+var dualShock = require('../../dist/dualshock-controller/src/dualshock');
+try {
+
+ var controller = dualShock({
+ config: "dualshock4-generic-driver"
+ });
+
+ controller.on('error', err => console.log(err));
+
+ function setExtras(obj) {
+ controller.setExtras(obj);
+ }
+ var connected = false;
+
+ controller.on('connected', () => {
+ connected = true;
+ });
+ controller.on("disconnected", () => {
+ connected = false;
+ })
+
+ function isConnected() {
+ return connected;
+ }
+
+ function on(event, handler) {
+ controller.on(event, handler);
+ }
+ module.exports = {
+ on,
+ isConnected,
+ setExtras
+ }
+} catch (e) {
+ console.error(e);
+ module.exports = {
+ isConnected: ()=>{return false}
+ }
+}
diff --git a/html/views/menu/connected.js b/html/views/menu/connected.js
index f1d8f5a..8ccf261 100644
--- a/html/views/menu/connected.js
+++ b/html/views/menu/connected.js
@@ -2,6 +2,7 @@ const utils = require("../../utils");
const gui = require("./gui");
const Gamepad = require("../../gamepad/gamepad");
const gamepad = new Gamepad;
+const controller = require("../../gamepad/ps4controller");
function gamepadConnected(){
console.log("Gamepad connected");
@@ -18,6 +19,15 @@ function gamepadConnected(){
gui.renderUserCardList(cards);
var selected = 0;
+ if(controller.isConnected()){
+ controller.setExtras({
+ rumbleLeft: 0, // 0-255 (Rumble left intensity)
+ rumbleRight: 0, // 0-255 (Rumble right intensity)
+ red: 0, // 0-255 (Red intensity)
+ green: 75, // 0-255 (Blue intensity)
+ blue: 225, // 0-255 (Green intensity)
+ });
+ }
gamepad.on("press", "d_pad_right", () => {
if(selected < max){
selected++;
diff --git a/package-lock.json b/package-lock.json
index 48f66ea..5421aec 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -93,8 +93,7 @@
"ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
- "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
- "dev": true
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
},
"ansi-styles": {
"version": "3.2.1",
@@ -113,6 +112,54 @@
"picomatch": "^2.0.4"
}
},
+ "aproba": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
+ "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
+ },
+ "are-we-there-yet": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
+ "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
+ "requires": {
+ "delegates": "^1.0.0",
+ "readable-stream": "^2.0.6"
+ },
+ "dependencies": {
+ "isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
+ },
+ "readable-stream": {
+ "version": "2.3.6",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ }
+ }
+ },
"array-back": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/array-back/-/array-back-1.0.4.tgz",
@@ -207,6 +254,42 @@
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz",
"integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow=="
},
+ "bindings": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
+ "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
+ "requires": {
+ "file-uri-to-path": "1.0.0"
+ }
+ },
+ "bl": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/bl/-/bl-3.0.0.tgz",
+ "integrity": "sha512-EUAyP5UHU5hxF8BPT0LKW8gjYLhq1DQIcneOX/pL/m2Alo+OYDQAJlHq+yseMP50Os2nHXOSic6Ss3vSQeyf4A==",
+ "requires": {
+ "readable-stream": "^3.0.1"
+ },
+ "dependencies": {
+ "readable-stream": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz",
+ "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==",
+ "requires": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ }
+ },
+ "string_decoder": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+ "requires": {
+ "safe-buffer": "~5.2.0"
+ }
+ }
+ }
+ },
"bluebird": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
@@ -345,6 +428,11 @@
"readdirp": "~3.3.0"
}
},
+ "chownr": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.3.tgz",
+ "integrity": "sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw=="
+ },
"chromium-pickle-js": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz",
@@ -363,8 +451,7 @@
"code-point-at": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
- "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
- "dev": true
+ "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
},
"color-convert": {
"version": "1.9.3",
@@ -499,6 +586,11 @@
"proto-list": "~1.2.1"
}
},
+ "console-control-strings": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
+ "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
+ },
"core-js": {
"version": "3.6.1",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.1.tgz",
@@ -509,8 +601,7 @@
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
- "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
- "dev": true
+ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
},
"cross-zip": {
"version": "2.1.6",
@@ -616,6 +707,16 @@
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
"dev": true
},
+ "delegates": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
+ "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o="
+ },
+ "detect-libc": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
+ "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups="
+ },
"detect-node": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz",
@@ -802,7 +903,6 @@
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
"integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
- "dev": true,
"requires": {
"once": "^1.4.0"
}
@@ -834,6 +934,11 @@
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
},
+ "expand-template": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
+ "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg=="
+ },
"extend": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
@@ -904,6 +1009,11 @@
"array-back": "^1.0.4"
}
},
+ "file-uri-to-path": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
+ "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw=="
+ },
"fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
@@ -991,6 +1101,11 @@
"mime-types": "^2.1.12"
}
},
+ "fs-constants": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
+ "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="
+ },
"fs-extra": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz",
@@ -1025,6 +1140,21 @@
"fs-extra": "^4.0.0"
}
},
+ "gauge": {
+ "version": "2.7.4",
+ "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
+ "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
+ "requires": {
+ "aproba": "^1.0.3",
+ "console-control-strings": "^1.0.0",
+ "has-unicode": "^2.0.0",
+ "object-assign": "^4.1.0",
+ "signal-exit": "^3.0.0",
+ "string-width": "^1.0.1",
+ "strip-ansi": "^3.0.1",
+ "wide-align": "^1.1.0"
+ }
+ },
"get-package-info": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/get-package-info/-/get-package-info-1.0.0.tgz",
@@ -1135,6 +1265,11 @@
"assert-plus": "^1.0.0"
}
},
+ "github-from-package": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
+ "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4="
+ },
"glob": {
"version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
@@ -1251,6 +1386,11 @@
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
},
+ "has-unicode": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
+ "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk="
+ },
"hosted-git-info": {
"version": "2.8.5",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz",
@@ -1296,14 +1436,12 @@
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
- "dev": true
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"ini": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
- "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
- "dev": true
+ "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw=="
},
"is-arrayish": {
"version": "0.2.1",
@@ -1337,7 +1475,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
- "dev": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@@ -1587,14 +1724,12 @@
"minimist": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
- "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
- "dev": true
+ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
},
"mkdirp": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
- "dev": true,
"requires": {
"minimist": "0.0.8"
},
@@ -1602,8 +1737,7 @@
"minimist": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
- "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
- "dev": true
+ "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
}
}
},
@@ -1613,6 +1747,34 @@
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
},
+ "nan": {
+ "version": "2.14.0",
+ "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz",
+ "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg=="
+ },
+ "napi-build-utils": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.1.tgz",
+ "integrity": "sha512-boQj1WFgQH3v4clhu3mTNfP+vOBxorDlE8EKiMjUlLG3C4qAESnn9AxIOkFgTR2c9LtzNjPrjS60cT27ZKBhaA=="
+ },
+ "node-abi": {
+ "version": "2.13.0",
+ "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.13.0.tgz",
+ "integrity": "sha512-9HrZGFVTR5SOu3PZAnAY2hLO36aW1wmA+FDsVkr85BTST32TLCA1H/AEcatVRAsWLyXS3bqUDYCAjq5/QGuSTA==",
+ "requires": {
+ "semver": "^5.4.1"
+ }
+ },
+ "node-hid": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/node-hid/-/node-hid-1.0.0.tgz",
+ "integrity": "sha512-KOkrN0nn82ffj30iYAmzJmif6h0/5r3NlG68NJQf8hxYpy3pzkr7TjjOL4fgoB4Ehc4YIdinP1F6pGOJqdModg==",
+ "requires": {
+ "bindings": "^1.5.0",
+ "nan": "^2.14.0",
+ "prebuild-install": "^5.3.3"
+ }
+ },
"node-wifi": {
"version": "2.0.12",
"resolved": "https://registry.npmjs.org/node-wifi/-/node-wifi-2.0.12.tgz",
@@ -1622,6 +1784,11 @@
"command-line-usage": "^5.0.5"
}
},
+ "noop-logger": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz",
+ "integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI="
+ },
"normalize-package-data": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
@@ -1665,6 +1832,17 @@
}
}
},
+ "npmlog": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
+ "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
+ "requires": {
+ "are-we-there-yet": "~1.1.2",
+ "console-control-strings": "~1.1.0",
+ "gauge": "~2.7.3",
+ "set-blocking": "~2.0.0"
+ }
+ },
"nugget": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/nugget/-/nugget-2.0.1.tgz",
@@ -1700,8 +1878,7 @@
"number-is-nan": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
- "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
- "dev": true
+ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
},
"oauth-sign": {
"version": "0.9.0",
@@ -1712,8 +1889,7 @@
"object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
- "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
- "dev": true
+ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
},
"object-keys": {
"version": "0.4.0",
@@ -1725,7 +1901,6 @@
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
- "dev": true,
"requires": {
"wrappy": "1"
}
@@ -1856,6 +2031,28 @@
"xmldom": "0.1.x"
}
},
+ "prebuild-install": {
+ "version": "5.3.3",
+ "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.3.3.tgz",
+ "integrity": "sha512-GV+nsUXuPW2p8Zy7SarF/2W/oiK8bFQgJcncoJ0d7kRpekEA0ftChjfEaF9/Y+QJEc/wFR7RAEa8lYByuUIe2g==",
+ "requires": {
+ "detect-libc": "^1.0.3",
+ "expand-template": "^2.0.3",
+ "github-from-package": "0.0.0",
+ "minimist": "^1.2.0",
+ "mkdirp": "^0.5.1",
+ "napi-build-utils": "^1.0.1",
+ "node-abi": "^2.7.0",
+ "noop-logger": "^0.1.1",
+ "npmlog": "^4.0.1",
+ "pump": "^3.0.0",
+ "rc": "^1.2.7",
+ "simple-get": "^3.0.3",
+ "tar-fs": "^2.0.0",
+ "tunnel-agent": "^0.6.0",
+ "which-pm-runs": "^1.0.0"
+ }
+ },
"prepend-http": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz",
@@ -1875,8 +2072,7 @@
"process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
- "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
- "dev": true
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
},
"progress-stream": {
"version": "1.2.0",
@@ -1905,7 +2101,6 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
"integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
- "dev": true,
"requires": {
"end-of-stream": "^1.1.0",
"once": "^1.3.1"
@@ -1927,7 +2122,6 @@
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
"integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
- "dev": true,
"requires": {
"deep-extend": "^0.6.0",
"ini": "~1.3.0",
@@ -2079,8 +2273,7 @@
"safe-buffer": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
- "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==",
- "dev": true
+ "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg=="
},
"safer-buffer": {
"version": "2.1.2",
@@ -2100,8 +2293,7 @@
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
- "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
- "dev": true
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
},
"semver-compare": {
"version": "1.0.0",
@@ -2120,11 +2312,45 @@
"type-fest": "^0.8.0"
}
},
+ "set-blocking": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
+ },
"signal-exit": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
- "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
- "dev": true
+ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
+ },
+ "simple-concat": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.0.tgz",
+ "integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY="
+ },
+ "simple-get": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz",
+ "integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==",
+ "requires": {
+ "decompress-response": "^4.2.0",
+ "once": "^1.3.1",
+ "simple-concat": "^1.0.0"
+ },
+ "dependencies": {
+ "decompress-response": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz",
+ "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==",
+ "requires": {
+ "mimic-response": "^2.0.0"
+ }
+ },
+ "mimic-response": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.0.0.tgz",
+ "integrity": "sha512-8ilDoEapqA4uQ3TwS0jakGONKXVJqpy+RpM+3b7pLdOjghCrEiGp9SRkFbUHAmZW9vdnrENWHjaweIoTIJExSQ=="
+ }
+ }
},
"single-line-log": {
"version": "1.1.2",
@@ -2201,7 +2427,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
- "dev": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@@ -2218,7 +2443,6 @@
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
- "dev": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@@ -2244,8 +2468,7 @@
"strip-json-comments": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
- "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
- "dev": true
+ "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
},
"sumchecker": {
"version": "2.0.2",
@@ -2303,6 +2526,49 @@
}
}
},
+ "tar-fs": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.0.0.tgz",
+ "integrity": "sha512-vaY0obB6Om/fso8a8vakQBzwholQ7v5+uy+tF3Ozvxv1KNezmVQAiWtcNmMHFSFPqL3dJA8ha6gdtFbfX9mcxA==",
+ "requires": {
+ "chownr": "^1.1.1",
+ "mkdirp": "^0.5.1",
+ "pump": "^3.0.0",
+ "tar-stream": "^2.0.0"
+ }
+ },
+ "tar-stream": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.0.tgz",
+ "integrity": "sha512-+DAn4Nb4+gz6WZigRzKEZl1QuJVOLtAwwF+WUxy1fJ6X63CaGaUAxJRD2KEn1OMfcbCjySTYpNC6WmfQoIEOdw==",
+ "requires": {
+ "bl": "^3.0.0",
+ "end-of-stream": "^1.4.1",
+ "fs-constants": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^3.1.1"
+ },
+ "dependencies": {
+ "readable-stream": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz",
+ "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==",
+ "requires": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ }
+ },
+ "string_decoder": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+ "requires": {
+ "safe-buffer": "~5.2.0"
+ }
+ }
+ }
+ },
"test-value": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/test-value/-/test-value-2.1.0.tgz",
@@ -2405,7 +2671,6 @@
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
"integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
- "dev": true,
"requires": {
"safe-buffer": "^5.0.1"
}
@@ -2467,8 +2732,7 @@
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
- "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
- "dev": true
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
"uuid": {
"version": "3.3.3",
@@ -2497,6 +2761,19 @@
"extsprintf": "^1.2.0"
}
},
+ "which-pm-runs": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz",
+ "integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs="
+ },
+ "wide-align": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
+ "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
+ "requires": {
+ "string-width": "^1.0.2 || 2"
+ }
+ },
"wordwrapjs": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-3.0.0.tgz",
@@ -2509,8 +2786,7 @@
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
- "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
- "dev": true
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
},
"xmlbuilder": {
"version": "9.0.7",
diff --git a/package.json b/package.json
index d1a703c..3059a7e 100644
--- a/package.json
+++ b/package.json
@@ -17,6 +17,7 @@
},
"dependencies": {
"electron-reload": "^1.5.0",
+ "node-hid": "^1.0.0",
"node-wifi": "^2.0.5"
}
}