mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
Merge pull request #109 from Tyriar/65_send_ctrl_l_r_key
Jump over words with ctrl+left/right
This commit is contained in:
+111
-113
@@ -2305,223 +2305,221 @@
|
||||
// Key Resources:
|
||||
// https://developer.mozilla.org/en-US/docs/DOM/KeyboardEvent
|
||||
Terminal.prototype.keyDown = function(ev) {
|
||||
var self = this, key;
|
||||
var self = this;
|
||||
var result = this.evaluateKeyEscapeSequence(ev);
|
||||
|
||||
if (result.scrollDisp) {
|
||||
this.scrollDisp(result.scrollDisp);
|
||||
return this.cancel(ev);
|
||||
}
|
||||
|
||||
if (result.cancel) {
|
||||
// The event is canceled at the end already, is this necessary?
|
||||
this.cancel(ev, true);
|
||||
}
|
||||
|
||||
if (!result.key || (this.isMac && ev.metaKey)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
this.emit('keydown', ev);
|
||||
this.emit('key', result.key, ev);
|
||||
this.showCursor();
|
||||
this.handler(result.key);
|
||||
|
||||
return this.cancel(ev, true);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns an object that determines how a KeyboardEvent should be handled. The key of the
|
||||
* returned value is the new key code to pass to the PTY.
|
||||
*
|
||||
* Reference: http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
|
||||
*/
|
||||
Terminal.prototype.evaluateKeyEscapeSequence = function(ev) {
|
||||
var result = {
|
||||
// Whether to cancel event propogation (NOTE: this may not be needed since the event is
|
||||
// canceled at the end of keyDown
|
||||
cancel: false,
|
||||
// The new key even to emit
|
||||
key: undefined,
|
||||
// The number of characters to scroll, if this is defined it will cancel the event
|
||||
scrollDisp: undefined
|
||||
};
|
||||
switch (ev.keyCode) {
|
||||
// backspace
|
||||
case 8:
|
||||
if (ev.shiftKey) {
|
||||
key = '\x08'; // ^H
|
||||
result.key = '\x08'; // ^H
|
||||
break;
|
||||
}
|
||||
key = '\x7f'; // ^?
|
||||
result.key = '\x7f'; // ^?
|
||||
break;
|
||||
// tab
|
||||
case 9:
|
||||
if (ev.shiftKey) {
|
||||
key = '\x1b[Z';
|
||||
result.key = '\x1b[Z';
|
||||
break;
|
||||
}
|
||||
key = '\t';
|
||||
this.cancel(ev, true);
|
||||
result.key = '\t';
|
||||
result.cancel = true;
|
||||
break;
|
||||
// return/enter
|
||||
case 13:
|
||||
key = '\r';
|
||||
this.cancel(ev, true);
|
||||
result.key = '\r';
|
||||
result.cancel = true;
|
||||
break;
|
||||
// escape
|
||||
case 27:
|
||||
key = '\x1b';
|
||||
this.cancel(ev, true);
|
||||
result.key = '\x1b';
|
||||
result.cancel = true;
|
||||
break;
|
||||
// left-arrow
|
||||
case 37:
|
||||
if (ev.altKey) {
|
||||
this.cancel(ev, true);
|
||||
key = '\x1bb' // Jump a word back
|
||||
break;
|
||||
} else if (this.applicationCursor) {
|
||||
key = '\x1bOD'; // SS3 as ^[O for 7-bit
|
||||
result.key = '\x1bb' // Jump a word back
|
||||
result.cancel = true;
|
||||
break;
|
||||
}
|
||||
key = '\x1b[D';
|
||||
if (ev.ctrlKey) {
|
||||
result.key = '\x1b[5D'; // Jump a word back
|
||||
break;
|
||||
}
|
||||
if (this.applicationCursor) {
|
||||
result.key = '\x1bOD'; // SS3 as ^[O for 7-bit
|
||||
break;
|
||||
}
|
||||
result.key = '\x1b[D';
|
||||
break;
|
||||
// right-arrow
|
||||
case 39:
|
||||
if (ev.altKey) {
|
||||
this.cancel(ev, true);
|
||||
key = '\x1bf' // Jump a word forward
|
||||
break;
|
||||
} else if (this.applicationCursor) {
|
||||
key = '\x1bOC';
|
||||
result.key = '\x1bf' // Jump a word forward
|
||||
result.cancel = true;
|
||||
break;
|
||||
}
|
||||
key = '\x1b[C';
|
||||
if (ev.ctrlKey) {
|
||||
result.key = '\x1b[5C'; // Jump a word forward
|
||||
break;
|
||||
}
|
||||
if (this.applicationCursor) {
|
||||
result.key = '\x1bOC';
|
||||
break;
|
||||
}
|
||||
result.key = '\x1b[C';
|
||||
break;
|
||||
// up-arrow
|
||||
case 38:
|
||||
if (this.applicationCursor) {
|
||||
key = '\x1bOA';
|
||||
result.key = '\x1bOA';
|
||||
break;
|
||||
}
|
||||
if (ev.ctrlKey) {
|
||||
this.scrollDisp(-1);
|
||||
return this.cancel(ev);
|
||||
result.scrollDisp = -1;
|
||||
} else {
|
||||
key = '\x1b[A';
|
||||
result.key = '\x1b[A';
|
||||
}
|
||||
break;
|
||||
// down-arrow
|
||||
case 40:
|
||||
if (this.applicationCursor) {
|
||||
key = '\x1bOB';
|
||||
result.key = '\x1bOB';
|
||||
break;
|
||||
}
|
||||
if (ev.ctrlKey) {
|
||||
this.scrollDisp(1);
|
||||
return this.cancel(ev);
|
||||
result.scrollDisp = 1;
|
||||
} else {
|
||||
key = '\x1b[B';
|
||||
result.key = '\x1b[B';
|
||||
}
|
||||
break;
|
||||
// delete
|
||||
case 46:
|
||||
key = '\x1b[3~';
|
||||
break;
|
||||
// insert
|
||||
case 45:
|
||||
if (!ev.shiftKey && !ev.ctrlKey) {
|
||||
// <Ctrl> or <Shift> + <Insert> are used to
|
||||
// copy-paste on some systems.
|
||||
key = '\x1b[2~';
|
||||
result.key = '\x1b[2~';
|
||||
}
|
||||
break;
|
||||
// delete
|
||||
case 46: result.key = '\x1b[3~'; break;
|
||||
// home
|
||||
case 36:
|
||||
if (this.applicationKeypad) {
|
||||
key = '\x1bOH';
|
||||
result.key = '\x1bOH';
|
||||
break;
|
||||
}
|
||||
key = '\x1bOH';
|
||||
result.key = '\x1bOH';
|
||||
break;
|
||||
// end
|
||||
case 35:
|
||||
if (this.applicationKeypad) {
|
||||
key = '\x1bOF';
|
||||
result.key = '\x1bOF';
|
||||
break;
|
||||
}
|
||||
key = '\x1bOF';
|
||||
result.key = '\x1bOF';
|
||||
break;
|
||||
// page up
|
||||
case 33:
|
||||
if (ev.shiftKey) {
|
||||
this.scrollDisp(-(this.rows - 1));
|
||||
return this.cancel(ev);
|
||||
result.scrollDisp = -(this.rows - 1);
|
||||
} else {
|
||||
key = '\x1b[5~';
|
||||
result.key = '\x1b[5~';
|
||||
}
|
||||
break;
|
||||
// page down
|
||||
case 34:
|
||||
if (ev.shiftKey) {
|
||||
this.scrollDisp(this.rows - 1);
|
||||
return this.cancel(ev);
|
||||
result.scrollDisp = this.rows - 1;
|
||||
} else {
|
||||
key = '\x1b[6~';
|
||||
result.key = '\x1b[6~';
|
||||
}
|
||||
break;
|
||||
// F1
|
||||
case 112:
|
||||
key = '\x1bOP';
|
||||
break;
|
||||
// F2
|
||||
case 113:
|
||||
key = '\x1bOQ';
|
||||
break;
|
||||
// F3
|
||||
case 114:
|
||||
key = '\x1bOR';
|
||||
break;
|
||||
// F4
|
||||
case 115:
|
||||
key = '\x1bOS';
|
||||
break;
|
||||
// F5
|
||||
case 116:
|
||||
key = '\x1b[15~';
|
||||
break;
|
||||
// F6
|
||||
case 117:
|
||||
key = '\x1b[17~';
|
||||
break;
|
||||
// F7
|
||||
case 118:
|
||||
key = '\x1b[18~';
|
||||
break;
|
||||
// F8
|
||||
case 119:
|
||||
key = '\x1b[19~';
|
||||
break;
|
||||
// F9
|
||||
case 120:
|
||||
key = '\x1b[20~';
|
||||
break;
|
||||
// F10
|
||||
case 121:
|
||||
key = '\x1b[21~';
|
||||
break;
|
||||
// F11
|
||||
case 122:
|
||||
key = '\x1b[23~';
|
||||
break;
|
||||
// F12
|
||||
case 123:
|
||||
key = '\x1b[24~';
|
||||
break;
|
||||
// F1-F12
|
||||
case 112: result.key = '\x1bOP'; break;
|
||||
case 113: result.key = '\x1bOQ'; break;
|
||||
case 114: result.key = '\x1bOR'; break;
|
||||
case 115: result.key = '\x1bOS'; break;
|
||||
case 116: result.key = '\x1b[15~'; break;
|
||||
case 117: result.key = '\x1b[17~'; break;
|
||||
case 118: result.key = '\x1b[18~'; break;
|
||||
case 119: result.key = '\x1b[19~'; break;
|
||||
case 120: result.key = '\x1b[20~'; break;
|
||||
case 121: result.key = '\x1b[21~'; break;
|
||||
case 122: result.key = '\x1b[23~'; break;
|
||||
case 123: result.key = '\x1b[24~'; break;
|
||||
default:
|
||||
// a-z and space
|
||||
if (ev.ctrlKey && !ev.shiftKey && !ev.altKey && !ev.metaKey) {
|
||||
if (ev.keyCode >= 65 && ev.keyCode <= 90) {
|
||||
key = String.fromCharCode(ev.keyCode - 64);
|
||||
result.key = String.fromCharCode(ev.keyCode - 64);
|
||||
} else if (ev.keyCode === 32) {
|
||||
// NUL
|
||||
key = String.fromCharCode(0);
|
||||
result.key = String.fromCharCode(0);
|
||||
} else if (ev.keyCode >= 51 && ev.keyCode <= 55) {
|
||||
// escape, file sep, group sep, record sep, unit sep
|
||||
key = String.fromCharCode(ev.keyCode - 51 + 27);
|
||||
result.key = String.fromCharCode(ev.keyCode - 51 + 27);
|
||||
} else if (ev.keyCode === 56) {
|
||||
// delete
|
||||
key = String.fromCharCode(127);
|
||||
result.key = String.fromCharCode(127);
|
||||
} else if (ev.keyCode === 219) {
|
||||
// ^[ - escape
|
||||
key = String.fromCharCode(27);
|
||||
result.key = String.fromCharCode(27);
|
||||
} else if (ev.keyCode === 221) {
|
||||
// ^] - group sep
|
||||
key = String.fromCharCode(29);
|
||||
result.key = String.fromCharCode(29);
|
||||
}
|
||||
} else if ((!this.isMac && ev.altKey) || (this.isMac && ev.metaKey)) {
|
||||
if (ev.keyCode >= 65 && ev.keyCode <= 90) {
|
||||
key = '\x1b' + String.fromCharCode(ev.keyCode + 32);
|
||||
result.key = '\x1b' + String.fromCharCode(ev.keyCode + 32);
|
||||
} else if (ev.keyCode === 192) {
|
||||
key = '\x1b`';
|
||||
result.key = '\x1b`';
|
||||
} else if (ev.keyCode >= 48 && ev.keyCode <= 57) {
|
||||
key = '\x1b' + (ev.keyCode - 48);
|
||||
result.key = '\x1b' + (ev.keyCode - 48);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!key || (this.isMac && ev.metaKey)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
this.emit('keydown', ev);
|
||||
this.emit('key', key, ev);
|
||||
this.showCursor();
|
||||
this.handler(key);
|
||||
|
||||
return this.cancel(ev, true);
|
||||
return result;
|
||||
};
|
||||
|
||||
Terminal.prototype.setgLevel = function(g) {
|
||||
|
||||
+53
-2
@@ -1,6 +1,57 @@
|
||||
var assert = require('chai').assert;
|
||||
var Terminal = require('../src/xterm');
|
||||
|
||||
describe('xterm.js', function() {
|
||||
var xterm;
|
||||
|
||||
describe('xterm', function() {
|
||||
// Just a dummy first test
|
||||
beforeEach(function () {
|
||||
xterm = new Terminal();
|
||||
});
|
||||
|
||||
describe('evaluateKeyEscapeSequence', function() {
|
||||
it('should return the correct escape sequence for unmodified keys', function() {
|
||||
// Backspace
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 8 }).key, '\x7f'); // ^?
|
||||
// Tab
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 9 }).key, '\t');
|
||||
// Return/enter
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 13 }).key, '\r'); // CR
|
||||
// Escape
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 27 }).key, '\x1b');
|
||||
// Page up, page down
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 33 }).key, '\x1b[5~'); // CSI 5 ~
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 34 }).key, '\x1b[6~'); // CSI 6 ~
|
||||
// End, Home
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 35 }).key, '\x1bOF'); // SS3 F
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 36 }).key, '\x1bOH'); // SS3 H
|
||||
// Left, up, right, down arrows
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 37 }).key, '\x1b[D'); // CSI D
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 38 }).key, '\x1b[A'); // CSI A
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 39 }).key, '\x1b[C'); // CSI C
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 40 }).key, '\x1b[B'); // CSI B
|
||||
// Insert
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 45 }).key, '\x1b[2~'); // CSI 2 ~
|
||||
// Delete
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 46 }).key, '\x1b[3~'); // CSI 3 ~
|
||||
// F1-F12
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 112 }).key, '\x1bOP'); // SS3 P
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 113 }).key, '\x1bOQ'); // SS3 Q
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 114 }).key, '\x1bOR'); // SS3 R
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 115 }).key, '\x1bOS'); // SS3 S
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 116 }).key, '\x1b[15~'); // CSI 1 5 ~
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 117 }).key, '\x1b[17~'); // CSI 1 7 ~
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 118 }).key, '\x1b[18~'); // CSI 1 8 ~
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 119 }).key, '\x1b[19~'); // CSI 1 9 ~
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 120 }).key, '\x1b[20~'); // CSI 2 0 ~
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 121 }).key, '\x1b[21~'); // CSI 2 1 ~
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 122 }).key, '\x1b[23~'); // CSI 2 3 ~
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 123 }).key, '\x1b[24~'); // CSI 2 4 ~
|
||||
});
|
||||
it('should return \\x1b[5D for ctrl+left', function() {
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 37 }).key, '\x1b[5D'); // CSI 5 D
|
||||
});
|
||||
it('should return \\x1b[5C for ctrl+right', function() {
|
||||
assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 39 }).key, '\x1b[5C'); // CSI 5 C
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user