diff options
Diffstat (limited to 'lib/device.js')
-rw-r--r-- | lib/device.js | 87 |
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; |