forked from olizilla/node-logitech-dual-action-controller
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.js
186 lines (147 loc) · 4 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
/*
Logitech Dual Action Controller
===============================
HID info:
{
vendorId: 1133,
productId: 49686,
path: 'USB_046d_c216_14300000',
serialNumber: '',
manufacturer: 'Logitech',
product: 'Logitech Dual Action',
release: 768,
interface: -1
}
We get an 8 byte Buffer from each `data` event.
byte 0: left analog stick horizontal
byte 1: left analog stick vertical
byte 2: right analog stick horizontal
byte 3: right analog stick vertical
byte 4: dpad direciton and buttons 1,2,3,4
byte 5: buttons 5,6,7,8,9,10,11,12
byte 6: mode switch... flips the dpad and left analog stick. 4 is on, 5 is off.
byte 7: nothing. Seems to always return 252.
See: http://www.autohotkey.com/board/topic/64178-hid-template-and-example-for-logitech-dual-action/
*/
var util = require('util')
var events = require('events')
var hid = require('node-hid')
var pad = require('pad')
var buttons = require('./buttons.json')
var VENDOR_ID = 1133
var PRODUCT_ID = 49686
function LogitechDualActionController() {
for (button in buttons) {
this[button] = 0
}
this.dpad = []
this.leftstick = { x:0, y:0 }
this.rightstick = { x:0, y:0 }
getDevice(VENDOR_ID, PRODUCT_ID, function(err, device){
if (err) return consle.error(err)
this.emit('ready')
device.on('data', interpretData.bind(this))
}.bind(this))
}
util.inherits(LogitechDualActionController, events.EventEmitter);
module.exports = LogitechDualActionController
// Read the byte Buffer from the device and translate it into somthing useful
function interpretData (data) {
var info = {
buttons: readButtons(data),
dpad: readDpad(data),
leftstick: readStick(data[0],data[1]),
rightstick: readStick(data[2],data[3])
}
for (name in info.buttons) {
var state = info.buttons[name]
if (this[name] === state) continue;
this[name] = state
var evt = name + (state ? ':press' : ':release')
this.emit(evt, evt)
}
function moved(a, b){
return a.x !== b.x || a.y !== b.y
}
if (moved(this.leftstick, info.leftstick)) {
this.leftstick = info.leftstick
this.emit('left:move', info.leftstick)
}
if (moved(this.rightstick, info.rightstick)) {
this.rightstick = info.rightstick
this.emit('right:move', info.rightstick)
}
// check if a dpad has been released
this.dpad.forEach(function(item){
if(info.dpad.indexOf(item) < 0){
this.emit(item + ":release", item + ":release")
}
}.bind(this))
// check if a dpad has been pressed
info.dpad.forEach(function(item){
if(this.dpad.indexOf(item) < 0){
this.emit(item + ":press", item + ":press")
}
}.bind(this))
this.dpad = info.dpad
this.emit('data', info)
}
// Figure out which buttons are pressed
function readButtons(data) {
var res = {}
for (name in buttons) {
var button = buttons[name]
var block = data[button.block]
var bit = button.bit
// apply the mask for each key and determine if it is pressed.
res[name] = (block & bit) ? 1 : 0
}
return res
}
// Figure out where the dpad is pointing
function readDpad (data) {
var dpadMap = [
['dup'],
['dup', 'dright'],
['dright'],
['ddown', 'dright'],
['ddown'],
['ddown', 'dleft'],
['dleft'],
['dup', 'dleft'],
['dcenter']
]
var input = data[4] & 0x0F
return dpadMap[input] || []
}
/*
map raw input to:
100
|
-100 - o - 100
|
-100
*/
function readStick(rawX, rawY) {
return {
x: Math.round(((rawX - 128)/128) * 100),
y: Math.round(-((rawY - 128)/128) * 100)
}
}
// Helpful byte logging
function formatByte (num) {
return pad(8, num.toString(2), '0')
}
// Ask HID for access to the device
function getDevice(vendorId, productId, cb) {
var deviceData = hid.devices().filter(function(d){
return (d.vendorId === vendorId && d.productId === productId)
})[0]
if (deviceData) {
return cb(null, new hid.HID(deviceData.path))
}
console.error('Please connect Logitech Dual Action Controller...')
setTimeout(function(){
getDevice(vendorId, productId, cb)
}, 1000)
}