UNPKG

@theia/core

Version:

Theia is a cloud & desktop IDE framework implemented in TypeScript.

436 lines • 17.3 kB
"use strict"; // ***************************************************************************** // Copyright (C) 2019 TypeFox and others. // // This program and the accompanying materials are made available under the // terms of the Eclipse Public License v. 2.0 which is available at // http://www.eclipse.org/legal/epl-2.0. // // This Source Code may also be made available under the following Secondary // Licenses when the conditions for such availability set forth in the Eclipse // Public License v. 2.0 are satisfied: GNU General Public License, version 2 // with the GNU Classpath Exception which is available at // https://www.gnu.org/software/classpath/license.html. // // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 // ***************************************************************************** var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.KeyboardLayoutService = void 0; const inversify_1 = require("inversify"); const os_1 = require("../../common/os"); const keyboard_layout_provider_1 = require("../../common/keyboard/keyboard-layout-provider"); const event_1 = require("../../common/event"); const keys_1 = require("./keys"); let KeyboardLayoutService = class KeyboardLayoutService { constructor() { this.keyboardLayoutChanged = new event_1.Emitter(); } updateLayout(newLayout) { const transformed = this.transformNativeLayout(newLayout); this.currentLayout = transformed; this.keyboardLayoutChanged.fire(transformed); return transformed; } get onKeyboardLayoutChanged() { return this.keyboardLayoutChanged.event; } async initialize() { this.layoutChangeNotifier.onDidChangeNativeLayout(newLayout => this.updateLayout(newLayout)); const initialLayout = await this.layoutProvider.getNativeLayout(); this.updateLayout(initialLayout); } /** * Resolve a KeyCode of a keybinding using the current keyboard layout. * If no keyboard layout has been detected or the layout does not contain the * key used in the KeyCode, the KeyCode is returned unchanged. */ resolveKeyCode(inCode) { const layout = this.currentLayout; if (layout && inCode.key) { for (let shift = 0; shift <= 1; shift++) { const index = this.getCharacterIndex(inCode.key, !!shift); const mappedCode = layout.key2KeyCode[index]; if (mappedCode) { const transformed = this.transformKeyCode(inCode, mappedCode, !!shift); if (transformed) { return transformed; } } } } return inCode; } /** * Return the character shown on the user's keyboard for the given key. * Use this to determine UI representations of keybindings. */ getKeyboardCharacter(key) { var _a; const layout = this.currentLayout; if (layout) { const value = (_a = layout.code2Character[key.code]) === null || _a === void 0 ? void 0 : _a.trim(); // Special cases from native keymap if (value === '\u001b') { return 'escape'; } if (value === '\u007f') { return 'delete'; } if (value === '\u0008') { return 'backspace'; } if (value === null || value === void 0 ? void 0 : value.replace(/[\n\r\t]/g, '')) { return value; } } return key.easyString; } /** * Called when a KeyboardEvent is processed by the KeybindingRegistry. * The KeyValidator may trigger a keyboard layout change. */ validateKeyCode(keyCode) { if (this.keyValidator && keyCode.key && keyCode.character) { this.keyValidator.validateKey({ code: keyCode.key.code, character: keyCode.character, shiftKey: keyCode.shift, ctrlKey: keyCode.ctrl, altKey: keyCode.alt }); } } transformKeyCode(inCode, mappedCode, keyNeedsShift) { if (!inCode.shift && keyNeedsShift) { return undefined; } if (mappedCode.alt && (inCode.alt || inCode.ctrl || inCode.shift && !keyNeedsShift)) { return undefined; } return new keys_1.KeyCode({ key: mappedCode.key, meta: inCode.meta, ctrl: inCode.ctrl || mappedCode.alt, shift: inCode.shift && !keyNeedsShift || mappedCode.shift, alt: inCode.alt || mappedCode.alt }); } transformNativeLayout(nativeLayout) { const key2KeyCode = new Array(2 * (keys_1.Key.MAX_KEY_CODE + 1)); const code2Character = {}; const mapping = nativeLayout.mapping; for (const code in mapping) { if (mapping.hasOwnProperty(code)) { const keyMapping = mapping[code]; const mappedKey = keys_1.Key.getKey(code); if (mappedKey && this.shouldIncludeKey(code)) { if (os_1.isWindows) { this.addWindowsKeyMapping(key2KeyCode, mappedKey, keyMapping.vkey, keyMapping.value); } else { if (keyMapping.value) { this.addKeyMapping(key2KeyCode, mappedKey, keyMapping.value, false, false); } if (keyMapping.withShift) { this.addKeyMapping(key2KeyCode, mappedKey, keyMapping.withShift, true, false); } if (keyMapping.withAltGr) { this.addKeyMapping(key2KeyCode, mappedKey, keyMapping.withAltGr, false, true); } if (keyMapping.withShiftAltGr) { this.addKeyMapping(key2KeyCode, mappedKey, keyMapping.withShiftAltGr, true, true); } } } if (keyMapping.value) { code2Character[code] = keyMapping.value; } } } return { key2KeyCode, code2Character }; } shouldIncludeKey(code) { // Exclude all numpad keys because they produce values that are already found elsewhere on the keyboard. // This can cause problems, e.g. if `Numpad3` maps to `PageDown` then commands bound to `PageDown` would // be resolved to `Digit3` (`Numpad3` is associated with `Key.DIGIT3`), effectively blocking the user // from typing `3` in an editor. return !code.startsWith('Numpad'); } addKeyMapping(key2KeyCode, mappedKey, value, shift, alt) { const key = VALUE_TO_KEY[value]; if (key) { const index = this.getCharacterIndex(key.key, key.shift); if (key2KeyCode[index] === undefined) { key2KeyCode[index] = new keys_1.KeyCode({ key: mappedKey, shift, alt, character: value }); } } } addWindowsKeyMapping(key2KeyCode, mappedKey, vkey, value) { const key = VKEY_TO_KEY[vkey]; if (key) { const index = this.getCharacterIndex(key); if (key2KeyCode[index] === undefined) { key2KeyCode[index] = new keys_1.KeyCode({ key: mappedKey, character: value }); } } } getCharacterIndex(key, shift) { if (shift) { return keys_1.Key.MAX_KEY_CODE + key.keyCode + 1; } else { return key.keyCode; } } }; __decorate([ (0, inversify_1.inject)(keyboard_layout_provider_1.KeyboardLayoutProvider), __metadata("design:type", Object) ], KeyboardLayoutService.prototype, "layoutProvider", void 0); __decorate([ (0, inversify_1.inject)(keyboard_layout_provider_1.KeyboardLayoutChangeNotifier), __metadata("design:type", Object) ], KeyboardLayoutService.prototype, "layoutChangeNotifier", void 0); __decorate([ (0, inversify_1.inject)(keyboard_layout_provider_1.KeyValidator), (0, inversify_1.optional)(), __metadata("design:type", Object) ], KeyboardLayoutService.prototype, "keyValidator", void 0); KeyboardLayoutService = __decorate([ (0, inversify_1.injectable)() ], KeyboardLayoutService); exports.KeyboardLayoutService = KeyboardLayoutService; /** * Mapping of character values to the corresponding keys on a standard US keyboard layout. */ const VALUE_TO_KEY = { '`': { key: keys_1.Key.BACKQUOTE }, '~': { key: keys_1.Key.BACKQUOTE, shift: true }, '1': { key: keys_1.Key.DIGIT1 }, '!': { key: keys_1.Key.DIGIT1, shift: true }, '2': { key: keys_1.Key.DIGIT2 }, '@': { key: keys_1.Key.DIGIT2, shift: true }, '3': { key: keys_1.Key.DIGIT3 }, '#': { key: keys_1.Key.DIGIT3, shift: true }, '4': { key: keys_1.Key.DIGIT4 }, '$': { key: keys_1.Key.DIGIT4, shift: true }, '5': { key: keys_1.Key.DIGIT5 }, '%': { key: keys_1.Key.DIGIT5, shift: true }, '6': { key: keys_1.Key.DIGIT6 }, '^': { key: keys_1.Key.DIGIT6, shift: true }, '7': { key: keys_1.Key.DIGIT7 }, '&': { key: keys_1.Key.DIGIT7, shift: true }, '8': { key: keys_1.Key.DIGIT8 }, '*': { key: keys_1.Key.DIGIT8, shift: true }, '9': { key: keys_1.Key.DIGIT9 }, '(': { key: keys_1.Key.DIGIT9, shift: true }, '0': { key: keys_1.Key.DIGIT0 }, ')': { key: keys_1.Key.DIGIT0, shift: true }, '-': { key: keys_1.Key.MINUS }, '_': { key: keys_1.Key.MINUS, shift: true }, '=': { key: keys_1.Key.EQUAL }, '+': { key: keys_1.Key.EQUAL, shift: true }, 'a': { key: keys_1.Key.KEY_A }, 'A': { key: keys_1.Key.KEY_A, shift: true }, 'b': { key: keys_1.Key.KEY_B }, 'B': { key: keys_1.Key.KEY_B, shift: true }, 'c': { key: keys_1.Key.KEY_C }, 'C': { key: keys_1.Key.KEY_C, shift: true }, 'd': { key: keys_1.Key.KEY_D }, 'D': { key: keys_1.Key.KEY_D, shift: true }, 'e': { key: keys_1.Key.KEY_E }, 'E': { key: keys_1.Key.KEY_E, shift: true }, 'f': { key: keys_1.Key.KEY_F }, 'F': { key: keys_1.Key.KEY_F, shift: true }, 'g': { key: keys_1.Key.KEY_G }, 'G': { key: keys_1.Key.KEY_G, shift: true }, 'h': { key: keys_1.Key.KEY_H }, 'H': { key: keys_1.Key.KEY_H, shift: true }, 'i': { key: keys_1.Key.KEY_I }, 'I': { key: keys_1.Key.KEY_I, shift: true }, 'j': { key: keys_1.Key.KEY_J }, 'J': { key: keys_1.Key.KEY_J, shift: true }, 'k': { key: keys_1.Key.KEY_K }, 'K': { key: keys_1.Key.KEY_K, shift: true }, 'l': { key: keys_1.Key.KEY_L }, 'L': { key: keys_1.Key.KEY_L, shift: true }, 'm': { key: keys_1.Key.KEY_M }, 'M': { key: keys_1.Key.KEY_M, shift: true }, 'n': { key: keys_1.Key.KEY_N }, 'N': { key: keys_1.Key.KEY_N, shift: true }, 'o': { key: keys_1.Key.KEY_O }, 'O': { key: keys_1.Key.KEY_O, shift: true }, 'p': { key: keys_1.Key.KEY_P }, 'P': { key: keys_1.Key.KEY_P, shift: true }, 'q': { key: keys_1.Key.KEY_Q }, 'Q': { key: keys_1.Key.KEY_Q, shift: true }, 'r': { key: keys_1.Key.KEY_R }, 'R': { key: keys_1.Key.KEY_R, shift: true }, 's': { key: keys_1.Key.KEY_S }, 'S': { key: keys_1.Key.KEY_S, shift: true }, 't': { key: keys_1.Key.KEY_T }, 'T': { key: keys_1.Key.KEY_T, shift: true }, 'u': { key: keys_1.Key.KEY_U }, 'U': { key: keys_1.Key.KEY_U, shift: true }, 'v': { key: keys_1.Key.KEY_V }, 'V': { key: keys_1.Key.KEY_V, shift: true }, 'w': { key: keys_1.Key.KEY_W }, 'W': { key: keys_1.Key.KEY_W, shift: true }, 'x': { key: keys_1.Key.KEY_X }, 'X': { key: keys_1.Key.KEY_X, shift: true }, 'y': { key: keys_1.Key.KEY_Y }, 'Y': { key: keys_1.Key.KEY_Y, shift: true }, 'z': { key: keys_1.Key.KEY_Z }, 'Z': { key: keys_1.Key.KEY_Z, shift: true }, '[': { key: keys_1.Key.BRACKET_LEFT }, '{': { key: keys_1.Key.BRACKET_LEFT, shift: true }, ']': { key: keys_1.Key.BRACKET_RIGHT }, '}': { key: keys_1.Key.BRACKET_RIGHT, shift: true }, ';': { key: keys_1.Key.SEMICOLON }, ':': { key: keys_1.Key.SEMICOLON, shift: true }, "'": { key: keys_1.Key.QUOTE }, '"': { key: keys_1.Key.QUOTE, shift: true }, ',': { key: keys_1.Key.COMMA }, '<': { key: keys_1.Key.COMMA, shift: true }, '.': { key: keys_1.Key.PERIOD }, '>': { key: keys_1.Key.PERIOD, shift: true }, '/': { key: keys_1.Key.SLASH }, '?': { key: keys_1.Key.SLASH, shift: true }, '\\': { key: keys_1.Key.BACKSLASH }, '|': { key: keys_1.Key.BACKSLASH, shift: true }, '\t': { key: keys_1.Key.TAB }, '\r': { key: keys_1.Key.ENTER }, '\n': { key: keys_1.Key.ENTER }, ' ': { key: keys_1.Key.SPACE }, }; /** * Mapping of Windows Virtual Keys to the corresponding keys on a standard US keyboard layout. */ const VKEY_TO_KEY = { VK_SHIFT: keys_1.Key.SHIFT_LEFT, VK_LSHIFT: keys_1.Key.SHIFT_LEFT, VK_RSHIFT: keys_1.Key.SHIFT_RIGHT, VK_CONTROL: keys_1.Key.CONTROL_LEFT, VK_LCONTROL: keys_1.Key.CONTROL_LEFT, VK_RCONTROL: keys_1.Key.CONTROL_RIGHT, VK_MENU: keys_1.Key.ALT_LEFT, VK_COMMAND: keys_1.Key.OS_LEFT, VK_LWIN: keys_1.Key.OS_LEFT, VK_RWIN: keys_1.Key.OS_RIGHT, VK_0: keys_1.Key.DIGIT0, VK_1: keys_1.Key.DIGIT1, VK_2: keys_1.Key.DIGIT2, VK_3: keys_1.Key.DIGIT3, VK_4: keys_1.Key.DIGIT4, VK_5: keys_1.Key.DIGIT5, VK_6: keys_1.Key.DIGIT6, VK_7: keys_1.Key.DIGIT7, VK_8: keys_1.Key.DIGIT8, VK_9: keys_1.Key.DIGIT9, VK_A: keys_1.Key.KEY_A, VK_B: keys_1.Key.KEY_B, VK_C: keys_1.Key.KEY_C, VK_D: keys_1.Key.KEY_D, VK_E: keys_1.Key.KEY_E, VK_F: keys_1.Key.KEY_F, VK_G: keys_1.Key.KEY_G, VK_H: keys_1.Key.KEY_H, VK_I: keys_1.Key.KEY_I, VK_J: keys_1.Key.KEY_J, VK_K: keys_1.Key.KEY_K, VK_L: keys_1.Key.KEY_L, VK_M: keys_1.Key.KEY_M, VK_N: keys_1.Key.KEY_N, VK_O: keys_1.Key.KEY_O, VK_P: keys_1.Key.KEY_P, VK_Q: keys_1.Key.KEY_Q, VK_R: keys_1.Key.KEY_R, VK_S: keys_1.Key.KEY_S, VK_T: keys_1.Key.KEY_T, VK_U: keys_1.Key.KEY_U, VK_V: keys_1.Key.KEY_V, VK_W: keys_1.Key.KEY_W, VK_X: keys_1.Key.KEY_X, VK_Y: keys_1.Key.KEY_Y, VK_Z: keys_1.Key.KEY_Z, VK_OEM_1: keys_1.Key.SEMICOLON, VK_OEM_2: keys_1.Key.SLASH, VK_OEM_3: keys_1.Key.BACKQUOTE, VK_OEM_4: keys_1.Key.BRACKET_LEFT, VK_OEM_5: keys_1.Key.BACKSLASH, VK_OEM_6: keys_1.Key.BRACKET_RIGHT, VK_OEM_7: keys_1.Key.QUOTE, VK_OEM_PLUS: keys_1.Key.EQUAL, VK_OEM_COMMA: keys_1.Key.COMMA, VK_OEM_MINUS: keys_1.Key.MINUS, VK_OEM_PERIOD: keys_1.Key.PERIOD, VK_F1: keys_1.Key.F1, VK_F2: keys_1.Key.F2, VK_F3: keys_1.Key.F3, VK_F4: keys_1.Key.F4, VK_F5: keys_1.Key.F5, VK_F6: keys_1.Key.F6, VK_F7: keys_1.Key.F7, VK_F8: keys_1.Key.F8, VK_F9: keys_1.Key.F9, VK_F10: keys_1.Key.F10, VK_F11: keys_1.Key.F11, VK_F12: keys_1.Key.F12, VK_F13: keys_1.Key.F13, VK_F14: keys_1.Key.F14, VK_F15: keys_1.Key.F15, VK_F16: keys_1.Key.F16, VK_F17: keys_1.Key.F17, VK_F18: keys_1.Key.F18, VK_F19: keys_1.Key.F19, VK_BACK: keys_1.Key.BACKSPACE, VK_TAB: keys_1.Key.TAB, VK_RETURN: keys_1.Key.ENTER, VK_CAPITAL: keys_1.Key.CAPS_LOCK, VK_ESCAPE: keys_1.Key.ESCAPE, VK_SPACE: keys_1.Key.SPACE, VK_PRIOR: keys_1.Key.PAGE_UP, VK_NEXT: keys_1.Key.PAGE_DOWN, VK_END: keys_1.Key.END, VK_HOME: keys_1.Key.HOME, VK_INSERT: keys_1.Key.INSERT, VK_DELETE: keys_1.Key.DELETE, VK_LEFT: keys_1.Key.ARROW_LEFT, VK_UP: keys_1.Key.ARROW_UP, VK_RIGHT: keys_1.Key.ARROW_RIGHT, VK_DOWN: keys_1.Key.ARROW_DOWN, VK_NUMLOCK: keys_1.Key.NUM_LOCK, VK_NUMPAD0: keys_1.Key.DIGIT0, VK_NUMPAD1: keys_1.Key.DIGIT1, VK_NUMPAD2: keys_1.Key.DIGIT2, VK_NUMPAD3: keys_1.Key.DIGIT3, VK_NUMPAD4: keys_1.Key.DIGIT4, VK_NUMPAD5: keys_1.Key.DIGIT5, VK_NUMPAD6: keys_1.Key.DIGIT6, VK_NUMPAD7: keys_1.Key.DIGIT7, VK_NUMPAD8: keys_1.Key.DIGIT8, VK_NUMPAD9: keys_1.Key.DIGIT9, VK_MULTIPLY: keys_1.Key.MULTIPLY, VK_ADD: keys_1.Key.ADD, VK_SUBTRACT: keys_1.Key.SUBTRACT, VK_DECIMAL: keys_1.Key.DECIMAL, VK_DIVIDE: keys_1.Key.DIVIDE }; //# sourceMappingURL=keyboard-layout-service.js.map