forked from node-hid/node-hid
-
Notifications
You must be signed in to change notification settings - Fork 0
/
nodehid.js
207 lines (181 loc) · 6.25 KB
/
nodehid.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
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
const EventEmitter = require("events").EventEmitter;
const util = require("util");
let driverType = null;
function setDriverType(type) {
driverType = type;
}
// lazy load the C++ binding
let binding = null;
function loadBinding() {
if (!binding) {
const options = require('./binding-options');
if (process.platform === "linux" && (!driverType || driverType === "hidraw")) {
options.name = 'HID_hidraw';
}
binding = require("pkg-prebuilds/bindings")(__dirname, options);
}
}
//This class is a wrapper for `binding.HID` class
function HID() {
// see issue #150 (enhancement, solves issue #149)
// throw an error for those who forget to instantiate, i.e. by "*new* HID.HID()"
// and who would otherwise be left trying to figure out why "self.on is not a function"
if (!new.target) {
throw new Error('HID() must be called with \'new\' operator');
}
//Inherit from EventEmitter
EventEmitter.call(this);
loadBinding();
/* We also want to inherit from `binding.HID`, but unfortunately,
it's not so easy for native Objects. For example, the
following won't work since `new` keyword isn't used:
`binding.HID.apply(this, arguments);`
So... we do this craziness instead...
*/
var thisPlusArgs = new Array(arguments.length + 1);
thisPlusArgs[0] = null;
for(var i = 0; i < arguments.length; i++)
thisPlusArgs[i + 1] = arguments[i];
this._raw = new (Function.prototype.bind.apply(binding.HID,
thisPlusArgs) )();
/* Now we have `this._raw` Object from which we need to
inherit. So, one solution is to simply copy all
prototype methods over to `this` and binding them to
`this._raw`
*/
for(var i in binding.HID.prototype)
this[i] = binding.HID.prototype[i].bind(this._raw);
/* We are now done inheriting from `binding.HID` and EventEmitter.
Now upon adding a new listener for "data" events, we start
polling the HID device using `read(...)`
See `resume()` for more details. */
this._paused = true;
var self = this;
self.on("newListener", function(eventName, listener) {
if(eventName == "data")
process.nextTick(self.resume.bind(self) );
});
}
//Inherit prototype methods
util.inherits(HID, EventEmitter);
//Don't inherit from `binding.HID`; that's done above already!
HID.prototype.close = function close() {
this._closing = true;
this.removeAllListeners();
this._raw.close();
this._closed = true;
};
//Pauses the reader, which stops "data" events from being emitted
HID.prototype.pause = function pause() {
this._paused = true;
};
HID.prototype.read = function read(callback) {
if (this._closed) {
throw new Error('Unable to read from a closed HID device');
} else {
return this._raw.read(callback);
}
};
HID.prototype.resume = function resume() {
var self = this;
if(self._paused && self.listeners("data").length > 0)
{
//Start polling & reading loop
self._paused = false;
self.read(function readFunc(err, data) {
if(err)
{
//Emit error and pause reading
self._paused = true;
if(!self._closing)
self.emit("error", err);
//else ignore any errors if I'm closing the device
}
else
{
//If there are no "data" listeners, we pause
if(self.listeners("data").length <= 0)
self._paused = true;
//Keep reading if we aren't paused
if(!self._paused)
self.read(readFunc);
//Now emit the event
self.emit("data", data);
}
});
}
};
class HIDAsync extends EventEmitter {
constructor(raw) {
super()
if (!(raw instanceof binding.HIDAsync)) {
throw new Error(`HIDAsync cannot be constructed directly. Use HIDAsync.open() instead`)
}
this._raw = raw
/* Now we have `this._raw` Object from which we need to
inherit. So, one solution is to simply copy all
prototype methods over to `this` and binding them to
`this._raw`.
We explicitly wrap them in an async method, to ensure
that any thrown errors are promise rejections
*/
for (let i in this._raw) {
this[i] = async (...args) => this._raw[i](...args);
}
/* Now upon adding a new listener for "data" events, we start
the read thread executing. See `resume()` for more details.
*/
this.on("newListener", (eventName, listener) =>{
if(eventName == "data")
process.nextTick(this.resume.bind(this) );
});
this.on("removeListener", (eventName, listener) => {
if(eventName == "data" && this.listenerCount("data") == 0)
process.nextTick(this.pause.bind(this) );
})
}
static async open(...args) {
loadBinding();
const native = await binding.openAsyncHIDDevice(...args);
return new HIDAsync(native)
}
async close() {
this._closing = true;
this.removeAllListeners();
await this._raw.close();
this._closed = true;
}
//Pauses the reader, which stops "data" events from being emitted
pause() {
this._raw.readStop();
}
resume() {
if(this.listenerCount("data") > 0)
{
//Start polling & reading loop
this._raw.readStart((err, data) => {
if (err) {
if(!this._closing)
this.emit("error", err);
//else ignore any errors if I'm closing the device
} else {
this.emit("data", data);
}
})
}
}
}
function showdevices() {
loadBinding();
return binding.devices.apply(HID,arguments);
}
function showdevicesAsync(...args) {
loadBinding();
return binding.devicesAsync(...args);
}
//Expose API
exports.HID = HID;
exports.HIDAsync = HIDAsync;
exports.devices = showdevices;
exports.devicesAsync = showdevicesAsync;
exports.setDriverType = setDriverType;