c9-core/plugins/c9.ide.terminal/aceterm/mouse.js

311 wiersze
9.9 KiB
JavaScript

define(function(require, exports, module) {
var lang = require("ace/lib/lang");
module.exports = function bindMouse(ace) {
var pressed = 32;
var wheelEvent = "mousewheel";
// mouseup, mousedown, mousewheel
// left click: ^[[M 3<^[[M#3<
// mousewheel up: ^[[M`3>
function sendButton(ev) {
var term = ace.session.term
// get the xterm-style button
var button = getButton(ev);
// get mouse coordinates
var pos = getCoords(ev);
if (!pos) return;
sendEvent(button, pos);
switch (ev.type) {
case 'mousedown':
pressed = button;
break;
case 'mouseup':
// keep it at the left
// button, just in case.
pressed = 32;
break;
case wheelEvent:
// nothing. don't
// interfere with
// `pressed`.
break;
}
}
// motion example of a left click:
// ^[[M 3<^[[M@4<^[[M@5<^[[M@6<^[[M@7<^[[M#7<
function sendMove(ev) {
var term = ace.session.term
var button = pressed;
var pos = getCoords(ev);
if (!pos) return;
// buttons marked as motions
// are incremented by 32
button += 32;
sendEvent(button, pos);
}
// encode button and
// position to characters
function encode(data, ch) {
var term = ace.session.term;
if (!term.utfMouse) {
if (ch === 255) return data.push(0);
if (ch > 127) ch = 127;
data.push(ch);
}
else {
if (ch === 2047) return data.push(0);
if (ch < 127) {
data.push(ch);
}
else {
if (ch > 2047) ch = 2047;
data.push(0xC0 | (ch >> 6));
data.push(0x80 | (ch & 0x3F));
}
}
}
// send a mouse event:
// regular/utf8: ^[[M Cb Cx Cy
// urxvt: ^[[ Cb ; Cx ; Cy M
// sgr: ^[[ Cb ; Cx ; Cy M/m
// vt300: ^[[ 24(1/3/5)~ [ Cx , Cy ] \r
// locator: CSI P e ; P b ; P r ; P c ; P p & w
function sendEvent(button, pos) {
var term = ace.session.term;
// term.emit('mouse', {
// x: pos.x - 32,
// y: pos.x - 32,
// button: button
// });
if (term.vt300Mouse) {
// NOTE: Unstable.
// http://www.vt100.net/docs/vt3xx-gp/chapter15.html
button &= 3;
pos.x -= 32;
pos.y -= 32;
var data = '\x1b[24';
if (button === 0) data += '1';
else if (button === 1) data += '3';
else if (button === 2) data += '5';
else if (button === 3) return;
else data += '0';
data += '~[' + pos.x + ',' + pos.y + ']\r';
term.send(data);
return;
}
if (term.decLocator) {
// NOTE: Unstable.
button &= 3;
pos.x -= 32;
pos.y -= 32;
if (button === 0) button = 2;
else if (button === 1) button = 4;
else if (button === 2) button = 6;
else if (button === 3) button = 3;
term.send('\x1b[' + button + ';' + (button === 3 ? 4 : 0) + ';' + pos.y + ';' + pos.x + ';' + (pos.tab || 0) + '&w');
return;
}
if (term.urxvtMouse) {
pos.x -= 32;
pos.y -= 32;
pos.x++;
pos.y++;
term.send('\x1b[' + button + ';' + pos.x + ';' + pos.y + 'M');
return;
}
if (term.sgrMouse) {
pos.x -= 32;
pos.y -= 32;
term.send('\x1b[<' + ((button & 3) === 3 ? button & ~3 : button) + ';' + pos.x + ';' + pos.y + ((button & 3) === 3 ? 'm' : 'M'));
return;
}
var data = [];
encode(data, button);
encode(data, pos.x);
encode(data, pos.y);
term.send('\x1b[M' + String.fromCharCode.apply(String, data));
}
function getButton(ev) {
var term = ace.session.term;
var button, shift, meta, ctrl, mod;
// two low bits:
// 0 = left
// 1 = middle
// 2 = right
// 3 = release
// wheel up/down:
// 1, and 2 - with 64 added
switch (ev.type) {
case 'mousedown':
button = ev.button || 0;
break;
case 'mouseup':
button = 3;
break;
case 'mousewheel':
button = ev.wheelY < 0 ? 64 : 65;
break;
}
// next three bits are the modifiers:
// 4 = shift, 8 = meta, 16 = control
shift = ev.shiftKey ? 4 : 0;
meta = ev.metaKey ? 8 : 0;
ctrl = ev.ctrlKey ? 16 : 0;
mod = shift | meta | ctrl;
// no mods
if (term.vt200Mouse) {
// ctrl only
mod &= ctrl;
}
else if (!term.normalMouse) {
mod = 0;
}
// increment to SP
button = (32 + (mod << 2)) + button;
return button;
}
// mouse coordinates measured in cols/rows
function getCoords(ev) {
var term = ace.session.term;
var pos = ace.renderer.pixelToScreenCoordinates(ev.clientX, ev.clientY);
var x = pos.column, y = pos.row;
// be sure to avoid sending
// bad positions to the program
if (x < 0) x = 0;
if (x > term.cols) x = term.cols;
if (y < 0) y = 0;
if (y > term.rows) y = term.rows;
// xterm sends raw bytes and
// starts at 32 (SP) for each.
x += 32;
y += 32;
return {
x: x,
y: y,
down: ev.type === 'mousedown',
up: ev.type === 'mouseup',
wheel: ev.type === wheelEvent,
move: ev.type === 'mousemove'
};
}
function altOnly(e) {
return e.altKey && !e.shiftKey && !e.metaKey && !e.ctrlKey;
}
ace.on('mousedown', function(ev) {
var term = ace.session.term;
if (!term || !term.mouseEvents
|| term.copyMode && !altOnly(ev.domEvent)) {
return;
}
ace.focus();
// send the button
sendButton(ev);
// fix for odd bug
if (term.vt200Mouse) {
sendButton({__proto__: ev, type: 'mouseup'});
return ev.stop();
}
// bind events
if (term.normalMouse) ace.on('mousemove', sendMove);
// x10 compatibility mode can't send button releases
if (!term.x10Mouse) {
ace.on('mouseup', function up(ev) {
sendButton(ev);
if (term.normalMouse) ace.off('mousemove', sendMove);
ace.off('mouseup', up);
return ev.stop(ev);
});
}
return ev.stop(ev);
}, true);
ace.on("mousewheel", function(ev) {
var term = ace.session.term;
if (!term.mouseEvents) return;
if (term.x10Mouse || term.vt300Mouse || term.decLocator) return;
ev.type = "mousewheel";
ev.shiftKey = ev.domEvent.shiftKey;
ev.metaKey = ev.domEvent.metaKey;
ev.ctrlKey = ev.domEvent.ctrlKey;
sendButton(ev);
return ev.stop();
}, true);
// allow mousewheel scrolling in
// the shell for example
ace.on("mousewheel", function(ev) {
var term = ace.session.term;
if (term.mouseEvents) return;
if (term.applicationKeypad) {
term.send(ev.wheelY < 0
? '\x1bOA\x1bOA\x1bOA'
: '\x1bOB\x1bOB\x1bOB'
);
return ev.stop(ev);
}
});
ace.on("click", function(e) {
var term = ace.session.term;
if (term.mouseEvents) return;
var pos = e.getDocumentPosition();
if (e.domEvent.altKey && ace.session.selection.isEmpty()) {
var row = pos.row;
var wrappedLen = 0;
var cursorRow = term.ybase + term.y;
while (row < cursorRow) {
var lineData = ace.session.getLineData(row);
if (!lineData || !lineData.wrapped)
break;
wrappedLen -= ace.session.getLine(row).length;
row ++;
}
while (row > cursorRow) {
var lineData = ace.session.getLineData(row - 1);
if (!lineData || !lineData.wrapped)
break;
wrappedLen += ace.session.getLine(row - 1).length;
row --;
}
if (row == cursorRow) {
var dx = pos.column + wrappedLen - term.x;
if (dx < 0)
var str = lang.stringRepeat("\x1b[D", -dx);
else
var str = lang.stringRepeat("\x1b[C", dx);
term.send(str);
}
}
});
};
});