diff --git a/demo/index.html b/demo/index.html index 93399f9cd..da348f5e6 100644 --- a/demo/index.html +++ b/demo/index.html @@ -23,6 +23,9 @@
cursorBlink
+ macOptionIsMeta +
cursorStyle diff --git a/demo/main.js b/demo/main.js index d41705939..1faf77d8a 100644 --- a/demo/main.js +++ b/demo/main.js @@ -27,6 +27,7 @@ var terminalContainer = document.getElementById('terminal-container'), optionElements = { cursorBlink: document.querySelector('#option-cursor-blink'), cursorStyle: document.querySelector('#option-cursor-style'), + macOptionIsMeta: document.querySelector('#option-mac-option-is-meta'), scrollback: document.querySelector('#option-scrollback'), tabstopwidth: document.querySelector('#option-tabstopwidth'), bellStyle: document.querySelector('#option-bell-style') @@ -72,6 +73,9 @@ optionElements.cursorStyle.addEventListener('change', function () { optionElements.bellStyle.addEventListener('change', function () { term.setOption('bellStyle', optionElements.bellStyle.value); }); +optionElements.macOptionIsMeta.addEventListener('change', function () { + term.setOption('macOptionIsMeta', optionElements.macOptionIsMeta.checked); +}); optionElements.scrollback.addEventListener('change', function () { term.setOption('scrollback', parseInt(optionElements.scrollback.value, 10)); }); @@ -87,7 +91,7 @@ function createTerminal() { terminalContainer.removeChild(terminalContainer.children[0]); } term = new Terminal({ - altIsMeta: true, + macOptionIsMeta: optionElements.macOptionIsMeta.enabled, cursorBlink: optionElements.cursorBlink.checked, scrollback: parseInt(optionElements.scrollback.value, 10), tabStopWidth: parseInt(optionElements.tabstopwidth.value, 10) diff --git a/fixtures/typings-test/typings-test.ts b/fixtures/typings-test/typings-test.ts index 5a5f6c501..0a88bd376 100644 --- a/fixtures/typings-test/typings-test.ts +++ b/fixtures/typings-test/typings-test.ts @@ -144,6 +144,7 @@ namespace methods_core { const r20: string = t.getOption('bellStyle'); const r21: boolean = t.getOption('enableBold'); const r22: number = t.getOption('letterSpacing'); + const r23: boolean = t.getOption('macOptionIsMeta'); } { const t: Terminal = new Terminal(); @@ -177,6 +178,7 @@ namespace methods_core { t.setOption('lineHeight', 1); t.setOption('fontFamily', 'foo'); t.setOption('theme', {background: '#ff0000'}); + t.setOption('macOptionIsMeta', true); } } namespace scrolling { diff --git a/src/Interfaces.ts b/src/Interfaces.ts index 119322b55..70b8509fe 100644 --- a/src/Interfaces.ts +++ b/src/Interfaces.ts @@ -128,7 +128,6 @@ export interface IInputHandlingTerminal extends IEventEmitter { } export interface ITerminalOptions { - altIsMeta?: boolean; bellSound?: string; bellStyle?: string; cancelEvents?: boolean; @@ -144,6 +143,7 @@ export interface ITerminalOptions { handler?: (data: string) => void; letterSpacing?: number; lineHeight?: number; + macOptionIsMeta?: boolean; rows?: number; screenKeys?: boolean; scrollback?: number; diff --git a/src/Terminal.test.ts b/src/Terminal.test.ts index 430c43320..946e9efb1 100644 --- a/src/Terminal.test.ts +++ b/src/Terminal.test.ts @@ -523,10 +523,10 @@ describe('term.js addons', () => { }); }); - describe('with altIsMeta', () => { + describe('with macOptionIsMeta', () => { beforeEach(() => { term.browser.isMac = true; - term.setOption('altIsMeta', true); + term.setOption('macOptionIsMeta', true); }); it('should return \\x1ba for alt+a', () => { assert.equal(term.evaluateKeyEscapeSequence({ altKey: true, keyCode: 65 }).key, '\x1ba'); @@ -613,10 +613,10 @@ describe('term.js addons', () => { }; }); - describe('with altIsMeta', () => { + describe('with macOptionIsMeta', () => { beforeEach(() => { term.browser.isMac = true; - term.setOption('altIsMeta', true); + term.setOption('macOptionIsMeta', true); }); it('should interfere with the alt key on keyDown', () => { diff --git a/src/Terminal.ts b/src/Terminal.ts index db2e2f6dd..b56caf83f 100644 --- a/src/Terminal.ts +++ b/src/Terminal.ts @@ -80,7 +80,7 @@ const DEFAULT_OPTIONS: ITerminalOptions = { scrollback: 1000, screenKeys: false, debug: false, - altIsMeta: false, + macOptionIsMeta: false, cancelEvents: false, disableStdin: false, useFlowControl: false, @@ -1375,7 +1375,7 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT return this.cancel(ev, true); } - if (!this.options.altIsMeta && isThirdLevelShift(this.browser, ev)) { + if (this._isThirdLevelShift(this.browser, ev)) { return true; } @@ -1396,6 +1396,19 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT return this.cancel(ev, true); } + private _isThirdLevelShift(browser: IBrowser, ev: KeyboardEvent): boolean { + const thirdLevelKey = + (browser.isMac && !this.options.macOptionIsMeta && ev.altKey && !ev.ctrlKey && !ev.metaKey) || + (browser.isMSWindows && ev.altKey && ev.ctrlKey && !ev.metaKey); + + if (ev.type === 'keypress') { + return thirdLevelKey; + } + + // Don't invoke for arrows, pageDown, home, backspace, etc. (on non-keypress events) + 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. @@ -1700,8 +1713,8 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT // ^] - Operating System Command (OSC) result.key = String.fromCharCode(29); } - } else if ((!this.browser.isMac || this.options.altIsMeta) && ev.altKey && !ev.ctrlKey && !ev.metaKey) { - // On Mac this is a third level shift. Use instead if !altIsMeta + } else if ((!this.browser.isMac || this.options.macOptionIsMeta) && ev.altKey && !ev.ctrlKey && !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) { @@ -1767,7 +1780,7 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT } if (!key || ( - (ev.altKey || ev.ctrlKey || ev.metaKey) && !isThirdLevelShift(this.browser, ev) + (ev.altKey || ev.ctrlKey || ev.metaKey) && !this._isThirdLevelShift(this.browser, ev) )) { return false; } @@ -2159,19 +2172,6 @@ function off(el: any, type: string, handler: (event: Event) => any, capture: boo el.removeEventListener(type, handler, capture); } -function isThirdLevelShift(browser: IBrowser, ev: KeyboardEvent): boolean { - const thirdLevelKey = - (browser.isMac && ev.altKey && !ev.ctrlKey && !ev.metaKey) || - (browser.isMSWindows && ev.altKey && ev.ctrlKey && !ev.metaKey); - - if (ev.type === 'keypress') { - return thirdLevelKey; - } - - // Don't invoke for arrows, pageDown, home, backspace, etc. (on non-keypress events) - return thirdLevelKey && (!ev.keyCode || ev.keyCode > 47); -} - function wasMondifierKeyOnlyEvent(ev: KeyboardEvent): boolean { return ev.keyCode === 16 || // Shift ev.keyCode === 17 || // Ctrl diff --git a/typings/xterm.d.ts b/typings/xterm.d.ts index 83199e08b..43842bad6 100644 --- a/typings/xterm.d.ts +++ b/typings/xterm.d.ts @@ -454,7 +454,7 @@ declare module 'xterm' { * @param key The option key. * @param value The option value. */ - setOption(key: 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'debug' | 'disableStdin' | 'enableBold' | 'popOnBell' | 'screenKeys' | 'useFlowControl' | 'visualBell', value: boolean): void; + setOption(key: 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'debug' | 'disableStdin' | 'enableBold' | 'macOptionIsMeta' | 'popOnBell' | 'screenKeys' | 'useFlowControl' | 'visualBell', value: boolean): void; /** * Sets an option on the terminal. * @param key The option key.