Merge pull request #1508 from Tyriar/layering

Start of improved layering
This commit is contained in:
Daniel Imms
2018-06-20 21:35:51 +10:00
committed by GitHub
22 changed files with 918 additions and 678 deletions
+3 -3
View File
@@ -170,7 +170,7 @@ function initOptions(term) {
fontWeight: ['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900'],
fontWeightBold: ['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900']
};
var options = Object.keys(term.options);
var options = Object.keys(term._core.options);
var booleanOptions = [];
var numberOptions = [];
options.filter(o => blacklistedOptions.indexOf(o) === -1).forEach(o => {
@@ -241,8 +241,8 @@ function initOptions(term) {
function updateTerminalSize() {
var cols = parseInt(document.getElementById(`opt-cols`).value, 10);
var rows = parseInt(document.getElementById(`opt-rows`).value, 10);
var width = (cols * term.renderer.dimensions.actualCellWidth + term.viewport.scrollBarWidth).toString() + 'px';
var height = (rows * term.renderer.dimensions.actualCellHeight).toString() + 'px';
var width = (cols * term._core.renderer.dimensions.actualCellWidth + term._core.viewport.scrollBarWidth).toString() + 'px';
var height = (rows * term._core.renderer.dimensions.actualCellHeight).toString() + 'px';
terminalContainer.style.width = width;
terminalContainer.style.height = height;
term.fit();
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "xterm",
"description": "Full xterm terminal, in your browser",
"version": "3.4.0",
"main": "lib/Terminal.js",
"main": "lib/public/Terminal.js",
"types": "typings/xterm.d.ts",
"repository": "https://github.com/xtermjs/xterm.js",
"license": "MIT",
+4 -3
View File
@@ -4,13 +4,14 @@
* @license MIT
*/
import { CharData, IInputHandler, IDcsHandler, IEscapeSequenceParser, IBuffer, ICharset } from './Types';
import { C0, C1 } from './EscapeSequences';
import { CHARSETS, DEFAULT_CHARSET } from './Charsets';
import { CharData, IInputHandler, IDcsHandler, IEscapeSequenceParser, IBuffer } from './Types';
import { C0, C1 } from './common/data/EscapeSequences';
import { CHARSETS, DEFAULT_CHARSET } from './core/data/Charsets';
import { CHAR_DATA_CHAR_INDEX, CHAR_DATA_WIDTH_INDEX, CHAR_DATA_CODE_INDEX, DEFAULT_ATTR } from './Buffer';
import { FLAGS } from './renderer/Types';
import { wcwidth } from './CharWidth';
import { EscapeSequenceParser } from './EscapeSequenceParser';
import { ICharset } from './core/Types';
/**
* Map collect to glevel. Used in `selectCharset`.
+2 -2
View File
@@ -4,9 +4,9 @@
* @license MIT
*/
import { C0 } from './EscapeSequences';
import { C0 } from './common/data/EscapeSequences';
import { IInputHandler, IInputHandlingTerminal } from './Types';
import { CHARSETS, DEFAULT_CHARSET } from './Charsets';
import { CHARSETS, DEFAULT_CHARSET } from './core/data/Charsets';
const normalStateHandler: {[key: string]: (parser: Parser, handler: IInputHandler) => void} = {};
normalStateHandler[C0.BEL] = (parser, handler) => handler.bell();
+5 -260
View File
@@ -5,7 +5,6 @@
import { assert, expect } from 'chai';
import { Terminal } from './Terminal';
import * as attach from './addons/attach/attach';
import { MockViewport, MockCompositionHelper, MockRenderer } from './utils/TestUtils.test';
import { CHAR_DATA_CHAR_INDEX, CHAR_DATA_WIDTH_INDEX } from './Buffer';
@@ -13,7 +12,6 @@ const INIT_COLS = 80;
const INIT_ROWS = 24;
class TestTerminal extends Terminal {
public evaluateKeyEscapeSequence(ev: any): {cancel: boolean, key: string, scrollLines: number} { return this._evaluateKeyEscapeSequence(<KeyboardEvent>ev); }
public keyDown(ev: any): boolean { return this._keyDown(ev); }
public keyPress(ev: any): boolean { return this._keyPress(ev); }
}
@@ -53,13 +51,6 @@ describe('term.js addons', () => {
});
});
it('should apply addons with Terminal.applyAddon', () => {
Terminal.applyAddon(attach);
// Test that addon was applied successfully, adding attach to Terminal's
// prototype.
assert.equal(typeof (<any>Terminal).prototype.attach, 'function');
});
describe('getOption', () => {
it('should retrieve the option correctly', () => {
// In the `options` namespace.
@@ -296,22 +287,19 @@ describe('term.js addons', () => {
});
});
describe('keyDown', () => {
describe('keyPress', () => {
it('should scroll down, when a key is pressed and terminal is scrolled up', () => {
// Override _evaluateKeyEscapeSequence to return cancel code
(<any>term)._evaluateKeyEscapeSequence = () => {
return { key: 'a' };
};
const event = <KeyboardEvent>{
type: 'keydown',
keyCode: 0,
key: 'a',
keyCode: 65,
preventDefault: () => {},
stopPropagation: () => {}
};
term.buffer.ydisp = 0;
term.buffer.ybase = 40;
term.keyDown(event);
term.keyPress(event);
// Ensure that now the terminal is scrolled to bottom
assert.equal(term.buffer.ydisp, term.buffer.ybase);
@@ -330,7 +318,7 @@ describe('term.js addons', () => {
assert.equal(term.buffer.ydisp, startYDisp);
term.scrollLines(-1);
assert.equal(term.buffer.ydisp, startYDisp - 1);
term.keyDown(<KeyboardEvent>{ keyCode: 0 });
term.keyPress(<KeyboardEvent>{ keyCode: 0 });
assert.equal(term.buffer.ydisp, startYDisp - 1);
});
});
@@ -468,249 +456,6 @@ describe('term.js addons', () => {
});
});
describe('evaluateKeyEscapeSequence', () => {
it('should return the correct escape sequence for unmodified keys', () => {
// Backspace
assert.equal(term.evaluateKeyEscapeSequence({ keyCode: 8 }).key, '\x7f'); // ^?
// Tab
assert.equal(term.evaluateKeyEscapeSequence({ keyCode: 9 }).key, '\t');
// Return/enter
assert.equal(term.evaluateKeyEscapeSequence({ keyCode: 13 }).key, '\r'); // CR
// Escape
assert.equal(term.evaluateKeyEscapeSequence({ keyCode: 27 }).key, '\x1b');
// Page up, page down
assert.equal(term.evaluateKeyEscapeSequence({ keyCode: 33 }).key, '\x1b[5~'); // CSI 5 ~
assert.equal(term.evaluateKeyEscapeSequence({ keyCode: 34 }).key, '\x1b[6~'); // CSI 6 ~
// End, Home
assert.equal(term.evaluateKeyEscapeSequence({ keyCode: 35 }).key, '\x1b[F'); // SS3 F
assert.equal(term.evaluateKeyEscapeSequence({ keyCode: 36 }).key, '\x1b[H'); // SS3 H
// Left, up, right, down arrows
assert.equal(term.evaluateKeyEscapeSequence({ keyCode: 37 }).key, '\x1b[D'); // CSI D
assert.equal(term.evaluateKeyEscapeSequence({ keyCode: 38 }).key, '\x1b[A'); // CSI A
assert.equal(term.evaluateKeyEscapeSequence({ keyCode: 39 }).key, '\x1b[C'); // CSI C
assert.equal(term.evaluateKeyEscapeSequence({ keyCode: 40 }).key, '\x1b[B'); // CSI B
// Insert
assert.equal(term.evaluateKeyEscapeSequence({ keyCode: 45 }).key, '\x1b[2~'); // CSI 2 ~
// Delete
assert.equal(term.evaluateKeyEscapeSequence({ keyCode: 46 }).key, '\x1b[3~'); // CSI 3 ~
// F1-F12
assert.equal(term.evaluateKeyEscapeSequence({ keyCode: 112 }).key, '\x1bOP'); // SS3 P
assert.equal(term.evaluateKeyEscapeSequence({ keyCode: 113 }).key, '\x1bOQ'); // SS3 Q
assert.equal(term.evaluateKeyEscapeSequence({ keyCode: 114 }).key, '\x1bOR'); // SS3 R
assert.equal(term.evaluateKeyEscapeSequence({ keyCode: 115 }).key, '\x1bOS'); // SS3 S
assert.equal(term.evaluateKeyEscapeSequence({ keyCode: 116 }).key, '\x1b[15~'); // CSI 1 5 ~
assert.equal(term.evaluateKeyEscapeSequence({ keyCode: 117 }).key, '\x1b[17~'); // CSI 1 7 ~
assert.equal(term.evaluateKeyEscapeSequence({ keyCode: 118 }).key, '\x1b[18~'); // CSI 1 8 ~
assert.equal(term.evaluateKeyEscapeSequence({ keyCode: 119 }).key, '\x1b[19~'); // CSI 1 9 ~
assert.equal(term.evaluateKeyEscapeSequence({ keyCode: 120 }).key, '\x1b[20~'); // CSI 2 0 ~
assert.equal(term.evaluateKeyEscapeSequence({ keyCode: 121 }).key, '\x1b[21~'); // CSI 2 1 ~
assert.equal(term.evaluateKeyEscapeSequence({ keyCode: 122 }).key, '\x1b[23~'); // CSI 2 3 ~
assert.equal(term.evaluateKeyEscapeSequence({ keyCode: 123 }).key, '\x1b[24~'); // CSI 2 4 ~
});
it('should return \\x1b[3;5~ for ctrl+delete', () => {
assert.equal(term.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 46 }).key, '\x1b[3;5~');
});
it('should return \\x1b[3;2~ for shift+delete', () => {
assert.equal(term.evaluateKeyEscapeSequence({ shiftKey: true, keyCode: 46 }).key, '\x1b[3;2~');
});
it('should return \\x1b[3;3~ for alt+delete', () => {
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, keyCode: 46 }).key, '\x1b[3;3~');
});
it('should return \\x1b[5D for ctrl+left', () => {
assert.equal(term.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 37 }).key, '\x1b[1;5D'); // CSI 5 D
});
it('should return \\x1b[5C for ctrl+right', () => {
assert.equal(term.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 39 }).key, '\x1b[1;5C'); // CSI 5 C
});
it('should return \\x1b[5A for ctrl+up', () => {
assert.equal(term.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 38 }).key, '\x1b[1;5A'); // CSI 5 A
});
it('should return \\x1b[5B for ctrl+down', () => {
assert.equal(term.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 40 }).key, '\x1b[1;5B'); // CSI 5 B
});
describe('On non-macOS platforms', () => {
beforeEach(() => {
term.browser.isMac = false;
});
// Evalueate alt + arrow key movement, which is a feature of terminal emulators but not VT100
// http://unix.stackexchange.com/a/108106
it('should return \\x1b[5D for alt+left', () => {
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, keyCode: 37 }).key, '\x1b[1;5D'); // CSI 5 D
});
it('should return \\x1b[5C for alt+right', () => {
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, keyCode: 39 }).key, '\x1b[1;5C'); // CSI 5 C
});
it('should return \\x1ba for alt+a', () => {
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, keyCode: 65 }).key, '\x1ba');
});
});
describe('On macOS platforms', () => {
beforeEach(() => {
term.browser.isMac = true;
});
it('should return \\x1bb for alt+left', () => {
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, keyCode: 37 }).key, '\x1bb'); // CSI 5 D
});
it('should return \\x1bf for alt+right', () => {
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, keyCode: 39 }).key, '\x1bf'); // CSI 5 C
});
it('should return undefined for alt+a', () => {
assert.strictEqual(term.evaluateKeyEscapeSequence({ altKey: true, keyCode: 65 }).key, undefined);
});
});
describe('with macOptionIsMeta', () => {
beforeEach(() => {
term.browser.isMac = true;
term.setOption('macOptionIsMeta', true);
});
it('should return \\x1ba for alt+a', () => {
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, keyCode: 65 }).key, '\x1ba');
});
});
it('should return \\x1b[5A for alt+up', () => {
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, keyCode: 38 }).key, '\x1b[1;5A'); // CSI 5 A
});
it('should return \\x1b[5B for alt+down', () => {
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, keyCode: 40 }).key, '\x1b[1;5B'); // CSI 5 B
});
it('should return the correct escape sequence for modified F1-F12 keys', () => {
assert.equal(term.evaluateKeyEscapeSequence({ shiftKey: true, keyCode: 112 }).key, '\x1b[1;2P');
assert.equal(term.evaluateKeyEscapeSequence({ shiftKey: true, keyCode: 113 }).key, '\x1b[1;2Q');
assert.equal(term.evaluateKeyEscapeSequence({ shiftKey: true, keyCode: 114 }).key, '\x1b[1;2R');
assert.equal(term.evaluateKeyEscapeSequence({ shiftKey: true, keyCode: 115 }).key, '\x1b[1;2S');
assert.equal(term.evaluateKeyEscapeSequence({ shiftKey: true, keyCode: 116 }).key, '\x1b[15;2~');
assert.equal(term.evaluateKeyEscapeSequence({ shiftKey: true, keyCode: 117 }).key, '\x1b[17;2~');
assert.equal(term.evaluateKeyEscapeSequence({ shiftKey: true, keyCode: 118 }).key, '\x1b[18;2~');
assert.equal(term.evaluateKeyEscapeSequence({ shiftKey: true, keyCode: 119 }).key, '\x1b[19;2~');
assert.equal(term.evaluateKeyEscapeSequence({ shiftKey: true, keyCode: 120 }).key, '\x1b[20;2~');
assert.equal(term.evaluateKeyEscapeSequence({ shiftKey: true, keyCode: 121 }).key, '\x1b[21;2~');
assert.equal(term.evaluateKeyEscapeSequence({ shiftKey: true, keyCode: 122 }).key, '\x1b[23;2~');
assert.equal(term.evaluateKeyEscapeSequence({ shiftKey: true, keyCode: 123 }).key, '\x1b[24;2~');
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, keyCode: 112 }).key, '\x1b[1;3P');
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, keyCode: 113 }).key, '\x1b[1;3Q');
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, keyCode: 114 }).key, '\x1b[1;3R');
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, keyCode: 115 }).key, '\x1b[1;3S');
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, keyCode: 116 }).key, '\x1b[15;3~');
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, keyCode: 117 }).key, '\x1b[17;3~');
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, keyCode: 118 }).key, '\x1b[18;3~');
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, keyCode: 119 }).key, '\x1b[19;3~');
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, keyCode: 120 }).key, '\x1b[20;3~');
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, keyCode: 121 }).key, '\x1b[21;3~');
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, keyCode: 122 }).key, '\x1b[23;3~');
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, keyCode: 123 }).key, '\x1b[24;3~');
assert.equal(term.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 112 }).key, '\x1b[1;5P');
assert.equal(term.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 113 }).key, '\x1b[1;5Q');
assert.equal(term.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 114 }).key, '\x1b[1;5R');
assert.equal(term.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 115 }).key, '\x1b[1;5S');
assert.equal(term.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 116 }).key, '\x1b[15;5~');
assert.equal(term.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 117 }).key, '\x1b[17;5~');
assert.equal(term.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 118 }).key, '\x1b[18;5~');
assert.equal(term.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 119 }).key, '\x1b[19;5~');
assert.equal(term.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 120 }).key, '\x1b[20;5~');
assert.equal(term.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 121 }).key, '\x1b[21;5~');
assert.equal(term.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 122 }).key, '\x1b[23;5~');
assert.equal(term.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 123 }).key, '\x1b[24;5~');
});
// Characters using ctrl+alt sequences
it('should return proper sequence for ctrl+alt+a', () => {
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, ctrlKey: true, keyCode: 65 }).key, '\x1b\x01');
});
// Characters using alt sequences (numbers)
it('should return proper sequences for alt+0', () => {
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: false, keyCode: 48 }).key, '\x1b0');
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: true, keyCode: 48 }).key, '\x1b)');
});
it('should return proper sequences for alt+1', () => {
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: false, keyCode: 49 }).key, '\x1b1');
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: true, keyCode: 49 }).key, '\x1b!');
});
it('should return proper sequences for alt+2', () => {
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: false, keyCode: 50 }).key, '\x1b2');
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: true, keyCode: 50 }).key, '\x1b@');
});
it('should return proper sequences for alt+3', () => {
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: false, keyCode: 51 }).key, '\x1b3');
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: true, keyCode: 51 }).key, '\x1b#');
});
it('should return proper sequences for alt+4', () => {
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: false, keyCode: 52 }).key, '\x1b4');
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: true, keyCode: 52 }).key, '\x1b$');
});
it('should return proper sequences for alt+5', () => {
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: false, keyCode: 53 }).key, '\x1b5');
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: true, keyCode: 53 }).key, '\x1b%');
});
it('should return proper sequences for alt+6', () => {
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: false, keyCode: 54 }).key, '\x1b6');
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: true, keyCode: 54 }).key, '\x1b^');
});
it('should return proper sequences for alt+7', () => {
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: false, keyCode: 55 }).key, '\x1b7');
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: true, keyCode: 55 }).key, '\x1b&');
});
it('should return proper sequences for alt+8', () => {
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: false, keyCode: 56 }).key, '\x1b8');
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: true, keyCode: 56 }).key, '\x1b*');
});
it('should return proper sequences for alt+9', () => {
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: false, keyCode: 57 }).key, '\x1b9');
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: true, keyCode: 57 }).key, '\x1b(');
});
// Characters using alt sequences (special chars)
it('should return proper sequences for alt+;', () => {
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: false, keyCode: 186 }).key, '\x1b;');
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: true, keyCode: 186 }).key, '\x1b:');
});
it('should return proper sequences for alt+=', () => {
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: false, keyCode: 187 }).key, '\x1b=');
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: true, keyCode: 187 }).key, '\x1b+');
});
it('should return proper sequences for alt+,', () => {
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: false, keyCode: 188 }).key, '\x1b,');
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: true, keyCode: 188 }).key, '\x1b<');
});
it('should return proper sequences for alt+-', () => {
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: false, keyCode: 189 }).key, '\x1b-');
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: true, keyCode: 189 }).key, '\x1b_');
});
it('should return proper sequences for alt+.', () => {
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: false, keyCode: 190 }).key, '\x1b.');
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: true, keyCode: 190 }).key, '\x1b>');
});
it('should return proper sequences for alt+/', () => {
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: false, keyCode: 191 }).key, '\x1b/');
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: true, keyCode: 191 }).key, '\x1b?');
});
it('should return proper sequences for alt+~', () => {
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: false, keyCode: 192 }).key, '\x1b`');
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: true, keyCode: 192 }).key, '\x1b~');
});
it('should return proper sequences for alt+[', () => {
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: false, keyCode: 219 }).key, '\x1b[');
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: true, keyCode: 219 }).key, '\x1b{');
});
it('should return proper sequences for alt+\\', () => {
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: false, keyCode: 220 }).key, '\x1b\\');
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: true, keyCode: 220 }).key, '\x1b|');
});
it('should return proper sequences for alt+]', () => {
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: false, keyCode: 221 }).key, '\x1b]');
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: true, keyCode: 221 }).key, '\x1b}');
});
it('should return proper sequences for alt+\'', () => {
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: false, keyCode: 222 }).key, '\x1b\'');
assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: true, keyCode: 222 }).key, '\x1b"');
});
});
describe('Third level shift', () => {
let evKeyDown: any;
let evKeyPress: any;
+24 -379
View File
@@ -21,7 +21,7 @@
* http://linux.die.net/man/7/urxvt
*/
import { ICharset, IInputHandlingTerminal, IViewport, ICompositionHelper, ITerminalOptions, ITerminal, IBrowser, ILinkifier, ILinkMatcherOptions, CustomKeyEventHandler, LinkMatcherHandler, CharData, LineData } from './Types';
import { IInputHandlingTerminal, IViewport, ICompositionHelper, ITerminalOptions, ITerminal, IBrowser, ILinkifier, ILinkMatcherOptions, CustomKeyEventHandler, LinkMatcherHandler, CharData, LineData } from './Types';
import { IMouseZoneManager } from './input/Types';
import { IRenderer } from './renderer/Types';
import { BufferSet } from './BufferSet';
@@ -30,7 +30,7 @@ import { CompositionHelper } from './CompositionHelper';
import { EventEmitter } from './EventEmitter';
import { Viewport } from './Viewport';
import { rightClickHandler, moveTextAreaUnderMouseCursor, pasteHandler, copyHandler } from './handlers/Clipboard';
import { C0 } from './EscapeSequences';
import { C0 } from './common/data/EscapeSequences';
import { InputHandler } from './InputHandler';
// import { Parser } from './Parser';
import { Renderer } from './renderer/Renderer';
@@ -47,37 +47,12 @@ import { DEFAULT_ANSI_COLORS } from './renderer/ColorManager';
import { MouseZoneManager } from './input/MouseZoneManager';
import { AccessibilityManager } from './AccessibilityManager';
import { ScreenDprMonitor } from './utils/ScreenDprMonitor';
import { ITheme, ILocalizableStrings, IMarker, IDisposable } from 'xterm';
import { ITheme, IMarker, IDisposable } from 'xterm';
import { removeTerminalFromCache } from './renderer/atlas/CharAtlasCache';
import { DomRenderer } from './renderer/dom/DomRenderer';
// reg + shift key mappings for digits and special chars
const KEYCODE_KEY_MAPPINGS: { [key: number]: [string, string]} = {
// digits 0-9
48: ['0', ')'],
49: ['1', '!'],
50: ['2', '@'],
51: ['3', '#'],
52: ['4', '$'],
53: ['5', '%'],
54: ['6', '^'],
55: ['7', '&'],
56: ['8', '*'],
57: ['9', '('],
// special chars
186: [';', ':'],
187: ['=', '+'],
188: [',', '<'],
189: ['-', '_'],
190: ['.', '>'],
191: ['/', '?'],
192: ['`', '~'],
219: ['[', '{'],
220: ['\\', '|'],
221: [']', '}'],
222: ['\'', '"']
};
import { IKeyboardEvent } from './common/Types';
import { evaluateKeyboardEvent } from './core/input/Keyboard';
import { KeyboardResultType, ICharset } from './core/Types';
// Let it work inside Node.js for automated testing purposes.
const document = (typeof window !== 'undefined') ? window.document : null;
@@ -353,10 +328,6 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
return this.buffers.active;
}
public static get strings(): ILocalizableStrings {
return Strings;
}
/**
* back_color_erase feature for xterm.
*/
@@ -772,14 +743,6 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
}
}
/**
* Apply the provided addon on the `Terminal` class.
* @param addon The addon to apply.
*/
public static applyAddon(addon: any): void {
addon.apply(Terminal);
}
/**
* XTerm mouse events
* http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#Mouse%20Tracking
@@ -1436,19 +1399,19 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
* - https://developer.mozilla.org/en-US/docs/DOM/KeyboardEvent
* @param {KeyboardEvent} ev The keydown event to be handled.
*/
protected _keyDown(ev: KeyboardEvent): boolean {
if (this._customKeyEventHandler && this._customKeyEventHandler(ev) === false) {
protected _keyDown(event: KeyboardEvent): boolean {
if (this._customKeyEventHandler && this._customKeyEventHandler(event) === false) {
return false;
}
if (!this._compositionHelper.keydown(ev)) {
if (!this._compositionHelper.keydown(event)) {
if (this.buffer.ybase !== this.buffer.ydisp) {
this.scrollToBottom();
}
return false;
}
const result = this._evaluateKeyEscapeSequence(ev);
const result = evaluateKeyboardEvent(event, this.applicationCursor, this.browser.isMac, this.options.macOptionIsMeta);
// if (result.key === C0.DC3) { // XOFF
// this._writeStopped = true;
@@ -1456,33 +1419,38 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
// this._writeStopped = false;
// }
if (result.scrollLines) {
this.scrollLines(result.scrollLines);
return this.cancel(ev, true);
if (result.type === KeyboardResultType.PAGE_DOWN || result.type === KeyboardResultType.PAGE_UP) {
const scrollCount = this.rows - 1;
this.scrollLines(result.type === KeyboardResultType.PAGE_UP ? -scrollCount : scrollCount);
return this.cancel(event, true);
}
if (this._isThirdLevelShift(this.browser, ev)) {
if (result.type === KeyboardResultType.SELECT_ALL) {
this.selectAll();
}
if (this._isThirdLevelShift(this.browser, event)) {
return true;
}
if (result.cancel) {
// The event is canceled at the end already, is this necessary?
this.cancel(ev, true);
this.cancel(event, true);
}
if (!result.key) {
return true;
}
this.emit('keydown', ev);
this.emit('key', result.key, ev);
this.emit('keydown', event);
this.emit('key', result.key, event);
this.showCursor();
this.handler(result.key);
return this.cancel(ev, true);
return this.cancel(event, true);
}
private _isThirdLevelShift(browser: IBrowser, ev: KeyboardEvent): boolean {
private _isThirdLevelShift(browser: IBrowser, ev: IKeyboardEvent): boolean {
const thirdLevelKey =
(browser.isMac && !this.options.macOptionIsMeta && ev.altKey && !ev.ctrlKey && !ev.metaKey) ||
(browser.isMSWindows && ev.altKey && ev.ctrlKey && !ev.metaKey);
@@ -1495,329 +1463,6 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
return thirdLevelKey && (!ev.keyCode || ev.keyCode > 47);
}
/**
* 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
* @param ev The keyboard event to be translated to key escape sequence.
*/
protected _evaluateKeyEscapeSequence(ev: KeyboardEvent): {cancel: boolean, key: string, scrollLines: number} {
const result: {cancel: boolean, key: string, scrollLines: number} = {
// 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
scrollLines: undefined
};
const modifiers = (ev.shiftKey ? 1 : 0) | (ev.altKey ? 2 : 0) | (ev.ctrlKey ? 4 : 0) | (ev.metaKey ? 8 : 0);
switch (ev.keyCode) {
case 0:
if (ev.key === 'UIKeyInputUpArrow') {
if (this.applicationCursor) {
result.key = C0.ESC + 'OA';
} else {
result.key = C0.ESC + '[A';
}
}
else if (ev.key === 'UIKeyInputLeftArrow') {
if (this.applicationCursor) {
result.key = C0.ESC + 'OD';
} else {
result.key = C0.ESC + '[D';
}
}
else if (ev.key === 'UIKeyInputRightArrow') {
if (this.applicationCursor) {
result.key = C0.ESC + 'OC';
} else {
result.key = C0.ESC + '[C';
}
}
else if (ev.key === 'UIKeyInputDownArrow') {
if (this.applicationCursor) {
result.key = C0.ESC + 'OB';
} else {
result.key = C0.ESC + '[B';
}
}
break;
case 8:
// backspace
if (ev.shiftKey) {
result.key = C0.BS; // ^H
break;
} else if (ev.altKey) {
result.key = C0.ESC + C0.DEL; // \e ^?
break;
}
result.key = C0.DEL; // ^?
break;
case 9:
// tab
if (ev.shiftKey) {
result.key = C0.ESC + '[Z';
break;
}
result.key = C0.HT;
result.cancel = true;
break;
case 13:
// return/enter
result.key = C0.CR;
result.cancel = true;
break;
case 27:
// escape
result.key = C0.ESC;
result.cancel = true;
break;
case 37:
// left-arrow
if (modifiers) {
result.key = C0.ESC + '[1;' + (modifiers + 1) + 'D';
// HACK: Make Alt + left-arrow behave like Ctrl + left-arrow: move one word backwards
// http://unix.stackexchange.com/a/108106
// macOS uses different escape sequences than linux
if (result.key === C0.ESC + '[1;3D') {
result.key = (this.browser.isMac) ? C0.ESC + 'b' : C0.ESC + '[1;5D';
}
} else if (this.applicationCursor) {
result.key = C0.ESC + 'OD';
} else {
result.key = C0.ESC + '[D';
}
break;
case 39:
// right-arrow
if (modifiers) {
result.key = C0.ESC + '[1;' + (modifiers + 1) + 'C';
// HACK: Make Alt + right-arrow behave like Ctrl + right-arrow: move one word forward
// http://unix.stackexchange.com/a/108106
// macOS uses different escape sequences than linux
if (result.key === C0.ESC + '[1;3C') {
result.key = (this.browser.isMac) ? C0.ESC + 'f' : C0.ESC + '[1;5C';
}
} else if (this.applicationCursor) {
result.key = C0.ESC + 'OC';
} else {
result.key = C0.ESC + '[C';
}
break;
case 38:
// up-arrow
if (modifiers) {
result.key = C0.ESC + '[1;' + (modifiers + 1) + 'A';
// HACK: Make Alt + up-arrow behave like Ctrl + up-arrow
// http://unix.stackexchange.com/a/108106
if (result.key === C0.ESC + '[1;3A') {
result.key = C0.ESC + '[1;5A';
}
} else if (this.applicationCursor) {
result.key = C0.ESC + 'OA';
} else {
result.key = C0.ESC + '[A';
}
break;
case 40:
// down-arrow
if (modifiers) {
result.key = C0.ESC + '[1;' + (modifiers + 1) + 'B';
// HACK: Make Alt + down-arrow behave like Ctrl + down-arrow
// http://unix.stackexchange.com/a/108106
if (result.key === C0.ESC + '[1;3B') {
result.key = C0.ESC + '[1;5B';
}
} else if (this.applicationCursor) {
result.key = C0.ESC + 'OB';
} else {
result.key = C0.ESC + '[B';
}
break;
case 45:
// insert
if (!ev.shiftKey && !ev.ctrlKey) {
// <Ctrl> or <Shift> + <Insert> are used to
// copy-paste on some systems.
result.key = C0.ESC + '[2~';
}
break;
case 46:
// delete
if (modifiers) {
result.key = C0.ESC + '[3;' + (modifiers + 1) + '~';
} else {
result.key = C0.ESC + '[3~';
}
break;
case 36:
// home
if (modifiers) {
result.key = C0.ESC + '[1;' + (modifiers + 1) + 'H';
} else if (this.applicationCursor) {
result.key = C0.ESC + 'OH';
} else {
result.key = C0.ESC + '[H';
}
break;
case 35:
// end
if (modifiers) {
result.key = C0.ESC + '[1;' + (modifiers + 1) + 'F';
} else if (this.applicationCursor) {
result.key = C0.ESC + 'OF';
} else {
result.key = C0.ESC + '[F';
}
break;
case 33:
// page up
if (ev.shiftKey) {
result.scrollLines = -(this.rows - 1);
} else {
result.key = C0.ESC + '[5~';
}
break;
case 34:
// page down
if (ev.shiftKey) {
result.scrollLines = this.rows - 1;
} else {
result.key = C0.ESC + '[6~';
}
break;
case 112:
// F1-F12
if (modifiers) {
result.key = C0.ESC + '[1;' + (modifiers + 1) + 'P';
} else {
result.key = C0.ESC + 'OP';
}
break;
case 113:
if (modifiers) {
result.key = C0.ESC + '[1;' + (modifiers + 1) + 'Q';
} else {
result.key = C0.ESC + 'OQ';
}
break;
case 114:
if (modifiers) {
result.key = C0.ESC + '[1;' + (modifiers + 1) + 'R';
} else {
result.key = C0.ESC + 'OR';
}
break;
case 115:
if (modifiers) {
result.key = C0.ESC + '[1;' + (modifiers + 1) + 'S';
} else {
result.key = C0.ESC + 'OS';
}
break;
case 116:
if (modifiers) {
result.key = C0.ESC + '[15;' + (modifiers + 1) + '~';
} else {
result.key = C0.ESC + '[15~';
}
break;
case 117:
if (modifiers) {
result.key = C0.ESC + '[17;' + (modifiers + 1) + '~';
} else {
result.key = C0.ESC + '[17~';
}
break;
case 118:
if (modifiers) {
result.key = C0.ESC + '[18;' + (modifiers + 1) + '~';
} else {
result.key = C0.ESC + '[18~';
}
break;
case 119:
if (modifiers) {
result.key = C0.ESC + '[19;' + (modifiers + 1) + '~';
} else {
result.key = C0.ESC + '[19~';
}
break;
case 120:
if (modifiers) {
result.key = C0.ESC + '[20;' + (modifiers + 1) + '~';
} else {
result.key = C0.ESC + '[20~';
}
break;
case 121:
if (modifiers) {
result.key = C0.ESC + '[21;' + (modifiers + 1) + '~';
} else {
result.key = C0.ESC + '[21~';
}
break;
case 122:
if (modifiers) {
result.key = C0.ESC + '[23;' + (modifiers + 1) + '~';
} else {
result.key = C0.ESC + '[23~';
}
break;
case 123:
if (modifiers) {
result.key = C0.ESC + '[24;' + (modifiers + 1) + '~';
} else {
result.key = C0.ESC + '[24~';
}
break;
default:
// a-z and space
if (ev.ctrlKey && !ev.shiftKey && !ev.altKey && !ev.metaKey) {
if (ev.keyCode >= 65 && ev.keyCode <= 90) {
result.key = String.fromCharCode(ev.keyCode - 64);
} else if (ev.keyCode === 32) {
// NUL
result.key = String.fromCharCode(0);
} else if (ev.keyCode >= 51 && ev.keyCode <= 55) {
// escape, file sep, group sep, record sep, unit sep
result.key = String.fromCharCode(ev.keyCode - 51 + 27);
} else if (ev.keyCode === 56) {
// delete
result.key = String.fromCharCode(127);
} else if (ev.keyCode === 219) {
// ^[ - Control Sequence Introducer (CSI)
result.key = String.fromCharCode(27);
} else if (ev.keyCode === 220) {
// ^\ - String Terminator (ST)
result.key = String.fromCharCode(28);
} else if (ev.keyCode === 221) {
// ^] - Operating System Command (OSC)
result.key = String.fromCharCode(29);
}
} else if ((!this.browser.isMac || this.options.macOptionIsMeta) && ev.altKey && !ev.metaKey) {
// On macOS this is a third level shift when !macOptionIsMeta. Use <Esc> instead.
const keyMapping = KEYCODE_KEY_MAPPINGS[ev.keyCode];
const key = keyMapping && keyMapping[!ev.shiftKey ? 0 : 1];
if (key) {
result.key = C0.ESC + key;
} else if (ev.keyCode >= 65 && ev.keyCode <= 90) {
const keyCode = ev.ctrlKey ? ev.keyCode - 64 : ev.keyCode + 32;
result.key = C0.ESC + String.fromCharCode(keyCode);
}
} else if (this.browser.isMac && !ev.altKey && !ev.ctrlKey && ev.metaKey) {
if (ev.keyCode === 65) { // cmd + a
this.selectAll();
}
}
break;
}
return result;
}
/**
* Set the G level of the terminal
* @param g
+1 -4
View File
@@ -6,6 +6,7 @@
import { Terminal as PublicTerminal, ITerminalOptions as IPublicTerminalOptions, IEventEmitter } from 'xterm';
import { IColorSet, IRenderer } from './renderer/Types';
import { IMouseZoneManager } from './input/Types';
import { ICharset } from './core/Types';
export type CustomKeyEventHandler = (event: KeyboardEvent) => boolean;
@@ -191,10 +192,6 @@ export interface ILinkMatcher {
willLinkActivate?: (event: MouseEvent, uri: string) => boolean;
}
export interface ICharset {
[key: string]: string;
}
export interface ILinkHoverEvent {
x1: number;
y1: number;
+4 -4
View File
@@ -37,10 +37,10 @@ export function proposeGeometry(term: Terminal): IGeometry {
const elementPaddingVer = elementPadding.top + elementPadding.bottom;
const elementPaddingHor = elementPadding.right + elementPadding.left;
const availableHeight = parentElementHeight - elementPaddingVer;
const availableWidth = parentElementWidth - elementPaddingHor - (<any>term).viewport.scrollBarWidth;
const availableWidth = parentElementWidth - elementPaddingHor - (<any>term)._core.viewport.scrollBarWidth;
const geometry = {
cols: Math.floor(availableWidth / (<any>term).renderer.dimensions.actualCellWidth),
rows: Math.floor(availableHeight / (<any>term).renderer.dimensions.actualCellHeight)
cols: Math.floor(availableWidth / (<any>term)._core.renderer.dimensions.actualCellWidth),
rows: Math.floor(availableHeight / (<any>term)._core.renderer.dimensions.actualCellHeight)
};
return geometry;
}
@@ -50,7 +50,7 @@ export function fit(term: Terminal): void {
if (geometry) {
// Force a full render
if (term.rows !== geometry.rows || term.cols !== geometry.cols) {
(<any>term).renderer.clear();
(<any>term)._core.renderer.clear();
term.resize(geometry.cols, geometry.rows);
}
}
+7 -4
View File
@@ -5,14 +5,17 @@
import { Terminal } from 'xterm';
export interface ISearchAddonTerminal extends Terminal {
__searchHelper?: ISearchHelper;
// TODO: Reuse ITerminal from core
// TODO: Don't rely on this private API
export interface ITerminalCore {
buffer: any;
selectionManager: any;
}
export interface ISearchAddonTerminal extends Terminal {
__searchHelper?: ISearchHelper;
_core: ITerminalCore;
}
export interface ISearchHelper {
findNext(term: string): boolean;
findPrevious(term: string): boolean;
+12 -12
View File
@@ -35,14 +35,14 @@ export class SearchHelper implements ISearchHelper {
let result: ISearchResult;
let startRow = this._terminal.buffer.ydisp;
if (this._terminal.selectionManager.selectionEnd) {
let startRow = this._terminal._core.buffer.ydisp;
if (this._terminal._core.selectionManager.selectionEnd) {
// Start from the selection end if there is a selection
startRow = this._terminal.selectionManager.selectionEnd[1];
startRow = this._terminal._core.selectionManager.selectionEnd[1];
}
// Search from ydisp + 1 to end
for (let y = startRow + 1; y < this._terminal.buffer.ybase + this._terminal.rows; y++) {
for (let y = startRow + 1; y < this._terminal._core.buffer.ybase + this._terminal.rows; y++) {
result = this._findInLine(term, y);
if (result) {
break;
@@ -76,10 +76,10 @@ export class SearchHelper implements ISearchHelper {
let result: ISearchResult;
let startRow = this._terminal.buffer.ydisp;
if (this._terminal.selectionManager.selectionStart) {
let startRow = this._terminal._core.buffer.ydisp;
if (this._terminal._core.selectionManager.selectionStart) {
// Start from the selection end if there is a selection
startRow = this._terminal.selectionManager.selectionStart[1];
startRow = this._terminal._core.selectionManager.selectionStart[1];
}
// Search from ydisp + 1 to end
@@ -92,7 +92,7 @@ export class SearchHelper implements ISearchHelper {
// Search from the top to the current ydisp
if (!result) {
for (let y = this._terminal.buffer.ybase + this._terminal.rows - 1; y > startRow; y--) {
for (let y = this._terminal._core.buffer.ybase + this._terminal.rows - 1; y > startRow; y--) {
result = this._findInLine(term, y);
if (result) {
break;
@@ -111,11 +111,11 @@ export class SearchHelper implements ISearchHelper {
* @return The search result if it was found.
*/
private _findInLine(term: string, y: number): ISearchResult {
const lowerStringLine = this._terminal.buffer.translateBufferLineToString(y, true).toLowerCase();
const lowerStringLine = this._terminal._core.buffer.translateBufferLineToString(y, true).toLowerCase();
const lowerTerm = term.toLowerCase();
let searchIndex = lowerStringLine.indexOf(lowerTerm);
if (searchIndex >= 0) {
const line = this._terminal.buffer.lines.get(y);
const line = this._terminal._core.buffer.lines.get(y);
for (let i = 0; i < searchIndex; i++) {
const charData = line[i];
// Adjust the searchIndex to normalize emoji into single chars
@@ -147,8 +147,8 @@ export class SearchHelper implements ISearchHelper {
if (!result) {
return false;
}
this._terminal.selectionManager.setSelection(result.col, result.row, result.term.length);
this._terminal.scrollLines(result.row - this._terminal.buffer.ydisp);
this._terminal._core.selectionManager.setSelection(result.col, result.row, result.term.length);
this._terminal.scrollLines(result.row - this._terminal._core.buffer.ydisp);
return true;
}
}
+5 -1
View File
@@ -5,6 +5,10 @@
import { Terminal } from 'xterm';
export interface IWinptyCompatAddonTerminal extends Terminal {
export interface ITerminalCore {
buffer: any;
}
export interface IWinptyCompatAddonTerminal extends Terminal {
_core: ITerminalCore;
}
+2 -2
View File
@@ -26,11 +26,11 @@ export function winptyCompatInit(terminal: Terminal): void {
// Windows when text reaches the end of the terminal it's likely going to be
// wrapped.
addonTerminal.on('linefeed', () => {
const line = addonTerminal.buffer.lines.get(addonTerminal.buffer.ybase + addonTerminal.buffer.y - 1);
const line = addonTerminal._core.buffer.lines.get(addonTerminal._core.buffer.ybase + addonTerminal._core.buffer.y - 1);
const lastChar = line[addonTerminal.cols - 1];
if (lastChar[3] !== 32 /* ' ' */) {
const nextLine = addonTerminal.buffer.lines.get(addonTerminal.buffer.ybase + addonTerminal.buffer.y);
const nextLine = addonTerminal._core.buffer.lines.get(addonTerminal._core.buffer.ybase + addonTerminal._core.buffer.y);
(<any>nextLine).isWrapped = true;
}
});
+18
View File
@@ -0,0 +1,18 @@
/**
* Copyright (c) 2018 The xterm.js authors. All rights reserved.
* @license MIT
*/
/**
* A keyboard event interface which does not depend on the DOM, KeyboardEvent implicitly extends
* this event.
*/
export interface IKeyboardEvent {
altKey: boolean;
ctrlKey: boolean;
shiftKey: boolean;
metaKey: boolean;
keyCode: number;
key: string;
type: string;
}
+21
View File
@@ -0,0 +1,21 @@
/**
* Copyright (c) 2018 The xterm.js authors. All rights reserved.
* @license MIT
*/
export const enum KeyboardResultType {
SEND_KEY,
SELECT_ALL,
PAGE_UP,
PAGE_DOWN
}
export interface IKeyboardResult {
type: KeyboardResultType;
cancel: boolean;
key: string | undefined;
}
export interface ICharset {
[key: string]: string;
}
@@ -3,7 +3,7 @@
* @license MIT
*/
import { ICharset } from './Types';
import { ICharset } from '../Types';
/**
* The character sets supported by the terminal. These enable several languages
+284
View File
@@ -0,0 +1,284 @@
import { assert } from 'chai';
import { evaluateKeyboardEvent } from './Keyboard';
import { IKeyboardResult } from '../Types';
/**
* A helper function for testing which allows passing in a partial event and defaults will be filled
* in on it.
*/
function testEvaluateKeyboardEvent(partialEvent: {
altKey?: boolean;
ctrlKey?: boolean;
shiftKey?: boolean;
metaKey?: boolean;
keyCode?: number;
key?: string;
type?: string;
}, partialOptions: {
applicationCursorMode?: boolean;
isMac?: boolean;
macOptionIsMeta?: boolean;
} = {}): IKeyboardResult {
const event = {
altKey: partialEvent.altKey || false,
ctrlKey: partialEvent.ctrlKey || false,
shiftKey: partialEvent.shiftKey || false,
metaKey: partialEvent.metaKey || false,
keyCode: partialEvent.keyCode !== undefined ? partialEvent.keyCode : undefined,
key: partialEvent.key || '',
type: partialEvent.type || ''
};
const options = {
applicationCursorMode: partialOptions.applicationCursorMode || false,
isMac: partialOptions.isMac || false,
macOptionIsMeta: partialOptions.macOptionIsMeta || false
};
return evaluateKeyboardEvent(event, options.applicationCursorMode, options.isMac, options.macOptionIsMeta);
}
describe('Keyboard', () => {
describe('evaluateKeyEscapeSequence', () => {
it('should return the correct escape sequence for unmodified keys', () => {
// Backspace
assert.equal(testEvaluateKeyboardEvent({ keyCode: 8 }).key, '\x7f'); // ^?
// Tab
assert.equal(testEvaluateKeyboardEvent({ keyCode: 9 }).key, '\t');
// Return/enter
assert.equal(testEvaluateKeyboardEvent({ keyCode: 13 }).key, '\r'); // CR
// Escape
assert.equal(testEvaluateKeyboardEvent({ keyCode: 27 }).key, '\x1b');
// Page up, page down
assert.equal(testEvaluateKeyboardEvent({ keyCode: 33 }).key, '\x1b[5~'); // CSI 5 ~
assert.equal(testEvaluateKeyboardEvent({ keyCode: 34 }).key, '\x1b[6~'); // CSI 6 ~
// End, Home
assert.equal(testEvaluateKeyboardEvent({ keyCode: 35 }).key, '\x1b[F'); // SS3 F
assert.equal(testEvaluateKeyboardEvent({ keyCode: 36 }).key, '\x1b[H'); // SS3 H
// Left, up, right, down arrows
assert.equal(testEvaluateKeyboardEvent({ keyCode: 37 }).key, '\x1b[D'); // CSI D
assert.equal(testEvaluateKeyboardEvent({ keyCode: 38 }).key, '\x1b[A'); // CSI A
assert.equal(testEvaluateKeyboardEvent({ keyCode: 39 }).key, '\x1b[C'); // CSI C
assert.equal(testEvaluateKeyboardEvent({ keyCode: 40 }).key, '\x1b[B'); // CSI B
// Insert
assert.equal(testEvaluateKeyboardEvent({ keyCode: 45 }).key, '\x1b[2~'); // CSI 2 ~
// Delete
assert.equal(testEvaluateKeyboardEvent({ keyCode: 46 }).key, '\x1b[3~'); // CSI 3 ~
// F1-F12
assert.equal(testEvaluateKeyboardEvent({ keyCode: 112 }).key, '\x1bOP'); // SS3 P
assert.equal(testEvaluateKeyboardEvent({ keyCode: 113 }).key, '\x1bOQ'); // SS3 Q
assert.equal(testEvaluateKeyboardEvent({ keyCode: 114 }).key, '\x1bOR'); // SS3 R
assert.equal(testEvaluateKeyboardEvent({ keyCode: 115 }).key, '\x1bOS'); // SS3 S
assert.equal(testEvaluateKeyboardEvent({ keyCode: 116 }).key, '\x1b[15~'); // CSI 1 5 ~
assert.equal(testEvaluateKeyboardEvent({ keyCode: 117 }).key, '\x1b[17~'); // CSI 1 7 ~
assert.equal(testEvaluateKeyboardEvent({ keyCode: 118 }).key, '\x1b[18~'); // CSI 1 8 ~
assert.equal(testEvaluateKeyboardEvent({ keyCode: 119 }).key, '\x1b[19~'); // CSI 1 9 ~
assert.equal(testEvaluateKeyboardEvent({ keyCode: 120 }).key, '\x1b[20~'); // CSI 2 0 ~
assert.equal(testEvaluateKeyboardEvent({ keyCode: 121 }).key, '\x1b[21~'); // CSI 2 1 ~
assert.equal(testEvaluateKeyboardEvent({ keyCode: 122 }).key, '\x1b[23~'); // CSI 2 3 ~
assert.equal(testEvaluateKeyboardEvent({ keyCode: 123 }).key, '\x1b[24~'); // CSI 2 4 ~
});
it('should return \\x1b[3;5~ for ctrl+delete', () => {
assert.equal(testEvaluateKeyboardEvent({ ctrlKey: true, keyCode: 46 }).key, '\x1b[3;5~');
});
it('should return \\x1b[3;2~ for shift+delete', () => {
assert.equal(testEvaluateKeyboardEvent({ shiftKey: true, keyCode: 46 }).key, '\x1b[3;2~');
});
it('should return \\x1b[3;3~ for alt+delete', () => {
assert.equal(testEvaluateKeyboardEvent({ altKey: true, keyCode: 46 }).key, '\x1b[3;3~');
});
it('should return \\x1b[5D for ctrl+left', () => {
assert.equal(testEvaluateKeyboardEvent({ ctrlKey: true, keyCode: 37 }).key, '\x1b[1;5D'); // CSI 5 D
});
it('should return \\x1b[5C for ctrl+right', () => {
assert.equal(testEvaluateKeyboardEvent({ ctrlKey: true, keyCode: 39 }).key, '\x1b[1;5C'); // CSI 5 C
});
it('should return \\x1b[5A for ctrl+up', () => {
assert.equal(testEvaluateKeyboardEvent({ ctrlKey: true, keyCode: 38 }).key, '\x1b[1;5A'); // CSI 5 A
});
it('should return \\x1b[5B for ctrl+down', () => {
assert.equal(testEvaluateKeyboardEvent({ ctrlKey: true, keyCode: 40 }).key, '\x1b[1;5B'); // CSI 5 B
});
describe('On non-macOS platforms', () => {
// Evalueate alt + arrow key movement, which is a feature of terminal emulators but not VT100
// http://unix.stackexchange.com/a/108106
it('should return \\x1b[5D for alt+left', () => {
assert.equal(testEvaluateKeyboardEvent({ altKey: true, keyCode: 37 }, { isMac: false }).key, '\x1b[1;5D'); // CSI 5 D
});
it('should return \\x1b[5C for alt+right', () => {
assert.equal(testEvaluateKeyboardEvent({ altKey: true, keyCode: 39 }, { isMac: false }).key, '\x1b[1;5C'); // CSI 5 C
});
it('should return \\x1ba for alt+a', () => {
assert.equal(testEvaluateKeyboardEvent({ altKey: true, keyCode: 65 }, { isMac: false }).key, '\x1ba');
});
});
describe('On macOS platforms', () => {
it('should return \\x1bb for alt+left', () => {
assert.equal(testEvaluateKeyboardEvent({ altKey: true, keyCode: 37 }, { isMac: true }).key, '\x1bb'); // CSI 5 D
});
it('should return \\x1bf for alt+right', () => {
assert.equal(testEvaluateKeyboardEvent({ altKey: true, keyCode: 39 }, { isMac: true }).key, '\x1bf'); // CSI 5 C
});
it('should return undefined for alt+a', () => {
assert.strictEqual(testEvaluateKeyboardEvent({ altKey: true, keyCode: 65 }, { isMac: true }).key, undefined), { isMac: true };
});
});
describe('with macOptionIsMeta', () => {
it('should return \\x1ba for alt+a', () => {
assert.equal(testEvaluateKeyboardEvent({ altKey: true, keyCode: 65 }, { isMac: true, macOptionIsMeta: true }).key, '\x1ba');
});
});
it('should return \\x1b[5A for alt+up', () => {
assert.equal(testEvaluateKeyboardEvent({ altKey: true, keyCode: 38 }).key, '\x1b[1;5A'); // CSI 5 A
});
it('should return \\x1b[5B for alt+down', () => {
assert.equal(testEvaluateKeyboardEvent({ altKey: true, keyCode: 40 }).key, '\x1b[1;5B'); // CSI 5 B
});
it('should return the correct escape sequence for modified F1-F12 keys', () => {
assert.equal(testEvaluateKeyboardEvent({ shiftKey: true, keyCode: 112 }).key, '\x1b[1;2P');
assert.equal(testEvaluateKeyboardEvent({ shiftKey: true, keyCode: 113 }).key, '\x1b[1;2Q');
assert.equal(testEvaluateKeyboardEvent({ shiftKey: true, keyCode: 114 }).key, '\x1b[1;2R');
assert.equal(testEvaluateKeyboardEvent({ shiftKey: true, keyCode: 115 }).key, '\x1b[1;2S');
assert.equal(testEvaluateKeyboardEvent({ shiftKey: true, keyCode: 116 }).key, '\x1b[15;2~');
assert.equal(testEvaluateKeyboardEvent({ shiftKey: true, keyCode: 117 }).key, '\x1b[17;2~');
assert.equal(testEvaluateKeyboardEvent({ shiftKey: true, keyCode: 118 }).key, '\x1b[18;2~');
assert.equal(testEvaluateKeyboardEvent({ shiftKey: true, keyCode: 119 }).key, '\x1b[19;2~');
assert.equal(testEvaluateKeyboardEvent({ shiftKey: true, keyCode: 120 }).key, '\x1b[20;2~');
assert.equal(testEvaluateKeyboardEvent({ shiftKey: true, keyCode: 121 }).key, '\x1b[21;2~');
assert.equal(testEvaluateKeyboardEvent({ shiftKey: true, keyCode: 122 }).key, '\x1b[23;2~');
assert.equal(testEvaluateKeyboardEvent({ shiftKey: true, keyCode: 123 }).key, '\x1b[24;2~');
assert.equal(testEvaluateKeyboardEvent({ altKey: true, keyCode: 112 }).key, '\x1b[1;3P');
assert.equal(testEvaluateKeyboardEvent({ altKey: true, keyCode: 113 }).key, '\x1b[1;3Q');
assert.equal(testEvaluateKeyboardEvent({ altKey: true, keyCode: 114 }).key, '\x1b[1;3R');
assert.equal(testEvaluateKeyboardEvent({ altKey: true, keyCode: 115 }).key, '\x1b[1;3S');
assert.equal(testEvaluateKeyboardEvent({ altKey: true, keyCode: 116 }).key, '\x1b[15;3~');
assert.equal(testEvaluateKeyboardEvent({ altKey: true, keyCode: 117 }).key, '\x1b[17;3~');
assert.equal(testEvaluateKeyboardEvent({ altKey: true, keyCode: 118 }).key, '\x1b[18;3~');
assert.equal(testEvaluateKeyboardEvent({ altKey: true, keyCode: 119 }).key, '\x1b[19;3~');
assert.equal(testEvaluateKeyboardEvent({ altKey: true, keyCode: 120 }).key, '\x1b[20;3~');
assert.equal(testEvaluateKeyboardEvent({ altKey: true, keyCode: 121 }).key, '\x1b[21;3~');
assert.equal(testEvaluateKeyboardEvent({ altKey: true, keyCode: 122 }).key, '\x1b[23;3~');
assert.equal(testEvaluateKeyboardEvent({ altKey: true, keyCode: 123 }).key, '\x1b[24;3~');
assert.equal(testEvaluateKeyboardEvent({ ctrlKey: true, keyCode: 112 }).key, '\x1b[1;5P');
assert.equal(testEvaluateKeyboardEvent({ ctrlKey: true, keyCode: 113 }).key, '\x1b[1;5Q');
assert.equal(testEvaluateKeyboardEvent({ ctrlKey: true, keyCode: 114 }).key, '\x1b[1;5R');
assert.equal(testEvaluateKeyboardEvent({ ctrlKey: true, keyCode: 115 }).key, '\x1b[1;5S');
assert.equal(testEvaluateKeyboardEvent({ ctrlKey: true, keyCode: 116 }).key, '\x1b[15;5~');
assert.equal(testEvaluateKeyboardEvent({ ctrlKey: true, keyCode: 117 }).key, '\x1b[17;5~');
assert.equal(testEvaluateKeyboardEvent({ ctrlKey: true, keyCode: 118 }).key, '\x1b[18;5~');
assert.equal(testEvaluateKeyboardEvent({ ctrlKey: true, keyCode: 119 }).key, '\x1b[19;5~');
assert.equal(testEvaluateKeyboardEvent({ ctrlKey: true, keyCode: 120 }).key, '\x1b[20;5~');
assert.equal(testEvaluateKeyboardEvent({ ctrlKey: true, keyCode: 121 }).key, '\x1b[21;5~');
assert.equal(testEvaluateKeyboardEvent({ ctrlKey: true, keyCode: 122 }).key, '\x1b[23;5~');
assert.equal(testEvaluateKeyboardEvent({ ctrlKey: true, keyCode: 123 }).key, '\x1b[24;5~');
});
// Characters using ctrl+alt sequences
it('should return proper sequence for ctrl+alt+a', () => {
assert.equal(testEvaluateKeyboardEvent({ altKey: true, ctrlKey: true, keyCode: 65 }).key, '\x1b\x01');
});
// Characters using alt sequences (numbers)
it('should return proper sequences for alt+0', () => {
assert.equal(testEvaluateKeyboardEvent({ altKey: true, shiftKey: false, keyCode: 48 }).key, '\x1b0');
assert.equal(testEvaluateKeyboardEvent({ altKey: true, shiftKey: true, keyCode: 48 }).key, '\x1b)');
});
it('should return proper sequences for alt+1', () => {
assert.equal(testEvaluateKeyboardEvent({ altKey: true, shiftKey: false, keyCode: 49 }).key, '\x1b1');
assert.equal(testEvaluateKeyboardEvent({ altKey: true, shiftKey: true, keyCode: 49 }).key, '\x1b!');
});
it('should return proper sequences for alt+2', () => {
assert.equal(testEvaluateKeyboardEvent({ altKey: true, shiftKey: false, keyCode: 50 }).key, '\x1b2');
assert.equal(testEvaluateKeyboardEvent({ altKey: true, shiftKey: true, keyCode: 50 }).key, '\x1b@');
});
it('should return proper sequences for alt+3', () => {
assert.equal(testEvaluateKeyboardEvent({ altKey: true, shiftKey: false, keyCode: 51 }).key, '\x1b3');
assert.equal(testEvaluateKeyboardEvent({ altKey: true, shiftKey: true, keyCode: 51 }).key, '\x1b#');
});
it('should return proper sequences for alt+4', () => {
assert.equal(testEvaluateKeyboardEvent({ altKey: true, shiftKey: false, keyCode: 52 }).key, '\x1b4');
assert.equal(testEvaluateKeyboardEvent({ altKey: true, shiftKey: true, keyCode: 52 }).key, '\x1b$');
});
it('should return proper sequences for alt+5', () => {
assert.equal(testEvaluateKeyboardEvent({ altKey: true, shiftKey: false, keyCode: 53 }).key, '\x1b5');
assert.equal(testEvaluateKeyboardEvent({ altKey: true, shiftKey: true, keyCode: 53 }).key, '\x1b%');
});
it('should return proper sequences for alt+6', () => {
assert.equal(testEvaluateKeyboardEvent({ altKey: true, shiftKey: false, keyCode: 54 }).key, '\x1b6');
assert.equal(testEvaluateKeyboardEvent({ altKey: true, shiftKey: true, keyCode: 54 }).key, '\x1b^');
});
it('should return proper sequences for alt+7', () => {
assert.equal(testEvaluateKeyboardEvent({ altKey: true, shiftKey: false, keyCode: 55 }).key, '\x1b7');
assert.equal(testEvaluateKeyboardEvent({ altKey: true, shiftKey: true, keyCode: 55 }).key, '\x1b&');
});
it('should return proper sequences for alt+8', () => {
assert.equal(testEvaluateKeyboardEvent({ altKey: true, shiftKey: false, keyCode: 56 }).key, '\x1b8');
assert.equal(testEvaluateKeyboardEvent({ altKey: true, shiftKey: true, keyCode: 56 }).key, '\x1b*');
});
it('should return proper sequences for alt+9', () => {
assert.equal(testEvaluateKeyboardEvent({ altKey: true, shiftKey: false, keyCode: 57 }).key, '\x1b9');
assert.equal(testEvaluateKeyboardEvent({ altKey: true, shiftKey: true, keyCode: 57 }).key, '\x1b(');
});
// Characters using alt sequences (special chars)
it('should return proper sequences for alt+;', () => {
assert.equal(testEvaluateKeyboardEvent({ altKey: true, shiftKey: false, keyCode: 186 }).key, '\x1b;');
assert.equal(testEvaluateKeyboardEvent({ altKey: true, shiftKey: true, keyCode: 186 }).key, '\x1b:');
});
it('should return proper sequences for alt+=', () => {
assert.equal(testEvaluateKeyboardEvent({ altKey: true, shiftKey: false, keyCode: 187 }).key, '\x1b=');
assert.equal(testEvaluateKeyboardEvent({ altKey: true, shiftKey: true, keyCode: 187 }).key, '\x1b+');
});
it('should return proper sequences for alt+,', () => {
assert.equal(testEvaluateKeyboardEvent({ altKey: true, shiftKey: false, keyCode: 188 }).key, '\x1b,');
assert.equal(testEvaluateKeyboardEvent({ altKey: true, shiftKey: true, keyCode: 188 }).key, '\x1b<');
});
it('should return proper sequences for alt+-', () => {
assert.equal(testEvaluateKeyboardEvent({ altKey: true, shiftKey: false, keyCode: 189 }).key, '\x1b-');
assert.equal(testEvaluateKeyboardEvent({ altKey: true, shiftKey: true, keyCode: 189 }).key, '\x1b_');
});
it('should return proper sequences for alt+.', () => {
assert.equal(testEvaluateKeyboardEvent({ altKey: true, shiftKey: false, keyCode: 190 }).key, '\x1b.');
assert.equal(testEvaluateKeyboardEvent({ altKey: true, shiftKey: true, keyCode: 190 }).key, '\x1b>');
});
it('should return proper sequences for alt+/', () => {
assert.equal(testEvaluateKeyboardEvent({ altKey: true, shiftKey: false, keyCode: 191 }).key, '\x1b/');
assert.equal(testEvaluateKeyboardEvent({ altKey: true, shiftKey: true, keyCode: 191 }).key, '\x1b?');
});
it('should return proper sequences for alt+~', () => {
assert.equal(testEvaluateKeyboardEvent({ altKey: true, shiftKey: false, keyCode: 192 }).key, '\x1b`');
assert.equal(testEvaluateKeyboardEvent({ altKey: true, shiftKey: true, keyCode: 192 }).key, '\x1b~');
});
it('should return proper sequences for alt+[', () => {
assert.equal(testEvaluateKeyboardEvent({ altKey: true, shiftKey: false, keyCode: 219 }).key, '\x1b[');
assert.equal(testEvaluateKeyboardEvent({ altKey: true, shiftKey: true, keyCode: 219 }).key, '\x1b{');
});
it('should return proper sequences for alt+\\', () => {
assert.equal(testEvaluateKeyboardEvent({ altKey: true, shiftKey: false, keyCode: 220 }).key, '\x1b\\');
assert.equal(testEvaluateKeyboardEvent({ altKey: true, shiftKey: true, keyCode: 220 }).key, '\x1b|');
});
it('should return proper sequences for alt+]', () => {
assert.equal(testEvaluateKeyboardEvent({ altKey: true, shiftKey: false, keyCode: 221 }).key, '\x1b]');
assert.equal(testEvaluateKeyboardEvent({ altKey: true, shiftKey: true, keyCode: 221 }).key, '\x1b}');
});
it('should return proper sequences for alt+\'', () => {
assert.equal(testEvaluateKeyboardEvent({ altKey: true, shiftKey: false, keyCode: 222 }).key, '\x1b\'');
assert.equal(testEvaluateKeyboardEvent({ altKey: true, shiftKey: true, keyCode: 222 }).key, '\x1b"');
});
it('should handle mobile arrow events', () => {
assert.equal(testEvaluateKeyboardEvent({ keyCode: 0, key: 'UIKeyInputUpArrow' }).key, '\x1b[A');
assert.equal(testEvaluateKeyboardEvent({ keyCode: 0, key: 'UIKeyInputUpArrow' }, { applicationCursorMode: true }).key, '\x1bOA');
assert.equal(testEvaluateKeyboardEvent({ keyCode: 0, key: 'UIKeyInputLeftArrow' }).key, '\x1b[D');
assert.equal(testEvaluateKeyboardEvent({ keyCode: 0, key: 'UIKeyInputLeftArrow' }, { applicationCursorMode: true }).key, '\x1bOD');
assert.equal(testEvaluateKeyboardEvent({ keyCode: 0, key: 'UIKeyInputRightArrow' }).key, '\x1b[C');
assert.equal(testEvaluateKeyboardEvent({ keyCode: 0, key: 'UIKeyInputRightArrow' }, { applicationCursorMode: true }).key, '\x1bOC');
assert.equal(testEvaluateKeyboardEvent({ keyCode: 0, key: 'UIKeyInputDownArrow' }).key, '\x1b[B');
assert.equal(testEvaluateKeyboardEvent({ keyCode: 0, key: 'UIKeyInputDownArrow' }, { applicationCursorMode: true }).key, '\x1bOB');
});
});
});
+357
View File
@@ -0,0 +1,357 @@
/**
* Copyright (c) 2014 The xterm.js authors. All rights reserved.
* Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
* @license MIT
*/
import { IKeyboardEvent } from '../../common/Types';
import { IKeyboardResult, KeyboardResultType } from '../Types';
import { C0 } from '../../common/data/EscapeSequences';
// reg + shift key mappings for digits and special chars
const KEYCODE_KEY_MAPPINGS: { [key: number]: [string, string]} = {
// digits 0-9
48: ['0', ')'],
49: ['1', '!'],
50: ['2', '@'],
51: ['3', '#'],
52: ['4', '$'],
53: ['5', '%'],
54: ['6', '^'],
55: ['7', '&'],
56: ['8', '*'],
57: ['9', '('],
// special chars
186: [';', ':'],
187: ['=', '+'],
188: [',', '<'],
189: ['-', '_'],
190: ['.', '>'],
191: ['/', '?'],
192: ['`', '~'],
219: ['[', '{'],
220: ['\\', '|'],
221: [']', '}'],
222: ['\'', '"']
};
export function evaluateKeyboardEvent(
ev: IKeyboardEvent,
applicationCursorMode: boolean,
isMac: boolean,
macOptionIsMeta: boolean
): IKeyboardResult {
const result: IKeyboardResult = {
type: KeyboardResultType.SEND_KEY,
// 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
};
const modifiers = (ev.shiftKey ? 1 : 0) | (ev.altKey ? 2 : 0) | (ev.ctrlKey ? 4 : 0) | (ev.metaKey ? 8 : 0);
switch (ev.keyCode) {
case 0:
if (ev.key === 'UIKeyInputUpArrow') {
if (applicationCursorMode) {
result.key = C0.ESC + 'OA';
} else {
result.key = C0.ESC + '[A';
}
}
else if (ev.key === 'UIKeyInputLeftArrow') {
if (applicationCursorMode) {
result.key = C0.ESC + 'OD';
} else {
result.key = C0.ESC + '[D';
}
}
else if (ev.key === 'UIKeyInputRightArrow') {
if (applicationCursorMode) {
result.key = C0.ESC + 'OC';
} else {
result.key = C0.ESC + '[C';
}
}
else if (ev.key === 'UIKeyInputDownArrow') {
if (applicationCursorMode) {
result.key = C0.ESC + 'OB';
} else {
result.key = C0.ESC + '[B';
}
}
break;
case 8:
// backspace
if (ev.shiftKey) {
result.key = C0.BS; // ^H
break;
} else if (ev.altKey) {
result.key = C0.ESC + C0.DEL; // \e ^?
break;
}
result.key = C0.DEL; // ^?
break;
case 9:
// tab
if (ev.shiftKey) {
result.key = C0.ESC + '[Z';
break;
}
result.key = C0.HT;
result.cancel = true;
break;
case 13:
// return/enter
result.key = C0.CR;
result.cancel = true;
break;
case 27:
// escape
result.key = C0.ESC;
result.cancel = true;
break;
case 37:
// left-arrow
if (modifiers) {
result.key = C0.ESC + '[1;' + (modifiers + 1) + 'D';
// HACK: Make Alt + left-arrow behave like Ctrl + left-arrow: move one word backwards
// http://unix.stackexchange.com/a/108106
// macOS uses different escape sequences than linux
if (result.key === C0.ESC + '[1;3D') {
result.key = isMac ? C0.ESC + 'b' : C0.ESC + '[1;5D';
}
} else if (applicationCursorMode) {
result.key = C0.ESC + 'OD';
} else {
result.key = C0.ESC + '[D';
}
break;
case 39:
// right-arrow
if (modifiers) {
result.key = C0.ESC + '[1;' + (modifiers + 1) + 'C';
// HACK: Make Alt + right-arrow behave like Ctrl + right-arrow: move one word forward
// http://unix.stackexchange.com/a/108106
// macOS uses different escape sequences than linux
if (result.key === C0.ESC + '[1;3C') {
result.key = isMac ? C0.ESC + 'f' : C0.ESC + '[1;5C';
}
} else if (applicationCursorMode) {
result.key = C0.ESC + 'OC';
} else {
result.key = C0.ESC + '[C';
}
break;
case 38:
// up-arrow
if (modifiers) {
result.key = C0.ESC + '[1;' + (modifiers + 1) + 'A';
// HACK: Make Alt + up-arrow behave like Ctrl + up-arrow
// http://unix.stackexchange.com/a/108106
if (result.key === C0.ESC + '[1;3A') {
result.key = C0.ESC + '[1;5A';
}
} else if (applicationCursorMode) {
result.key = C0.ESC + 'OA';
} else {
result.key = C0.ESC + '[A';
}
break;
case 40:
// down-arrow
if (modifiers) {
result.key = C0.ESC + '[1;' + (modifiers + 1) + 'B';
// HACK: Make Alt + down-arrow behave like Ctrl + down-arrow
// http://unix.stackexchange.com/a/108106
if (result.key === C0.ESC + '[1;3B') {
result.key = C0.ESC + '[1;5B';
}
} else if (applicationCursorMode) {
result.key = C0.ESC + 'OB';
} else {
result.key = C0.ESC + '[B';
}
break;
case 45:
// insert
if (!ev.shiftKey && !ev.ctrlKey) {
// <Ctrl> or <Shift> + <Insert> are used to
// copy-paste on some systems.
result.key = C0.ESC + '[2~';
}
break;
case 46:
// delete
if (modifiers) {
result.key = C0.ESC + '[3;' + (modifiers + 1) + '~';
} else {
result.key = C0.ESC + '[3~';
}
break;
case 36:
// home
if (modifiers) {
result.key = C0.ESC + '[1;' + (modifiers + 1) + 'H';
} else if (applicationCursorMode) {
result.key = C0.ESC + 'OH';
} else {
result.key = C0.ESC + '[H';
}
break;
case 35:
// end
if (modifiers) {
result.key = C0.ESC + '[1;' + (modifiers + 1) + 'F';
} else if (applicationCursorMode) {
result.key = C0.ESC + 'OF';
} else {
result.key = C0.ESC + '[F';
}
break;
case 33:
// page up
if (ev.shiftKey) {
result.type = KeyboardResultType.PAGE_UP;
} else {
result.key = C0.ESC + '[5~';
}
break;
case 34:
// page down
if (ev.shiftKey) {
result.type = KeyboardResultType.PAGE_DOWN;
} else {
result.key = C0.ESC + '[6~';
}
break;
case 112:
// F1-F12
if (modifiers) {
result.key = C0.ESC + '[1;' + (modifiers + 1) + 'P';
} else {
result.key = C0.ESC + 'OP';
}
break;
case 113:
if (modifiers) {
result.key = C0.ESC + '[1;' + (modifiers + 1) + 'Q';
} else {
result.key = C0.ESC + 'OQ';
}
break;
case 114:
if (modifiers) {
result.key = C0.ESC + '[1;' + (modifiers + 1) + 'R';
} else {
result.key = C0.ESC + 'OR';
}
break;
case 115:
if (modifiers) {
result.key = C0.ESC + '[1;' + (modifiers + 1) + 'S';
} else {
result.key = C0.ESC + 'OS';
}
break;
case 116:
if (modifiers) {
result.key = C0.ESC + '[15;' + (modifiers + 1) + '~';
} else {
result.key = C0.ESC + '[15~';
}
break;
case 117:
if (modifiers) {
result.key = C0.ESC + '[17;' + (modifiers + 1) + '~';
} else {
result.key = C0.ESC + '[17~';
}
break;
case 118:
if (modifiers) {
result.key = C0.ESC + '[18;' + (modifiers + 1) + '~';
} else {
result.key = C0.ESC + '[18~';
}
break;
case 119:
if (modifiers) {
result.key = C0.ESC + '[19;' + (modifiers + 1) + '~';
} else {
result.key = C0.ESC + '[19~';
}
break;
case 120:
if (modifiers) {
result.key = C0.ESC + '[20;' + (modifiers + 1) + '~';
} else {
result.key = C0.ESC + '[20~';
}
break;
case 121:
if (modifiers) {
result.key = C0.ESC + '[21;' + (modifiers + 1) + '~';
} else {
result.key = C0.ESC + '[21~';
}
break;
case 122:
if (modifiers) {
result.key = C0.ESC + '[23;' + (modifiers + 1) + '~';
} else {
result.key = C0.ESC + '[23~';
}
break;
case 123:
if (modifiers) {
result.key = C0.ESC + '[24;' + (modifiers + 1) + '~';
} else {
result.key = C0.ESC + '[24~';
}
break;
default:
// a-z and space
if (ev.ctrlKey && !ev.shiftKey && !ev.altKey && !ev.metaKey) {
if (ev.keyCode >= 65 && ev.keyCode <= 90) {
result.key = String.fromCharCode(ev.keyCode - 64);
} else if (ev.keyCode === 32) {
// NUL
result.key = String.fromCharCode(0);
} else if (ev.keyCode >= 51 && ev.keyCode <= 55) {
// escape, file sep, group sep, record sep, unit sep
result.key = String.fromCharCode(ev.keyCode - 51 + 27);
} else if (ev.keyCode === 56) {
// delete
result.key = String.fromCharCode(127);
} else if (ev.keyCode === 219) {
// ^[ - Control Sequence Introducer (CSI)
result.key = String.fromCharCode(27);
} else if (ev.keyCode === 220) {
// ^\ - String Terminator (ST)
result.key = String.fromCharCode(28);
} else if (ev.keyCode === 221) {
// ^] - Operating System Command (OSC)
result.key = String.fromCharCode(29);
}
} else if ((!isMac || macOptionIsMeta) && ev.altKey && !ev.metaKey) {
// On macOS this is a third level shift when !macOptionIsMeta. Use <Esc> instead.
const keyMapping = KEYCODE_KEY_MAPPINGS[ev.keyCode];
const key = keyMapping && keyMapping[!ev.shiftKey ? 0 : 1];
if (key) {
result.key = C0.ESC + key;
} else if (ev.keyCode >= 65 && ev.keyCode <= 90) {
const keyCode = ev.ctrlKey ? ev.keyCode - 64 : ev.keyCode + 32;
result.key = C0.ESC + String.fromCharCode(keyCode);
}
} else if (isMac && !ev.altKey && !ev.ctrlKey && ev.metaKey) {
if (ev.keyCode === 65) { // cmd + a
result.type = KeyboardResultType.SELECT_ALL;
}
}
break;
}
return result;
}
+1 -1
View File
@@ -4,7 +4,7 @@
*/
import { ITerminal, ICircularList, LineData } from '../Types';
import { C0 } from '../EscapeSequences';
import { C0 } from '../common/data/EscapeSequences';
const enum Direction {
UP = 'A',
+17
View File
@@ -0,0 +1,17 @@
/**
* Copyright (c) 2016 The xterm.js authors. All rights reserved.
* @license MIT
*/
import { assert } from 'chai';
import { Terminal } from './Terminal';
import * as attach from '../addons/attach/attach';
describe('Terminal', () => {
it('should apply addons with Terminal.applyAddon', () => {
Terminal.applyAddon(attach);
// Test that addon was applied successfully, adding attach to Terminal's
// prototype.
assert.equal(typeof (<any>Terminal).prototype.attach, 'function');
});
});

Some files were not shown because too many files have changed in this diff Show More