From ec9f2702eb08a9fd7fe53c8b93ca7a278d000886 Mon Sep 17 00:00:00 2001 From: Saad Malik Date: Sun, 21 Jan 2018 16:40:38 -0800 Subject: [PATCH 1/4] Additional alt and control sequences * Add punctuation alt sequences * Add support for ctrl+alt sequences --- src/Terminal.test.ts | 44 ++++++++++++++++++++++++++++++++++++++++++++ src/Terminal.ts | 40 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 80 insertions(+), 4 deletions(-) diff --git a/src/Terminal.test.ts b/src/Terminal.test.ts index 946e9efb..746cdeba 100644 --- a/src/Terminal.test.ts +++ b/src/Terminal.test.ts @@ -578,6 +578,50 @@ describe('term.js addons', () => { 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 + 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+~', () => { + // tilde is a DEAD key + 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: 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', () => { diff --git a/src/Terminal.ts b/src/Terminal.ts index b56caf83..4df277d5 100644 --- a/src/Terminal.ts +++ b/src/Terminal.ts @@ -1713,14 +1713,46 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT // ^] - Operating System Command (OSC) result.key = String.fromCharCode(29); } - } else if ((!this.browser.isMac || this.options.macOptionIsMeta) && ev.altKey && !ev.ctrlKey && !ev.metaKey) { + } else if ((!this.browser.isMac || this.options.macOptionIsMeta) && ev.altKey && !ev.metaKey) { // On macOS this is a third level shift when !macOptionIsMeta. Use instead. if (ev.keyCode >= 65 && ev.keyCode <= 90) { - result.key = C0.ESC + String.fromCharCode(ev.keyCode + 32); - } else if (ev.keyCode === 192) { - result.key = C0.ESC + '`'; + const keyCode = ev.ctrlKey ? ev.keyCode - 64 : ev.keyCode + 32; + result.key = C0.ESC + String.fromCharCode(keyCode); } else if (ev.keyCode >= 48 && ev.keyCode <= 57) { result.key = C0.ESC + (ev.keyCode - 48); + } else { + const t = (p,s) => !ev.shiftKey ? p : s; + switch (ev.keyCode) { + case 186: + result.key = C0.ESC + t(';', ':'); + break; + case 187: + result.key = C0.ESC + t('=', '+'); + break; + case 188: + result.key = C0.ESC + t(',', '<'); + break; + case 189: + result.key = C0.ESC + t('-', '_'); + break; + case 190: + result.key = C0.ESC + t('.', '>'); + break; + case 192: + // the tilde is a DEAD key + result.key = C0.ESC + '`'; + break; + case 219: + result.key = C0.ESC + t('[', '{'); + break; + case 221: + result.key = C0.ESC + t(']', '}'); + break; + case 222: + result.key = C0.ESC + t('\'', '|'); + break; + + } } } else if (this.browser.isMac && !ev.altKey && !ev.ctrlKey && ev.metaKey) { if (ev.keyCode === 65) { // cmd + a From d62e4e25b73e74ab524f2a8513c954bc02207a10 Mon Sep 17 00:00:00 2001 From: Saad Malik Date: Sun, 21 Jan 2018 16:56:58 -0800 Subject: [PATCH 2/4] Cleaup whitespace --- src/Terminal.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Terminal.ts b/src/Terminal.ts index 4df277d5..4692f345 100644 --- a/src/Terminal.ts +++ b/src/Terminal.ts @@ -1721,7 +1721,7 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT } else if (ev.keyCode >= 48 && ev.keyCode <= 57) { result.key = C0.ESC + (ev.keyCode - 48); } else { - const t = (p,s) => !ev.shiftKey ? p : s; + const t = (p, s) => !ev.shiftKey ? p : s; switch (ev.keyCode) { case 186: result.key = C0.ESC + t(';', ':'); From 0104e4214e7c09331ba45087d8665a77faeb99ec Mon Sep 17 00:00:00 2001 From: Saad Malik Date: Fri, 26 Jan 2018 18:33:37 -0800 Subject: [PATCH 3/4] Reimplement using map * Reimplemented reg + shift alt digits and characters using a map * Add test cases for digits --- src/Terminal.test.ts | 51 +++++++++++++++++++++++++++++++-- src/Terminal.ts | 68 +++++++++++++++++++++----------------------- 2 files changed, 80 insertions(+), 39 deletions(-) diff --git a/src/Terminal.test.ts b/src/Terminal.test.ts index 746cdeba..301ab020 100644 --- a/src/Terminal.test.ts +++ b/src/Terminal.test.ts @@ -584,7 +584,49 @@ describe('term.js addons', () => { assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, ctrlKey: true, keyCode: 65 }).key, '\x1b\x01'); }); - // Characters using alt sequences + // 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:'); @@ -605,10 +647,13 @@ describe('term.js addons', () => { 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+~', () => { - // tilde is a DEAD key assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: false, keyCode: 192 }).key, '\x1b`'); - assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: true, 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['); diff --git a/src/Terminal.ts b/src/Terminal.ts index f737adbb..ddb647da 100644 --- a/src/Terminal.ts +++ b/src/Terminal.ts @@ -46,6 +46,33 @@ import { DEFAULT_ANSI_COLORS } from './renderer/ColorManager'; import { MouseZoneManager } from './input/MouseZoneManager'; import { ITheme } from 'xterm'; +// reg + shift key mappings for digits and special chars +const KEYCODE_KEY_MAPPINGS = { + // 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: ['[', '{'], + 221: [']', '}'], + 222: ['\'', '|'] +}; + // Let it work inside Node.js for automated testing purposes. const document = (typeof window !== 'undefined') ? window.document : null; @@ -1727,44 +1754,13 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT } } else if ((!this.browser.isMac || this.options.macOptionIsMeta) && ev.altKey && !ev.metaKey) { // On macOS this is a third level shift when !macOptionIsMeta. Use instead. - if (ev.keyCode >= 65 && ev.keyCode <= 90) { + 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 (ev.keyCode >= 48 && ev.keyCode <= 57) { - result.key = C0.ESC + (ev.keyCode - 48); - } else { - const t = (p, s) => !ev.shiftKey ? p : s; - switch (ev.keyCode) { - case 186: - result.key = C0.ESC + t(';', ':'); - break; - case 187: - result.key = C0.ESC + t('=', '+'); - break; - case 188: - result.key = C0.ESC + t(',', '<'); - break; - case 189: - result.key = C0.ESC + t('-', '_'); - break; - case 190: - result.key = C0.ESC + t('.', '>'); - break; - case 192: - // the tilde is a DEAD key - result.key = C0.ESC + '`'; - break; - case 219: - result.key = C0.ESC + t('[', '{'); - break; - case 221: - result.key = C0.ESC + t(']', '}'); - break; - case 222: - result.key = C0.ESC + t('\'', '|'); - break; - - } } } else if (this.browser.isMac && !ev.altKey && !ev.ctrlKey && ev.metaKey) { if (ev.keyCode === 65) { // cmd + a From 9ade1f0a5d8586fcbc88f8e66fe6cbfc1512fead Mon Sep 17 00:00:00 2001 From: Saad Malik Date: Sun, 28 Jan 2018 17:11:13 -0800 Subject: [PATCH 4/4] Add mapping for backward slash * Add mapping for backward slash * Fix mapping for single/double quote --- src/Terminal.test.ts | 8 ++++++-- src/Terminal.ts | 3 ++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/Terminal.test.ts b/src/Terminal.test.ts index 301ab020..12467d84 100644 --- a/src/Terminal.test.ts +++ b/src/Terminal.test.ts @@ -659,13 +659,17 @@ describe('term.js addons', () => { 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+\\', () => { + 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|'); + assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, shiftKey: true, keyCode: 222 }).key, '\x1b"'); }); }); diff --git a/src/Terminal.ts b/src/Terminal.ts index cdbda41f..88dc2b6b 100644 --- a/src/Terminal.ts +++ b/src/Terminal.ts @@ -69,8 +69,9 @@ const KEYCODE_KEY_MAPPINGS = { 191: ['/', '?'], 192: ['`', '~'], 219: ['[', '{'], + 220: ['\\', '|'], 221: [']', '}'], - 222: ['\'', '|'] + 222: ['\'', '"'] }; // Let it work inside Node.js for automated testing purposes.