From 368e1cc49be2b3f017035d71c0f230cff481d694 Mon Sep 17 00:00:00 2001 From: Pavel Feldman Date: Sat, 11 Apr 2020 00:24:17 -0700 Subject: [PATCH] chore(input): refactor keyboard layout, extract pure layout (#1681) --- src/input.ts | 129 ++++++---- src/macEditingCommands.ts | 133 ++++++++++ src/usKeyboardLayout.ts | 506 ++++++++++---------------------------- src/webkit/wkInput.ts | 2 +- test/keyboard.spec.js | 49 ++++ 5 files changed, 397 insertions(+), 422 deletions(-) create mode 100644 src/macEditingCommands.ts diff --git a/src/input.ts b/src/input.ts index 6322c7d596..5010ecc366 100644 --- a/src/input.ts +++ b/src/input.ts @@ -40,6 +40,7 @@ type KeyDescription = { text: string, code: string, location: number, + shifted?: KeyDescription; }; const kModifiers: Modifier[] = ['Alt', 'Control', 'Meta', 'Shift']; @@ -70,51 +71,14 @@ export class Keyboard { } private _keyDescriptionForString(keyString: string): KeyDescription { + let description = usKeyboardLayout.get(keyString); + assert(description, `Unknown key: "${keyString}"`); const shift = this._pressedModifiers.has('Shift'); - const description: KeyDescription = { - key: '', - keyCode: 0, - keyCodeWithoutLocation: 0, - code: '', - text: '', - location: 0 - }; - - const definition = keyboardLayout.keyDefinitions[keyString]; - assert(definition, `Unknown key: "${keyString}"`); - - if (definition.key) - description.key = definition.key; - if (shift && definition.shiftKey) - description.key = definition.shiftKey; - - if (definition.keyCode) - description.keyCode = definition.keyCode; - if (shift && definition.shiftKeyCode) - description.keyCode = definition.shiftKeyCode; - - if (definition.code) - description.code = definition.code; - - if (definition.location) - description.location = definition.location; - - if (description.key.length === 1) - description.text = description.key; - - if (definition.text) - description.text = definition.text; - if (shift && definition.shiftText) - description.text = definition.shiftText; + description = shift && description.shifted ? description.shifted : description; // if any modifiers besides shift are pressed, no text should be sent if (this._pressedModifiers.size > 1 || (!this._pressedModifiers.has('Shift') && this._pressedModifiers.size === 1)) - description.text = ''; - - if (definition.keyCodeWithoutLocation) - description.keyCodeWithoutLocation = definition.keyCodeWithoutLocation; - else - description.keyCodeWithoutLocation = description.keyCode; + return { ...description, text: '' }; return description; } @@ -133,7 +97,7 @@ export class Keyboard { async type(text: string, options?: { delay?: number }) { const delay = (options && options.delay) || undefined; for (const char of text) { - if (keyboardLayout.keyDefinitions[char]) { + if (usKeyboardLayout.has(char)) { await this.press(char, { delay }); } else { if (delay) @@ -144,10 +108,31 @@ export class Keyboard { } async press(key: string, options: { delay?: number } = {}) { + function split(keyString: string) { + const keys = []; + let building = ''; + for (const char of keyString) { + if (char === '+' && building) { + keys.push(building); + building = ''; + } else { + building += char; + } + } + keys.push(building); + return keys; + } + + const tokens = split(key); + key = tokens[tokens.length - 1]; + for (let i = 0; i < tokens.length - 1; ++i) + await this.down(tokens[i]); await this.down(key); if (options.delay) await new Promise(f => setTimeout(f, options.delay)); await this.up(key); + for (let i = tokens.length - 2; i >= 0; --i) + await this.up(tokens[i]); } async _ensureModifiers(modifiers: Modifier[]): Promise { @@ -246,3 +231,63 @@ export class Mouse { await this.click(x, y, { ...options, clickCount: 2 }); } } + +const aliases = new Map([ + ['ShiftLeft', ['Shift']], + ['ControlLeft', ['Control']], + ['AltLeft', ['Alt']], + ['MetaLeft', ['Meta']], + ['Enter', ['\n', '\r']], +]); + +const usKeyboardLayout = buildLayoutClosure(keyboardLayout.USKeyboardLayout); + +function buildLayoutClosure(layout: keyboardLayout.KeyboardLayout): Map { + const result = new Map(); + for (const code in layout) { + const definition = layout[code]; + const description: KeyDescription = { + key: definition.key || '', + keyCode: definition.keyCode || 0, + keyCodeWithoutLocation: definition.keyCodeWithoutLocation || definition.keyCode || 0, + code, + text: definition.text || '', + location: definition.location || 0, + }; + if (definition.key.length === 1) + description.text = description.key; + + // Generate shifted definition. + let shiftedDescription: KeyDescription | undefined; + if (definition.shiftKey) { + assert(definition.shiftKey.length === 1); + shiftedDescription = { ...description }; + shiftedDescription.key = definition.shiftKey; + shiftedDescription.text = definition.shiftKey; + if (definition.shiftKeyCode) + shiftedDescription.keyCode = definition.shiftKeyCode; + } + + // Map from code: Digit3 -> { ... descrption, shifted } + result.set(code, { ...description, shifted: shiftedDescription }); + + // Map from aliases: Shift -> non-shiftable definition + if (aliases.has(code)) { + for (const alias of aliases.get(code)!) + result.set(alias, description); + } + + // Do not use numpad when converting keys to codes. + if (definition.location) + continue; + + // Map from key, no shifted + if (description.key.length === 1) + result.set(description.key, description); + + // Map from shiftKey, no shifted + if (shiftedDescription) + result.set(shiftedDescription.key, { ...shiftedDescription, shifted: undefined }); + } + return result; +} diff --git a/src/macEditingCommands.ts b/src/macEditingCommands.ts new file mode 100644 index 0000000000..6004964ff9 --- /dev/null +++ b/src/macEditingCommands.ts @@ -0,0 +1,133 @@ +/** + * Copyright 2017 Google Inc. All rights reserved. + * Modifications copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export const macEditingCommands: {[key: string]: string|string[]} = { + 'Backspace': 'deleteBackward:', + 'Tab': 'insertTab:', + 'Enter': 'insertNewline:', + 'NumpadEnter': 'insertNewline:', + 'Escape': 'cancelOperation:', + 'ArrowUp': 'moveUp:', + 'ArrowDown': 'moveDown:', + 'ArrowLeft': 'moveLeft:', + 'ArrowRight': 'moveRight:', + 'F5': 'complete:', + 'Delete': 'deleteForward:', + 'Home': 'scrollToBeginningOfDocument:', + 'End': 'scrollToEndOfDocument:', + 'PageUp': 'scrollPageUp:', + 'PageDown': 'scrollPageDown:', + 'Shift+Backspace': 'deleteBackward:', + 'Shift+Enter': 'insertNewline:', + 'Shift+NumpadEnter': 'insertNewline:', + 'Shift+Tab': 'insertBacktab:', + 'Shift+Escape': 'cancelOperation:', + 'Shift+ArrowUp': 'moveUpAndModifySelection:', + 'Shift+ArrowDown': 'moveDownAndModifySelection:', + 'Shift+ArrowLeft': 'moveLeftAndModifySelection:', + 'Shift+ArrowRight': 'moveRightAndModifySelection:', + 'Shift+F5': 'complete:', + 'Shift+Delete': 'deleteForward:', + 'Shift+Home': 'moveToBeginningOfDocumentAndModifySelection:', + 'Shift+End': 'moveToEndOfDocumentAndModifySelection:', + 'Shift+PageUp': 'pageUpAndModifySelection:', + 'Shift+PageDown': 'pageDownAndModifySelection:', + 'Shift+Numpad5': 'delete:', + 'Control+Tab': 'selectNextKeyView:', + 'Control+Enter': 'insertLineBreak:', + 'Control+NumpadEnter': 'insertLineBreak:', + 'Control+Quote': 'insertSingleQuoteIgnoringSubstitution:', + 'Control+KeyA': 'moveToBeginningOfParagraph:', + 'Control+KeyB': 'moveBackward:', + 'Control+KeyD': 'deleteForward:', + 'Control+KeyE': 'moveToEndOfParagraph:', + 'Control+KeyF': 'moveForward:', + 'Control+KeyH': 'deleteBackward:', + 'Control+KeyK': 'deleteToEndOfParagraph:', + 'Control+KeyL': 'centerSelectionInVisibleArea:', + 'Control+KeyN': 'moveDown:', + 'Control+KeyO': ['insertNewlineIgnoringFieldEditor:', 'moveBackward:'], + 'Control+KeyP': 'moveUp:', + 'Control+KeyT': 'transpose:', + 'Control+KeyV': 'pageDown:', + 'Control+KeyY': 'yank:', + 'Control+Backspace': 'deleteBackwardByDecomposingPreviousCharacter:', + 'Control+ArrowUp': 'scrollPageUp:', + 'Control+ArrowDown': 'scrollPageDown:', + 'Control+ArrowLeft': 'moveToLeftEndOfLine:', + 'Control+ArrowRight': 'moveToRightEndOfLine:', + 'Shift+Control+Enter': 'insertLineBreak:', + 'Shift+Control+NumpadEnter': 'insertLineBreak:', + 'Shift+Control+Tab': 'selectPreviousKeyView:', + 'Shift+Control+Quote': 'insertDoubleQuoteIgnoringSubstitution:', + 'Shift+Control+KeyA': 'moveToBeginningOfParagraphAndModifySelection:', + 'Shift+Control+KeyB': 'moveBackwardAndModifySelection:', + 'Shift+Control+KeyE': 'moveToEndOfParagraphAndModifySelection:', + 'Shift+Control+KeyF': 'moveForwardAndModifySelection:', + 'Shift+Control+KeyN': 'moveDownAndModifySelection:', + 'Shift+Control+KeyP': 'moveUpAndModifySelection:', + 'Shift+Control+KeyV': 'pageDownAndModifySelection:', + 'Shift+Control+Backspace': 'deleteBackwardByDecomposingPreviousCharacter:', + 'Shift+Control+ArrowUp': 'scrollPageUp:', + 'Shift+Control+ArrowDown': 'scrollPageDown:', + 'Shift+Control+ArrowLeft': 'moveToLeftEndOfLineAndModifySelection:', + 'Shift+Control+ArrowRight': 'moveToRightEndOfLineAndModifySelection:', + 'Alt+Backspace': 'deleteWordBackward:', + 'Alt+Tab': 'insertTabIgnoringFieldEditor:', + 'Alt+Enter': 'insertNewlineIgnoringFieldEditor:', + 'Alt+NumpadEnter': 'insertNewlineIgnoringFieldEditor:', + 'Alt+Escape': 'complete:', + 'Alt+ArrowUp': ['moveBackward:', 'moveToBeginningOfParagraph:'], + 'Alt+ArrowDown': ['moveForward:', 'moveToEndOfParagraph:'], + 'Alt+ArrowLeft': 'moveWordLeft:', + 'Alt+ArrowRight': 'moveWordRight:', + 'Alt+Delete': 'deleteWordForward:', + 'Alt+PageUp': 'pageUp:', + 'Alt+PageDown': 'pageDown:', + 'Shift+Alt+Backspace': 'deleteWordBackward:', + 'Shift+Alt+Tab': 'insertTabIgnoringFieldEditor:', + 'Shift+Alt+Enter': 'insertNewlineIgnoringFieldEditor:', + 'Shift+Alt+NumpadEnter': 'insertNewlineIgnoringFieldEditor:', + 'Shift+Alt+Escape': 'complete:', + 'Shift+Alt+ArrowUp': 'moveParagraphBackwardAndModifySelection:', + 'Shift+Alt+ArrowDown': 'moveParagraphForwardAndModifySelection:', + 'Shift+Alt+ArrowLeft': 'moveWordLeftAndModifySelection:', + 'Shift+Alt+ArrowRight': 'moveWordRightAndModifySelection:', + 'Shift+Alt+Delete': 'deleteWordForward:', + 'Shift+Alt+PageUp': 'pageUp:', + 'Shift+Alt+PageDown': 'pageDown:', + 'Control+Alt+KeyB': 'moveWordBackward:', + 'Control+Alt+KeyF': 'moveWordForward:', + 'Control+Alt+Backspace': 'deleteWordBackward:', + 'Shift+Control+Alt+KeyB': 'moveWordBackwardAndModifySelection:', + 'Shift+Control+Alt+KeyF': 'moveWordForwardAndModifySelection:', + 'Shift+Control+Alt+Backspace': 'deleteWordBackward:', + 'Meta+NumpadSubtract': 'cancel:', + 'Meta+Backspace': 'deleteToBeginningOfLine:', + 'Meta+ArrowUp': 'moveToBeginningOfDocument:', + 'Meta+ArrowDown': 'moveToEndOfDocument:', + 'Meta+ArrowLeft': 'moveToLeftEndOfLine:', + 'Meta+ArrowRight': 'moveToRightEndOfLine:', + 'Shift+Meta+NumpadSubtract': 'cancel:', + 'Shift+Meta+Backspace': 'deleteToBeginningOfLine:', + 'Shift+Meta+ArrowUp': 'moveToBeginningOfDocumentAndModifySelection:', + 'Shift+Meta+ArrowDown': 'moveToEndOfDocumentAndModifySelection:', + 'Shift+Meta+ArrowLeft': 'moveToLeftEndOfLineAndModifySelection:', + 'Shift+Meta+ArrowRight': 'moveToRightEndOfLineAndModifySelection:', + + 'Meta+KeyA': 'selectAll:', +}; diff --git a/src/usKeyboardLayout.ts b/src/usKeyboardLayout.ts index c9a93da873..9b21ef27c1 100644 --- a/src/usKeyboardLayout.ts +++ b/src/usKeyboardLayout.ts @@ -15,392 +15,140 @@ * limitations under the License. */ -type KeyDefinition = { - keyCode?: number; +export type KeyDefinition = { + key: string; + keyCode: number; keyCodeWithoutLocation?: number; - shiftKeyCode?: number; - key?: string; shiftKey?: string; - code?: string; + shiftKeyCode?: number; text?: string; - shiftText?: string; - location? : number; - windowsVirtualKeyCode?: number; + location?: number; } +export type KeyboardLayout = { [s: string]: KeyDefinition; }; + export const keypadLocation = 3; -export const keyDefinitions: { [s: string]: KeyDefinition; } = { - '0': {'keyCode': 48, 'key': '0', 'code': 'Digit0'}, - '1': {'keyCode': 49, 'key': '1', 'code': 'Digit1'}, - '2': {'keyCode': 50, 'key': '2', 'code': 'Digit2'}, - '3': {'keyCode': 51, 'key': '3', 'code': 'Digit3'}, - '4': {'keyCode': 52, 'key': '4', 'code': 'Digit4'}, - '5': {'keyCode': 53, 'key': '5', 'code': 'Digit5'}, - '6': {'keyCode': 54, 'key': '6', 'code': 'Digit6'}, - '7': {'keyCode': 55, 'key': '7', 'code': 'Digit7'}, - '8': {'keyCode': 56, 'key': '8', 'code': 'Digit8'}, - '9': {'keyCode': 57, 'key': '9', 'code': 'Digit9'}, - 'Power': {'key': 'Power', 'code': 'Power'}, - 'Eject': {'key': 'Eject', 'code': 'Eject'}, - 'Abort': {'keyCode': 3, 'code': 'Abort', 'key': 'Cancel'}, - 'Help': {'keyCode': 6, 'code': 'Help', 'key': 'Help'}, - 'Backspace': {'keyCode': 8, 'code': 'Backspace', 'key': 'Backspace'}, - 'Tab': {'keyCode': 9, 'code': 'Tab', 'key': 'Tab'}, - 'Numpad5': {'keyCode': 12, 'shiftKeyCode': 101, 'key': 'Clear', 'code': 'Numpad5', 'shiftKey': '5', 'location': 3}, - 'NumpadEnter': {'keyCode': 13, 'code': 'NumpadEnter', 'key': 'Enter', 'text': '\r', 'location': 3}, - 'Enter': {'keyCode': 13, 'code': 'Enter', 'key': 'Enter', 'text': '\r'}, - '\r': {'keyCode': 13, 'code': 'Enter', 'key': 'Enter', 'text': '\r'}, - '\n': {'keyCode': 13, 'code': 'Enter', 'key': 'Enter', 'text': '\r'}, - 'ShiftLeft': {'keyCode': 160, 'keyCodeWithoutLocation': 16, 'code': 'ShiftLeft', 'key': 'Shift', 'location': 1, 'windowsVirtualKeyCode': 160}, - 'ShiftRight': {'keyCode': 161, 'keyCodeWithoutLocation': 16, 'code': 'ShiftRight', 'key': 'Shift', 'location': 2, 'windowsVirtualKeyCode': 161}, - 'ControlLeft': {'keyCode': 162, 'keyCodeWithoutLocation': 17, 'code': 'ControlLeft', 'key': 'Control', 'location': 1, 'windowsVirtualKeyCode': 162}, - 'ControlRight': {'keyCode': 163, 'keyCodeWithoutLocation': 17, 'code': 'ControlRight', 'key': 'Control', 'location': 2, 'windowsVirtualKeyCode': 163}, - 'AltLeft': {'keyCode': 164, 'keyCodeWithoutLocation': 18, 'code': 'AltLeft', 'key': 'Alt', 'location': 1, 'windowsVirtualKeyCode': 164}, - 'AltRight': {'keyCode': 165, 'keyCodeWithoutLocation': 18, 'code': 'AltRight', 'key': 'Alt', 'location': 2, 'windowsVirtualKeyCode': 165}, - 'Pause': {'keyCode': 19, 'code': 'Pause', 'key': 'Pause'}, - 'CapsLock': {'keyCode': 20, 'code': 'CapsLock', 'key': 'CapsLock'}, - 'Escape': {'keyCode': 27, 'code': 'Escape', 'key': 'Escape'}, - 'Convert': {'keyCode': 28, 'code': 'Convert', 'key': 'Convert'}, - 'NonConvert': {'keyCode': 29, 'code': 'NonConvert', 'key': 'NonConvert'}, - 'Space': {'keyCode': 32, 'code': 'Space', 'key': ' '}, - 'Numpad9': {'keyCode': 33, 'shiftKeyCode': 105, 'key': 'PageUp', 'code': 'Numpad9', 'shiftKey': '9', 'location': 3}, - 'PageUp': {'keyCode': 33, 'code': 'PageUp', 'key': 'PageUp'}, - 'Numpad3': {'keyCode': 34, 'shiftKeyCode': 99, 'key': 'PageDown', 'code': 'Numpad3', 'shiftKey': '3', 'location': 3}, - 'PageDown': {'keyCode': 34, 'code': 'PageDown', 'key': 'PageDown'}, - 'End': {'keyCode': 35, 'code': 'End', 'key': 'End'}, - 'Numpad1': {'keyCode': 35, 'shiftKeyCode': 97, 'key': 'End', 'code': 'Numpad1', 'shiftKey': '1', 'location': 3}, - 'Home': {'keyCode': 36, 'code': 'Home', 'key': 'Home'}, - 'Numpad7': {'keyCode': 36, 'shiftKeyCode': 103, 'key': 'Home', 'code': 'Numpad7', 'shiftKey': '7', 'location': 3}, - 'ArrowLeft': {'keyCode': 37, 'code': 'ArrowLeft', 'key': 'ArrowLeft'}, - 'Numpad4': {'keyCode': 37, 'shiftKeyCode': 100, 'key': 'ArrowLeft', 'code': 'Numpad4', 'shiftKey': '4', 'location': 3}, - 'Numpad8': {'keyCode': 38, 'shiftKeyCode': 104, 'key': 'ArrowUp', 'code': 'Numpad8', 'shiftKey': '8', 'location': 3}, - 'ArrowUp': {'keyCode': 38, 'code': 'ArrowUp', 'key': 'ArrowUp'}, - 'ArrowRight': {'keyCode': 39, 'code': 'ArrowRight', 'key': 'ArrowRight'}, - 'Numpad6': {'keyCode': 39, 'shiftKeyCode': 102, 'key': 'ArrowRight', 'code': 'Numpad6', 'shiftKey': '6', 'location': 3}, - 'Numpad2': {'keyCode': 40, 'shiftKeyCode': 98, 'key': 'ArrowDown', 'code': 'Numpad2', 'shiftKey': '2', 'location': 3}, - 'ArrowDown': {'keyCode': 40, 'code': 'ArrowDown', 'key': 'ArrowDown'}, - 'Select': {'keyCode': 41, 'code': 'Select', 'key': 'Select'}, - 'Open': {'keyCode': 43, 'code': 'Open', 'key': 'Execute'}, - 'PrintScreen': {'keyCode': 44, 'code': 'PrintScreen', 'key': 'PrintScreen'}, - 'Insert': {'keyCode': 45, 'code': 'Insert', 'key': 'Insert'}, - 'Numpad0': {'keyCode': 45, 'shiftKeyCode': 96, 'key': 'Insert', 'code': 'Numpad0', 'shiftKey': '0', 'location': 3}, - 'Delete': {'keyCode': 46, 'code': 'Delete', 'key': 'Delete'}, - 'NumpadDecimal': {'keyCode': 46, 'shiftKeyCode': 110, 'code': 'NumpadDecimal', 'key': '\u0000', 'shiftKey': '.', 'location': 3}, - 'Digit0': {'keyCode': 48, 'code': 'Digit0', 'shiftKey': ')', 'key': '0'}, - 'Digit1': {'keyCode': 49, 'code': 'Digit1', 'shiftKey': '!', 'key': '1'}, - 'Digit2': {'keyCode': 50, 'code': 'Digit2', 'shiftKey': '@', 'key': '2'}, - 'Digit3': {'keyCode': 51, 'code': 'Digit3', 'shiftKey': '#', 'key': '3'}, - 'Digit4': {'keyCode': 52, 'code': 'Digit4', 'shiftKey': '$', 'key': '4'}, - 'Digit5': {'keyCode': 53, 'code': 'Digit5', 'shiftKey': '%', 'key': '5'}, - 'Digit6': {'keyCode': 54, 'code': 'Digit6', 'shiftKey': '^', 'key': '6'}, - 'Digit7': {'keyCode': 55, 'code': 'Digit7', 'shiftKey': '&', 'key': '7'}, - 'Digit8': {'keyCode': 56, 'code': 'Digit8', 'shiftKey': '*', 'key': '8'}, - 'Digit9': {'keyCode': 57, 'code': 'Digit9', 'shiftKey': '\(', 'key': '9'}, - 'KeyA': {'keyCode': 65, 'code': 'KeyA', 'shiftKey': 'A', 'key': 'a'}, - 'KeyB': {'keyCode': 66, 'code': 'KeyB', 'shiftKey': 'B', 'key': 'b'}, - 'KeyC': {'keyCode': 67, 'code': 'KeyC', 'shiftKey': 'C', 'key': 'c'}, - 'KeyD': {'keyCode': 68, 'code': 'KeyD', 'shiftKey': 'D', 'key': 'd'}, - 'KeyE': {'keyCode': 69, 'code': 'KeyE', 'shiftKey': 'E', 'key': 'e'}, - 'KeyF': {'keyCode': 70, 'code': 'KeyF', 'shiftKey': 'F', 'key': 'f'}, - 'KeyG': {'keyCode': 71, 'code': 'KeyG', 'shiftKey': 'G', 'key': 'g'}, - 'KeyH': {'keyCode': 72, 'code': 'KeyH', 'shiftKey': 'H', 'key': 'h'}, - 'KeyI': {'keyCode': 73, 'code': 'KeyI', 'shiftKey': 'I', 'key': 'i'}, - 'KeyJ': {'keyCode': 74, 'code': 'KeyJ', 'shiftKey': 'J', 'key': 'j'}, - 'KeyK': {'keyCode': 75, 'code': 'KeyK', 'shiftKey': 'K', 'key': 'k'}, - 'KeyL': {'keyCode': 76, 'code': 'KeyL', 'shiftKey': 'L', 'key': 'l'}, - 'KeyM': {'keyCode': 77, 'code': 'KeyM', 'shiftKey': 'M', 'key': 'm'}, - 'KeyN': {'keyCode': 78, 'code': 'KeyN', 'shiftKey': 'N', 'key': 'n'}, - 'KeyO': {'keyCode': 79, 'code': 'KeyO', 'shiftKey': 'O', 'key': 'o'}, - 'KeyP': {'keyCode': 80, 'code': 'KeyP', 'shiftKey': 'P', 'key': 'p'}, - 'KeyQ': {'keyCode': 81, 'code': 'KeyQ', 'shiftKey': 'Q', 'key': 'q'}, - 'KeyR': {'keyCode': 82, 'code': 'KeyR', 'shiftKey': 'R', 'key': 'r'}, - 'KeyS': {'keyCode': 83, 'code': 'KeyS', 'shiftKey': 'S', 'key': 's'}, - 'KeyT': {'keyCode': 84, 'code': 'KeyT', 'shiftKey': 'T', 'key': 't'}, - 'KeyU': {'keyCode': 85, 'code': 'KeyU', 'shiftKey': 'U', 'key': 'u'}, - 'KeyV': {'keyCode': 86, 'code': 'KeyV', 'shiftKey': 'V', 'key': 'v'}, - 'KeyW': {'keyCode': 87, 'code': 'KeyW', 'shiftKey': 'W', 'key': 'w'}, - 'KeyX': {'keyCode': 88, 'code': 'KeyX', 'shiftKey': 'X', 'key': 'x'}, - 'KeyY': {'keyCode': 89, 'code': 'KeyY', 'shiftKey': 'Y', 'key': 'y'}, - 'KeyZ': {'keyCode': 90, 'code': 'KeyZ', 'shiftKey': 'Z', 'key': 'z'}, - 'MetaLeft': {'keyCode': 91, 'code': 'MetaLeft', 'key': 'Meta', 'location': 1}, - 'MetaRight': {'keyCode': 92, 'code': 'MetaRight', 'key': 'Meta', 'location': 2}, - 'ContextMenu': {'keyCode': 93, 'code': 'ContextMenu', 'key': 'ContextMenu'}, - 'NumpadMultiply': {'keyCode': 106, 'code': 'NumpadMultiply', 'key': '*', 'location': 3}, - 'NumpadAdd': {'keyCode': 107, 'code': 'NumpadAdd', 'key': '+', 'location': 3}, - 'NumpadSubtract': {'keyCode': 109, 'code': 'NumpadSubtract', 'key': '-', 'location': 3}, - 'NumpadDivide': {'keyCode': 111, 'code': 'NumpadDivide', 'key': '/', 'location': 3}, - 'F1': {'keyCode': 112, 'code': 'F1', 'key': 'F1'}, - 'F2': {'keyCode': 113, 'code': 'F2', 'key': 'F2'}, - 'F3': {'keyCode': 114, 'code': 'F3', 'key': 'F3'}, - 'F4': {'keyCode': 115, 'code': 'F4', 'key': 'F4'}, - 'F5': {'keyCode': 116, 'code': 'F5', 'key': 'F5'}, - 'F6': {'keyCode': 117, 'code': 'F6', 'key': 'F6'}, - 'F7': {'keyCode': 118, 'code': 'F7', 'key': 'F7'}, - 'F8': {'keyCode': 119, 'code': 'F8', 'key': 'F8'}, - 'F9': {'keyCode': 120, 'code': 'F9', 'key': 'F9'}, - 'F10': {'keyCode': 121, 'code': 'F10', 'key': 'F10'}, - 'F11': {'keyCode': 122, 'code': 'F11', 'key': 'F11'}, - 'F12': {'keyCode': 123, 'code': 'F12', 'key': 'F12'}, - 'F13': {'keyCode': 124, 'code': 'F13', 'key': 'F13'}, - 'F14': {'keyCode': 125, 'code': 'F14', 'key': 'F14'}, - 'F15': {'keyCode': 126, 'code': 'F15', 'key': 'F15'}, - 'F16': {'keyCode': 127, 'code': 'F16', 'key': 'F16'}, - 'F17': {'keyCode': 128, 'code': 'F17', 'key': 'F17'}, - 'F18': {'keyCode': 129, 'code': 'F18', 'key': 'F18'}, - 'F19': {'keyCode': 130, 'code': 'F19', 'key': 'F19'}, - 'F20': {'keyCode': 131, 'code': 'F20', 'key': 'F20'}, - 'F21': {'keyCode': 132, 'code': 'F21', 'key': 'F21'}, - 'F22': {'keyCode': 133, 'code': 'F22', 'key': 'F22'}, - 'F23': {'keyCode': 134, 'code': 'F23', 'key': 'F23'}, - 'F24': {'keyCode': 135, 'code': 'F24', 'key': 'F24'}, - 'NumLock': {'keyCode': 144, 'code': 'NumLock', 'key': 'NumLock'}, - 'ScrollLock': {'keyCode': 145, 'code': 'ScrollLock', 'key': 'ScrollLock'}, - 'AudioVolumeMute': {'keyCode': 173, 'code': 'AudioVolumeMute', 'key': 'AudioVolumeMute'}, - 'AudioVolumeDown': {'keyCode': 174, 'code': 'AudioVolumeDown', 'key': 'AudioVolumeDown'}, - 'AudioVolumeUp': {'keyCode': 175, 'code': 'AudioVolumeUp', 'key': 'AudioVolumeUp'}, - 'MediaTrackNext': {'keyCode': 176, 'code': 'MediaTrackNext', 'key': 'MediaTrackNext'}, - 'MediaTrackPrevious': {'keyCode': 177, 'code': 'MediaTrackPrevious', 'key': 'MediaTrackPrevious'}, - 'MediaStop': {'keyCode': 178, 'code': 'MediaStop', 'key': 'MediaStop'}, - 'MediaPlayPause': {'keyCode': 179, 'code': 'MediaPlayPause', 'key': 'MediaPlayPause'}, - 'Semicolon': {'keyCode': 186, 'code': 'Semicolon', 'shiftKey': ':', 'key': ';'}, - 'Equal': {'keyCode': 187, 'code': 'Equal', 'shiftKey': '+', 'key': '='}, - 'NumpadEqual': {'keyCode': 187, 'code': 'NumpadEqual', 'key': '=', 'location': 3}, - 'Comma': {'keyCode': 188, 'code': 'Comma', 'shiftKey': '\<', 'key': ','}, - 'Minus': {'keyCode': 189, 'code': 'Minus', 'shiftKey': '_', 'key': '-'}, - 'Period': {'keyCode': 190, 'code': 'Period', 'shiftKey': '>', 'key': '.'}, - 'Slash': {'keyCode': 191, 'code': 'Slash', 'shiftKey': '?', 'key': '/'}, - 'Backquote': {'keyCode': 192, 'code': 'Backquote', 'shiftKey': '~', 'key': '`'}, - 'BracketLeft': {'keyCode': 219, 'code': 'BracketLeft', 'shiftKey': '{', 'key': '['}, - 'Backslash': {'keyCode': 220, 'code': 'Backslash', 'shiftKey': '|', 'key': '\\'}, - 'BracketRight': {'keyCode': 221, 'code': 'BracketRight', 'shiftKey': '}', 'key': ']'}, - 'Quote': {'keyCode': 222, 'code': 'Quote', 'shiftKey': '"', 'key': '\''}, - 'AltGraph': {'keyCode': 225, 'code': 'AltGraph', 'key': 'AltGraph'}, - 'Props': {'keyCode': 247, 'code': 'Props', 'key': 'CrSel'}, - 'Cancel': {'keyCode': 3, 'key': 'Cancel', 'code': 'Abort'}, - 'Clear': {'keyCode': 12, 'key': 'Clear', 'code': 'Numpad5', 'location': 3}, - 'Shift': {'keyCode': 160, 'keyCodeWithoutLocation': 16, 'key': 'Shift', 'code': 'ShiftLeft', 'location': 1, 'windowsVirtualKeyCode': 160}, - 'Control': {'keyCode': 162, 'keyCodeWithoutLocation': 17, 'key': 'Control', 'code': 'ControlLeft', 'location': 1, 'windowsVirtualKeyCode': 162}, - 'Alt': {'keyCode': 164, 'keyCodeWithoutLocation': 18, 'key': 'Alt', 'code': 'AltLeft', 'location': 1, 'windowsVirtualKeyCode': 164}, - 'Accept': {'keyCode': 30, 'key': 'Accept'}, - 'ModeChange': {'keyCode': 31, 'key': 'ModeChange'}, - ' ': {'keyCode': 32, 'key': ' ', 'code': 'Space'}, - 'Print': {'keyCode': 42, 'key': 'Print'}, - 'Execute': {'keyCode': 43, 'key': 'Execute', 'code': 'Open'}, - '\u0000': {'keyCode': 46, 'key': '\u0000', 'code': 'NumpadDecimal', 'location': 3}, - 'a': {'keyCode': 65, 'key': 'a', 'code': 'KeyA'}, - 'b': {'keyCode': 66, 'key': 'b', 'code': 'KeyB'}, - 'c': {'keyCode': 67, 'key': 'c', 'code': 'KeyC'}, - 'd': {'keyCode': 68, 'key': 'd', 'code': 'KeyD'}, - 'e': {'keyCode': 69, 'key': 'e', 'code': 'KeyE'}, - 'f': {'keyCode': 70, 'key': 'f', 'code': 'KeyF'}, - 'g': {'keyCode': 71, 'key': 'g', 'code': 'KeyG'}, - 'h': {'keyCode': 72, 'key': 'h', 'code': 'KeyH'}, - 'i': {'keyCode': 73, 'key': 'i', 'code': 'KeyI'}, - 'j': {'keyCode': 74, 'key': 'j', 'code': 'KeyJ'}, - 'k': {'keyCode': 75, 'key': 'k', 'code': 'KeyK'}, - 'l': {'keyCode': 76, 'key': 'l', 'code': 'KeyL'}, - 'm': {'keyCode': 77, 'key': 'm', 'code': 'KeyM'}, - 'n': {'keyCode': 78, 'key': 'n', 'code': 'KeyN'}, - 'o': {'keyCode': 79, 'key': 'o', 'code': 'KeyO'}, - 'p': {'keyCode': 80, 'key': 'p', 'code': 'KeyP'}, - 'q': {'keyCode': 81, 'key': 'q', 'code': 'KeyQ'}, - 'r': {'keyCode': 82, 'key': 'r', 'code': 'KeyR'}, - 's': {'keyCode': 83, 'key': 's', 'code': 'KeyS'}, - 't': {'keyCode': 84, 'key': 't', 'code': 'KeyT'}, - 'u': {'keyCode': 85, 'key': 'u', 'code': 'KeyU'}, - 'v': {'keyCode': 86, 'key': 'v', 'code': 'KeyV'}, - 'w': {'keyCode': 87, 'key': 'w', 'code': 'KeyW'}, - 'x': {'keyCode': 88, 'key': 'x', 'code': 'KeyX'}, - 'y': {'keyCode': 89, 'key': 'y', 'code': 'KeyY'}, - 'z': {'keyCode': 90, 'key': 'z', 'code': 'KeyZ'}, - 'Meta': {'keyCode': 91, 'key': 'Meta', 'code': 'MetaLeft', 'location': 1}, - '*': {'keyCode': 106, 'key': '*', 'code': 'NumpadMultiply', 'location': 3}, - '+': {'keyCode': 107, 'key': '+', 'code': 'NumpadAdd', 'location': 3}, - '-': {'keyCode': 109, 'key': '-', 'code': 'NumpadSubtract', 'location': 3}, - '/': {'keyCode': 111, 'key': '/', 'code': 'NumpadDivide', 'location': 3}, - ';': {'keyCode': 186, 'key': ';', 'code': 'Semicolon'}, - '=': {'keyCode': 187, 'key': '=', 'code': 'Equal'}, - ',': {'keyCode': 188, 'key': ',', 'code': 'Comma'}, - '.': {'keyCode': 190, 'key': '.', 'code': 'Period'}, - '`': {'keyCode': 192, 'key': '`', 'code': 'Backquote'}, - '[': {'keyCode': 219, 'key': '[', 'code': 'BracketLeft'}, - '\\': {'keyCode': 220, 'key': '\\', 'code': 'Backslash'}, - ']': {'keyCode': 221, 'key': ']', 'code': 'BracketRight'}, - '\'': {'keyCode': 222, 'key': '\'', 'code': 'Quote'}, - 'Attn': {'keyCode': 246, 'key': 'Attn'}, - 'CrSel': {'keyCode': 247, 'key': 'CrSel', 'code': 'Props'}, - 'ExSel': {'keyCode': 248, 'key': 'ExSel'}, - 'EraseEof': {'keyCode': 249, 'key': 'EraseEof'}, - 'Play': {'keyCode': 250, 'key': 'Play'}, - 'ZoomOut': {'keyCode': 251, 'key': 'ZoomOut'}, - ')': {'keyCode': 48, 'key': ')', 'code': 'Digit0'}, - '!': {'keyCode': 49, 'key': '!', 'code': 'Digit1'}, - '@': {'keyCode': 50, 'key': '@', 'code': 'Digit2'}, - '#': {'keyCode': 51, 'key': '#', 'code': 'Digit3'}, - '$': {'keyCode': 52, 'key': '$', 'code': 'Digit4'}, - '%': {'keyCode': 53, 'key': '%', 'code': 'Digit5'}, - '^': {'keyCode': 54, 'key': '^', 'code': 'Digit6'}, - '&': {'keyCode': 55, 'key': '&', 'code': 'Digit7'}, - '(': {'keyCode': 57, 'key': '\(', 'code': 'Digit9'}, - 'A': {'keyCode': 65, 'key': 'A', 'code': 'KeyA'}, - 'B': {'keyCode': 66, 'key': 'B', 'code': 'KeyB'}, - 'C': {'keyCode': 67, 'key': 'C', 'code': 'KeyC'}, - 'D': {'keyCode': 68, 'key': 'D', 'code': 'KeyD'}, - 'E': {'keyCode': 69, 'key': 'E', 'code': 'KeyE'}, - 'F': {'keyCode': 70, 'key': 'F', 'code': 'KeyF'}, - 'G': {'keyCode': 71, 'key': 'G', 'code': 'KeyG'}, - 'H': {'keyCode': 72, 'key': 'H', 'code': 'KeyH'}, - 'I': {'keyCode': 73, 'key': 'I', 'code': 'KeyI'}, - 'J': {'keyCode': 74, 'key': 'J', 'code': 'KeyJ'}, - 'K': {'keyCode': 75, 'key': 'K', 'code': 'KeyK'}, - 'L': {'keyCode': 76, 'key': 'L', 'code': 'KeyL'}, - 'M': {'keyCode': 77, 'key': 'M', 'code': 'KeyM'}, - 'N': {'keyCode': 78, 'key': 'N', 'code': 'KeyN'}, - 'O': {'keyCode': 79, 'key': 'O', 'code': 'KeyO'}, - 'P': {'keyCode': 80, 'key': 'P', 'code': 'KeyP'}, - 'Q': {'keyCode': 81, 'key': 'Q', 'code': 'KeyQ'}, - 'R': {'keyCode': 82, 'key': 'R', 'code': 'KeyR'}, - 'S': {'keyCode': 83, 'key': 'S', 'code': 'KeyS'}, - 'T': {'keyCode': 84, 'key': 'T', 'code': 'KeyT'}, - 'U': {'keyCode': 85, 'key': 'U', 'code': 'KeyU'}, - 'V': {'keyCode': 86, 'key': 'V', 'code': 'KeyV'}, - 'W': {'keyCode': 87, 'key': 'W', 'code': 'KeyW'}, - 'X': {'keyCode': 88, 'key': 'X', 'code': 'KeyX'}, - 'Y': {'keyCode': 89, 'key': 'Y', 'code': 'KeyY'}, - 'Z': {'keyCode': 90, 'key': 'Z', 'code': 'KeyZ'}, - ':': {'keyCode': 186, 'key': ':', 'code': 'Semicolon'}, - '<': {'keyCode': 188, 'key': '\<', 'code': 'Comma'}, - '_': {'keyCode': 189, 'key': '_', 'code': 'Minus'}, - '>': {'keyCode': 190, 'key': '>', 'code': 'Period'}, - '?': {'keyCode': 191, 'key': '?', 'code': 'Slash'}, - '~': {'keyCode': 192, 'key': '~', 'code': 'Backquote'}, - '{': {'keyCode': 219, 'key': '{', 'code': 'BracketLeft'}, - '|': {'keyCode': 220, 'key': '|', 'code': 'Backslash'}, - '}': {'keyCode': 221, 'key': '}', 'code': 'BracketRight'}, - '"': {'keyCode': 222, 'key': '"', 'code': 'Quote'}, - 'SoftLeft': {'key': 'SoftLeft', 'code': 'SoftLeft', 'location': 4}, - 'SoftRight': {'key': 'SoftRight', 'code': 'SoftRight', 'location': 4}, - 'Camera': {'keyCode': 44, 'key': 'Camera', 'code': 'Camera', 'location': 4}, - 'Call': {'key': 'Call', 'code': 'Call', 'location': 4}, - 'EndCall': {'keyCode': 95, 'key': 'EndCall', 'code': 'EndCall', 'location': 4}, - 'VolumeDown': {'keyCode': 182, 'key': 'VolumeDown', 'code': 'VolumeDown', 'location': 4}, - 'VolumeUp': {'keyCode': 183, 'key': 'VolumeUp', 'code': 'VolumeUp', 'location': 4}, -}; +export const USKeyboardLayout: KeyboardLayout = { + // Functions row + 'Escape': { 'keyCode': 27, 'key': 'Escape' }, + 'F1': { 'keyCode': 112, 'key': 'F1' }, + 'F2': { 'keyCode': 113, 'key': 'F2' }, + 'F3': { 'keyCode': 114, 'key': 'F3' }, + 'F4': { 'keyCode': 115, 'key': 'F4' }, + 'F5': { 'keyCode': 116, 'key': 'F5' }, + 'F6': { 'keyCode': 117, 'key': 'F6' }, + 'F7': { 'keyCode': 118, 'key': 'F7' }, + 'F8': { 'keyCode': 119, 'key': 'F8' }, + 'F9': { 'keyCode': 120, 'key': 'F9' }, + 'F10': { 'keyCode': 121, 'key': 'F10' }, + 'F11': { 'keyCode': 122, 'key': 'F11' }, + 'F12': { 'keyCode': 123, 'key': 'F12' }, -export const macEditingCommands: {[key: string]: string|string[]} = { - 'Backspace': 'deleteBackward:', - 'Tab': 'insertTab:', - 'Enter': 'insertNewline:', - 'NumpadEnter': 'insertNewline:', - 'Escape': 'cancelOperation:', - 'ArrowUp': 'moveUp:', - 'ArrowDown': 'moveDown:', - 'ArrowLeft': 'moveLeft:', - 'ArrowRight': 'moveRight:', - 'F5': 'complete:', - 'Delete': 'deleteForward:', - 'Home': 'scrollToBeginningOfDocument:', - 'End': 'scrollToEndOfDocument:', - 'PageUp': 'scrollPageUp:', - 'PageDown': 'scrollPageDown:', - 'Shift+Backspace': 'deleteBackward:', - 'Shift+Enter': 'insertNewline:', - 'Shift+NumpadEnter': 'insertNewline:', - 'Shift+Tab': 'insertBacktab:', - 'Shift+Escape': 'cancelOperation:', - 'Shift+ArrowUp': 'moveUpAndModifySelection:', - 'Shift+ArrowDown': 'moveDownAndModifySelection:', - 'Shift+ArrowLeft': 'moveLeftAndModifySelection:', - 'Shift+ArrowRight': 'moveRightAndModifySelection:', - 'Shift+F5': 'complete:', - 'Shift+Delete': 'deleteForward:', - 'Shift+Home': 'moveToBeginningOfDocumentAndModifySelection:', - 'Shift+End': 'moveToEndOfDocumentAndModifySelection:', - 'Shift+PageUp': 'pageUpAndModifySelection:', - 'Shift+PageDown': 'pageDownAndModifySelection:', - 'Shift+Numpad5': 'delete:', - 'Control+Tab': 'selectNextKeyView:', - 'Control+Enter': 'insertLineBreak:', - 'Control+NumpadEnter': 'insertLineBreak:', - 'Control+Quote': 'insertSingleQuoteIgnoringSubstitution:', - 'Control+KeyA': 'moveToBeginningOfParagraph:', - 'Control+KeyB': 'moveBackward:', - 'Control+KeyD': 'deleteForward:', - 'Control+KeyE': 'moveToEndOfParagraph:', - 'Control+KeyF': 'moveForward:', - 'Control+KeyH': 'deleteBackward:', - 'Control+KeyK': 'deleteToEndOfParagraph:', - 'Control+KeyL': 'centerSelectionInVisibleArea:', - 'Control+KeyN': 'moveDown:', - 'Control+KeyO': ['insertNewlineIgnoringFieldEditor:', 'moveBackward:'], - 'Control+KeyP': 'moveUp:', - 'Control+KeyT': 'transpose:', - 'Control+KeyV': 'pageDown:', - 'Control+KeyY': 'yank:', - 'Control+Backspace': 'deleteBackwardByDecomposingPreviousCharacter:', - 'Control+ArrowUp': 'scrollPageUp:', - 'Control+ArrowDown': 'scrollPageDown:', - 'Control+ArrowLeft': 'moveToLeftEndOfLine:', - 'Control+ArrowRight': 'moveToRightEndOfLine:', - 'Shift+Control+Enter': 'insertLineBreak:', - 'Shift+Control+NumpadEnter': 'insertLineBreak:', - 'Shift+Control+Tab': 'selectPreviousKeyView:', - 'Shift+Control+Quote': 'insertDoubleQuoteIgnoringSubstitution:', - 'Shift+Control+KeyA': 'moveToBeginningOfParagraphAndModifySelection:', - 'Shift+Control+KeyB': 'moveBackwardAndModifySelection:', - 'Shift+Control+KeyE': 'moveToEndOfParagraphAndModifySelection:', - 'Shift+Control+KeyF': 'moveForwardAndModifySelection:', - 'Shift+Control+KeyN': 'moveDownAndModifySelection:', - 'Shift+Control+KeyP': 'moveUpAndModifySelection:', - 'Shift+Control+KeyV': 'pageDownAndModifySelection:', - 'Shift+Control+Backspace': 'deleteBackwardByDecomposingPreviousCharacter:', - 'Shift+Control+ArrowUp': 'scrollPageUp:', - 'Shift+Control+ArrowDown': 'scrollPageDown:', - 'Shift+Control+ArrowLeft': 'moveToLeftEndOfLineAndModifySelection:', - 'Shift+Control+ArrowRight': 'moveToRightEndOfLineAndModifySelection:', - 'Alt+Backspace': 'deleteWordBackward:', - 'Alt+Tab': 'insertTabIgnoringFieldEditor:', - 'Alt+Enter': 'insertNewlineIgnoringFieldEditor:', - 'Alt+NumpadEnter': 'insertNewlineIgnoringFieldEditor:', - 'Alt+Escape': 'complete:', - 'Alt+ArrowUp': ['moveBackward:', 'moveToBeginningOfParagraph:'], - 'Alt+ArrowDown': ['moveForward:', 'moveToEndOfParagraph:'], - 'Alt+ArrowLeft': 'moveWordLeft:', - 'Alt+ArrowRight': 'moveWordRight:', - 'Alt+Delete': 'deleteWordForward:', - 'Alt+PageUp': 'pageUp:', - 'Alt+PageDown': 'pageDown:', - 'Shift+Alt+Backspace': 'deleteWordBackward:', - 'Shift+Alt+Tab': 'insertTabIgnoringFieldEditor:', - 'Shift+Alt+Enter': 'insertNewlineIgnoringFieldEditor:', - 'Shift+Alt+NumpadEnter': 'insertNewlineIgnoringFieldEditor:', - 'Shift+Alt+Escape': 'complete:', - 'Shift+Alt+ArrowUp': 'moveParagraphBackwardAndModifySelection:', - 'Shift+Alt+ArrowDown': 'moveParagraphForwardAndModifySelection:', - 'Shift+Alt+ArrowLeft': 'moveWordLeftAndModifySelection:', - 'Shift+Alt+ArrowRight': 'moveWordRightAndModifySelection:', - 'Shift+Alt+Delete': 'deleteWordForward:', - 'Shift+Alt+PageUp': 'pageUp:', - 'Shift+Alt+PageDown': 'pageDown:', - 'Control+Alt+KeyB': 'moveWordBackward:', - 'Control+Alt+KeyF': 'moveWordForward:', - 'Control+Alt+Backspace': 'deleteWordBackward:', - 'Shift+Control+Alt+KeyB': 'moveWordBackwardAndModifySelection:', - 'Shift+Control+Alt+KeyF': 'moveWordForwardAndModifySelection:', - 'Shift+Control+Alt+Backspace': 'deleteWordBackward:', - 'Meta+NumpadSubtract': 'cancel:', - 'Meta+Backspace': 'deleteToBeginningOfLine:', - 'Meta+ArrowUp': 'moveToBeginningOfDocument:', - 'Meta+ArrowDown': 'moveToEndOfDocument:', - 'Meta+ArrowLeft': 'moveToLeftEndOfLine:', - 'Meta+ArrowRight': 'moveToRightEndOfLine:', - 'Shift+Meta+NumpadSubtract': 'cancel:', - 'Shift+Meta+Backspace': 'deleteToBeginningOfLine:', - 'Shift+Meta+ArrowUp': 'moveToBeginningOfDocumentAndModifySelection:', - 'Shift+Meta+ArrowDown': 'moveToEndOfDocumentAndModifySelection:', - 'Shift+Meta+ArrowLeft': 'moveToLeftEndOfLineAndModifySelection:', - 'Shift+Meta+ArrowRight': 'moveToRightEndOfLineAndModifySelection:', + // Numbers row + 'Backquote': { 'keyCode': 192, 'shiftKey': '~', 'key': '`' }, + 'Digit1': { 'keyCode': 49, 'shiftKey': '!', 'key': '1' }, + 'Digit2': { 'keyCode': 50, 'shiftKey': '@', 'key': '2' }, + 'Digit3': { 'keyCode': 51, 'shiftKey': '#', 'key': '3' }, + 'Digit4': { 'keyCode': 52, 'shiftKey': '$', 'key': '4' }, + 'Digit5': { 'keyCode': 53, 'shiftKey': '%', 'key': '5' }, + 'Digit6': { 'keyCode': 54, 'shiftKey': '^', 'key': '6' }, + 'Digit7': { 'keyCode': 55, 'shiftKey': '&', 'key': '7' }, + 'Digit8': { 'keyCode': 56, 'shiftKey': '*', 'key': '8' }, + 'Digit9': { 'keyCode': 57, 'shiftKey': '\(', 'key': '9' }, + 'Digit0': { 'keyCode': 48, 'shiftKey': ')', 'key': '0' }, + 'Minus': { 'keyCode': 189, 'shiftKey': '_', 'key': '-' }, + 'Equal': { 'keyCode': 187, 'shiftKey': '+', 'key': '=' }, + 'Backslash': { 'keyCode': 220, 'shiftKey': '|', 'key': '\\' }, + 'Backspace': { 'keyCode': 8, 'key': 'Backspace' }, - 'Meta+KeyA': 'selectAll:', + // First row + 'Tab': { 'keyCode': 9, 'key': 'Tab' }, + 'KeyQ': { 'keyCode': 81, 'shiftKey': 'Q', 'key': 'q' }, + 'KeyW': { 'keyCode': 87, 'shiftKey': 'W', 'key': 'w' }, + 'KeyE': { 'keyCode': 69, 'shiftKey': 'E', 'key': 'e' }, + 'KeyR': { 'keyCode': 82, 'shiftKey': 'R', 'key': 'r' }, + 'KeyT': { 'keyCode': 84, 'shiftKey': 'T', 'key': 't' }, + 'KeyY': { 'keyCode': 89, 'shiftKey': 'Y', 'key': 'y' }, + 'KeyU': { 'keyCode': 85, 'shiftKey': 'U', 'key': 'u' }, + 'KeyI': { 'keyCode': 73, 'shiftKey': 'I', 'key': 'i' }, + 'KeyO': { 'keyCode': 79, 'shiftKey': 'O', 'key': 'o' }, + 'KeyP': { 'keyCode': 80, 'shiftKey': 'P', 'key': 'p' }, + 'BracketLeft': { 'keyCode': 219, 'shiftKey': '{', 'key': '[' }, + 'BracketRight': { 'keyCode': 221, 'shiftKey': '}', 'key': ']' }, + + // Second row + 'CapsLock': { 'keyCode': 20, 'key': 'CapsLock' }, + 'KeyA': { 'keyCode': 65, 'shiftKey': 'A', 'key': 'a' }, + 'KeyS': { 'keyCode': 83, 'shiftKey': 'S', 'key': 's' }, + 'KeyD': { 'keyCode': 68, 'shiftKey': 'D', 'key': 'd' }, + 'KeyF': { 'keyCode': 70, 'shiftKey': 'F', 'key': 'f' }, + 'KeyG': { 'keyCode': 71, 'shiftKey': 'G', 'key': 'g' }, + 'KeyH': { 'keyCode': 72, 'shiftKey': 'H', 'key': 'h' }, + 'KeyJ': { 'keyCode': 74, 'shiftKey': 'J', 'key': 'j' }, + 'KeyK': { 'keyCode': 75, 'shiftKey': 'K', 'key': 'k' }, + 'KeyL': { 'keyCode': 76, 'shiftKey': 'L', 'key': 'l' }, + 'Semicolon': { 'keyCode': 186, 'shiftKey': ':', 'key': ';' }, + 'Quote': { 'keyCode': 222, 'shiftKey': '"', 'key': '\'' }, + 'Enter': { 'keyCode': 13, 'key': 'Enter', 'text': '\r' }, + + // Third row + 'ShiftLeft': { 'keyCode': 160, 'keyCodeWithoutLocation': 16, 'key': 'Shift', 'location': 1 }, + 'KeyZ': { 'keyCode': 90, 'shiftKey': 'Z', 'key': 'z' }, + 'KeyX': { 'keyCode': 88, 'shiftKey': 'X', 'key': 'x' }, + 'KeyC': { 'keyCode': 67, 'shiftKey': 'C', 'key': 'c' }, + 'KeyV': { 'keyCode': 86, 'shiftKey': 'V', 'key': 'v' }, + 'KeyB': { 'keyCode': 66, 'shiftKey': 'B', 'key': 'b' }, + 'KeyN': { 'keyCode': 78, 'shiftKey': 'N', 'key': 'n' }, + 'KeyM': { 'keyCode': 77, 'shiftKey': 'M', 'key': 'm' }, + 'Comma': { 'keyCode': 188, 'shiftKey': '\<', 'key': ',' }, + 'Period': { 'keyCode': 190, 'shiftKey': '>', 'key': '.' }, + 'Slash': { 'keyCode': 191, 'shiftKey': '?', 'key': '/' }, + 'ShiftRight': { 'keyCode': 161, 'keyCodeWithoutLocation': 16, 'key': 'Shift', 'location': 2 }, + + // Last row + 'ControlLeft': { 'keyCode': 162, 'keyCodeWithoutLocation': 17, 'key': 'Control', 'location': 1 }, + 'MetaLeft': { 'keyCode': 91, 'key': 'Meta', 'location': 1 }, + 'AltLeft': { 'keyCode': 164, 'keyCodeWithoutLocation': 18, 'key': 'Alt', 'location': 1 }, + 'Space': { 'keyCode': 32, 'key': ' ' }, + 'AltRight': { 'keyCode': 165, 'keyCodeWithoutLocation': 18, 'key': 'Alt', 'location': 2 }, + 'MetaRight': { 'keyCode': 92, 'key': 'Meta', 'location': 2 }, + 'ContextMenu': { 'keyCode': 93, 'key': 'ContextMenu' }, + 'ControlRight': { 'keyCode': 163, 'keyCodeWithoutLocation': 17, 'key': 'Control', 'location': 2 }, + + // Center block + 'PrintScreen': { 'keyCode': 44, 'key': 'PrintScreen' }, + 'ScrollLock': { 'keyCode': 145, 'key': 'ScrollLock' }, + 'Pause': { 'keyCode': 19, 'key': 'Pause' }, + + 'PageUp': { 'keyCode': 33, 'key': 'PageUp' }, + 'PageDown': { 'keyCode': 34, 'key': 'PageDown' }, + 'Insert': { 'keyCode': 45, 'key': 'Insert' }, + 'Delete': { 'keyCode': 46, 'key': 'Delete' }, + 'Home': { 'keyCode': 36, 'key': 'Home' }, + 'End': { 'keyCode': 35, 'key': 'End' }, + + 'ArrowLeft': { 'keyCode': 37, 'key': 'ArrowLeft' }, + 'ArrowUp': { 'keyCode': 38, 'key': 'ArrowUp' }, + 'ArrowRight': { 'keyCode': 39, 'key': 'ArrowRight' }, + 'ArrowDown': { 'keyCode': 40, 'key': 'ArrowDown' }, + + // Numpad + 'NumLock': { 'keyCode': 144, 'key': 'NumLock' }, + 'NumpadDivide': { 'keyCode': 111, 'key': '/', 'location': 3 }, + 'NumpadMultiply': { 'keyCode': 106, 'key': '*', 'location': 3 }, + 'NumpadSubtract': { 'keyCode': 109, 'key': '-', 'location': 3 }, + 'Numpad7': { 'keyCode': 36, 'shiftKeyCode': 103, 'key': 'Home', 'shiftKey': '7', 'location': 3 }, + 'Numpad8': { 'keyCode': 38, 'shiftKeyCode': 104, 'key': 'ArrowUp', 'shiftKey': '8', 'location': 3 }, + 'Numpad9': { 'keyCode': 33, 'shiftKeyCode': 105, 'key': 'PageUp', 'shiftKey': '9', 'location': 3 }, + 'Numpad4': { 'keyCode': 37, 'shiftKeyCode': 100, 'key': 'ArrowLeft', 'shiftKey': '4', 'location': 3 }, + 'Numpad5': { 'keyCode': 12, 'shiftKeyCode': 101, 'key': 'Clear', 'shiftKey': '5', 'location': 3 }, + 'Numpad6': { 'keyCode': 39, 'shiftKeyCode': 102, 'key': 'ArrowRight', 'shiftKey': '6', 'location': 3 }, + 'NumpadAdd': { 'keyCode': 107, 'key': '+', 'location': 3 }, + 'Numpad1': { 'keyCode': 35, 'shiftKeyCode': 97, 'key': 'End', 'shiftKey': '1', 'location': 3 }, + 'Numpad2': { 'keyCode': 40, 'shiftKeyCode': 98, 'key': 'ArrowDown', 'shiftKey': '2', 'location': 3 }, + 'Numpad3': { 'keyCode': 34, 'shiftKeyCode': 99, 'key': 'PageDown', 'shiftKey': '3', 'location': 3 }, + 'Numpad0': { 'keyCode': 45, 'shiftKeyCode': 96, 'key': 'Insert', 'shiftKey': '0', 'location': 3 }, + 'NumpadDecimal': { 'keyCode': 46, 'shiftKeyCode': 110, 'key': '\u0000', 'shiftKey': '.', 'location': 3 }, + 'NumpadEnter': { 'keyCode': 13, 'key': 'Enter', 'text': '\r', 'location': 3 }, }; diff --git a/src/webkit/wkInput.ts b/src/webkit/wkInput.ts index 9123f498fa..389d7cc67a 100644 --- a/src/webkit/wkInput.ts +++ b/src/webkit/wkInput.ts @@ -17,7 +17,7 @@ import * as input from '../input'; import { helper } from '../helper'; -import { macEditingCommands } from '../usKeyboardLayout'; +import { macEditingCommands } from '../macEditingCommands'; import { WKSession } from './wkConnection'; function toModifiersMask(modifiers: Set): number { diff --git a/test/keyboard.spec.js b/test/keyboard.spec.js index 3653d8734b..ec4b263c39 100644 --- a/test/keyboard.spec.js +++ b/test/keyboard.spec.js @@ -155,6 +155,55 @@ describe('Keyboard', function() { await page.keyboard.type('Hello World!'); expect(await page.evaluate(() => textarea.value)).toBe('He Wrd!'); }); + it('should press plus', async({page, server}) => { + await page.goto(server.PREFIX + '/input/keyboard.html'); + await page.keyboard.press('+'); + expect(await page.evaluate(() => getResult())).toBe( + [ 'Keydown: + Equal 187 []', // 192 is ` keyCode + 'Keypress: + Equal 43 43 []', // 126 is ~ charCode + 'Keyup: + Equal 187 []'].join('\n')); + }); + it('should press shift plus', async({page, server}) => { + await page.goto(server.PREFIX + '/input/keyboard.html'); + await page.keyboard.press('Shift++'); + expect(await page.evaluate(() => getResult())).toBe( + [ 'Keydown: Shift ShiftLeft 16 [Shift]', + 'Keydown: + Equal 187 [Shift]', // 192 is ` keyCode + 'Keypress: + Equal 43 43 [Shift]', // 126 is ~ charCode + 'Keyup: + Equal 187 [Shift]', + 'Keyup: Shift ShiftLeft 16 []'].join('\n')); + }); + it('should support plus-separated modifiers', async({page, server}) => { + await page.goto(server.PREFIX + '/input/keyboard.html'); + await page.keyboard.press('Shift+~'); + expect(await page.evaluate(() => getResult())).toBe( + [ 'Keydown: Shift ShiftLeft 16 [Shift]', + 'Keydown: ~ Backquote 192 [Shift]', // 192 is ` keyCode + 'Keypress: ~ Backquote 126 126 [Shift]', // 126 is ~ charCode + 'Keyup: ~ Backquote 192 [Shift]', + 'Keyup: Shift ShiftLeft 16 []'].join('\n')); + }); + it('should support multiple plus-separated modifiers', async({page, server}) => { + await page.goto(server.PREFIX + '/input/keyboard.html'); + await page.keyboard.press('Control+Shift+~'); + expect(await page.evaluate(() => getResult())).toBe( + [ 'Keydown: Control ControlLeft 17 [Control]', + 'Keydown: Shift ShiftLeft 16 [Control Shift]', + 'Keydown: ~ Backquote 192 [Control Shift]', // 192 is ` keyCode + 'Keyup: ~ Backquote 192 [Control Shift]', + 'Keyup: Shift ShiftLeft 16 [Control]', + 'Keyup: Control ControlLeft 17 []'].join('\n')); + }); + it('should shift raw codes', async({page, server}) => { + await page.goto(server.PREFIX + '/input/keyboard.html'); + await page.keyboard.press('Shift+Digit3'); + expect(await page.evaluate(() => getResult())).toBe( + [ 'Keydown: Shift ShiftLeft 16 [Shift]', + 'Keydown: # Digit3 51 [Shift]', // 51 is # keyCode + 'Keypress: # Digit3 35 35 [Shift]', // 35 is # charCode + 'Keyup: # Digit3 51 [Shift]', + 'Keyup: Shift ShiftLeft 16 []'].join('\n')); + }); it('should specify repeat property', async({page, server}) => { await page.goto(server.PREFIX + '/input/textarea.html'); await page.focus('textarea');