{"version":3,"sources":["../../../packages/core/data/accessibility-manager.ts"],"names":[],"mappings":"AAKA;;GAEG;AACH,qBAAa,oBAAoB;IAC7B;;OAEG;IACH,OAAO,CAAC,8BAA8B,CAAS;IAE/C;;OAEG;IACH,OAAO,CAAC,qBAAqB,CAAiD;IAE9E;;OAEG;IACI,gBAAgB,SAAsB;IAE7C;;OAEG;IACI,wBAAwB,SAAkC;IAEjE;;OAEG;IACI,2BAA2B,SAAqC;IAEvE;;OAEG;IACI,mBAAmB,EAAE,WAAW,EAAE,CAAM;IAE/C;;OAEG;IACH,OAAO,CAAC,gBAAgB,CAAc;;IAQtC;;OAEG;IACI,4BAA4B,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,GAAG,MAAM,IAAI;IAY/F;;;;;OAKG;IACH,OAAO,CAAC,cAAc;IAYtB;;;;OAIG;IACH,OAAO,CAAC,+BAA+B;IAKvC;;OAEG;IACI,sBAAsB,CAAC,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,WAAW,EAC3E,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,yBAAyB,CAAC,EAAE,OAAO;IA2BzF;;;;OAIG;IACH,OAAO,CAAC,cAAc;IAOtB;;;OAGG;IACI,uBAAuB,CAAC,YAAY,EAAE,OAAO;IAiBpD;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAS9B;;OAEG;IACH,OAAO,CAAC,oBAAoB;CAgI/B;AAED;;GAEG;AACH,qBAAa,WAAW;IAEpB;;OAEG;IACI,WAAW,UAAS;IAE3B;;OAEG;IACI,SAAS,UAAS;IAEzB;;OAEG;IACI,UAAU,UAAS;IAE1B;;OAEG;IACI,OAAO,EAAE,OAAO,CAAC;IAExB;;;OAGG;gBACS,SAAS,EAAE,MAAM;IAM7B;;;OAGG;IACH,OAAO,CAAC,WAAW;IAkBnB;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAY3B;;;OAGG;IACH,OAAO,CAAC,UAAU;IAalB;;;OAGG;IACI,WAAW,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO;CAMpD;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACjC;;OAEG;IACH,UAAU,EAAE,WAAW,CAAC;IAExB;;OAEG;IACH,UAAU,EAAE,WAAW,CAAC;IAExB;;OAEG;IACH,aAAa,EAAE,WAAW,CAAC;IAE3B;;OAEG;IACH,2BAA2B,EAAE,MAAM,IAAI,CAAC;IAExC;;OAEG;IACH,mBAAmB,EAAE,MAAM,IAAI,CAAC;IAEhC,WAAW,EAAE,aAAa,CAAC;CAC9B;AAGD,oBAAY,OAAO;IACf,SAAS,IAAI;IACb,GAAG,IAAI;IACP,KAAK,KAAK;IACV,KAAK,KAAK;IACV,IAAI,KAAK;IACT,GAAG,KAAK;IACR,KAAK,KAAK;IACV,QAAQ,KAAK;IACb,MAAM,KAAK;IACX,KAAK,KAAK;IACV,MAAM,KAAK;IACX,QAAQ,KAAK;IACb,GAAG,KAAK;IACR,IAAI,KAAK;IACT,SAAS,KAAK;IACd,OAAO,KAAK;IACZ,UAAU,KAAK;IACf,SAAS,KAAK;IACd,MAAM,KAAK;IACX,MAAM,KAAK;IACX,IAAI,KAAK;IACT,IAAI,KAAK;IACT,IAAI,KAAK;IACT,IAAI,KAAK;IACT,IAAI,KAAK;IACT,IAAI,KAAK;IACT,IAAI,KAAK;IACT,IAAI,KAAK;IACT,IAAI,KAAK;IACT,IAAI,KAAK;IACT,CAAC,KAAK;IACN,CAAC,KAAK;IACN,CAAC,KAAK;IACN,CAAC,KAAK;IACN,CAAC,KAAK;IACN,CAAC,KAAK;IACN,CAAC,KAAK;IACN,CAAC,KAAK;IACN,CAAC,KAAK;IACN,CAAC,KAAK;IACN,CAAC,KAAK;IACN,CAAC,KAAK;IACN,CAAC,KAAK;IACN,CAAC,KAAK;IACN,CAAC,KAAK;IACN,CAAC,KAAK;IACN,CAAC,KAAK;IACN,CAAC,KAAK;IACN,CAAC,KAAK;IACN,CAAC,KAAK;IACN,CAAC,KAAK;IACN,CAAC,KAAK;IACN,CAAC,KAAK;IACN,CAAC,KAAK;IACN,CAAC,KAAK;IACN,CAAC,KAAK;IACN,WAAW,KAAK;IAChB,YAAY,KAAK;IACjB,MAAM,KAAK;IACX,OAAO,KAAK;IACZ,OAAO,KAAK;IACZ,OAAO,KAAK;IACZ,OAAO,KAAK;IACZ,OAAO,MAAM;IACb,OAAO,MAAM;IACb,OAAO,MAAM;IACb,OAAO,MAAM;IACb,OAAO,MAAM;IACb,OAAO,MAAM;IACb,QAAQ,MAAM;IACd,GAAG,MAAM;IACT,QAAQ,MAAM;IACd,WAAW,MAAM;IACjB,MAAM,MAAM;IACZ,EAAE,MAAM;IACR,EAAE,MAAM;IACR,EAAE,MAAM;IACR,EAAE,MAAM;IACR,EAAE,MAAM;IACR,EAAE,MAAM;IACR,EAAE,MAAM;IACR,EAAE,MAAM;IACR,EAAE,MAAM;IACR,GAAG,MAAM;IACT,GAAG,MAAM;IACT,GAAG,MAAM;IACT,OAAO,MAAM;IACb,UAAU,MAAM;IAChB,SAAS,MAAM;IACf,SAAS,MAAM;IACf,KAAK,MAAM;IACX,IAAI,MAAM;IACV,MAAM,MAAM;IACZ,YAAY,MAAM;IAClB,WAAW,MAAM;IACjB,WAAW,MAAM;IACjB,SAAS,MAAM;IACf,WAAW,MAAM;IACjB,WAAW,MAAM;CACpB","file":"accessibility-manager.d.ts","sourcesContent":["import { LogLevel } from '../diagnostics/log-level';\r\nimport { LogRecord } from '../diagnostics/log-record';\r\nimport { Logging } from '../diagnostics/logging';\r\nimport { Dom } from '../dom/dom';\r\n\r\n/**\r\n * Class for accessibility manager\r\n */\r\nexport class AccessibilityManager {\r\n    /**\r\n     * Indicates that body focus class handlers have already been setup and should not be setup again\r\n     */\r\n    private hiddenFocusHandlersInitialized = false;\r\n\r\n    /**\r\n     * The set of events for element focusing.\r\n     */\r\n    private elementFocusingEvents: ((event: ElementFocusingEvent) => void)[] = [];\r\n\r\n    /**\r\n     * The CSS class to disable the focus rectangle even in keyboard mode\r\n     */\r\n    public hiddenFocusClass = 'sme-hidden-focus';\r\n\r\n    /**\r\n     * The CSS class to enable mouse specific accessibility styles\r\n     */\r\n    public mouseNavigationModeClass = 'sme-accessibility-mode-mouse';\r\n\r\n    /**\r\n     * The CSS class to enable keyboard specific accessibility styles\r\n     */\r\n    public keyboardNavigationModeClass = 'sme-accessibility-mode-keyboard';\r\n\r\n    /**\r\n     * The set of elements that have had the hiddenFocusClass applied\r\n     */\r\n    public hiddenFocusElements: HTMLElement[] = [];\r\n\r\n    /**\r\n     * The object of ctrl+alt+a key.\r\n     */\r\n    private ctrlAltAShortKey: KeyResolver;\r\n\r\n    constructor() {\r\n        // hookup global handlers\r\n        this.hookupGlobalHandlers();\r\n        this.ctrlAltAShortKey = new KeyResolver('Ctrl+Alt+A');\r\n    }\r\n\r\n    /**\r\n     * Registers the event handler for ElementFocusingEvent\r\n     */\r\n    public registerElementFocusingEvent(handler: (event: ElementFocusingEvent) => void): () => void {\r\n        const unregisterEventFunction = () => {\r\n            const index = this.elementFocusingEvents.indexOf(handler);\r\n            if (index !== -1) {\r\n                this.elementFocusingEvents.splice(index, 1);\r\n            }\r\n        };\r\n        this.elementFocusingEvents.push(handler);\r\n\r\n        return unregisterEventFunction;\r\n    }\r\n\r\n    /**\r\n     * focus on given element and prevent the default of the event\r\n     * @param element the element to focus on\r\n     * @param event the event that triggered the focus\r\n     * @param allowBrowserFocusHandling it indicates whether to allow browser to handle focus.\r\n     */\r\n    private focusOnElement(element: HTMLElement, event: KeyboardEvent, allowBrowserFocusHandling?: boolean) {\r\n        if (element) {\r\n            // this change needs to be taken in any snap-in implementations\r\n            // use param {preventScroll: true} if element is in an extension iframe\r\n            // TODO: try below code with snap-ins that use new snap-in listener code\r\n            element.focus();\r\n            if (!allowBrowserFocusHandling) {\r\n                event.preventDefault();\r\n            }\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Find the first focusable descendant of an element and focus on it\r\n     * @param element the element to work with\r\n     * @param event the event that triggered the focus\r\n     */\r\n    private focusOnFirstFocusableDescendant(element: HTMLElement, event: KeyboardEvent) {\r\n        const firstFocusableDescendant = Dom.getFirstFocusableDescendent(element);\r\n        this.focusOnElement(firstFocusableDescendant, event);\r\n    }\r\n\r\n    /**\r\n     * Handlers the element focusing in either the default way or custom ways based on ElementFocusingEvent handler.\r\n     */\r\n    public processElementFocusing(event: KeyboardEvent, elementToFocus: HTMLElement,\r\n        sourceZone: HTMLElement, targetZone: HTMLElement, allowBrowserFocusHandling?: boolean) {\r\n        let useCustomFocusHandling = false;\r\n        let preventDefaultEvent = false;\r\n        this.elementFocusingEvents.forEach(focusEvent => {\r\n            focusEvent({\r\n                nativeEvent: event,\r\n                sourceZone: sourceZone,\r\n                targetZone: targetZone,\r\n                targetElement: elementToFocus,\r\n                preventDefaultFocusBehavior: () => {\r\n                    useCustomFocusHandling = true;\r\n                },\r\n                preventDefaultEvent: () => {\r\n                    preventDefaultEvent = true;\r\n                }\r\n            });\r\n        });\r\n        if (useCustomFocusHandling) {\r\n            if (preventDefaultEvent) {\r\n                event.stopPropagation();\r\n                event.preventDefault();\r\n            }\r\n        } else {\r\n            this.focusOnElement(elementToFocus, event, allowBrowserFocusHandling);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * click on given element and prevent the default of the event\r\n     * @param element the element to click\r\n     * @param event the event that triggered the click\r\n     */\r\n    private clickOnElement(element: HTMLElement, event: KeyboardEvent) {\r\n        if (element) {\r\n            element.click();\r\n            event.preventDefault();\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Changes the Accessibility Mode to mouse or keyboard\r\n     * @param keyboardMode indicates that keyboard mode should be set\r\n     */\r\n    public changeAccessibilityMode(keyboardMode: boolean) {\r\n        // toggle accessibility mode across all iframes in the document\r\n        // only works for same origin iframes\r\n        // TODO: support cross origin iframes and replace this with RPC broadcasting to all iframes\r\n        const allBodys = Dom.getAllBodys();\r\n\r\n        for (let i = 0; i < allBodys.length; i++) {\r\n            const currentBody = allBodys[i];\r\n            currentBody.classList.toggle(this.mouseNavigationModeClass, !keyboardMode);\r\n            currentBody.classList.toggle(this.keyboardNavigationModeClass, keyboardMode);\r\n        }\r\n\r\n        // register accessibility mode with self so RPC can use it\r\n        const self = MsftSme.self();\r\n        self.Resources.accessibilityMode = keyboardMode;\r\n    }\r\n\r\n    /**\r\n     * Query the accessibility mode of parent\r\n     */\r\n    private queryAccessibilityMode(): boolean {\r\n        return !MsftSme.isNullOrUndefined(\r\n            Dom.getSpecificAncestor(\r\n                document.body,\r\n                (x: HTMLElement) => Dom.isBody(x) && x.classList.contains(this.keyboardNavigationModeClass)\r\n            )\r\n        );\r\n    }\r\n\r\n    /**\r\n     * Hooks up the global event handlers\r\n     */\r\n    private hookupGlobalHandlers() {\r\n        // hookup body focus class handlers.\r\n        // We do not need to unhook these as they last the entire applications lifecycle.\r\n        if (!this.hiddenFocusHandlersInitialized) {\r\n            // ensure this is only called once\r\n            this.hiddenFocusHandlersInitialized = true;\r\n            // apply the mouse navigation class to the body of the document as default\r\n            this.changeAccessibilityMode(false);\r\n\r\n            // when the user clicks on the page, we need to exit keyboard mode and enter mouse mode again\r\n            document.body.addEventListener('mousedown', (event) => {\r\n                // If event.buttons is 0, it means this mouse action is triggered by narrator.\r\n                // If event.buttons is greater than 0, it means this mouse action is triggered by actual mouse device.\r\n                // Then exit accessibility mode.\r\n                if (event.buttons) {\r\n                    this.changeAccessibilityMode(false);\r\n                    setTimeout(() => Dom.checkActiveTab(), 0);\r\n                }\r\n            });\r\n            document.body.addEventListener('keydown', (event) => {\r\n                const isKeyboardMode = this.queryAccessibilityMode();\r\n                this.changeAccessibilityMode(isKeyboardMode);\r\n                const currentElement = <HTMLElement>event.target;\r\n                const currentElementProperties = Dom.getElementProperties(currentElement);\r\n                const currentTrap = currentElementProperties.currentTrap;\r\n                const allowCustomArrowKeyFunctionality =\r\n                    Dom.allowCustomArrowKeyFunctionality(currentElementProperties);\r\n                const allowCustomHomeEndKeyFunctionality =\r\n                    Dom.allowCustomHomeEndKeyFunctionality(currentElement, currentElementProperties);\r\n                const currentZone = currentElementProperties.currentZone;\r\n                const keyCode = event.keyCode;\r\n\r\n                setTimeout(() => Dom.checkActiveTab(), 0);\r\n\r\n                if (event.shiftKey && keyCode === KeyCode.Tab) {\r\n                    // shift tab - go back to previous zone\r\n                    let focusOn = Dom.getPreviousZoneElement(currentElement);\r\n                    const targetZone = Dom.getAncestorZone(focusOn);\r\n\r\n                    if (Dom.isTablist(targetZone)) {\r\n                        focusOn = Dom.getFirstActiveOrSelectedDescendant(targetZone) || focusOn;\r\n                    }\r\n                    if (!currentElementProperties.withinTrap || Dom.getAncestorTrap(targetZone) === currentElementProperties.currentTrap) {\r\n                        this.processElementFocusing(event, focusOn, currentZone, targetZone);\r\n                    } else {\r\n                        event.preventDefault();\r\n                    }\r\n                    // else we are at the beginning of the page and want shift tab to perform its default action\r\n\r\n                } else if (keyCode === KeyCode.Tab) {\r\n                    // when the user presses 'tab' we will enter keyboard mode\r\n                    this.changeAccessibilityMode(true);\r\n\r\n                    const focusOn = Dom.getNextZoneElement(currentElement);\r\n                    const targetZone = Dom.getAncestorZone(focusOn);\r\n\r\n                    if (focusOn && targetZone !== currentZone) {\r\n                        // go to next zone\r\n                        let newFocusOn = focusOn;\r\n                        if (Dom.isTablist(targetZone)) {\r\n                            newFocusOn = Dom.getFirstActiveOrSelectedDescendant(targetZone);\r\n                        }\r\n                        if (!currentElementProperties.withinTrap\r\n                            || Dom.getAncestorTrap(targetZone) === currentElementProperties.currentTrap) {\r\n                            this.processElementFocusing(event, newFocusOn, currentZone, targetZone);\r\n                        } else {\r\n                            // we are at the end of the trap so go back to the beginning of the trap\r\n                            this.focusOnFirstFocusableDescendant(currentTrap, event);\r\n                            event.preventDefault();\r\n                        }\r\n                    } else if (!currentElementProperties.withinTrap) {\r\n                        // else we are at the end of the page and want tab to perform its default action\r\n                        const lastElement = Dom.getLastElementInZone(currentElement);\r\n                        if (lastElement) {\r\n                            this.processElementFocusing(event, lastElement, currentZone, targetZone, true);\r\n                        }\r\n                    } else {\r\n                        // we are at the end of the trap so go back to the beginning of the trap\r\n                        this.focusOnFirstFocusableDescendant(currentTrap, event);\r\n                    }\r\n\r\n                } else if (keyCode === KeyCode.RightArrow && allowCustomArrowKeyFunctionality) {\r\n                    // use default if the cursor is in the middle of search box text\r\n                    const useArrowKeys = Dom.useArrowKeysWithinSearchbox(currentElement, true);\r\n                    if (!useArrowKeys && isKeyboardMode) {\r\n                        // go to next focusable element within current zone\r\n                        this.focusOnElement(Dom.getNextFocusableElement(currentElement), event);\r\n                    }\r\n                } else if (keyCode === KeyCode.DownArrow && allowCustomArrowKeyFunctionality) {\r\n                    // go to next focusable element within current zone\r\n                    this.focusOnElement(Dom.getNextFocusableElement(currentElement), event);\r\n                } else if (keyCode === KeyCode.UpArrow && allowCustomArrowKeyFunctionality) {\r\n                    // go to previous focusable element within current zone\r\n                    this.focusOnElement(Dom.getPreviousFocusableElement(currentElement), event);\r\n                } else if (event.keyCode === KeyCode.LeftArrow && allowCustomArrowKeyFunctionality) {\r\n                    // use default if the cursor is in the middle of search box text\r\n                    const useArrowKeys = Dom.useArrowKeysWithinSearchbox(currentElement, false);\r\n                    if (!useArrowKeys && isKeyboardMode) {\r\n                        // go to previous focusable element within current zone\r\n                        this.focusOnElement(Dom.getPreviousFocusableElement(currentElement), event);\r\n                    }\r\n                } else if (event.keyCode === KeyCode.Enter) {\r\n                    if (document.body.classList.contains(this.keyboardNavigationModeClass)) {\r\n                        if ((currentZone || currentElementProperties.isZone)\r\n                            && (!currentElementProperties.withinForm || Dom.shouldTreatEnterAsClick(currentElement))) {\r\n                            this.clickOnElement(currentElement, event);\r\n                        }\r\n                    }\r\n                } else if (event.keyCode === KeyCode.End && allowCustomHomeEndKeyFunctionality) {\r\n                    this.focusOnElement(Dom.getLastElementInZone(currentElement), event);\r\n                } else if (event.keyCode === KeyCode.Home && allowCustomHomeEndKeyFunctionality) {\r\n                    this.focusOnElement(Dom.getFirstElementInZone(currentElement), event);\r\n                } else if (this.ctrlAltAShortKey.matchesWith(event)) {\r\n                    let targetElement: HTMLElement;\r\n                    if (Dom.isInActionBar(currentElement)) {\r\n                        targetElement = Dom.getNextActionBar(currentElement);\r\n                    } else {\r\n                        targetElement = Dom.getFirstActionBar(currentElement);\r\n                    }\r\n\r\n                    if (!MsftSme.isNullOrUndefined(targetElement)) {\r\n                        this.changeAccessibilityMode(true);\r\n                        this.focusOnElement(targetElement, event, false);\r\n                    }\r\n                }\r\n            });\r\n        }\r\n    }\r\n}\r\n\r\n/**\r\n * Class to resolve keys.\r\n */\r\nexport class KeyResolver {\r\n\r\n    /**\r\n     * Whether has shift key.\r\n     */\r\n    public hasShiftKey = false;\r\n\r\n    /**\r\n     * Whether has alt key.\r\n     */\r\n    public hasAltKey = false;\r\n\r\n    /**\r\n     * Whether has ctrl key.\r\n     */\r\n    public hasCtrlKey = false;\r\n\r\n    /**\r\n     * The main key code for key combination.\r\n     */\r\n    public keyCode: KeyCode;\r\n\r\n    /**\r\n     * Initializes an instance of KeyLocalizer\r\n     * @param inputkeys Input keys.\r\n     */\r\n    constructor(inputkeys: string) {\r\n        if (!MsftSme.isNullOrWhiteSpace(inputkeys)) {\r\n            this.resolveKeys(inputkeys);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Resolves localized keys in to this class structure.\r\n     * @param inputKeys Input keys.\r\n     */\r\n    private resolveKeys(inputKeys: string) {\r\n\r\n        if (inputKeys === '+') {\r\n            this.keyCode = KeyCode.Add;\r\n            return;\r\n        }\r\n        const keys = inputKeys.split('+');\r\n        if (keys.length > 0 && keys.length === 1) {\r\n            this.setModifierKeyFlags(keys[0]);\r\n            this.setKeycode(keys[0]);\r\n        } else {\r\n            for (let i = 0; i < keys.length - 1; i++) {\r\n                this.setModifierKeyFlags(keys[i]);\r\n            }\r\n            this.setKeycode(keys[keys.length - 1]);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Sets modifier key flags if found in key combinations.\r\n     * @param key The key.\r\n     */\r\n    private setModifierKeyFlags(key: string) {\r\n\r\n        // These should always be passed as english keys.\r\n        if (key === 'Ctrl') {\r\n            this.hasCtrlKey = true;\r\n        } else if (key === 'Alt') {\r\n            this.hasAltKey = true;\r\n        } else if (key === 'Shift') {\r\n            this.hasShiftKey = true;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Set the key code extracted from the input key.\r\n     * @param key the key string.\r\n     */\r\n    private setKeycode(key: string) {\r\n        const keyCode: KeyCode = (<any>KeyCode)[key];\r\n        this.keyCode = keyCode;\r\n        if (this.keyCode === undefined) {\r\n            Logging.log(<LogRecord>{\r\n                level: LogLevel.Error,\r\n                message: 'Could not resolve key ' + key,\r\n                source: KeyResolver.name\r\n            });\r\n        }\r\n\r\n    }\r\n\r\n    /**\r\n     * Checks if keyboard event matches with resolved keys.\r\n     * @param event The keyboard event containing pressed key information.\r\n     */\r\n    public matchesWith(event: KeyboardEvent): boolean {\r\n        return this.hasCtrlKey === event.ctrlKey &&\r\n            this.hasAltKey === event.altKey &&\r\n            this.hasShiftKey === event.shiftKey &&\r\n            this.keyCode === event.keyCode;\r\n    }\r\n}\r\n\r\n/**\r\n * Interface for ElementFocusingEvent.\r\n */\r\nexport interface ElementFocusingEvent {\r\n    /**\r\n     * It indicates the source focus zone.\r\n     */\r\n    sourceZone: HTMLElement;\r\n\r\n    /**\r\n     * It indicates the target focus zone.\r\n     */\r\n    targetZone: HTMLElement;\r\n\r\n    /**\r\n     * It indicates the target focus element.\r\n     */\r\n    targetElement: HTMLElement;\r\n\r\n    /**\r\n     * If this function is called in the event handler, it cancels the default behavior of focusing\r\n     */\r\n    preventDefaultFocusBehavior: () => void;\r\n\r\n    /**\r\n     * If this function is called in the event handler, it cancels the default event of focusing\r\n     */\r\n    preventDefaultEvent: () => void;\r\n\r\n    nativeEvent: KeyboardEvent;\r\n}\r\n\r\n// Keyboard codes\r\nexport enum KeyCode {\r\n    Backspace = 8,\r\n    Tab = 9,\r\n    Enter = 13,\r\n    Shift = 16,\r\n    Ctrl = 17,\r\n    Alt = 18,\r\n    Pause = 19,\r\n    CapsLock = 20,\r\n    Escape = 27,\r\n    Space = 32,\r\n    PageUp = 33,\r\n    PageDown = 34,\r\n    End = 35,\r\n    Home = 36,\r\n    LeftArrow = 37,\r\n    UpArrow = 38,\r\n    RightArrow = 39,\r\n    DownArrow = 40,\r\n    Insert = 45,\r\n    Delete = 46,\r\n    Num0 = 48,\r\n    Num1 = 49,\r\n    Num2 = 50,\r\n    Num3 = 51,\r\n    Num4 = 52,\r\n    Num5 = 53,\r\n    Num6 = 54,\r\n    Num7 = 55,\r\n    Num8 = 56,\r\n    Num9 = 57,\r\n    A = 65,\r\n    B = 66,\r\n    C = 67,\r\n    D = 68,\r\n    E = 69,\r\n    F = 70,\r\n    G = 71,\r\n    H = 72,\r\n    I = 73,\r\n    J = 74,\r\n    K = 75,\r\n    L = 76,\r\n    M = 77,\r\n    N = 78,\r\n    O = 79,\r\n    P = 80,\r\n    Q = 81,\r\n    R = 82,\r\n    S = 83,\r\n    T = 84,\r\n    U = 85,\r\n    V = 86,\r\n    W = 87,\r\n    X = 88,\r\n    Y = 89,\r\n    Z = 90,\r\n    LeftWindows = 91,\r\n    RightWindows = 92,\r\n    Select = 93,\r\n    Numpad0 = 96,\r\n    Numpad1 = 97,\r\n    Numpad2 = 98,\r\n    Numpad3 = 99,\r\n    Numpad4 = 100,\r\n    Numpad5 = 101,\r\n    Numpad6 = 102,\r\n    Numpad7 = 103,\r\n    Numpad8 = 104,\r\n    Numpad9 = 105,\r\n    Multiply = 106,\r\n    Add = 107,\r\n    Subtract = 109,\r\n    DecimaPoint = 110,\r\n    Divide = 111,\r\n    F1 = 112,\r\n    F2 = 113,\r\n    F3 = 114,\r\n    F4 = 115,\r\n    F5 = 116,\r\n    F6 = 117,\r\n    F7 = 118,\r\n    F8 = 119,\r\n    F9 = 120,\r\n    F10 = 121,\r\n    F11 = 122,\r\n    F12 = 123,\r\n    NumLock = 144,\r\n    ScrollLock = 145,\r\n    SemiColon = 186,\r\n    EqualSign = 187,\r\n    Comma = 188,\r\n    Dash = 189,\r\n    Period = 190,\r\n    ForwardSlash = 191,\r\n    GraveAccent = 192,\r\n    OpenBracket = 219,\r\n    BackSlash = 220,\r\n    CloseBraket = 221,\r\n    SingleQuote = 222\r\n}\r\n"]}