Mon 21 Jul 22:43:21 CEST 2025
This commit is contained in:
parent
8e336f8dc8
commit
c258614290
221
js/term/gpmclient.js
Normal file
221
js/term/gpmclient.js
Normal file
|
@ -0,0 +1,221 @@
|
|||
/**
|
||||
* gpmclient.js - support the gpm mouse protocol
|
||||
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
|
||||
* https://github.com/chjj/blessed
|
||||
*/
|
||||
|
||||
var net = require('net');
|
||||
var fs = require('fs');
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
|
||||
var GPM_USE_MAGIC = false;
|
||||
|
||||
var GPM_MOVE = 1
|
||||
, GPM_DRAG = 2
|
||||
, GPM_DOWN = 4
|
||||
, GPM_UP = 8;
|
||||
|
||||
var GPM_DOUBLE = 32
|
||||
, GPM_MFLAG = 128;
|
||||
|
||||
var GPM_REQ_NOPASTE = 3
|
||||
, GPM_HARD = 256;
|
||||
|
||||
var GPM_MAGIC = 0x47706D4C;
|
||||
var GPM_SOCKET = '/dev/gpmctl';
|
||||
|
||||
// typedef struct Gpm_Connect {
|
||||
// unsigned short eventMask, defaultMask;
|
||||
// unsigned short minMod, maxMod;
|
||||
// int pid;
|
||||
// int vc;
|
||||
// } Gpm_Connect;
|
||||
|
||||
function send_config(socket, Gpm_Connect, callback) {
|
||||
var buffer;
|
||||
if (GPM_USE_MAGIC) {
|
||||
buffer = new Buffer(20);
|
||||
buffer.writeUInt32LE(GPM_MAGIC, 0);
|
||||
buffer.writeUInt16LE(Gpm_Connect.eventMask, 4);
|
||||
buffer.writeUInt16LE(Gpm_Connect.defaultMask, 6);
|
||||
buffer.writeUInt16LE(Gpm_Connect.minMod, 8);
|
||||
buffer.writeUInt16LE(Gpm_Connect.maxMod, 10);
|
||||
buffer.writeInt16LE(process.pid, 12);
|
||||
buffer.writeInt16LE(Gpm_Connect.vc, 16);
|
||||
} else {
|
||||
buffer = new Buffer(16);
|
||||
buffer.writeUInt16LE(Gpm_Connect.eventMask, 0);
|
||||
buffer.writeUInt16LE(Gpm_Connect.defaultMask, 2);
|
||||
buffer.writeUInt16LE(Gpm_Connect.minMod, 4);
|
||||
buffer.writeUInt16LE(Gpm_Connect.maxMod, 6);
|
||||
buffer.writeInt16LE(Gpm_Connect.pid, 8);
|
||||
buffer.writeInt16LE(Gpm_Connect.vc, 12);
|
||||
}
|
||||
socket.write(buffer, function() {
|
||||
if (callback) callback();
|
||||
});
|
||||
}
|
||||
|
||||
// typedef struct Gpm_Event {
|
||||
// unsigned char buttons, modifiers; // try to be a multiple of 4
|
||||
// unsigned short vc;
|
||||
// short dx, dy, x, y; // displacement x,y for this event, and absolute x,y
|
||||
// enum Gpm_Etype type;
|
||||
// // clicks e.g. double click are determined by time-based processing
|
||||
// int clicks;
|
||||
// enum Gpm_Margin margin;
|
||||
// // wdx/y: displacement of wheels in this event. Absolute values are not
|
||||
// // required, because wheel movement is typically used for scrolling
|
||||
// // or selecting fields, not for cursor positioning. The application
|
||||
// // can determine when the end of file or form is reached, and not
|
||||
// // go any further.
|
||||
// // A single mouse will use wdy, "vertical scroll" wheel.
|
||||
// short wdx, wdy;
|
||||
// } Gpm_Event;
|
||||
|
||||
function parseEvent(raw) {
|
||||
var evnt = {};
|
||||
evnt.buttons = raw[0];
|
||||
evnt.modifiers = raw[1];
|
||||
evnt.vc = raw.readUInt16LE(2);
|
||||
evnt.dx = raw.readInt16LE(4);
|
||||
evnt.dy = raw.readInt16LE(6);
|
||||
evnt.x = raw.readInt16LE(8);
|
||||
evnt.y = raw.readInt16LE(10);
|
||||
evnt.type = raw.readInt16LE(12);
|
||||
evnt.clicks = raw.readInt32LE(16);
|
||||
evnt.margin = raw.readInt32LE(20);
|
||||
evnt.wdx = raw.readInt16LE(24);
|
||||
evnt.wdy = raw.readInt16LE(26);
|
||||
return evnt;
|
||||
}
|
||||
|
||||
function GpmClient(options) {
|
||||
if (!(this instanceof GpmClient)) {
|
||||
return new GpmClient(options);
|
||||
}
|
||||
|
||||
EventEmitter.call(this);
|
||||
|
||||
var pid = process.pid;
|
||||
|
||||
// check tty for /dev/tty[n]
|
||||
var path;
|
||||
try {
|
||||
path = fs.readlinkSync('/proc/' + pid + '/fd/0');
|
||||
} catch (e) {
|
||||
;
|
||||
}
|
||||
var tty = /tty[0-9]+$/.exec(path);
|
||||
if (tty === null) {
|
||||
// TODO: should also check for /dev/input/..
|
||||
}
|
||||
|
||||
var vc;
|
||||
if (tty) {
|
||||
tty = tty[0];
|
||||
vc = +/[0-9]+$/.exec(tty)[0];
|
||||
}
|
||||
|
||||
var self = this;
|
||||
|
||||
if (tty) {
|
||||
fs.stat(GPM_SOCKET, function(err, stat) {
|
||||
if (err || !stat.isSocket()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var conf = {
|
||||
eventMask: 0xffff,
|
||||
defaultMask: GPM_MOVE | GPM_HARD,
|
||||
minMod: 0,
|
||||
maxMod: 0xffff,
|
||||
pid: pid,
|
||||
vc: vc
|
||||
};
|
||||
|
||||
var gpm = net.createConnection(GPM_SOCKET);
|
||||
this.gpm = gpm;
|
||||
|
||||
gpm.on('connect', function() {
|
||||
send_config(gpm, conf, function() {
|
||||
conf.pid = 0;
|
||||
conf.vc = GPM_REQ_NOPASTE;
|
||||
//send_config(gpm, conf);
|
||||
});
|
||||
});
|
||||
|
||||
gpm.on('data', function(packet) {
|
||||
var evnt = parseEvent(packet);
|
||||
switch (evnt.type & 15) {
|
||||
case GPM_MOVE:
|
||||
if (evnt.dx || evnt.dy) {
|
||||
self.emit('move', evnt.buttons, evnt.modifiers, evnt.x, evnt.y);
|
||||
}
|
||||
if (evnt.wdx || evnt.wdy) {
|
||||
self.emit('mousewheel',
|
||||
evnt.buttons, evnt.modifiers,
|
||||
evnt.x, evnt.y, evnt.wdx, evnt.wdy);
|
||||
}
|
||||
break;
|
||||
case GPM_DRAG:
|
||||
if (evnt.dx || evnt.dy) {
|
||||
self.emit('drag', evnt.buttons, evnt.modifiers, evnt.x, evnt.y);
|
||||
}
|
||||
if (evnt.wdx || evnt.wdy) {
|
||||
self.emit('mousewheel',
|
||||
evnt.buttons, evnt.modifiers,
|
||||
evnt.x, evnt.y, evnt.wdx, evnt.wdy);
|
||||
}
|
||||
break;
|
||||
case GPM_DOWN:
|
||||
self.emit('btndown', evnt.buttons, evnt.modifiers, evnt.x, evnt.y);
|
||||
if (evnt.type & GPM_DOUBLE) {
|
||||
self.emit('dblclick', evnt.buttons, evnt.modifiers, evnt.x, evnt.y);
|
||||
}
|
||||
break;
|
||||
case GPM_UP:
|
||||
self.emit('btnup', evnt.buttons, evnt.modifiers, evnt.x, evnt.y);
|
||||
if (!(evnt.type & GPM_MFLAG)) {
|
||||
self.emit('click', evnt.buttons, evnt.modifiers, evnt.x, evnt.y);
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
gpm.on('error', function() {
|
||||
self.stop();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
GpmClient.prototype.__proto__ = EventEmitter.prototype;
|
||||
|
||||
GpmClient.prototype.stop = function() {
|
||||
if (this.gpm) {
|
||||
this.gpm.end();
|
||||
}
|
||||
delete this.gpm;
|
||||
};
|
||||
|
||||
GpmClient.prototype.ButtonName = function(btn) {
|
||||
if (btn & 4) return 'left';
|
||||
if (btn & 2) return 'middle';
|
||||
if (btn & 1) return 'right';
|
||||
return '';
|
||||
};
|
||||
|
||||
GpmClient.prototype.hasShiftKey = function(mod) {
|
||||
return (mod & 1) ? true : false;
|
||||
};
|
||||
|
||||
GpmClient.prototype.hasCtrlKey = function(mod) {
|
||||
return (mod & 4) ? true : false;
|
||||
};
|
||||
|
||||
GpmClient.prototype.hasMetaKey = function(mod) {
|
||||
return (mod & 8) ? true : false;
|
||||
};
|
||||
|
||||
module.exports = GpmClient;
|
Loading…
Reference in New Issue
Block a user