aboutsummaryrefslogtreecommitdiff
path: root/lib/device.js
diff options
context:
space:
mode:
Diffstat (limited to 'lib/device.js')
-rw-r--r--lib/device.js87
1 files changed, 87 insertions, 0 deletions
diff --git a/lib/device.js b/lib/device.js
new file mode 100644
index 0000000..a9fb71d
--- /dev/null
+++ b/lib/device.js
@@ -0,0 +1,87 @@
+const fs = require("fs")
+ , util = require("util")
+ , EventEmitter = require("events").EventEmitter
+ , {eviocgrab, eviocgid} = require("bindings")("ioctl.node")
+ , events = require("./events");
+
+const arch = (process.arch.indexOf("64")>=0)?64:32;
+
+function Device(path) {
+ this.grabbed = false;
+ if (path) this.open(path);
+}
+
+util.inherits(Device, EventEmitter);
+
+Device.prototype.open = function(path) {
+ this.stream = fs
+ .createReadStream(path, {flags: "r", autoClose: true})
+ .on("error", e => this.emit("error", e))
+ .on("open", fd => { this.fd = fd;
+ try { this.id = eviocgid(fd); }
+ catch(e) { this.emit("error",
+ new Error("Reader eviocgid error:"+e)); }
+ if (this.grabbed) eviocgrab(this.fd, 1);
+ this.emit("open", fd); })
+ .on("data", buf => {
+ var i, j, chunk = (arch===64)?24:16;
+ for (i=0, j=buf.length; i<j; i+=chunk) {
+ const e = parse(buf.slice(i, i+chunk));
+ this.emit("event", e);
+ this.emit(e.type, e);
+ }});
+};
+
+Device.prototype.close = function() {
+ this.grabbed = false;
+ this.stream.close();
+ delete this.stream;
+ delete this.fd;
+ delete this.id;
+};
+
+Device.prototype.grab = function() {
+ if (this.grabbed) return; this.grabbed = true;
+ if (this.fd) eviocgrab(this.fd, 1);
+};
+
+Device.prototype.ungrab = function() {
+ if (!this.grabbed) return; this.grabbed = false;
+ if (this.fd) eviocgrab(this.fd, 0);
+};
+
+// struct input_event {
+// struct timeval {
+// long tv_sec; // s32/64 (arch)
+// long tv_usec; // LE (always?)
+// } time;
+// __u16 type;
+// __u16 code;
+// __s32 value;
+// };
+function parse(buf) {
+ var e = {time: {sec: null, usec: null},
+ type: null, code: null, value: null};
+
+ var offset;
+ if (arch === 64) { offset = 16;
+ e.time.sec = buf.readBigInt64LE(0);
+ e.time.usec = buf.readBigInt64LE(8);
+ } else { offset = 8;
+ e.time.sec = buf.readInt32LE(0);
+ e.time.usec = buf.readInt32LE(4);
+ }
+
+ e.type = buf.readUInt16LE(offset);
+ e.code = buf.readUInt16LE(offset + 2);
+ e.value = buf.readInt32LE(offset + 4);
+
+ if (events.types[e.type])
+ e.type = events.types[e.type];
+ if (events[e.type] && events[e.type][e.code])
+ e.code = events[e.type][e.code];
+
+ return e;
+};
+
+module.exports = Device;