/********************************************************************************
 * Copyright (C) 2017-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
 ********************************************************************************/ import { isOSX } from './os' ; export type KeySequence = KeyCode [ ] ; export namespace KeySequence { export function equals ( a , b ) { if ( a . length !== b . length ) { return false ; } for ( let i = 0 ; i < a . length ; i ++ ) { if ( ! a [ i ] . equals ( b [ i ] ) ) { return false ; } } return true ; } export enum CompareResult { NONE = 0 , PARTIAL , SHADOW , FULL } export function compare ( a , b ) { let first = a ; let second = b ; let shadow = false ; if ( b . length < a . length ) { first = b ; second = a ; shadow = true ; } for ( let i = 0 ; i < first . length ; i ++ ) { if ( first [ i ] . equals ( second [ i ] ) === false ) { return KeySequence . CompareResult . NONE ; } } if ( first . length < second . length ) { if ( shadow === false ) { return KeySequence . CompareResult . PARTIAL ; } else { return KeySequence . CompareResult . SHADOW ; } } return KeySequence . CompareResult . FULL ; } export function parse ( keybinding ) { const keyCodes = [ ] ; const rawKeyCodes = keybinding . trim ( ) . split ( /\s+/g ) ; for ( const rawKeyCode of rawKeyCodes ) { const keyCode = KeyCode . parse ( rawKeyCode ) ; if ( keyCode !== undefined ) { keyCodes . push ( keyCode ) ; } } return keyCodes ; } } /**
 * The key sequence for this binding. This key sequence should consist of one or more key strokes. Key strokes
 * consist of one or more keys held down at the same time. This should be zero or more modifier keys, and zero or one other key.
 * Since `M2+M3+<Key>` (Alt+Shift+<Key>) is reserved on MacOS X for writing special characters, such bindings are commonly
 * undefined for platform MacOS X and redefined as `M1+M3+<Key>`. The rule applies on the `M3+M2+<Key>` sequence.
 */ export interface Keystroke { readonly first ? : Key ; readonly modifiers ? : KeyModifier [ ] ; } export interface KeyCodeSchema { key ? : Partial < Key > ; ctrl ? : boolean ; shift ? : boolean ; alt ? : boolean ; meta ? : boolean ; character ? : string ; } /**
 * Representation of a pressed key combined with key modifiers.
 */ export class KeyCode { public readonly key : Key | undefined ; public readonly ctrl : boolean ; public readonly shift : boolean ; public readonly alt : boolean ; public readonly meta : boolean ; public readonly character : string | undefined ; public constructor ( schema ) { const key = schema . key ; if ( key ) { if ( key . code && key . keyCode && key . easyString ) { this . key = key as Key ; } else if ( key . code ) { this . key = Key . getKey ( key . code ) ; } else if ( key . keyCode ) { this . key = Key . getKey ( key . keyCode ) ; } } this . ctrl = ! ! schema . ctrl ; this . shift = ! ! schema . shift ; this . alt = ! ! schema . alt ; this . meta = ! ! schema . meta ; this . character = schema . character ; } /**
     * Return true if this KeyCode only contains modifiers.
     */ public isModifierOnly ( ) { return this . key === undefined ; } /**
     * Return true if the given KeyCode is equal to this one.
     */ equals ( other ) { if ( this . key && ( ! other . key || this . key . code !== other . key . code ) || ! this . key && other . key ) { return false ; } return this . ctrl === other . ctrl && this . alt === other . alt && this . shift === other . shift && this . meta === other . meta ; } toString ( ) { const result = [ ] ; if ( this . meta ) { result . push ( SpecialCases . META ) ; } if ( this . shift ) { result . push ( Key . SHIFT_LEFT . easyString ) ; } if ( this . alt ) { result . push ( Key . ALT_LEFT . easyString ) ; } if ( this . ctrl ) { result . push ( Key . CONTROL_LEFT . easyString ) ; } if ( this . key ) { result . push ( this . key . easyString ) ; } return result . join ( '+' ) ; } /**
     * Create a KeyCode from one of several input types.
     */ public static createKeyCode ( input , eventDispatch = 'code' ) { if ( typeof input === 'string' ) { const parts = input . split ( '+' ) ; if ( ! KeyCode . isModifierString ( parts [ 0 ] ) ) { return KeyCode . createKeyCode ( { first : Key . getKey ( parts [ 0 ] ) , modifiers : parts . slice ( 1 ) as KeyModifier [ ] } ) ; } return KeyCode . createKeyCode ( { modifiers : parts as KeyModifier [ ] } ) ; } else if ( KeyCode . isKeyboardEvent ( input ) ) { const key = KeyCode . toKey ( input , eventDispatch ) ; return new KeyCode ( { key : Key . isModifier ( key . code ) ? undefined : key , meta : isOSX && input . metaKey , shift : input . shiftKey , alt : input . altKey , ctrl : input . ctrlKey , character : KeyCode . toCharacter ( input ) } ) ; } else if ( ( input as Keystroke ) . first || ( input as Keystroke ) . modifiers ) { const keystroke = input as Keystroke ; const schema = { key : keystroke . first } ; if ( keystroke . modifiers ) { if ( isOSX ) { schema . meta = keystroke . modifiers . some ( mod => mod === KeyModifier . CtrlCmd ) ; schema . ctrl = keystroke . modifiers . some ( mod => mod === KeyModifier . MacCtrl ) ; } else { schema . meta = false ; schema . ctrl = keystroke . modifiers . some ( mod => mod === KeyModifier . CtrlCmd ) ; } schema . shift = keystroke . modifiers . some ( mod => mod === KeyModifier . Shift ) ; schema . alt = keystroke . modifiers . some ( mod => mod === KeyModifier . Alt ) ; } return new KeyCode ( schema ) ; } else { return new KeyCode ( input as KeyCodeSchema ) ; } } private static keybindings : { [ key ] : KeyCode ; } = { } ; public static resetKeyBindings ( ) { KeyCode . keybindings = { } ; } param keybinding public static parse ( keybinding ) { if ( KeyCode . keybindings [ keybinding ] ) { return KeyCode . keybindings [ keybinding ] ; } const schema = { } ; const keys = [ ] ; let currentKey = '' ; for ( const character of keybinding . trim ( ) . toLowerCase ( ) ) { if ( currentKey && ( character === '-' || character === '+' ) ) { keys . push ( currentKey ) ; currentKey = '' ; } else if ( character !== '+' ) { currentKey += character ; } } if ( currentKey ) { keys . push ( currentKey ) ; } if ( keys . length !== new Set ( keys ) . size ) { throw new Error ( `Can't parse keybinding ${ keybinding } Duplicate modifiers` ) ; } for ( let keyString of keys ) { if ( SPECIAL_ALIASES [ keyString ] !== undefined ) { keyString = SPECIAL_ALIASES [ keyString ] ; } const key = EASY_TO_KEY [ keyString ] ; if ( keyString === SpecialCases . META ) { if ( isOSX ) { schema . meta = true ; } else { throw new Error ( `Can't parse keybinding ${ keybinding } meta is for OSX only` ) ; } } else if ( keyString === SpecialCases . CTRLCMD ) { if ( isOSX ) { schema . meta = true ; } else { schema . ctrl = true ; } } else if ( Key . isKey ( key ) ) { if ( Key . isModifier ( key . code ) ) { if ( key . code === Key . CONTROL_LEFT . code || key . code === Key . CONTROL_RIGHT . code ) { schema . ctrl = true ; } else if ( key . code === Key . SHIFT_LEFT . code || key . code === Key . SHIFT_RIGHT . code ) { schema . shift = true ; } else if ( key . code === Key . ALT_LEFT . code || key . code === Key . ALT_RIGHT . code ) { schema . alt = true ; } } else { schema . key = key ; } } else { throw new Error ( `Unrecognized key '${ keyString }' in '${ keybinding }'` ) ; } } KeyCode . keybindings [ keybinding ] = new KeyCode ( schema ) ; return KeyCode . keybindings [ keybinding ] ; } } export namespace KeyCode { /**
     * Determines a `true` of `false` value for the key code argument.
     */ export type Predicate = ( keyCode : KeyCode ) => boolean ; export function isModifierString ( key ) { return key === KeyModifier . CtrlCmd || key === KeyModifier . Shift || key === KeyModifier . Alt || key === KeyModifier . MacCtrl ; } /**
     * Different scopes have different execution environments. This means that they have different built-ins
     * (different global object, different constructors, etc.). This may result in unexpected results. For instance,
     * `[] instanceof window.frames[0].Array` will return `false`, because `Array.prototype !== window.frames[0].Array`
     * and arrays inherit from the former.
     * See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof
     *
     * Note: just add another check if the current `event.type` checking is insufficient.
     */ export function isKeyboardEvent ( event ) { if ( typeof KeyboardEvent === 'undefined' ) { return false ; } if ( event instanceof KeyboardEvent ) { return true ; } const { type } = event ; if ( type ) { return type === 'keypress' || type === 'keydown' || type === 'keyup' ; } return false ; } /**
     * Determine the pressed key of a keyboard event. This key should correspond to the physical key according
     * to a standard US keyboard layout. International keyboard layouts are handled by `KeyboardLayoutService`.
     *
     * `keyIdentifier` is used to access this deprecated field:
     * https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyIdentifier
     */ export function toKey ( event , dispatch = 'code' ) { const code = event . code ; if ( code && dispatch === 'code' ) { if ( isOSX ) { const char = event . key ; if ( code === 'IntlBackslash' && ( char === '`' || char === '~' ) ) { return Key . BACKQUOTE ; } else if ( code === 'Backquote' && ( char === '§' || char === '±' ) ) { return Key . INTL_BACKSLASH ; } } if ( code . startsWith ( 'Numpad' ) && event . key && event . key . length > 1 ) { const k = Key . getKey ( event . key ) ; if ( k ) { return k ; } } const key = Key . getKey ( code ) ; if ( key ) { return key ; } } const keyCode = event . keyCode ; if ( keyCode ) { const key = Key . getKey ( keyCode ) ; if ( key ) { return key ; } } const keyIdentifier = ( event as KeyboardEvent & { keyIdentifier ? : string ; } ) . keyIdentifier ; if ( keyIdentifier ) { const key = Key . getKey ( keyIdentifier ) ; if ( key ) { return key ; } } throw new Error ( `Cannot get key code from the keyboard event: ${ event }.` ) ; } /**
     * Determine the actual printable character that is generated from a pressed key.
     * If the key does not correspond to a printable character, `undefined` is returned.
     * The result may be altered by modifier keys.
     */ export function toCharacter ( event ) { const key = event . key ; if ( key && Array . from ( key ) . length === 1 ) { return key ; } const charCode = event . charCode ; if ( charCode && charCode > 0x1f && ! ( charCode >= 0x80 && charCode <= 0x9f ) ) { return String . fromCharCode ( charCode ) ; } return undefined ; } } export enum KeyModifier { /**
     * M1 is the COMMAND key on MacOS X, and the CTRL key on most other platforms.
     */ CtrlCmd = 'M1' , /**
     * M2 is the SHIFT key.
     */ Shift = 'M2' , /**
     * M3 is the Option key on MacOS X, and the ALT key on most other platforms.
     */ Alt = 'M3' , /**
     * M4 is the CTRL key on MacOS X, and is undefined on other platforms.
     */ MacCtrl = 'M4' } export namespace KeyModifier { /**
     * The CTRL key, independently of the platform.
     * _Note:_ In general `KeyModifier.CtrlCmd` should be preferred over this constant.
     */ export const CTRL = isOSX ? KeyModifier . MacCtrl : KeyModifier . CtrlCmd ; /**
     * An alias for the SHIFT key (`KeyModifier.Shift`).
     */ export const SHIFT = KeyModifier . Shift ; /**
     * `true` if the argument represents a modifier. Otherwise, `false`.
     */ export function isModifier ( key ) { if ( key ) { switch ( key ) { case 'M1' : case 'M2' : case 'M3' : case 'M4' : return true ; default : return false ; } } return false ; } } export interface Key { readonly code : string ; readonly keyCode : number ; readonly easyString : string ; } const CODE_TO_KEY = { } ; const KEY_CODE_TO_KEY = { } ; const EASY_TO_KEY = { } ; const MODIFIERS = [ ] ; const SPECIAL_ALIASES = { 'option' : 'alt' , 'command' : 'meta' , 'cmd' : 'meta' , 'return' : 'enter' , 'esc' : 'escape' , 'mod' : 'ctrl' , 'ins' : 'insert' , 'del' : 'delete' , 'control' : 'ctrl' , } ; export namespace SpecialCases { export const META = 'meta' ; export const CTRLCMD = 'ctrlcmd' ; } export namespace Key { export function isKey ( arg ) { return typeof arg === 'object' && ( 'code' in arg ) && ( 'keyCode' in arg ) ; } export function getKey ( arg ) { if ( typeof arg === 'number' ) { return KEY_CODE_TO_KEY [ arg ] ; } else { return CODE_TO_KEY [ arg ] ; } } export function isModifier ( arg ) { if ( typeof arg === 'number' ) { return MODIFIERS . find ( key => key . keyCode === arg ) !== undefined ; } return MODIFIERS . find ( key => key . code === arg ) !== undefined ; } export function equals ( key , keyCode ) { return ! ! keyCode . key && key . keyCode === keyCode . key . keyCode ; } export const BACKSPACE = { code : 'Backspace' , keyCode : 8 , easyString : 'backspace' } ; export const TAB = { code : 'Tab' , keyCode : 9 , easyString : 'tab' } ; export const ENTER = { code : 'Enter' , keyCode : 13 , easyString : 'enter' } ; export const ESCAPE = { code : 'Escape' , keyCode : 27 , easyString : 'escape' } ; export const SPACE = { code : 'Space' , keyCode : 32 , easyString : 'space' } ; export const PAGE_UP = { code : 'PageUp' , keyCode : 33 , easyString : 'pageup' } ; export const PAGE_DOWN = { code : 'PageDown' , keyCode : 34 , easyString : 'pagedown' } ; export const END = { code : 'End' , keyCode : 35 , easyString : 'end' } ; export const HOME = { code : 'Home' , keyCode : 36 , easyString : 'home' } ; export const ARROW_LEFT = { code : 'ArrowLeft' , keyCode : 37 , easyString : 'left' } ; export const ARROW_UP = { code : 'ArrowUp' , keyCode : 38 , easyString : 'up' } ; export const ARROW_RIGHT = { code : 'ArrowRight' , keyCode : 39 , easyString : 'right' } ; export const ARROW_DOWN = { code : 'ArrowDown' , keyCode : 40 , easyString : 'down' } ; export const INSERT = { code : 'Insert' , keyCode : 45 , easyString : 'insert' } ; export const DELETE = { code : 'Delete' , keyCode : 46 , easyString : 'delete' } ; export const SHIFT_LEFT = { code : 'ShiftLeft' , keyCode : 16 , easyString : 'shift' } ; export const SHIFT_RIGHT = { code : 'ShiftRight' , keyCode : 16 , easyString : 'shift' } ; export const CONTROL_LEFT = { code : 'ControlLeft' , keyCode : 17 , easyString : 'ctrl' } ; export const CONTROL_RIGHT = { code : 'ControlRight' , keyCode : 17 , easyString : 'ctrl' } ; export const ALT_LEFT = { code : 'AltLeft' , keyCode : 18 , easyString : 'alt' } ; export const ALT_RIGHT = { code : 'AltRight' , keyCode : 18 , easyString : 'alt' } ; export const CAPS_LOCK = { code : 'CapsLock' , keyCode : 20 , easyString : 'capslock' } ; export const OS_LEFT = { code : 'OSLeft' , keyCode : 91 , easyString : 'super' } ; export const OS_RIGHT = { code : 'OSRight' , keyCode : 92 , easyString : 'super' } ; export const DIGIT0 = { code : 'Digit0' , keyCode : 48 , easyString : '0' } ; export const DIGIT1 = { code : 'Digit1' , keyCode : 49 , easyString : '1' } ; export const DIGIT2 = { code : 'Digit2' , keyCode : 50 , easyString : '2' } ; export const DIGIT3 = { code : 'Digit3' , keyCode : 51 , easyString : '3' } ; export const DIGIT4 = { code : 'Digit4' , keyCode : 52 , easyString : '4' } ; export const DIGIT5 = { code : 'Digit5' , keyCode : 53 , easyString : '5' } ; export const DIGIT6 = { code : 'Digit6' , keyCode : 54 , easyString : '6' } ; export const DIGIT7 = { code : 'Digit7' , keyCode : 55 , easyString : '7' } ; export const DIGIT8 = { code : 'Digit8' , keyCode : 56 , easyString : '8' } ; export const DIGIT9 = { code : 'Digit9' , keyCode : 57 , easyString : '9' } ; export const KEY_A = { code : 'KeyA' , keyCode : 65 , easyString : 'a' } ; export const KEY_B = { code : 'KeyB' , keyCode : 66 , easyString : 'b' } ; export const KEY_C = { code : 'KeyC' , keyCode : 67 , easyString : 'c' } ; export const KEY_D = { code : 'KeyD' , keyCode : 68 , easyString : 'd' } ; export const KEY_E = { code : 'KeyE' , keyCode : 69 , easyString : 'e' } ; export const KEY_F = { code : 'KeyF' , keyCode : 70 , easyString : 'f' } ; export const KEY_G = { code : 'KeyG' , keyCode : 71 , easyString : 'g' } ; export const KEY_H = { code : 'KeyH' , keyCode : 72 , easyString : 'h' } ; export const KEY_I = { code : 'KeyI' , keyCode : 73 , easyString : 'i' } ; export const KEY_J = { code : 'KeyJ' , keyCode : 74 , easyString : 'j' } ; export const KEY_K = { code : 'KeyK' , keyCode : 75 , easyString : 'k' } ; export const KEY_L = { code : 'KeyL' , keyCode : 76 , easyString : 'l' } ; export const KEY_M = { code : 'KeyM' , keyCode : 77 , easyString : 'm' } ; export const KEY_N = { code : 'KeyN' , keyCode : 78 , easyString : 'n' } ; export const KEY_O = { code : 'KeyO' , keyCode : 79 , easyString : 'o' } ; export const KEY_P = { code : 'KeyP' , keyCode : 80 , easyString : 'p' } ; export const KEY_Q = { code : 'KeyQ' , keyCode : 81 , easyString : 'q' } ; export const KEY_R = { code : 'KeyR' , keyCode : 82 , easyString : 'r' } ; export const KEY_S = { code : 'KeyS' , keyCode : 83 , easyString : 's' } ; export const KEY_T = { code : 'KeyT' , keyCode : 84 , easyString : 't' } ; export const KEY_U = { code : 'KeyU' , keyCode : 85 , easyString : 'u' } ; export const KEY_V = { code : 'KeyV' , keyCode : 86 , easyString : 'v' } ; export const KEY_W = { code : 'KeyW' , keyCode : 87 , easyString : 'w' } ; export const KEY_X = { code : 'KeyX' , keyCode : 88 , easyString : 'x' } ; export const KEY_Y = { code : 'KeyY' , keyCode : 89 , easyString : 'y' } ; export const KEY_Z = { code : 'KeyZ' , keyCode : 90 , easyString : 'z' } ; export const MULTIPLY = { code : 'NumpadMultiply' , keyCode : 106 , easyString : 'multiply' } ; export const ADD = { code : 'NumpadAdd' , keyCode : 107 , easyString : 'add' } ; export const DECIMAL = { code : 'NumpadDecimal' , keyCode : 108 , easyString : 'decimal' } ; export const SUBTRACT = { code : 'NumpadSubtract' , keyCode : 109 , easyString : 'subtract' } ; export const DIVIDE = { code : 'NumpadDivide' , keyCode : 111 , easyString : 'divide' } ; export const F1 = { code : 'F1' , keyCode : 112 , easyString : 'f1' } ; export const F2 = { code : 'F2' , keyCode : 113 , easyString : 'f2' } ; export const F3 = { code : 'F3' , keyCode : 114 , easyString : 'f3' } ; export const F4 = { code : 'F4' , keyCode : 115 , easyString : 'f4' } ; export const F5 = { code : 'F5' , keyCode : 116 , easyString : 'f5' } ; export const F6 = { code : 'F6' , keyCode : 117 , easyString : 'f6' } ; export const F7 = { code : 'F7' , keyCode : 118 , easyString : 'f7' } ; export const F8 = { code : 'F8' , keyCode : 119 , easyString : 'f8' } ; export const F9 = { code : 'F9' , keyCode : 120 , easyString : 'f9' } ; export const F10 = { code : 'F10' , keyCode : 121 , easyString : 'f10' } ; export const F11 = { code : 'F11' , keyCode : 122 , easyString : 'f11' } ; export const F12 = { code : 'F12' , keyCode : 123 , easyString : 'f12' } ; export const F13 = { code : 'F13' , keyCode : 124 , easyString : 'f13' } ; export const F14 = { code : 'F14' , keyCode : 125 , easyString : 'f14' } ; export const F15 = { code : 'F15' , keyCode : 126 , easyString : 'f15' } ; export const F16 = { code : 'F16' , keyCode : 127 , easyString : 'f16' } ; export const F17 = { code : 'F17' , keyCode : 128 , easyString : 'f17' } ; export const F18 = { code : 'F18' , keyCode : 129 , easyString : 'f18' } ; export const F19 = { code : 'F19' , keyCode : 130 , easyString : 'f19' } ; export const F20 = { code : 'F20' , keyCode : 131 , easyString : 'f20' } ; export const F21 = { code : 'F21' , keyCode : 132 , easyString : 'f21' } ; export const F22 = { code : 'F22' , keyCode : 133 , easyString : 'f22' } ; export const F23 = { code : 'F23' , keyCode : 134 , easyString : 'f23' } ; export const F24 = { code : 'F24' , keyCode : 135 , easyString : 'f24' } ; export const NUM_LOCK = { code : 'NumLock' , keyCode : 144 , easyString : 'numlock' } ; export const SEMICOLON = { code : 'Semicolon' , keyCode : 186 , easyString : ';' } ; export const EQUAL = { code : 'Equal' , keyCode : 187 , easyString : '=' } ; export const COMMA = { code : 'Comma' , keyCode : 188 , easyString : ',' } ; export const MINUS = { code : 'Minus' , keyCode : 189 , easyString : '-' } ; export const PERIOD = { code : 'Period' , keyCode : 190 , easyString : '.' } ; export const SLASH = { code : 'Slash' , keyCode : 191 , easyString : '/' } ; export const BACKQUOTE = { code : 'Backquote' , keyCode : 192 , easyString : '`' } ; export const INTL_RO = { code : 'IntlRo' , keyCode : 193 , easyString : 'intlro' } ; export const BRACKET_LEFT = { code : 'BracketLeft' , keyCode : 219 , easyString : '[' } ; export const BACKSLASH = { code : 'Backslash' , keyCode : 220 , easyString : '\\' } ; export const BRACKET_RIGHT = { code : 'BracketRight' , keyCode : 221 , easyString : ']' } ; export const QUOTE = { code : 'Quote' , keyCode : 222 , easyString : '\'' } ; export const INTL_BACKSLASH = { code : 'IntlBackslash' , keyCode : 229 , easyString : 'intlbackslash' } ; export const INTL_YEN = { code : 'IntlYen' , keyCode : 255 , easyString : 'intlyen' } ; export const MAX_KEY_CODE = INTL_YEN . keyCode ; } ( ( ) => { Object . keys ( Key ) . map ( prop => Reflect . get ( Key , prop ) ) . filter ( key => Key . isKey ( key ) ) . forEach ( key => { CODE_TO_KEY [ key . code ] = key ; KEY_CODE_TO_KEY [ key . keyCode ] = key ; EASY_TO_KEY [ key . easyString ] = key ; } ) ; CODE_TO_KEY [ 'Numpad0' ] = Key . DIGIT0 ; KEY_CODE_TO_KEY [ 96 ] = Key . DIGIT0 ; CODE_TO_KEY [ 'Numpad1' ] = Key . DIGIT1 ; KEY_CODE_TO_KEY [ 97 ] = Key . DIGIT1 ; CODE_TO_KEY [ 'Numpad2' ] = Key . DIGIT2 ; KEY_CODE_TO_KEY [ 98 ] = Key . DIGIT2 ; CODE_TO_KEY [ 'Numpad3' ] = Key . DIGIT3 ; KEY_CODE_TO_KEY [ 99 ] = Key . DIGIT3 ; CODE_TO_KEY [ 'Numpad4' ] = Key . DIGIT4 ; KEY_CODE_TO_KEY [ 100 ] = Key . DIGIT4 ; CODE_TO_KEY [ 'Numpad5' ] = Key . DIGIT5 ; KEY_CODE_TO_KEY [ 101 ] = Key . DIGIT5 ; CODE_TO_KEY [ 'Numpad6' ] = Key . DIGIT6 ; KEY_CODE_TO_KEY [ 102 ] = Key . DIGIT6 ; CODE_TO_KEY [ 'Numpad7' ] = Key . DIGIT7 ; KEY_CODE_TO_KEY [ 103 ] = Key . DIGIT7 ; CODE_TO_KEY [ 'Numpad8' ] = Key . DIGIT8 ; KEY_CODE_TO_KEY [ 104 ] = Key . DIGIT8 ; CODE_TO_KEY [ 'Numpad9' ] = Key . DIGIT9 ; KEY_CODE_TO_KEY [ 105 ] = Key . DIGIT9 ; CODE_TO_KEY [ 'NumpadEnter' ] = Key . ENTER ; CODE_TO_KEY [ 'NumpadEqual' ] = Key . EQUAL ; CODE_TO_KEY [ 'MetaLeft' ] = Key . OS_LEFT ; KEY_CODE_TO_KEY [ 224 ] = Key . OS_LEFT ; CODE_TO_KEY [ 'MetaRight' ] = Key . OS_RIGHT ; KEY_CODE_TO_KEY [ 93 ] = Key . OS_RIGHT ; KEY_CODE_TO_KEY [ 225 ] = Key . ALT_RIGHT ; KEY_CODE_TO_KEY [ 110 ] = Key . DECIMAL ; KEY_CODE_TO_KEY [ 59 ] = Key . SEMICOLON ; KEY_CODE_TO_KEY [ 61 ] = Key . EQUAL ; KEY_CODE_TO_KEY [ 173 ] = Key . MINUS ; KEY_CODE_TO_KEY [ 226 ] = Key . BACKSLASH ; KEY_CODE_TO_KEY [ 60 ] = Key . BACKSLASH ; MODIFIERS . push ( ... [ Key . ALT_LEFT , Key . ALT_RIGHT , Key . CONTROL_LEFT , Key . CONTROL_RIGHT , Key . OS_LEFT , Key . OS_RIGHT , Key . SHIFT_LEFT , Key . SHIFT_RIGHT ] ) ; } ) ( ) ; export type KeysOrKeyCodes = Key | KeyCode | ( Key | KeyCode ) [ ] ; export namespace KeysOrKeyCodes { export const toKeyCode = ( keyOrKeyCode ) => keyOrKeyCode instanceof KeyCode ? keyOrKeyCode : KeyCode . createKeyCode ( { first : keyOrKeyCode } ) ; export const toKeyCodes = ( keysOrKeyCodes ) => { if ( keysOrKeyCodes instanceof KeyCode ) { return [ keysOrKeyCodes ] ; } else if ( Array . isArray ( keysOrKeyCodes ) ) { return keysOrKeyCodes . slice ( ) . map ( toKeyCode ) ; } return [ toKeyCode ( keysOrKeyCodes ) ] ; } ; }