gpm: refactor to fit style.

This commit is contained in:
Christopher Jeffrey 2015-02-01 07:07:55 -08:00
parent fae4acceef
commit 87a3d2f288
2 changed files with 327 additions and 281 deletions

View File

@ -1,193 +1,210 @@
var net=require('net'); var net = require('net');
var fs=require('fs'); var fs = require('fs');
var EventEmitter=require('events').EventEmitter; var EventEmitter = require('events').EventEmitter;
var util = require('util') var util = require('util')
var GPM_USE_MAGIC=false; var GPM_USE_MAGIC = false;
var GPM_MOVE=1, GPM_DRAG=2, GPM_DOWN=4, GPM_UP=8; var GPM_MOVE = 1
var GPM_DOUBLE=32,GPM_MFLAG=128; , GPM_DRAG = 2
, GPM_DOWN = 4
, GPM_UP = 8;
var GPM_REQ_NOPASTE=3, GPM_HARD=256; var GPM_DOUBLE = 32
, GPM_MFLAG = 128;
var GPM_MAGIC=0x47706D4C; var GPM_REQ_NOPASTE = 3
var GPM_SOCKET="/dev/gpmctl"; , GPM_HARD = 256;
var GPM_MAGIC = 0x47706D4C;
var GPM_SOCKET = '/dev/gpmctl';
/* // typedef struct Gpm_Connect {
typedef struct Gpm_Connect { // unsigned short eventMask, defaultMask;
unsigned short eventMask, defaultMask; // unsigned short minMod, maxMod;
unsigned short minMod, maxMod; // int pid;
int pid; // int vc;
int vc; // } Gpm_Connect;
} Gpm_Connect;
*/ function send_config(socket, Gpm_Connect, callback) {
function send_config(sock, Gpm_Connect, cb) { if (GPM_USE_MAGIC) {
if (GPM_USE_MAGIC) { var buffer = new Buffer(20);
var buffer=new Buffer(20); buffer.writeUInt32LE(GPM_MAGIC, 0);
buffer.writeUInt32LE(GPM_MAGIC, 0); buffer.writeUInt16LE(Gpm_Connect.eventMask, 4);
buffer.writeUInt16LE(Gpm_Connect.eventMask, 4); buffer.writeUInt16LE(Gpm_Connect.defaultMask, 6);
buffer.writeUInt16LE(Gpm_Connect.defaultMask, 6); buffer.writeUInt16LE(Gpm_Connect.minMod, 8);
buffer.writeUInt16LE(Gpm_Connect.minMod, 8); buffer.writeUInt16LE(Gpm_Connect.maxMod, 10);
buffer.writeUInt16LE(Gpm_Connect.maxMod, 10); buffer.writeInt16LE(process.pid, 12);
buffer.writeInt16LE(process.pid, 12); buffer.writeInt16LE(Gpm_Connect.vc, 16);
buffer.writeInt16LE(Gpm_Connect.vc, 16); } else {
} else { var buffer = new Buffer(16);
var buffer=new Buffer(16); buffer.writeUInt16LE(Gpm_Connect.eventMask, 0);
buffer.writeUInt16LE(Gpm_Connect.eventMask, 0); buffer.writeUInt16LE(Gpm_Connect.defaultMask, 2);
buffer.writeUInt16LE(Gpm_Connect.defaultMask, 2); buffer.writeUInt16LE(Gpm_Connect.minMod, 4);
buffer.writeUInt16LE(Gpm_Connect.minMod, 4); buffer.writeUInt16LE(Gpm_Connect.maxMod, 6);
buffer.writeUInt16LE(Gpm_Connect.maxMod, 6); buffer.writeInt16LE(Gpm_Connect.pid, 8);
buffer.writeInt16LE(Gpm_Connect.pid, 8); buffer.writeInt16LE(Gpm_Connect.vc, 12);
buffer.writeInt16LE(Gpm_Connect.vc, 12); }
} socket.write(buffer, function() {
sock.write(buffer, function () { if (callback) callback();
if (cb) cb(); });
}); }
}
// 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;
/*
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) { function parseEvent(raw) {
var evnt={}; var evnt = {};
evnt.buttons=raw[0]; evnt.buttons = raw[0];
evnt.modifiers=raw[1]; evnt.modifiers = raw[1];
evnt.vc=raw.readUInt16LE(2); evnt.vc = raw.readUInt16LE(2);
evnt.dx=raw.readInt16LE(4); evnt.dx = raw.readInt16LE(4);
evnt.dy=raw.readInt16LE(6); evnt.dy = raw.readInt16LE(6);
evnt.x=raw.readInt16LE(8); evnt.x = raw.readInt16LE(8);
evnt.y=raw.readInt16LE(10); evnt.y = raw.readInt16LE(10);
evnt.type=raw.readInt16LE(12); evnt.type = raw.readInt16LE(12);
evnt.clicks=raw.readInt32LE(16); evnt.clicks = raw.readInt32LE(16);
evnt.margin=raw.readInt32LE(20); evnt.margin = raw.readInt32LE(20);
evnt.wdx=raw.readInt16LE(24); evnt.wdx = raw.readInt16LE(24);
evnt.wdy=raw.readInt16LE(26); evnt.wdy = raw.readInt16LE(26);
return evnt; return evnt;
} }
function GpmClient(options) { function GpmClient(options) {
if (!(this instanceof GpmClient)) { if (!(this instanceof GpmClient)) {
return new GpmClient(options); return new GpmClient(options);
} }
EventEmitter.call(this);
var pid=process.pid;
// check tty for /dev/tty[n]
var tty=/tty[0-9]+$/.exec(fs.readlinkSync('/proc/'+pid+'/fd/0'));
if (tty === null) {
//TODO: should also check for /dev/input/..
}
var vc;
if (tty) {
var 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); EventEmitter.call(this);
this.gpm=gpm;
var pid = process.pid;
gpm.on('connect', function() {
send_config(gpm, conf, function() { // check tty for /dev/tty[n]
conf.pid=0; var tty = /tty[0-9]+$/.exec(fs.readlinkSync('/proc/' + pid + '/fd/0'));
conf.vc=GPM_REQ_NOPASTE; if (tty === null) {
//send_config(gpm, conf); // TODO: should also check for /dev/input/..
}); }
});
var vc;
gpm.on('data', function(packet) { if (tty) {
var evnt=parseEvent(packet); var tty = tty[0];
switch(evnt.type & 15) { vc = /[0-9]+$/.exec(tty)[0];
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) var self = this;
break;
case GPM_DRAG: if (tty) {
if (evnt.dx || evnt.dy) self.emit('drag', evnt.buttons, evnt.modifiers, evnt.x, evnt.y) fs.stat(GPM_SOCKET, function(err, stat) {
if (evnt.wdx || evnt.wdy) self.emit('mousewheel', evnt.buttons, evnt.modifiers, evnt.x, evnt.y, evnt.wdx, evnt.wdy) if (err || !stat.isSocket()) {
break; return;
case GPM_DOWN: }
self.emit('btndown', evnt.buttons, evnt.modifiers, evnt.x, evnt.y)
if (evnt.type & GPM_DOUBLE) { var conf = {
self.emit('dblclick', evnt.buttons, evnt.modifiers, evnt.x, evnt.y) eventMask: 0xffff,
} defaultMask: GPM_MOVE | GPM_HARD,
break; minMod: 0,
case GPM_UP: maxMod: 0xffff,
self.emit('btnup', evnt.buttons, evnt.modifiers, evnt.x, evnt.y) pid: pid,
if (!(evnt.type & GPM_MFLAG)) { vc: vc
self.emit('click', evnt.buttons, evnt.modifiers, evnt.x, evnt.y) };
}
break; var gpm = net.createConnection(GPM_SOCKET);
} this.gpm = gpm;
})
gpm.on('error', function(err) { gpm.on('connect', function() {
console.log('GPM ERROR', err); send_config(gpm, conf, function() {
self.stop(); 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(err) {
// console.log('GPM ERROR', err);
self.stop();
});
});
}
} }
GpmClient.prototype=new EventEmitter(); GpmClient.prototype.__proto__ = EventEmitter.prototype;
GpmClient.prototype.stop=function() { GpmClient.prototype.stop = function() {
if (this.gpm) this.gpm.end(); if (this.gpm) {
delete this.gpm; this.gpm.end();
} }
delete this.gpm;
};
GpmClient.prototype.ButtonName = function(btn) { GpmClient.prototype.ButtonName = function(btn) {
if (btn & 4) return 'left'; if (btn & 4) return 'left';
if (btn & 2) return 'middle'; if (btn & 2) return 'middle';
if (btn & 1) return 'right'; if (btn & 1) return 'right';
return '' return '';
} };
GpmClient.prototype.hasShiftKey = function(mod) { GpmClient.prototype.hasShiftKey = function(mod) {
return (mod & 1) ? true:false; return (mod & 1) ? true : false;
} };
GpmClient.prototype.hasCtrlKey = function(mod) { GpmClient.prototype.hasCtrlKey = function(mod) {
return (mod & 4) ? true:false; return (mod & 4) ? true : false;
} };
GpmClient.prototype.hasMetaKey = function(mod) { GpmClient.prototype.hasMetaKey = function(mod) {
return (mod & 8) ? true:false; return (mod & 8) ? true : false;
} };
module.exports = GpmClient;
module.exports=GpmClient;

View File

@ -635,94 +635,117 @@ Program.prototype._bindMouse = function(s, buf) {
/* gpm support for linux vc */ /* gpm support for linux vc */
Program.prototype.enableGpm = function() { Program.prototype.enableGpm = function() {
var gpmclient=require('./gpmclient') var self = this;
this.gpm=gpmclient(); var gpmclient = require('./gpmclient')
var self=this;
this.gpm.on('btndown', function(btn,modifier, x, y) {
x--, y--;
var key={
name: 'mouse', type: 'GPM',
action: 'mousedown',
button: self.gpm.ButtonName(btn),
raw: [btn,modifier, x, y],
x: x, y: y,
shift: self.gpm.hasShiftKey(modifier),
meta: self.gpm.hasMetaKey(modifier),
ctrl: self.gpm.hasCtrlKey(modifier)
};
self.emit('keypress', null, key);
self.emit('mouse', key);
});
this.gpm.on('btnup', function(btn,modifier, x, y) {
x--, y--;
var key={
name: 'mouse', type: 'GPM',
action: 'mouseup',
button: self.gpm.ButtonName(btn),
raw: [btn,modifier, x, y],
x: x, y: y,
shift: self.gpm.hasShiftKey(modifier),
meta: self.gpm.hasMetaKey(modifier),
ctrl: self.gpm.hasCtrlKey(modifier)
};
self.emit('keypress', null, key);
self.emit('mouse', key);
});
this.gpm.on('move', function(btn,modifier, x, y) {
x--, y--;
var key={
name: 'mouse', type: 'GPM',
action: 'mousemove',
button: self.gpm.ButtonName(btn),
raw: [btn,modifier, x, y],
x: x, y: y,
shift: self.gpm.hasShiftKey(modifier),
meta: self.gpm.hasMetaKey(modifier),
ctrl: self.gpm.hasCtrlKey(modifier)
};
self.emit('keypress', null, key);
self.emit('mouse', key);
});
this.gpm.on('drag', function(btn,modifier, x, y) {
x--, y--;
var key={
name: 'mouse', type: 'GPM',
action: 'mousemove',
button: self.gpm.ButtonName(btn),
raw: [btn,modifier, x, y],
x: x, y: y,
shift: self.gpm.hasShiftKey(modifier),
meta: self.gpm.hasMetaKey(modifier),
ctrl: self.gpm.hasCtrlKey(modifier)
};
self.emit('keypress', null, key);
self.emit('mouse', key);
});
this.gpm.on('mousewheel', function(btn,modifier, x, y, dx, dy) {
var key={
name: 'mouse', type: 'GPM',
action: dy>0? 'wheelup':'wheeldown',
button: self.gpm.ButtonName(btn),
raw: [btn,modifier, x, y, dx, dy],
x: x, y: y,
shift: self.gpm.hasShiftKey(modifier),
meta: self.gpm.hasMetaKey(modifier),
ctrl: self.gpm.hasCtrlKey(modifier)
};
self.emit('keypress', null, key); this.gpm = gpmclient();
self.emit('mouse', key);
}); this.gpm.on('btndown', function(btn, modifier, x, y) {
x--, y--;
var key = {
name: 'mouse',
type: 'GPM',
action: 'mousedown',
button: self.gpm.ButtonName(btn),
raw: [btn,modifier, x, y],
x: x,
y: y,
shift: self.gpm.hasShiftKey(modifier),
meta: self.gpm.hasMetaKey(modifier),
ctrl: self.gpm.hasCtrlKey(modifier)
};
self.emit('keypress', null, key);
self.emit('mouse', key);
});
this.gpm.on('btnup', function(btn, modifier, x, y) {
x--, y--;
var key = {
name: 'mouse',
type: 'GPM',
action: 'mouseup',
button: self.gpm.ButtonName(btn),
raw: [btn,modifier, x, y],
x: x,
y: y,
shift: self.gpm.hasShiftKey(modifier),
meta: self.gpm.hasMetaKey(modifier),
ctrl: self.gpm.hasCtrlKey(modifier)
};
self.emit('keypress', null, key);
self.emit('mouse', key);
});
this.gpm.on('move', function(btn, modifier, x, y) {
x--, y--;
var key = {
name: 'mouse',
type: 'GPM',
action: 'mousemove',
button: self.gpm.ButtonName(btn),
raw: [btn,modifier, x, y],
x: x,
y: y,
shift: self.gpm.hasShiftKey(modifier),
meta: self.gpm.hasMetaKey(modifier),
ctrl: self.gpm.hasCtrlKey(modifier)
};
self.emit('keypress', null, key);
self.emit('mouse', key);
});
this.gpm.on('drag', function(btn, modifier, x, y) {
x--, y--;
var key = {
name: 'mouse',
type: 'GPM',
action: 'mousemove',
button: self.gpm.ButtonName(btn),
raw: [btn,modifier, x, y],
x: x,
y: y,
shift: self.gpm.hasShiftKey(modifier),
meta: self.gpm.hasMetaKey(modifier),
ctrl: self.gpm.hasCtrlKey(modifier)
};
self.emit('keypress', null, key);
self.emit('mouse', key);
});
this.gpm.on('mousewheel', function(btn, modifier, x, y, dx, dy) {
var key = {
name: 'mouse',
type: 'GPM',
action: dy > 0 ? 'wheelup':'wheeldown',
button: self.gpm.ButtonName(btn),
raw: [btn,modifier, x, y, dx, dy],
x: x,
y: y,
shift: self.gpm.hasShiftKey(modifier),
meta: self.gpm.hasMetaKey(modifier),
ctrl: self.gpm.hasCtrlKey(modifier)
};
self.emit('keypress', null, key);
self.emit('mouse', key);
});
}; };
Program.prototype.disableGpm = function() { Program.prototype.disableGpm = function() {
if (this.gpm) { if (this.gpm) {
this.gpm.stop(); this.gpm.stop();
delete this.gpm; delete this.gpm;
} }
}; };
// All possible responses from the terminal // All possible responses from the terminal
Program.prototype.bindResponse = function() { Program.prototype.bindResponse = function() {
if (this._boundResponse) return; if (this._boundResponse) return;
@ -2751,37 +2774,43 @@ Program.prototype.normalBuffer = function() {
}; };
Program.prototype.enableMouse = function() { Program.prototype.enableMouse = function() {
console.log(process.env.BLESSED_FORCE_MODES);
if (process.env.BLESSED_FORCE_MODES) { if (process.env.BLESSED_FORCE_MODES) {
var modes=process.env.BLESSED_FORCE_MODES.split(','); var modes = process.env.BLESSED_FORCE_MODES.split(',');
var options={}; var options = {};
for (var n=0; n<modes.length; ++n) { for (var n = 0; n < modes.length; ++n) {
var mds=modes[n].split('='); var pair = modes[n].split('=');
var v=mds[1]=='0' ? false : true; var v = pair[1] !== '0';
switch(mds[0].toUpperCase()) { switch (pair[0].toUpperCase()) {
case 'SGRMOUSE': case 'SGRMOUSE':
options.sgrMouse=v; break; options.sgrMouse = v;
case 'UTFMOUSE': break;
options.utfMouse=v; break; case 'UTFMOUSE':
case 'VT200MOUSE': options.utfMouse = v;
options.vt200Mouse=v; break; break;
case 'URXVTMOUSE': case 'VT200MOUSE':
options.urxvtMouse=true; break; options.vt200Mouse = v;
case 'X10MOUSE': break;
options.x10Mouse=true; break; case 'URXVTMOUSE':
case 'GPMMOUSE': options.urxvtMouse = v;
this.enableGpm(); break;
break; case 'X10MOUSE':
case 'CELLMOTION': options.x10Mouse = v;
options.cellMotion=v; break; break;
case 'ALLMOTION': case 'GPMMOUSE':
options.allMotion=v; break; this.enableGpm();
case 'SENDFOCUS': break;
options.sendFocus=v; break; case 'CELLMOTION':
} options.cellMotion = v;
} break;
console.log(options); case 'ALLMOTION':
return this.setMouse(options, true); options.allMotion = v;
break;
case 'SENDFOCUS':
options.sendFocus = v;
break;
}
}
return this.setMouse(options, true);
} }
if (this.term('rxvt-unicode')) { if (this.term('rxvt-unicode')) {
@ -2810,7 +2839,7 @@ Program.prototype.enableMouse = function() {
} }
if (this.term('linux')) { if (this.term('linux')) {
this.enableGpm(); this.enableGpm();
return this.setMouse({ return this.setMouse({
vt200Mouse: true vt200Mouse: true
}, true); }, true);