├── .git-blame-ignore ├── .gitattributes ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .npmignore ├── .vscode ├── launch.json ├── settings.json └── tasks.json ├── License.txt ├── PoliCheckExclusions.xml ├── README.md ├── SECURITY.md ├── ThirdPartyNotices.txt ├── binding.gyp ├── deps └── chromium │ ├── dom_code_data.inc │ ├── keyboard_codes.h │ ├── macros.h │ └── x │ ├── keysym_to_unicode.cc │ └── keysym_to_unicode.h ├── index.d.ts ├── index.js ├── package-lock.json ├── package.json ├── pipeline.yml ├── src ├── common.h ├── keyboard_mac.mm ├── keyboard_win.cc ├── keyboard_x.cc ├── keymapping.cc ├── keymapping.h ├── string_conversion.cc └── string_conversion.h └── test ├── linux ├── de_ch.txt ├── de_neo.txt ├── en.txt └── es.txt ├── mac ├── chinese-pinyin.txt ├── de_ch.txt ├── de_de.txt ├── en_dvorak.txt ├── en_gb.txt ├── en_intl.txt ├── en_us.txt ├── japanese-hiragana.txt └── spanish-iso.txt └── test.js /.git-blame-ignore: -------------------------------------------------------------------------------- 1 | # https://git-scm.com/docs/git-blame#Documentation/git-blame.txt---ignore-revs-fileltfilegt 2 | 3 | # CRLF -> LF 4 | 76e18e1277a59ffc88adc9b9154d66454ccb0630 5 | 6 | # Reduce indentation 7 | 026f020d00a19f79feb816dd6a6538d8963a6864 8 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | windows: 7 | name: Windows 8 | runs-on: windows-latest 9 | steps: 10 | - uses: actions/checkout@v2 11 | - uses: actions/setup-node@v2 12 | with: 13 | node-version: 16 14 | - run: npm ci 15 | - run: npm test 16 | 17 | linux: 18 | name: Linux 19 | runs-on: ubuntu-latest 20 | steps: 21 | - uses: actions/checkout@v2 22 | - uses: actions/setup-node@v2 23 | with: 24 | node-version: 16 25 | - run: npm ci 26 | - run: npm test 27 | 28 | macos: 29 | name: macOS 30 | runs-on: macos-latest 31 | steps: 32 | - uses: actions/checkout@v2 33 | - uses: actions/setup-node@v2 34 | with: 35 | node-version: 16 36 | # https://github.com/nodejs/node-gyp/issues/2869 37 | - run: python3 -m pip install setuptools 38 | - run: npm ci 39 | - run: npm test 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /node_modules/ 3 | npm-debug.log 4 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /.github/ 2 | /.vscode/ 3 | /build/ 4 | /test/ 5 | /.git-blame-ignore 6 | /.gitattributes 7 | /.gitignore 8 | /.npmignore 9 | /npm-debug.log 10 | /pipeline.yml 11 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "preLaunchTask": "node-gyp", 6 | "name": "C++ Launch", 7 | "type": "cppdbg", 8 | "request": "launch", 9 | "program": "/usr/bin/node", 10 | "args": ["test/test.js"], 11 | "stopAtEntry": false, 12 | "cwd": "${workspaceRoot}", 13 | "environment": [], 14 | "externalConsole": true, 15 | "linux": { 16 | "MIMode": "gdb", 17 | "setupCommands": [ 18 | { 19 | "description": "Enable pretty-printing for gdb", 20 | "text": "-enable-pretty-printing", 21 | "ignoreFailures": true 22 | } 23 | ] 24 | }, 25 | "osx": { 26 | "MIMode": "lldb" 27 | }, 28 | "windows": { 29 | "MIMode": "gdb", 30 | "setupCommands": [ 31 | { 32 | "description": "Enable pretty-printing for gdb", 33 | "text": "-enable-pretty-printing", 34 | "ignoreFailures": true 35 | } 36 | ] 37 | } 38 | } 39 | ] 40 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "editor.insertSpaces": true, 4 | "files.trimTrailingWhitespace": true, 5 | "editor.tabSize": 2, 6 | "files.exclude": { 7 | "**/.git": true, 8 | "**/.DS_Store": true, 9 | "build/**": true 10 | }, 11 | "files.associations": { 12 | "*.inc": "cpp" 13 | }, 14 | "git.branchProtection": ["main", "release/*"], 15 | "git.branchProtectionPrompt": "alwaysCommitToNewBranch", 16 | "git.branchRandomName.enable": true 17 | } 18 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "command": "node-gyp", 6 | "args": [ 7 | "build" 8 | ], 9 | "problemMatcher": { 10 | "owner": "cpp", 11 | "fileLocation": [ 12 | "relative", 13 | "${workspaceRoot}/build" 14 | ], 15 | "pattern": { 16 | "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$", 17 | "file": 1, 18 | "line": 2, 19 | "column": 3, 20 | "severity": 4, 21 | "message": 5 22 | } 23 | }, 24 | "tasks": [ 25 | { 26 | "label": "node-gyp", 27 | "type": "shell", 28 | "command": "node-gyp", 29 | "args": [ 30 | "build" 31 | ], 32 | "problemMatcher": { 33 | "owner": "cpp", 34 | "fileLocation": [ 35 | "relative", 36 | "${workspaceRoot}/build" 37 | ], 38 | "pattern": { 39 | "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$", 40 | "file": 1, 41 | "line": 2, 42 | "column": 3, 43 | "severity": 4, 44 | "message": 5 45 | } 46 | }, 47 | "group": "build" 48 | } 49 | ] 50 | } -------------------------------------------------------------------------------- /License.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) Microsoft Corporation 2 | 3 | All rights reserved. 4 | 5 | MIT License 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 8 | files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, 9 | modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 15 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 16 | BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT 17 | OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /PoliCheckExclusions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | DEPS 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OS key mapping node module [![Build Status](https://dev.azure.com/ms/node-native-keymap/_apis/build/status/microsoft.node-native-keymap?branchName=master)](https://dev.azure.com/ms/node-native-keymap/_build/latest?definitionId=138&branchName=master) 2 | Returns what characters are produced by pressing keys with different modifiers on the current system keyboard layout. 3 | 4 | ## Installing 5 | 6 | * On Debian-based Linux: `sudo apt-get install libx11-dev libxkbfile-dev` 7 | * On Red Hat-based Linux: `sudo yum install libx11-devel.x86_64 libxkbfile-devel.x86_64 # or .i686` 8 | * On SUSE-based Linux: `sudo zypper install libX11-devel libxkbfile-devel` 9 | * On FreeBSD: `sudo pkg install libX11` 10 | 11 | ```sh 12 | npm install native-keymap 13 | ``` 14 | 15 | ## Using 16 | 17 | ```javascript 18 | var keymap = require('native-keymap'); 19 | console.log(keymap.getKeyMap()); 20 | ``` 21 | 22 | Example output when using standard US keyboard layout (on Windows): 23 | ``` 24 | [ 25 | ... 26 | Space: { vkey: 'VK_SPACE', value: ' ', withShift: ' ', withAltGr: '', withShiftAltGr: '' }, 27 | Minus: { vkey: 'VK_OEM_MINUS', value: '-', withShift: '_', withAltGr: '', withShiftAltGr: '' }, 28 | Equal: { vkey: 'VK_OEM_PLUS', value: '=', withShift: '+', withAltGr: '', withShiftAltGr: '' }, 29 | BracketLeft: { vkey: 'VK_OEM_4', value: '[', withShift: '{', withAltGr: '', withShiftAltGr: '' }, 30 | BracketRight: { vkey: 'VK_OEM_6', value: ']', withShift: '}', withAltGr: '', withShiftAltGr: '' }, 31 | Backslash: { vkey: 'VK_OEM_5', value: '\\', withShift: '|', withAltGr: '', withShiftAltGr: '' }, 32 | Semicolon: { vkey: 'VK_OEM_1', value: ';', withShift: ':', withAltGr: '', withShiftAltGr: '' }, 33 | Quote: { vkey: 'VK_OEM_7', value: '\'', withShift: '"', withAltGr: '', withShiftAltGr: '' }, 34 | Backquote: { vkey: 'VK_OEM_3', value: '`', withShift: '~', withAltGr: '', withShiftAltGr: '' }, 35 | Comma: { vkey: 'VK_OEM_COMMA', value: ',', withShift: '<', withAltGr: '', withShiftAltGr: '' }, 36 | Period: { vkey: 'VK_OEM_PERIOD', value: '.', withShift: '>', withAltGr: '', withShiftAltGr: '' }, 37 | Slash: { vkey: 'VK_OEM_2', value: '/', withShift: '?', withAltGr: '', withShiftAltGr: '' }, 38 | ... 39 | ] 40 | ``` 41 | 42 | Example output when using German (Swiss) keyboard layout (on Windows): 43 | ``` 44 | [ 45 | ... 46 | Space: { vkey: 'VK_SPACE', value: ' ', withShift: ' ', withAltGr: '', withShiftAltGr: '' }, 47 | Minus: { vkey: 'VK_OEM_4', value: '\'', withShift: '?', withAltGr: '´', withShiftAltGr: '' }, 48 | Equal: { vkey: 'VK_OEM_6', value: '^', withShift: '`', withAltGr: '~', withShiftAltGr: '' }, 49 | BracketLeft: { vkey: 'VK_OEM_1', value: 'ü', withShift: 'è', withAltGr: '[', withShiftAltGr: '' }, 50 | BracketRight: { vkey: 'VK_OEM_3', value: '¨', withShift: '!', withAltGr: ']', withShiftAltGr: '' }, 51 | Backslash: { vkey: 'VK_OEM_8', value: '$', withShift: '£', withAltGr: '}', withShiftAltGr: '' }, 52 | Semicolon: { vkey: 'VK_OEM_7', value: 'ö', withShift: 'é', withAltGr: '', withShiftAltGr: '' }, 53 | Quote: { vkey: 'VK_OEM_5', value: 'ä', withShift: 'à', withAltGr: '{', withShiftAltGr: '' }, 54 | Backquote: { vkey: 'VK_OEM_2', value: '§', withShift: '°', withAltGr: '', withShiftAltGr: '' }, 55 | Comma: { vkey: 'VK_OEM_COMMA', value: ',', withShift: ';', withAltGr: '', withShiftAltGr: '' }, 56 | Period: { vkey: 'VK_OEM_PERIOD', value: '.', withShift: ':', withAltGr: '', withShiftAltGr: '' }, 57 | Slash: { vkey: 'VK_OEM_MINUS', value: '-', withShift: '_', withAltGr: '', withShiftAltGr: '' }, 58 | ... 59 | ] 60 | ``` 61 | 62 | ## Supported OSes 63 | * linux (X11) 64 | * windows 65 | * mac 66 | * freebsd 67 | 68 | ## Known issues 69 | * only tested from the Electron Main process 70 | 71 | ## Developing 72 | * `npm install -g node-gyp` 73 | * `node-gyp configure` (for debugging use `node-gyp configure -d`) 74 | * `node-gyp build` 75 | * `npm test` (for debugging change `index.js` to load the node module from the `Debug` folder and press `F5`) 76 | 77 | ## License 78 | [MIT](https://github.com/Microsoft/node-native-keymap/blob/master/License.txt) 79 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /ThirdPartyNotices.txt: -------------------------------------------------------------------------------- 1 | THIRD-PARTY SOFTWARE NOTICES AND INFORMATION 2 | Do Not Translate or Localize 3 | 4 | This project incorporates material from the project(s) listed below (collectively, “Third Party Code”). 5 | Microsoft is not the original author of the Third Party Code. The original copyright notice and license 6 | under which Microsoft received such Third Party Code are set out below. This Third Party Code is licensed 7 | to you under their original license terms set forth below. Microsoft reserves all other rights not 8 | expressly granted, whether by implication, estoppel or otherwise. 9 | 10 | The following files/folders contain third party software: 11 | 12 | ========================================================================================================= 13 | deps/chromium/** 14 | --------------------------------------------------------------------------------------------------------- 15 | // Copyright 2015 The Chromium Authors. All rights reserved. 16 | // 17 | // Redistribution and use in source and binary forms, with or without 18 | // modification, are permitted provided that the following conditions are 19 | // met: 20 | // 21 | // * Redistributions of source code must retain the above copyright 22 | // notice, this list of conditions and the following disclaimer. 23 | // * Redistributions in binary form must reproduce the above 24 | // copyright notice, this list of conditions and the following disclaimer 25 | // in the documentation and/or other materials provided with the 26 | // distribution. 27 | // * Neither the name of Google Inc. nor the names of its 28 | // contributors may be used to endorse or promote products derived from 29 | // this software without specific prior written permission. 30 | // 31 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 34 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 36 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 37 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 38 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 39 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 40 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 41 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 42 | ========================================================================================================= 43 | -------------------------------------------------------------------------------- /binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "keymapping", 5 | "sources": [ 6 | "src/string_conversion.cc", 7 | "src/keymapping.cc" 8 | ], 9 | 'msvs_configuration_attributes': { 10 | 'SpectreMitigation': 'Spectre' 11 | }, 12 | 'msvs_settings': { 13 | 'VCCLCompilerTool': { 14 | 'AdditionalOptions': [ 15 | '/guard:cf', 16 | '/w34244', 17 | '/we4267', 18 | '/ZH:SHA_256' 19 | ] 20 | }, 21 | 'VCLinkerTool': { 22 | 'AdditionalOptions': [ 23 | '/guard:cf' 24 | ] 25 | } 26 | }, 27 | "conditions": [ 28 | ['OS=="linux"', { 29 | "sources": [ 30 | "deps/chromium/x/keysym_to_unicode.cc", 31 | "src/keyboard_x.cc" 32 | ], 33 | "include_dirs": [ 34 | " // For size_t. 14 | #include // For memcpy. 15 | 16 | namespace base { 17 | 18 | // C++14 implementation of C++17's std::size(): 19 | // http://en.cppreference.com/w/cpp/iterator/size 20 | template 21 | constexpr auto size(const Container& c) -> decltype(c.size()) { 22 | return c.size(); 23 | } 24 | 25 | template 26 | constexpr size_t size(const T (&array)[N]) noexcept { 27 | return N; 28 | } 29 | 30 | } 31 | 32 | #endif // BASE_MACROS_H_ 33 | -------------------------------------------------------------------------------- /deps/chromium/x/keysym_to_unicode.h: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------------------------------------------------- 2 | // 3 | // [13.01.2022] https://source.chromium.org/chromium/chromium/src/+/main:ui/events/keycodes/keysym_to_unicode.h 4 | // 5 | // ---------------------------------------------------------------------------------------------------------------- 6 | 7 | // Copyright 2014 The Chromium Authors. All rights reserved. 8 | // Use of this source code is governed by a BSD-style license that can be 9 | // found in the LICENSE file. 10 | 11 | #ifndef UI_EVENTS_KEYCODES_KEYSYM_TO_UNICODE_H_ 12 | #define UI_EVENTS_KEYCODES_KEYSYM_TO_UNICODE_H_ 13 | 14 | #include 15 | 16 | namespace ui { 17 | 18 | // Returns a Unicode character corresponding to the given |keysym|. If the 19 | // |keysym| doesn't represent a printable character, returns zero. We don't 20 | // support characters outside the Basic Plane, and this function returns zero 21 | // in that case. 22 | uint16_t GetUnicodeCharacterFromXKeySym(unsigned long keysym); 23 | 24 | } // namespace ui 25 | 26 | #endif // UI_EVENTS_KEYCODES_KEYSYM_TO_UNICODE_H_ 27 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | export interface IWindowsKeyMapping { 7 | vkey: string; 8 | value: string; 9 | withShift: string; 10 | withAltGr: string; 11 | withShiftAltGr: string; 12 | } 13 | export interface IWindowsKeyboardMapping { 14 | [code: string]: IWindowsKeyMapping; 15 | } 16 | export interface ILinuxKeyMapping { 17 | value: string; 18 | withShift: string; 19 | withAltGr: string; 20 | withShiftAltGr: string; 21 | } 22 | export interface ILinuxKeyboardMapping { 23 | [code: string]: ILinuxKeyMapping; 24 | } 25 | export interface IMacKeyMapping { 26 | value: string; 27 | valueIsDeadKey: boolean; 28 | withShift: string; 29 | withShiftIsDeadKey: boolean; 30 | withAltGr: string; 31 | withAltGrIsDeadKey: boolean; 32 | withShiftAltGr: string; 33 | withShiftAltGrIsDeadKey: boolean; 34 | } 35 | export interface IMacKeyboardMapping { 36 | [code: string]: IMacKeyMapping; 37 | } 38 | 39 | export type IKeyboardMapping = IWindowsKeyboardMapping | ILinuxKeyboardMapping | IMacKeyboardMapping; 40 | 41 | export function getKeyMap(): IKeyboardMapping; 42 | 43 | export interface IWindowsKeyboardLayoutInfo { 44 | name: string; 45 | id: string; 46 | text: string; 47 | } 48 | 49 | export interface ILinuxKeyboardLayoutInfo { 50 | model: string; 51 | group: number; 52 | layout: string; 53 | variant: string; 54 | options: string; 55 | rules: string; 56 | } 57 | 58 | export interface IMacKeyboardLayoutInfo { 59 | id: string; 60 | localizedName: string; 61 | lang: string; 62 | } 63 | 64 | export type IKeyboardLayoutInfo = IWindowsKeyboardLayoutInfo | ILinuxKeyboardLayoutInfo | IMacKeyboardLayoutInfo; 65 | 66 | export function getCurrentKeyboardLayout(): IKeyboardLayoutInfo; 67 | 68 | export function onDidChangeKeyboardLayout(callback: () => void): void; 69 | 70 | export function isISOKeyboard(): boolean | undefined; 71 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | function NativeBinding() { 7 | this._tried = false; 8 | this._keymapping = null; 9 | } 10 | NativeBinding.prototype._init = function() { 11 | if (this._tried) { 12 | return; 13 | } 14 | this._tried = true; 15 | try { 16 | this._keymapping = require('./build/Release/keymapping'); 17 | } catch (err) { 18 | // fallback to the debug build 19 | this._keymapping = require('./build/Debug/keymapping'); 20 | } 21 | }; 22 | NativeBinding.prototype.getKeyMap = function() { 23 | try { 24 | this._init(); 25 | return this._keymapping.getKeyMap(); 26 | } catch(err) { 27 | console.error(err); 28 | return []; 29 | } 30 | }; 31 | NativeBinding.prototype.getCurrentKeyboardLayout = function() { 32 | try { 33 | this._init(); 34 | return this._keymapping.getCurrentKeyboardLayout(); 35 | } catch(err) { 36 | console.error(err); 37 | return null; 38 | } 39 | }; 40 | NativeBinding.prototype.onDidChangeKeyboardLayout = function(callback) { 41 | try { 42 | this._init(); 43 | this._keymapping.onDidChangeKeyboardLayout(callback); 44 | } catch(err) { 45 | console.error(err); 46 | } 47 | } 48 | NativeBinding.prototype.isISOKeyboard = function(callback) { 49 | try { 50 | this._init(); 51 | return this._keymapping.isISOKeyboard(); 52 | } catch(err) { 53 | return false; 54 | } 55 | } 56 | 57 | var binding = new NativeBinding(); 58 | 59 | exports.getCurrentKeyboardLayout = function() { 60 | return binding.getCurrentKeyboardLayout(); 61 | }; 62 | exports.getKeyMap = function() { 63 | return binding.getKeyMap(); 64 | }; 65 | exports.onDidChangeKeyboardLayout = function(callback) { 66 | return binding.onDidChangeKeyboardLayout(callback); 67 | }; 68 | exports.isISOKeyboard = function(callback) { 69 | return binding.isISOKeyboard(callback); 70 | }; 71 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "native-keymap", 3 | "version": "3.3.5", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "native-keymap", 9 | "version": "3.3.5", 10 | "license": "MIT" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "native-keymap", 3 | "version": "3.3.5", 4 | "description": "Get OS key mapping", 5 | "main": "index.js", 6 | "typings": "index.d.ts", 7 | "scripts": { 8 | "test": "node test/test.js" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/Microsoft/node-native-keymap.git" 13 | }, 14 | "author": "Microsoft Corporation", 15 | "license": "MIT", 16 | "bugs": { 17 | "url": "https://github.com/Microsoft/node-native-keymap/issues" 18 | }, 19 | "homepage": "https://github.com/Microsoft/node-native-keymap#readme" 20 | } 21 | -------------------------------------------------------------------------------- /pipeline.yml: -------------------------------------------------------------------------------- 1 | name: $(Date:yyyyMMdd)$(Rev:.r) 2 | 3 | trigger: 4 | batch: true 5 | branches: 6 | include: 7 | - main 8 | pr: none 9 | 10 | resources: 11 | repositories: 12 | - repository: templates 13 | type: github 14 | name: microsoft/vscode-engineering 15 | ref: main 16 | endpoint: Monaco 17 | 18 | parameters: 19 | - name: publishPackage 20 | displayName: 🚀 Publish native-keymap 21 | type: boolean 22 | default: false 23 | 24 | extends: 25 | template: azure-pipelines/npm-package/pipeline.yml@templates 26 | parameters: 27 | npmPackages: 28 | - name: native-keymap 29 | 30 | buildSteps: 31 | - script: npm ci 32 | displayName: Install dependencies 33 | 34 | testPlatforms: 35 | - name: Linux 36 | nodeVersions: 37 | - 20.x 38 | - name: MacOS 39 | nodeVersions: 40 | - 20.x 41 | - name: Windows 42 | nodeVersions: 43 | - 20.x 44 | 45 | testSteps: 46 | # https://github.com/nodejs/node-gyp/issues/2869 47 | - script: python3 -m pip install setuptools 48 | - script: npm ci 49 | displayName: Install dependencies 50 | 51 | - script: npm test 52 | displayName: Test 53 | 54 | apiScanSoftwareName: 'vscode-native-keymap' 55 | apiScanSoftwareVersion: '3.3' 56 | 57 | publishPackage: ${{ parameters.publishPackage }} 58 | 59 | policheckExclusionsFile: '$(Build.SourcesDirectory)/PoliCheckExclusions.xml' 60 | -------------------------------------------------------------------------------- /src/common.h: -------------------------------------------------------------------------------- 1 | // """ 2 | // Copyright Node.js contributors. All rights reserved. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to 6 | // deal in the Software without restriction, including without limitation the 7 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | // sell copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | // IN THE SOFTWARE. 21 | // """ 22 | 23 | // Empty value so that macros here are able to return NULL or void 24 | #define NAPI_RETVAL_NOTHING // Intentionally blank #define 25 | 26 | #define GET_AND_THROW_LAST_ERROR(env) \ 27 | do { \ 28 | const napi_extended_error_info *error_info; \ 29 | napi_get_last_error_info((env), &error_info); \ 30 | bool is_pending; \ 31 | napi_is_exception_pending((env), &is_pending); \ 32 | /* If an exception is already pending, don't rethrow it */ \ 33 | if (!is_pending) { \ 34 | const char* error_message = error_info->error_message != NULL ? \ 35 | error_info->error_message : \ 36 | "empty error message"; \ 37 | napi_throw_error((env), NULL, error_message); \ 38 | } \ 39 | } while (0) 40 | 41 | #define NAPI_ASSERT_BASE(env, assertion, message, ret_val) \ 42 | do { \ 43 | if (!(assertion)) { \ 44 | napi_throw_error( \ 45 | (env), \ 46 | NULL, \ 47 | "assertion (" #assertion ") failed: " message); \ 48 | return ret_val; \ 49 | } \ 50 | } while (0) 51 | 52 | // Returns NULL on failed assertion. 53 | // This is meant to be used inside napi_callback methods. 54 | #define NAPI_ASSERT(env, assertion, message) \ 55 | NAPI_ASSERT_BASE(env, assertion, message, NULL) 56 | 57 | // Returns empty on failed assertion. 58 | // This is meant to be used inside functions with void return type. 59 | #define NAPI_ASSERT_RETURN_VOID(env, assertion, message) \ 60 | NAPI_ASSERT_BASE(env, assertion, message, NAPI_RETVAL_NOTHING) 61 | 62 | #define NAPI_CALL_BASE(env, the_call, ret_val) \ 63 | do { \ 64 | if ((the_call) != napi_ok) { \ 65 | GET_AND_THROW_LAST_ERROR((env)); \ 66 | return ret_val; \ 67 | } \ 68 | } while (0) 69 | 70 | // Returns NULL if the_call doesn't return napi_ok. 71 | #define NAPI_CALL(env, the_call) \ 72 | NAPI_CALL_BASE(env, the_call, NULL) 73 | 74 | // Returns empty if the_call doesn't return napi_ok. 75 | #define NAPI_CALL_RETURN_VOID(env, the_call) \ 76 | NAPI_CALL_BASE(env, the_call, NAPI_RETVAL_NOTHING) 77 | 78 | // Returns empty if the_call doesn't return napi_ok. 79 | #define NAPI_CALL_RETURN_STATUS(env, the_call) \ 80 | do { \ 81 | napi_status status = (the_call); \ 82 | if (status != napi_ok) { \ 83 | GET_AND_THROW_LAST_ERROR((env)); \ 84 | return status; \ 85 | } \ 86 | } while (0) 87 | 88 | #define DECLARE_NAPI_PROPERTY(name, func) \ 89 | { (name), NULL, (func), NULL, NULL, NULL, napi_default, NULL } 90 | 91 | #define DECLARE_NAPI_GETTER(name, func) \ 92 | { (name), NULL, NULL, (func), NULL, NULL, napi_default, NULL } 93 | -------------------------------------------------------------------------------- /src/keyboard_mac.mm: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | #import 7 | #include 8 | 9 | #include "string_conversion.h" 10 | #include "keymapping.h" 11 | #include "common.h" 12 | #include "../deps/chromium/macros.h" 13 | 14 | namespace { 15 | 16 | std::pair ConvertKeyCodeToText(const UCKeyboardLayout* keyboard_layout, int mac_key_code, int modifiers) { 17 | 18 | int mac_modifiers = 0; 19 | if (modifiers & kShiftKeyModifierMask) 20 | mac_modifiers |= shiftKey; 21 | if (modifiers & kControlKeyModifierMask) 22 | mac_modifiers |= controlKey; 23 | if (modifiers & kAltKeyModifierMask) 24 | mac_modifiers |= optionKey; 25 | if (modifiers & kMetaKeyModifierMask) 26 | mac_modifiers |= cmdKey; 27 | 28 | // Convert EventRecord modifiers to format UCKeyTranslate accepts. See docs 29 | // on UCKeyTranslate for more info. 30 | UInt32 modifier_key_state = (mac_modifiers >> 8) & 0xFF; 31 | 32 | UInt32 dead_key_state = 0; 33 | UniCharCount char_count = 0; 34 | UniChar character = 0; 35 | OSStatus status = UCKeyTranslate( 36 | keyboard_layout, 37 | static_cast(mac_key_code), 38 | kUCKeyActionDown, 39 | modifier_key_state, 40 | LMGetKbdLast(), 41 | kUCKeyTranslateNoDeadKeysBit, 42 | &dead_key_state, 43 | 1, 44 | &char_count, 45 | &character); 46 | 47 | bool is_dead_key = false; 48 | if (status == noErr && char_count == 0 && dead_key_state != 0) { 49 | is_dead_key = true; 50 | status = UCKeyTranslate( 51 | keyboard_layout, 52 | static_cast(mac_key_code), 53 | kUCKeyActionDown, 54 | modifier_key_state, 55 | LMGetKbdLast(), 56 | kUCKeyTranslateNoDeadKeysBit, 57 | &dead_key_state, 58 | 1, 59 | &char_count, 60 | &character); 61 | } 62 | 63 | if (status == noErr && char_count == 1 && !std::iscntrl(character)) { 64 | wchar_t value = character; 65 | return std::make_pair(is_dead_key, vscode_keyboard::UTF16toUTF8(&value, 1)); 66 | } 67 | return std::make_pair(false, std::string()); 68 | } 69 | 70 | } // namespace 71 | 72 | namespace vscode_keyboard { 73 | 74 | 75 | #define DOM_CODE(usb, evdev, xkb, win, mac, code, id) {usb, mac, code} 76 | #define DOM_CODE_DECLARATION const KeycodeMapEntry usb_keycode_map[] = 77 | #include "../deps/chromium/dom_code_data.inc" 78 | #undef DOM_CODE 79 | #undef DOM_CODE_DECLARATION 80 | 81 | napi_value GetKeyMapImpl(napi_env env, napi_callback_info info) { 82 | 83 | napi_value result; 84 | NAPI_CALL(env, napi_create_object(env, &result)); 85 | 86 | TISInputSourceRef source = TISCopyCurrentKeyboardInputSource(); 87 | CFDataRef layout_data = static_cast((TISGetInputSourceProperty(source, kTISPropertyUnicodeKeyLayoutData))); 88 | if (!layout_data) { 89 | // TISGetInputSourceProperty returns null with Japanese keyboard layout. 90 | // Using TISCopyCurrentKeyboardLayoutInputSource to fix NULL return. 91 | source = TISCopyCurrentKeyboardLayoutInputSource(); 92 | layout_data = static_cast((TISGetInputSourceProperty(source, kTISPropertyUnicodeKeyLayoutData))); 93 | if (!layout_data) { 94 | // https://developer.apple.com/library/mac/documentation/TextFonts/Reference/TextInputSourcesReference/#//apple_ref/c/func/TISGetInputSourceProperty 95 | return result; 96 | } 97 | } 98 | 99 | const UCKeyboardLayout* keyboard_layout = reinterpret_cast(CFDataGetBytePtr(layout_data)); 100 | 101 | size_t cnt = sizeof(usb_keycode_map) / sizeof(usb_keycode_map[0]); 102 | 103 | napi_value true_value; 104 | NAPI_CALL(env, napi_get_boolean(env, true, &true_value)); 105 | 106 | napi_value false_value; 107 | NAPI_CALL(env, napi_get_boolean(env, false, &false_value)); 108 | 109 | for (size_t i = 0; i < cnt; ++i) { 110 | const char *code = usb_keycode_map[i].code; 111 | int native_keycode = usb_keycode_map[i].native_keycode; 112 | 113 | if (!code || native_keycode >= 0xffff) { 114 | continue; 115 | } 116 | 117 | napi_value entry; 118 | NAPI_CALL(env, napi_create_object(env, &entry)); 119 | 120 | { 121 | std::pair value = ConvertKeyCodeToText(keyboard_layout, native_keycode, 0); 122 | NAPI_CALL(env, napi_set_named_property_string_utf8(env, entry, "value", value.second.c_str())); 123 | NAPI_CALL(env, napi_set_named_property(env, entry, "valueIsDeadKey", value.first ? true_value : false_value)); 124 | } 125 | 126 | { 127 | std::pair with_shift = ConvertKeyCodeToText(keyboard_layout, native_keycode, kShiftKeyModifierMask); 128 | NAPI_CALL(env, napi_set_named_property_string_utf8(env, entry, "withShift", with_shift.second.c_str())); 129 | NAPI_CALL(env, napi_set_named_property(env, entry, "withShiftIsDeadKey", with_shift.first ? true_value : false_value)); 130 | } 131 | 132 | { 133 | std::pair with_alt_gr = ConvertKeyCodeToText(keyboard_layout, native_keycode, kAltKeyModifierMask); 134 | NAPI_CALL(env, napi_set_named_property_string_utf8(env, entry, "withAltGr", with_alt_gr.second.c_str())); 135 | NAPI_CALL(env, napi_set_named_property(env, entry, "withAltGrIsDeadKey", with_alt_gr.first ? true_value : false_value)); 136 | } 137 | 138 | { 139 | std::pair with_shift_alt_gr = ConvertKeyCodeToText(keyboard_layout, native_keycode, kShiftKeyModifierMask | kAltKeyModifierMask); 140 | NAPI_CALL(env, napi_set_named_property_string_utf8(env, entry, "withShiftAltGr", with_shift_alt_gr.second.c_str())); 141 | NAPI_CALL(env, napi_set_named_property(env, entry, "withShiftAltGrIsDeadKey", with_shift_alt_gr.first ? true_value : false_value)); 142 | } 143 | 144 | NAPI_CALL(env, napi_set_named_property(env, result, code, entry)); 145 | } 146 | return result; 147 | } 148 | 149 | napi_value GetCurrentKeyboardLayoutImpl(napi_env env, napi_callback_info info) { 150 | 151 | napi_value result; 152 | NAPI_CALL(env, napi_create_object(env, &result)); 153 | 154 | TISInputSourceRef source = TISCopyCurrentKeyboardInputSource(); 155 | CFStringRef source_id = (CFStringRef) TISGetInputSourceProperty(source, kTISPropertyInputSourceID); 156 | if(source_id) { 157 | NAPI_CALL(env, napi_set_named_property_string_utf8(env, result, "id", std::string([(NSString *)source_id UTF8String]).c_str())); 158 | } 159 | 160 | TISInputSourceRef name_source = TISCopyCurrentKeyboardInputSource(); 161 | CFStringRef localized_name = (CFStringRef) TISGetInputSourceProperty(name_source, kTISPropertyLocalizedName); 162 | if(localized_name) { 163 | NAPI_CALL(env, napi_set_named_property_string_utf8(env, result, "localizedName", std::string([(NSString *)localized_name UTF8String]).c_str())); 164 | } 165 | 166 | NSArray* languages = (NSArray *) TISGetInputSourceProperty(source, kTISPropertyInputSourceLanguages); 167 | if (languages && [languages count] > 0) { 168 | NSString* lang = [languages objectAtIndex:0]; 169 | if (lang) { 170 | NAPI_CALL(env, napi_set_named_property_string_utf8(env, result, "lang", std::string([lang UTF8String]).c_str())); 171 | } 172 | } 173 | 174 | return result; 175 | } 176 | 177 | void NotificationCallback(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) { 178 | NotificationCallbackData *data = (NotificationCallbackData *)observer; 179 | InvokeNotificationCallback(data); 180 | } 181 | 182 | void RegisterKeyboardLayoutChangeListenerImpl(NotificationCallbackData *data) { 183 | CFNotificationCenterRef center = CFNotificationCenterGetDistributedCenter(); 184 | 185 | // add an observer 186 | CFNotificationCenterAddObserver(center, data, NotificationCallback, 187 | kTISNotifySelectedKeyboardInputSourceChanged, NULL, 188 | CFNotificationSuspensionBehaviorDeliverImmediately 189 | ); 190 | } 191 | 192 | void DisposeKeyboardLayoutChangeListenerImpl(NotificationCallbackData *data) { 193 | CFNotificationCenterRef center = CFNotificationCenterGetDistributedCenter(); 194 | 195 | // remove the observer 196 | CFNotificationCenterRemoveObserver(center, data, 197 | kTISNotifySelectedKeyboardInputSourceChanged, NULL 198 | ); 199 | } 200 | 201 | napi_value IsISOKeyboardImpl(napi_env env, napi_callback_info info) { 202 | if (KBGetLayoutType(LMGetKbdType()) == kKeyboardISO) { 203 | return napi_fetch_boolean(env, true); 204 | } else { 205 | return napi_fetch_boolean(env, false); 206 | } 207 | } 208 | 209 | } // namespace vscode_keyboard 210 | -------------------------------------------------------------------------------- /src/keyboard_win.cc: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | #include "keymapping.h" 7 | #include "common.h" 8 | 9 | #include "../deps/chromium/macros.h" 10 | 11 | #include "string_conversion.h" 12 | #include 13 | #include 14 | #include 15 | 16 | namespace { 17 | 18 | void ClearKeyboardBuffer(UINT key_code, UINT scan_code, BYTE* keyboard_state) { 19 | memset(keyboard_state, 0, 256); 20 | 21 | wchar_t chars[5]; 22 | int code = 0; 23 | do { 24 | code = ::ToUnicode(key_code, scan_code, keyboard_state, chars, 4, 0); 25 | } while (code < 0); 26 | } 27 | 28 | std::string GetStrFromKeyPress(UINT key_code, int modifiers, BYTE *keyboard_state, UINT clear_key_code, UINT clear_scan_code) { 29 | memset(keyboard_state, 0, 256); 30 | 31 | if (modifiers & kShiftKeyModifierMask) { 32 | keyboard_state[VK_SHIFT] |= 0x80; 33 | } 34 | 35 | if (modifiers & kControlKeyModifierMask) { 36 | keyboard_state[VK_CONTROL] |= 0x80; 37 | } 38 | 39 | if (modifiers & kAltKeyModifierMask) { 40 | keyboard_state[VK_MENU] |= 0x80; 41 | } 42 | 43 | UINT scan_code = ::MapVirtualKeyW(key_code, MAPVK_VK_TO_VSC); 44 | 45 | wchar_t chars[5]; 46 | int code = ::ToUnicode(key_code, scan_code, keyboard_state, chars, 4, 0); 47 | 48 | if (code == -1) { 49 | // dead key 50 | if (chars[0] == 0 || iswcntrl(chars[0])) { 51 | return std::string(); 52 | } 53 | code = 1; 54 | } 55 | 56 | ClearKeyboardBuffer(clear_key_code, clear_scan_code, keyboard_state); 57 | 58 | if (code <= 0 || (code == 1 && iswcntrl(chars[0]))) { 59 | return std::string(); 60 | } 61 | 62 | return vscode_keyboard::UTF16toUTF8(chars, code); 63 | } 64 | 65 | } // namespace 66 | 67 | namespace vscode_keyboard { 68 | 69 | #define DOM_CODE(usb, evdev, xkb, win, mac, code, id) {usb, win, code} 70 | #define DOM_CODE_DECLARATION const KeycodeMapEntry usb_keycode_map[] = 71 | #include "../deps/chromium/dom_code_data.inc" 72 | #undef DOM_CODE 73 | #undef DOM_CODE_DECLARATION 74 | 75 | typedef struct { 76 | int vkey; 77 | const char* str_vkey; 78 | } VKeyStrEntry; 79 | 80 | const char* VKeyToStr(int vkey) { 81 | switch (vkey) { 82 | case VK_LBUTTON: return "VK_LBUTTON"; // Left mouse button 83 | case VK_RBUTTON: return "VK_RBUTTON"; // Right mouse button 84 | case VK_CANCEL: return "VK_CANCEL"; // Control-break processing 85 | case VK_MBUTTON: return "VK_MBUTTON"; // Middle mouse button (three-button mouse) 86 | case VK_XBUTTON1: return "VK_XBUTTON1"; // X1 mouse button 87 | case VK_XBUTTON2: return "VK_XBUTTON2"; // X2 mouse button 88 | case VK_BACK: return "VK_BACK"; // BACKSPACE key 89 | case VK_TAB: return "VK_TAB"; // TAB key 90 | case VK_CLEAR: return "VK_CLEAR"; // CLEAR key 91 | case VK_RETURN: return "VK_RETURN"; // ENTER key 92 | case VK_SHIFT: return "VK_SHIFT"; // SHIFT key 93 | case VK_CONTROL: return "VK_CONTROL"; // CTRL key 94 | case VK_MENU: return "VK_MENU"; // ALT key 95 | case VK_PAUSE: return "VK_PAUSE"; // PAUSE key 96 | case VK_CAPITAL: return "VK_CAPITAL"; // CAPS LOCK key 97 | case VK_KANA: return "VK_KANA"; // IME Kana mode 98 | //case VK_HANGUL: return "VK_HANGUEL"; // IME Hangul mode 99 | case VK_JUNJA: return "VK_JUNJA"; // IME Junja mode 100 | case VK_FINAL: return "VK_FINAL"; // IME final mode 101 | case VK_HANJA: return "VK_HANJA"; // IME Hanja mode 102 | //case VK_KANJI: return "VK_KANJI"; // IME Kanji mode 103 | case VK_ESCAPE: return "VK_ESCAPE"; // ESC key 104 | case VK_CONVERT: return "VK_CONVERT"; // IME convert 105 | case VK_NONCONVERT: return "VK_NONCONVERT"; // IME nonconvert 106 | case VK_ACCEPT: return "VK_ACCEPT"; // IME accept 107 | case VK_MODECHANGE: return "VK_MODECHANGE"; // IME mode change request 108 | case VK_SPACE: return "VK_SPACE"; // SPACEBAR 109 | case VK_PRIOR: return "VK_PRIOR"; // PAGE UP key 110 | case VK_NEXT: return "VK_NEXT"; // PAGE DOWN key 111 | case VK_END: return "VK_END"; // END key 112 | case VK_HOME: return "VK_HOME"; // HOME key 113 | case VK_LEFT: return "VK_LEFT"; // LEFT ARROW key 114 | case VK_UP: return "VK_UP"; // UP ARROW key 115 | case VK_RIGHT: return "VK_RIGHT"; // RIGHT ARROW key 116 | case VK_DOWN: return "VK_DOWN"; // DOWN ARROW key 117 | case VK_SELECT: return "VK_SELECT"; // SELECT key 118 | case VK_PRINT: return "VK_PRINT"; // PRINT key 119 | case VK_EXECUTE: return "VK_EXECUTE"; // EXECUTE key 120 | case VK_SNAPSHOT: return "VK_SNAPSHOT"; // PRINT SCREEN key 121 | case VK_INSERT: return "VK_INSERT"; // INS key 122 | case VK_DELETE: return "VK_DELETE"; // DEL key 123 | case VK_HELP: return "VK_HELP"; // HELP key 124 | 125 | case '0': return "VK_0"; 126 | case '1': return "VK_1"; 127 | case '2': return "VK_2"; 128 | case '3': return "VK_3"; 129 | case '4': return "VK_4"; 130 | case '5': return "VK_5"; 131 | case '6': return "VK_6"; 132 | case '7': return "VK_7"; 133 | case '8': return "VK_8"; 134 | case '9': return "VK_9"; 135 | case 'A': return "VK_A"; 136 | case 'B': return "VK_B"; 137 | case 'C': return "VK_C"; 138 | case 'D': return "VK_D"; 139 | case 'E': return "VK_E"; 140 | case 'F': return "VK_F"; 141 | case 'G': return "VK_G"; 142 | case 'H': return "VK_H"; 143 | case 'I': return "VK_I"; 144 | case 'J': return "VK_J"; 145 | case 'K': return "VK_K"; 146 | case 'L': return "VK_L"; 147 | case 'M': return "VK_M"; 148 | case 'N': return "VK_N"; 149 | case 'O': return "VK_O"; 150 | case 'P': return "VK_P"; 151 | case 'Q': return "VK_Q"; 152 | case 'R': return "VK_R"; 153 | case 'S': return "VK_S"; 154 | case 'T': return "VK_T"; 155 | case 'U': return "VK_U"; 156 | case 'V': return "VK_V"; 157 | case 'W': return "VK_W"; 158 | case 'X': return "VK_X"; 159 | case 'Y': return "VK_Y"; 160 | case 'Z': return "VK_Z"; 161 | 162 | case VK_LWIN: return "VK_LWIN"; // Left Windows key (Natural keyboard) 163 | case VK_RWIN: return "VK_RWIN"; // Right Windows key (Natural keyboard) 164 | case VK_APPS: return "VK_APPS"; // Applications key (Natural keyboard) 165 | case VK_SLEEP: return "VK_SLEEP"; // Computer Sleep key 166 | case VK_NUMPAD0: return "VK_NUMPAD0"; // Numeric keypad 0 key 167 | case VK_NUMPAD1: return "VK_NUMPAD1"; // Numeric keypad 1 key 168 | case VK_NUMPAD2: return "VK_NUMPAD2"; // Numeric keypad 2 key 169 | case VK_NUMPAD3: return "VK_NUMPAD3"; // Numeric keypad 3 key 170 | case VK_NUMPAD4: return "VK_NUMPAD4"; // Numeric keypad 4 key 171 | case VK_NUMPAD5: return "VK_NUMPAD5"; // Numeric keypad 5 key 172 | case VK_NUMPAD6: return "VK_NUMPAD6"; // Numeric keypad 6 key 173 | case VK_NUMPAD7: return "VK_NUMPAD7"; // Numeric keypad 7 key 174 | case VK_NUMPAD8: return "VK_NUMPAD8"; // Numeric keypad 8 key 175 | case VK_NUMPAD9: return "VK_NUMPAD9"; // Numeric keypad 9 key 176 | case VK_MULTIPLY: return "VK_MULTIPLY"; // Multiply key 177 | case VK_ADD: return "VK_ADD"; // Add key 178 | case VK_SEPARATOR: return "VK_SEPARATOR"; // Separator key 179 | case VK_SUBTRACT: return "VK_SUBTRACT"; // Subtract key 180 | case VK_DECIMAL: return "VK_DECIMAL"; // Decimal key 181 | case VK_DIVIDE: return "VK_DIVIDE"; // Divide key 182 | case VK_F1: return "VK_F1"; // F1 key 183 | case VK_F2: return "VK_F2"; // F2 key 184 | case VK_F3: return "VK_F3"; // F3 key 185 | case VK_F4: return "VK_F4"; // F4 key 186 | case VK_F5: return "VK_F5"; // F5 key 187 | case VK_F6: return "VK_F6"; // F6 key 188 | case VK_F7: return "VK_F7"; // F7 key 189 | case VK_F8: return "VK_F8"; // F8 key 190 | case VK_F9: return "VK_F9"; // F9 key 191 | case VK_F10: return "VK_F10"; // F10 key 192 | case VK_F11: return "VK_F11"; // F11 key 193 | case VK_F12: return "VK_F12"; // F12 key 194 | case VK_F13: return "VK_F13"; // F13 key 195 | case VK_F14: return "VK_F14"; // F14 key 196 | case VK_F15: return "VK_F15"; // F15 key 197 | case VK_F16: return "VK_F16"; // F16 key 198 | case VK_F17: return "VK_F17"; // F17 key 199 | case VK_F18: return "VK_F18"; // F18 key 200 | case VK_F19: return "VK_F19"; // F19 key 201 | case VK_F20: return "VK_F20"; // F20 key 202 | case VK_F21: return "VK_F21"; // F21 key 203 | case VK_F22: return "VK_F22"; // F22 key 204 | case VK_F23: return "VK_F23"; // F23 key 205 | case VK_F24: return "VK_F24"; // F24 key 206 | case VK_NUMLOCK: return "VK_NUMLOCK"; // NUM LOCK key 207 | case VK_SCROLL: return "VK_SCROLL"; // SCROLL LOCK key 208 | case VK_LSHIFT: return "VK_LSHIFT"; // Left SHIFT key 209 | case VK_RSHIFT: return "VK_RSHIFT"; // Right SHIFT key 210 | case VK_LCONTROL: return "VK_LCONTROL"; // Left CONTROL key 211 | case VK_RCONTROL: return "VK_RCONTROL"; // Right CONTROL key 212 | case VK_LMENU: return "VK_LMENU"; // Left MENU key 213 | case VK_RMENU: return "VK_RMENU"; // Right MENU key 214 | case VK_BROWSER_BACK: return "VK_BROWSER_BACK"; // Browser Back key 215 | case VK_BROWSER_FORWARD: return "VK_BROWSER_FORWARD"; // Browser Forward key 216 | case VK_BROWSER_REFRESH: return "VK_BROWSER_REFRESH"; // Browser Refresh key 217 | case VK_BROWSER_STOP: return "VK_BROWSER_STOP"; // Browser Stop key 218 | case VK_BROWSER_SEARCH: return "VK_BROWSER_SEARCH"; // Browser Search key 219 | case VK_BROWSER_FAVORITES: return "VK_BROWSER_FAVORITES"; // Browser Favorites key 220 | case VK_BROWSER_HOME: return "VK_BROWSER_HOME"; // Browser Start and Home key 221 | case VK_VOLUME_MUTE: return "VK_VOLUME_MUTE"; // Volume Mute key 222 | case VK_VOLUME_DOWN: return "VK_VOLUME_DOWN"; // Volume Down key 223 | case VK_VOLUME_UP: return "VK_VOLUME_UP"; // Volume Up key 224 | case VK_MEDIA_NEXT_TRACK: return "VK_MEDIA_NEXT_TRACK"; // Next Track key 225 | case VK_MEDIA_PREV_TRACK: return "VK_MEDIA_PREV_TRACK"; // Previous Track key 226 | case VK_MEDIA_STOP: return "VK_MEDIA_STOP"; // Stop Media key 227 | case VK_MEDIA_PLAY_PAUSE: return "VK_MEDIA_PLAY_PAUSE"; // Play/Pause Media key 228 | case VK_LAUNCH_MAIL: return "VK_LAUNCH_MAIL"; // Start Mail key 229 | case VK_LAUNCH_MEDIA_SELECT: return "VK_LAUNCH_MEDIA_SELECT"; // Select Media key 230 | case VK_LAUNCH_APP1: return "VK_LAUNCH_APP1"; // Start Application 1 key 231 | case VK_LAUNCH_APP2: return "VK_LAUNCH_APP2"; // Start Application 2 key 232 | case VK_OEM_1: return "VK_OEM_1"; // Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the ';:' key 233 | case VK_OEM_PLUS: return "VK_OEM_PLUS"; // For any country/region, the '+' key 234 | case VK_OEM_COMMA: return "VK_OEM_COMMA"; // For any country/region, the ',' key 235 | case VK_OEM_MINUS: return "VK_OEM_MINUS"; // For any country/region, the '-' key 236 | case VK_OEM_PERIOD: return "VK_OEM_PERIOD"; // For any country/region, the '.' key 237 | case VK_OEM_2: return "VK_OEM_2"; // Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the '/?' key 238 | case VK_OEM_3: return "VK_OEM_3"; // Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the '`~' key 239 | case 0xC1: return "VK_ABNT_C1"; // Brazilian (ABNT) Keyboard 240 | case 0xC2: return "VK_ABNT_C2"; // Brazilian (ABNT) Keyboard 241 | case VK_OEM_4: return "VK_OEM_4"; // Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the '[{' key 242 | case VK_OEM_5: return "VK_OEM_5"; // Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the '\|' key 243 | case VK_OEM_6: return "VK_OEM_6"; // Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the ']}' key 244 | case VK_OEM_7: return "VK_OEM_7"; // Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the 'single-quote/double-quote' key 245 | case VK_OEM_8: return "VK_OEM_8"; // Used for miscellaneous characters; it can vary by keyboard. 246 | case VK_OEM_102: return "VK_OEM_102"; // Either the angle bracket key or the backslash key on the RT 102-key keyboard 247 | case VK_PROCESSKEY: return "VK_PROCESSKEY"; // IME PROCESS key 248 | case VK_PACKET: return "VK_PACKET"; // Used to pass Unicode characters as if they were keystrokes. The VK_PACKET key is the low word of a 32-bit Virtual Key value used for non-keyboard input methods. For more information, see Remark in KEYBDINPUT, SendInput, WM_KEYDOWN, and WM_KEYUP // 0xE8 249 | case VK_ATTN: return "VK_ATTN"; // Attn key 250 | case VK_CRSEL: return "VK_CRSEL"; // CrSel key 251 | case VK_EXSEL: return "VK_EXSEL"; // ExSel key 252 | case VK_EREOF: return "VK_EREOF"; // Erase EOF key 253 | case VK_PLAY: return "VK_PLAY"; // Play key 254 | case VK_ZOOM: return "VK_ZOOM"; // Zoom key 255 | case VK_NONAME: return "VK_NONAME"; // Reserved 256 | case VK_PA1: return "VK_PA1"; // PA1 key 257 | case VK_OEM_CLEAR: return "VK_OEM_CLEAR"; // Clear key 258 | } 259 | 260 | return "VK_UNKNOWN"; 261 | } 262 | 263 | class UseForegroundKeyboardLayoutScope { 264 | public: 265 | UseForegroundKeyboardLayoutScope() : original_layout_(GetKeyboardLayout(0)) { 266 | if (auto window = GetForegroundWindow()) { 267 | const auto thread_id = GetWindowThreadProcessId(window, nullptr); 268 | ActivateKeyboardLayout(GetKeyboardLayout(thread_id), 0); 269 | } 270 | } 271 | 272 | ~UseForegroundKeyboardLayoutScope() { 273 | ActivateKeyboardLayout(original_layout_, 0); 274 | } 275 | 276 | UseForegroundKeyboardLayoutScope(const UseForegroundKeyboardLayoutScope&) = delete; 277 | UseForegroundKeyboardLayoutScope& operator=(const UseForegroundKeyboardLayoutScope&) = delete; 278 | 279 | private: 280 | HKL original_layout_ = nullptr; 281 | }; 282 | 283 | napi_value GetKeyMapImpl(napi_env env, napi_callback_info info) { 284 | UseForegroundKeyboardLayoutScope use_foreground_keyboard_layout; 285 | 286 | napi_value result; 287 | NAPI_CALL(env, napi_create_object(env, &result)); 288 | 289 | UINT clear_key_code = VK_DECIMAL; 290 | UINT clear_scan_code = ::MapVirtualKeyW(clear_key_code, MAPVK_VK_TO_VSC); 291 | BYTE keyboard_state[256]; 292 | 293 | size_t cnt = sizeof(usb_keycode_map) / sizeof(usb_keycode_map[0]); 294 | for (size_t i = 0; i < cnt; ++i) { 295 | const char *code = usb_keycode_map[i].code; 296 | int native_scancode = usb_keycode_map[i].native_keycode; 297 | 298 | if (!code || native_scancode <= 0) { 299 | continue; 300 | } 301 | 302 | int native_keycode = ::MapVirtualKeyW(native_scancode, MAPVK_VSC_TO_VK); 303 | 304 | napi_value entry; 305 | NAPI_CALL(env, napi_create_object(env, &entry)); 306 | 307 | NAPI_CALL(env, napi_set_named_property_string_utf8(env, entry, "vkey", VKeyToStr(native_keycode))); 308 | 309 | std::string value = GetStrFromKeyPress(native_keycode, 0, keyboard_state, clear_key_code, clear_scan_code); 310 | NAPI_CALL(env, napi_set_named_property_string_utf8(env, entry, "value", value.c_str())); 311 | 312 | std::string with_shift = GetStrFromKeyPress(native_keycode, kShiftKeyModifierMask, keyboard_state, clear_key_code, clear_scan_code); 313 | NAPI_CALL(env, napi_set_named_property_string_utf8(env, entry, "withShift", with_shift.c_str())); 314 | 315 | std::string with_alt_gr = GetStrFromKeyPress(native_keycode, kControlKeyModifierMask | kAltKeyModifierMask, keyboard_state, clear_key_code, clear_scan_code); 316 | NAPI_CALL(env, napi_set_named_property_string_utf8(env, entry, "withAltGr", with_alt_gr.c_str())); 317 | 318 | std::string with_shift_alt_gr = GetStrFromKeyPress(native_keycode, kShiftKeyModifierMask | kControlKeyModifierMask | kAltKeyModifierMask, keyboard_state, clear_key_code, clear_scan_code); 319 | NAPI_CALL(env, napi_set_named_property_string_utf8(env, entry, "withShiftAltGr", with_shift_alt_gr.c_str())); 320 | 321 | NAPI_CALL(env, napi_set_named_property(env, result, code, entry)); 322 | } 323 | return result; 324 | } 325 | 326 | std::string GetStringRegKey(std::string path, std::string name) { 327 | std::string result = ""; 328 | 329 | HKEY hKey; 330 | if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, path.c_str(), 0, KEY_READ, &hKey)) { 331 | return result; 332 | } 333 | 334 | char szBuffer[512]; 335 | DWORD dwBufferSize = sizeof(szBuffer); 336 | 337 | if (ERROR_SUCCESS == RegQueryValueEx(hKey, name.c_str(), 0, NULL, (LPBYTE)szBuffer, &dwBufferSize)) { 338 | result = szBuffer; 339 | } 340 | 341 | RegCloseKey(hKey); 342 | 343 | return result; 344 | } 345 | 346 | napi_value GetCurrentKeyboardLayoutImpl(napi_env env, napi_callback_info info) { 347 | UseForegroundKeyboardLayoutScope use_foreground_keyboard_layout; 348 | 349 | char chr_layout_name[KL_NAMELENGTH]; 350 | if (!GetKeyboardLayoutName(chr_layout_name)) { 351 | return napi_fetch_null(env); 352 | } 353 | std::string layout_name = chr_layout_name; 354 | 355 | // https://docs.microsoft.com/windows-hardware/manufacture/desktop/windows-language-pack-default-values 356 | std::string layout_id = GetStringRegKey("System\\CurrentControlSet\\Control\\Keyboard Layouts\\" + layout_name, "Layout Id"); 357 | std::string layout_text = GetStringRegKey("System\\CurrentControlSet\\Control\\Keyboard Layouts\\" + layout_name, "Layout Text"); 358 | 359 | napi_value result; 360 | NAPI_CALL(env, napi_create_object(env, &result)); 361 | NAPI_CALL(env, napi_set_named_property_string_utf8(env, result, "name", layout_name.c_str())); 362 | NAPI_CALL(env, napi_set_named_property_string_utf8(env, result, "id", layout_id.c_str())); 363 | NAPI_CALL(env, napi_set_named_property_string_utf8(env, result, "text", layout_text.c_str())); 364 | return result; 365 | } 366 | 367 | class TfInputListener : public ITfInputProcessorProfileActivationSink { 368 | private: 369 | NotificationCallbackData *data_; 370 | ULONG ref_count_; 371 | ITfSource *source_; 372 | DWORD cookie_; 373 | 374 | public: 375 | explicit TfInputListener(NotificationCallbackData *data) { 376 | data_ = data; 377 | ref_count_ = 1; 378 | source_ = NULL; 379 | cookie_ = TF_INVALID_COOKIE; 380 | } 381 | 382 | void StartListening() { 383 | HRESULT hr; 384 | 385 | ITfThreadMgr* thread_mgr; 386 | hr = CoCreateInstance(CLSID_TF_ThreadMgr, NULL, CLSCTX_INPROC_SERVER, IID_ITfThreadMgr, (void**)&thread_mgr); 387 | if (!SUCCEEDED(hr)) { 388 | printf("native-keymap: Could not create ITfThreadMgr.\n"); 389 | return; 390 | } 391 | 392 | hr = thread_mgr->QueryInterface(IID_ITfSource, (LPVOID*)&source_); 393 | if (!SUCCEEDED(hr)) { 394 | printf("native-keymap: Could not obtain ITfSource.\n"); 395 | thread_mgr->Release(); 396 | return; 397 | } 398 | 399 | hr = source_->AdviseSink(IID_ITfInputProcessorProfileActivationSink, 400 | static_cast(this), 401 | &cookie_); 402 | 403 | if (!SUCCEEDED(hr)) { 404 | printf("native-keymap: Could not register ITfInputProcessorProfileActivationSink.\n"); 405 | } 406 | thread_mgr->Release(); 407 | } 408 | 409 | void StopListening() { 410 | if (source_ != NULL) { 411 | if (cookie_ != TF_INVALID_COOKIE) { 412 | source_->UnadviseSink(cookie_); 413 | cookie_ = TF_INVALID_COOKIE; 414 | } 415 | source_->Release(); 416 | source_ = NULL; 417 | } 418 | } 419 | 420 | virtual ~TfInputListener() { 421 | this->StopListening(); 422 | } 423 | 424 | virtual HRESULT STDMETHODCALLTYPE OnActivated( 425 | /* [in] */ DWORD dwProfileType, 426 | /* [in] */ LANGID langid, 427 | /* [in] */ __RPC__in REFCLSID clsid, 428 | /* [in] */ __RPC__in REFGUID catid, 429 | /* [in] */ __RPC__in REFGUID guidProfile, 430 | /* [in] */ HKL hkl, 431 | /* [in] */ DWORD dwFlags) override { 432 | 433 | InvokeNotificationCallback(data_); 434 | return S_OK; 435 | } 436 | 437 | // IUnknown methods 438 | ULONG STDMETHODCALLTYPE AddRef() override { 439 | return InterlockedIncrement(&ref_count_); 440 | } 441 | 442 | ULONG STDMETHODCALLTYPE Release() override { 443 | ULONG newCount = InterlockedDecrement(&ref_count_); 444 | if (0 == newCount) { 445 | delete this; 446 | } 447 | return newCount; 448 | } 449 | 450 | virtual HRESULT STDMETHODCALLTYPE QueryInterface(IID const& riid, void** ppvObject) override { 451 | if (__uuidof(IUnknown) == riid || __uuidof(ITfInputProcessorProfileActivationSink) == riid) { 452 | *ppvObject = this; 453 | this->AddRef(); 454 | return S_OK; 455 | } 456 | *ppvObject = nullptr; 457 | return E_FAIL; 458 | } 459 | }; 460 | 461 | void RegisterKeyboardLayoutChangeListenerImpl(NotificationCallbackData *data) { 462 | TfInputListener* listener = new TfInputListener(data); 463 | listener->StartListening(); 464 | data->listener = listener; 465 | } 466 | 467 | void DisposeKeyboardLayoutChangeListenerImpl(NotificationCallbackData *data) { 468 | TfInputListener* listener = static_cast(data->listener); 469 | listener->Release(); 470 | } 471 | 472 | napi_value IsISOKeyboardImpl(napi_env env, napi_callback_info info) { 473 | return napi_fetch_undefined(env); 474 | } 475 | 476 | } // namespace vscode_keyboard 477 | -------------------------------------------------------------------------------- /src/keyboard_x.cc: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | #include "keymapping.h" 7 | #include "string_conversion.h" 8 | #include "common.h" 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "../deps/chromium/macros.h" 16 | #include "../deps/chromium/x/keysym_to_unicode.h" 17 | 18 | typedef struct _XDisplay XDisplay; 19 | 20 | namespace { 21 | 22 | class KeyModifierMaskToXModifierMask { 23 | public: 24 | static KeyModifierMaskToXModifierMask& GetInstance() { 25 | static KeyModifierMaskToXModifierMask instance; 26 | return instance; 27 | } 28 | 29 | void Initialize(Display* display) { 30 | alt_modifier_ = 0; 31 | meta_modifier_ = 0; 32 | num_lock_modifier_ = 0; 33 | mode_switch_modifier_ = 0; 34 | level3_modifier_ = 0; // AltGr is often mapped to the level3 modifier 35 | level5_modifier_ = 0; // AltGr is mapped to the level5 modifier in the Neo layout family 36 | effective_group_index_ = 0; 37 | 38 | if (!display) { 39 | return; 40 | } 41 | 42 | // See https://www.x.org/releases/X11R7.6/doc/libX11/specs/XKB/xkblib.html#determining_keyboard_state 43 | XkbStateRec xkb_state; 44 | XkbGetState(display, XkbUseCoreKbd, &xkb_state); 45 | effective_group_index_ = xkb_state.group; 46 | 47 | XModifierKeymap* mod_map = XGetModifierMapping(display); 48 | int max_mod_keys = mod_map->max_keypermod; 49 | for (int mod_index = 0; mod_index <= 8; ++mod_index) { 50 | for (int key_index = 0; key_index < max_mod_keys; ++key_index) { 51 | int key = mod_map->modifiermap[mod_index * max_mod_keys + key_index]; 52 | if (!key) { 53 | continue; 54 | } 55 | 56 | int keysym = XkbKeycodeToKeysym(display, key, 0, 0); 57 | if (!keysym) { 58 | continue; 59 | } 60 | 61 | if (keysym == XK_Alt_L || keysym == XK_Alt_R) { 62 | alt_modifier_ = 1 << mod_index; 63 | } 64 | if (keysym == XK_Mode_switch) { 65 | mode_switch_modifier_ = 1 << mod_index; 66 | } 67 | if (keysym == XK_Meta_L || keysym == XK_Super_L || keysym == XK_Meta_R || keysym == XK_Super_R) { 68 | meta_modifier_ = 1 << mod_index; 69 | } 70 | if (keysym == XK_Num_Lock) { 71 | num_lock_modifier_ = 1 << mod_index; 72 | } 73 | if (keysym == XK_ISO_Level3_Shift) { 74 | level3_modifier_ = 1 << mod_index; 75 | } 76 | if (keysym == XK_ISO_Level5_Shift) { 77 | level5_modifier_ = 1 << mod_index; 78 | } 79 | } 80 | } 81 | 82 | XFreeModifiermap(mod_map); 83 | } 84 | 85 | int XStateFromKeyMod(int keyMod) { 86 | int x_modifier = 0; 87 | 88 | // Ctrl + Alt => AltGr 89 | if (keyMod & kControlKeyModifierMask && keyMod & kAltKeyModifierMask) { 90 | x_modifier |= mode_switch_modifier_;//alt_r_modifier; 91 | } else if (keyMod & kControlKeyModifierMask) { 92 | x_modifier |= ControlMask; 93 | } else if (keyMod & kAltKeyModifierMask) { 94 | x_modifier |= alt_modifier_; 95 | } 96 | 97 | if (keyMod & kShiftKeyModifierMask) { 98 | x_modifier |= ShiftMask; 99 | } 100 | 101 | if (keyMod & kMetaKeyModifierMask) { 102 | x_modifier |= meta_modifier_; 103 | } 104 | 105 | if (keyMod & kNumLockKeyModifierMask) { 106 | x_modifier |= num_lock_modifier_; 107 | } 108 | 109 | if (keyMod & kLevel3KeyModifierMask) { 110 | x_modifier |= level3_modifier_; 111 | } 112 | 113 | if (keyMod & kLevel5KeyModifierMask) { 114 | x_modifier |= level5_modifier_; 115 | } 116 | 117 | // See https://www.x.org/releases/X11R7.6/doc/libX11/specs/XKB/xkblib.html#xkb_state_to_core_protocol_state_transformation 118 | x_modifier |= (effective_group_index_ << 13); 119 | 120 | return x_modifier; 121 | } 122 | 123 | private: 124 | KeyModifierMaskToXModifierMask() { 125 | Initialize(NULL); 126 | } 127 | 128 | int alt_modifier_; 129 | int meta_modifier_; 130 | int num_lock_modifier_; 131 | int mode_switch_modifier_; 132 | int level3_modifier_; 133 | int level5_modifier_; 134 | int effective_group_index_; 135 | 136 | KeyModifierMaskToXModifierMask(const KeyModifierMaskToXModifierMask&) = delete; 137 | KeyModifierMaskToXModifierMask& operator=(const KeyModifierMaskToXModifierMask&) = delete; 138 | }; 139 | 140 | std::string GetStrFromXEvent(const XEvent* xev) { 141 | const XKeyEvent* xkey = &xev->xkey; 142 | KeySym keysym = XK_VoidSymbol; 143 | XLookupString(const_cast(xkey), NULL, 0, &keysym, NULL); 144 | uint16_t character = ui::GetUnicodeCharacterFromXKeySym(keysym); 145 | 146 | if (!character) 147 | return std::string(); 148 | 149 | wchar_t value = character; 150 | 151 | return vscode_keyboard::UTF16toUTF8(&value, 1); 152 | } 153 | 154 | } // namespace 155 | 156 | 157 | namespace vscode_keyboard { 158 | 159 | #define DOM_CODE(usb, evdev, xkb, win, mac, code, id) {usb, xkb, code} 160 | #define DOM_CODE_DECLARATION const KeycodeMapEntry usb_keycode_map[] = 161 | #include "../deps/chromium/dom_code_data.inc" 162 | #undef DOM_CODE 163 | #undef DOM_CODE_DECLARATION 164 | 165 | napi_value GetKeyMapImpl(napi_env env, napi_callback_info info) { 166 | 167 | napi_value result; 168 | NAPI_CALL(env, napi_create_object(env, &result)); 169 | 170 | Display *display; 171 | if (!(display = XOpenDisplay(""))) { 172 | return result; 173 | } 174 | 175 | XEvent event; 176 | memset(&event, 0, sizeof(XEvent)); 177 | XKeyEvent* key_event = &event.xkey; 178 | key_event->display = display; 179 | key_event->type = KeyPress; 180 | 181 | KeyModifierMaskToXModifierMask *mask_provider = &KeyModifierMaskToXModifierMask::GetInstance(); 182 | mask_provider->Initialize(display); 183 | 184 | size_t cnt = sizeof(usb_keycode_map) / sizeof(usb_keycode_map[0]); 185 | 186 | for (size_t i = 0; i < cnt; ++i) { 187 | const char *code = usb_keycode_map[i].code; 188 | int native_keycode = usb_keycode_map[i].native_keycode; 189 | 190 | if (!code || native_keycode <= 0) { 191 | continue; 192 | } 193 | 194 | napi_value entry; 195 | NAPI_CALL(env, napi_create_object(env, &entry)); 196 | 197 | key_event->keycode = native_keycode; 198 | { 199 | key_event->state = mask_provider->XStateFromKeyMod(0); 200 | std::string value = GetStrFromXEvent(&event); 201 | NAPI_CALL(env, napi_set_named_property_string_utf8(env, entry, "value", value.c_str())); 202 | } 203 | 204 | { 205 | key_event->state = mask_provider->XStateFromKeyMod(kShiftKeyModifierMask); 206 | std::string with_shift = GetStrFromXEvent(&event); 207 | NAPI_CALL(env, napi_set_named_property_string_utf8(env, entry, "withShift", with_shift.c_str())); 208 | } 209 | 210 | { 211 | key_event->state = mask_provider->XStateFromKeyMod(kLevel3KeyModifierMask); 212 | std::string with_alt_gr = GetStrFromXEvent(&event); 213 | NAPI_CALL(env, napi_set_named_property_string_utf8(env, entry, "withAltGr", with_alt_gr.c_str())); 214 | } 215 | 216 | { 217 | key_event->state = mask_provider->XStateFromKeyMod(kShiftKeyModifierMask | kLevel3KeyModifierMask); 218 | std::string with_shift_alt_gr = GetStrFromXEvent(&event); 219 | NAPI_CALL(env, napi_set_named_property_string_utf8(env, entry, "withShiftAltGr", with_shift_alt_gr.c_str())); 220 | } 221 | 222 | { 223 | // level 5 is important for the Neo layout family 224 | key_event->state = mask_provider->XStateFromKeyMod(kLevel5KeyModifierMask); 225 | std::string with_level5 = GetStrFromXEvent(&event); 226 | NAPI_CALL(env, napi_set_named_property_string_utf8(env, entry, "withLevel5", with_level5.c_str())); 227 | } 228 | 229 | { 230 | // level3 + level5 is Level 6 in terms of the Neo layout family. (Shift + level5 has no special meaning.) 231 | key_event->state = mask_provider->XStateFromKeyMod(kLevel3KeyModifierMask | kLevel5KeyModifierMask); 232 | std::string with_level3_level5 = GetStrFromXEvent(&event); 233 | NAPI_CALL(env, napi_set_named_property_string_utf8(env, entry, "withLevel3Level5", with_level3_level5.c_str())); 234 | } 235 | 236 | NAPI_CALL(env, napi_set_named_property(env, result, code, entry)); 237 | } 238 | 239 | XFlush(display); 240 | XCloseDisplay(display); 241 | 242 | return result; 243 | } 244 | 245 | napi_value GetCurrentKeyboardLayoutImpl(napi_env env, napi_callback_info info) { 246 | 247 | napi_value result; 248 | NAPI_CALL(env, napi_get_null(env, &result)); 249 | 250 | Display *display; 251 | if (!(display = XOpenDisplay(""))) { 252 | return result; 253 | } 254 | 255 | // See https://www.x.org/releases/X11R7.6/doc/libX11/specs/XKB/xkblib.html#determining_keyboard_state 256 | XkbStateRec xkb_state; 257 | XkbGetState(display, XkbUseCoreKbd, &xkb_state); 258 | int effective_group_index = xkb_state.group; 259 | 260 | XkbRF_VarDefsRec vdr; 261 | char *tmp = NULL; 262 | int res = XkbRF_GetNamesProp(display, &tmp, &vdr); 263 | if (res) { 264 | NAPI_CALL(env, napi_create_object(env, &result)); 265 | 266 | NAPI_CALL(env, napi_set_named_property_string_utf8(env, result, "model", vdr.model ? vdr.model : "")); 267 | NAPI_CALL(env, napi_set_named_property_int32(env, result, "group", effective_group_index)); 268 | NAPI_CALL(env, napi_set_named_property_string_utf8(env, result, "layout", vdr.layout ? vdr.layout : "")); 269 | NAPI_CALL(env, napi_set_named_property_string_utf8(env, result, "variant", vdr.variant ? vdr.variant : "")); 270 | NAPI_CALL(env, napi_set_named_property_string_utf8(env, result, "options", vdr.options ? vdr.options : "")); 271 | NAPI_CALL(env, napi_set_named_property_string_utf8(env, result, "rules", tmp ? tmp : "")); 272 | } 273 | 274 | XFlush(display); 275 | XCloseDisplay(display); 276 | return result; 277 | } 278 | 279 | typedef struct { 280 | int effective_group_index; 281 | std::string layout; 282 | std::string variant; 283 | } KbState; 284 | 285 | bool KbStatesEqual(KbState *a, KbState *b) { 286 | return ( 287 | a->effective_group_index == b->effective_group_index 288 | && a->layout == b->layout 289 | && a->variant == b->variant 290 | ); 291 | } 292 | 293 | void ReadKbState(Display *display, KbState *dst) { 294 | // See https://www.x.org/releases/X11R7.6/doc/libX11/specs/XKB/xkblib.html#determining_keyboard_state 295 | // Get effective group index 296 | XkbStateRec xkb_state; 297 | XkbGetState(display, XkbUseCoreKbd, &xkb_state); 298 | dst->effective_group_index = xkb_state.group; 299 | 300 | XkbRF_VarDefsRec vdr; 301 | char *tmp = NULL; 302 | int res = XkbRF_GetNamesProp(display, &tmp, &vdr); 303 | if (res) { 304 | dst->layout = (vdr.layout ? vdr.layout : ""); 305 | dst->variant = (vdr.variant ? vdr.variant : ""); 306 | } else { 307 | dst->layout = ""; 308 | dst->variant = ""; 309 | } 310 | } 311 | 312 | static void FlushAndCloseDisplay(void *arg) { 313 | Display *display = static_cast(arg); 314 | XFlush(display); 315 | XCloseDisplay(display); 316 | } 317 | 318 | void* ListenToXEvents(void *arg) { 319 | NotificationCallbackData *data = static_cast(arg); 320 | 321 | Display *display; 322 | if (!(display = XOpenDisplay(""))) { 323 | return NULL; 324 | } 325 | 326 | pthread_cleanup_push(FlushAndCloseDisplay, display); 327 | 328 | int xkblib_major = XkbMajorVersion; 329 | int xkblib_minor = XkbMinorVersion; 330 | if (!XkbLibraryVersion(&xkblib_major, &xkblib_minor)) { 331 | return NULL; 332 | } 333 | 334 | int opcode = 0; 335 | int xkb_base_event_code = 0; 336 | int xkb_base_error_code = 0; 337 | if (!XkbQueryExtension(display, &opcode, &xkb_base_event_code, &xkb_base_error_code, &xkblib_major, &xkblib_minor)) { 338 | return NULL; 339 | } 340 | 341 | // See https://www.x.org/releases/X11R7.6/doc/libX11/specs/XKB/xkblib.html#xkb_event_types 342 | // Listen only to the `XkbStateNotify` event 343 | XkbSelectEvents(display, XkbUseCoreKbd, XkbAllEventsMask, XkbStateNotifyMask); 344 | 345 | KbState last_state; 346 | ReadKbState(display, &last_state); 347 | 348 | XkbEvent event; 349 | KbState current_state; 350 | fd_set in_fds; 351 | struct timeval tv; 352 | int x11_fd = ConnectionNumber(display); 353 | 354 | while (true) { 355 | // See https://stackoverflow.com/a/8592969 which explains 356 | // the technique of waiting for an XEvent with a timeout 357 | 358 | // Create a File Description Set containing x11_fd 359 | FD_ZERO(&in_fds); 360 | FD_SET(x11_fd, &in_fds); 361 | 362 | // Set the timer to 1s. 363 | tv.tv_usec = 0; 364 | tv.tv_sec = 1; 365 | 366 | // Wait for X Event or the timer 367 | select(x11_fd + 1, &in_fds, NULL, NULL, &tv); 368 | 369 | // Handle pending XEvents 370 | while (XPending(display)) { 371 | 372 | XNextEvent(display, &event.core); 373 | 374 | if (event.type == xkb_base_event_code && event.any.xkb_type == XkbStateNotify) { 375 | ReadKbState(display, ¤t_state); 376 | // printf("current state: %d | %s | %s\n", current_state.effective_group_index, current_state.layout.c_str(), current_state.variant.c_str()); 377 | if (!KbStatesEqual(&last_state, ¤t_state)) { 378 | last_state.effective_group_index = current_state.effective_group_index; 379 | last_state.layout = current_state.layout; 380 | last_state.variant = current_state.variant; 381 | 382 | InvokeNotificationCallback(data); 383 | } 384 | } 385 | } 386 | } 387 | 388 | pthread_cleanup_pop(1); 389 | 390 | return NULL; 391 | } 392 | 393 | void RegisterKeyboardLayoutChangeListenerImpl(NotificationCallbackData *data) { 394 | pthread_create(&data->tid, NULL, &ListenToXEvents, data); 395 | } 396 | 397 | void DisposeKeyboardLayoutChangeListenerImpl(NotificationCallbackData *data) { 398 | pthread_cancel(data->tid); 399 | void *res; 400 | pthread_join(data->tid, &res); 401 | } 402 | 403 | napi_value IsISOKeyboardImpl(napi_env env, napi_callback_info info) { 404 | return napi_fetch_undefined(env); 405 | } 406 | 407 | } // namespace vscode_keyboard 408 | -------------------------------------------------------------------------------- /src/keymapping.cc: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | #define NODE_API_EXPERIMENTAL_NOGC_ENV_OPT_OUT 7 | #include 8 | #include 9 | 10 | #include "keymapping.h" 11 | #include "common.h" 12 | 13 | namespace vscode_keyboard { 14 | 15 | napi_status napi_set_named_property_string_utf8(napi_env env, napi_value object, const char *utf8_name, const char *value) { 16 | napi_value _value; 17 | NAPI_CALL_RETURN_STATUS(env, napi_create_string_utf8(env, value, NAPI_AUTO_LENGTH, &_value)); 18 | NAPI_CALL_RETURN_STATUS(env, napi_set_named_property(env, object, utf8_name, _value)); 19 | return napi_ok; 20 | } 21 | 22 | napi_status napi_set_named_property_int32(napi_env env, napi_value object, const char *utf8_name, int value) { 23 | napi_value _value; 24 | NAPI_CALL_RETURN_STATUS(env, napi_create_int32(env, value, &_value)); 25 | NAPI_CALL_RETURN_STATUS(env, napi_set_named_property(env, object, utf8_name, _value)); 26 | return napi_ok; 27 | } 28 | 29 | napi_value napi_fetch_null(napi_env env) { 30 | napi_value result; 31 | NAPI_CALL(env, napi_get_null(env, &result)); 32 | return result; 33 | } 34 | 35 | napi_value napi_fetch_undefined(napi_env env) { 36 | napi_value result; 37 | NAPI_CALL(env, napi_get_undefined(env, &result)); 38 | return result; 39 | } 40 | 41 | napi_value napi_fetch_boolean(napi_env env, bool value) { 42 | napi_value result; 43 | NAPI_CALL(env, napi_get_boolean(env, value, &result)); 44 | return result; 45 | } 46 | 47 | void InvokeNotificationCallback(NotificationCallbackData *data) { 48 | if (data->tsfn == NULL) { 49 | // This indicates we are in the shutdown phase and the thread safe function has been finalized 50 | return; 51 | } 52 | 53 | // No need to call napi_acquire_threadsafe_function because 54 | // the refcount is set to 1 in the main thread. 55 | napi_call_threadsafe_function(data->tsfn, NULL, napi_tsfn_blocking); 56 | } 57 | 58 | static void NotifyJS(napi_env env, napi_value func, void* context, void* data) { 59 | // env may be NULL if nodejs is shutting down 60 | if (env != NULL) { 61 | napi_value global; 62 | NAPI_CALL_RETURN_VOID(env, napi_get_global(env, &global)); 63 | 64 | std::vector argv; 65 | NAPI_CALL_RETURN_VOID(env, napi_call_function(env, global, func, argv.size(), argv.data(), NULL)); 66 | } 67 | } 68 | 69 | static void FinalizeThreadsafeFunction(napi_env env, void* raw_data, void* hint) { 70 | NotificationCallbackData *data; 71 | napi_get_instance_data(env, (void**)&data); 72 | data->tsfn = NULL; 73 | } 74 | 75 | static void EnvCleanupHook(void *raw_data) { 76 | NotificationCallbackData* data = static_cast(raw_data); 77 | DisposeKeyboardLayoutChangeListenerImpl(data); 78 | } 79 | 80 | napi_value OnDidChangeKeyboardLayoutImpl(napi_env env, napi_callback_info info) { 81 | size_t argc = 2; 82 | napi_value args[2]; 83 | NotificationCallbackData *data; 84 | NAPI_CALL(env, napi_get_instance_data(env, (void**)&data)); 85 | NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); 86 | 87 | NAPI_ASSERT(env, argc == 1, "Wrong number of arguments. Expects a single argument."); 88 | 89 | napi_valuetype valuetype0; 90 | NAPI_CALL(env, napi_typeof(env, args[0], &valuetype0)); 91 | NAPI_ASSERT(env, valuetype0 == napi_function, "Wrong type of arguments. Expects a function as first argument."); 92 | 93 | napi_value func = args[0]; 94 | 95 | napi_value resource_name; 96 | NAPI_CALL(env, napi_create_string_utf8(env, "onDidChangeKeyboardLayoutCallback", NAPI_AUTO_LENGTH, &resource_name)); 97 | 98 | // Convert the callback retrieved from JavaScript into a thread-safe function 99 | napi_threadsafe_function tsfn; 100 | NAPI_CALL(env, napi_create_threadsafe_function(env, func, NULL, resource_name, 0, 1, NULL, 101 | FinalizeThreadsafeFunction, NULL, NotifyJS, 102 | &tsfn)); 103 | data->tsfn = tsfn; 104 | 105 | RegisterKeyboardLayoutChangeListenerImpl(data); 106 | 107 | napi_add_env_cleanup_hook(env, EnvCleanupHook, data); 108 | 109 | return napi_fetch_undefined(env); 110 | } 111 | 112 | void DeleteInstanceData(napi_env env, void *raw_data, void *hint) { 113 | NotificationCallbackData *data = static_cast(raw_data); 114 | delete data; 115 | } 116 | 117 | napi_value Init(napi_env env, napi_value exports) { 118 | NotificationCallbackData *data = new NotificationCallbackData(); 119 | NAPI_CALL(env, napi_set_instance_data(env, data, DeleteInstanceData, NULL)); 120 | 121 | { 122 | napi_value get_key_map_fn; 123 | NAPI_CALL(env, napi_create_function(env, NULL, 0, GetKeyMapImpl, NULL, &get_key_map_fn)); 124 | NAPI_CALL(env, napi_set_named_property(env, exports, "getKeyMap", get_key_map_fn)); 125 | } 126 | { 127 | napi_value get_current_keyboard_layout_fn; 128 | NAPI_CALL(env, napi_create_function(env, NULL, 0, GetCurrentKeyboardLayoutImpl, NULL, &get_current_keyboard_layout_fn)); 129 | NAPI_CALL(env, napi_set_named_property(env, exports, "getCurrentKeyboardLayout", get_current_keyboard_layout_fn)); 130 | } 131 | { 132 | napi_value on_did_change_keyboard_layout_fn; 133 | NAPI_CALL(env, napi_create_function(env, NULL, 0, OnDidChangeKeyboardLayoutImpl, NULL, &on_did_change_keyboard_layout_fn)); 134 | NAPI_CALL(env, napi_set_named_property(env, exports, "onDidChangeKeyboardLayout", on_did_change_keyboard_layout_fn)); 135 | } 136 | { 137 | napi_value is_iso_keyboard_fn; 138 | NAPI_CALL(env, napi_create_function(env, NULL, 0, IsISOKeyboardImpl, NULL, &is_iso_keyboard_fn)); 139 | NAPI_CALL(env, napi_set_named_property(env, exports, "isISOKeyboard", is_iso_keyboard_fn)); 140 | } 141 | 142 | return exports; 143 | } 144 | 145 | NAPI_MODULE(NODE_GYP_MODULE_NAME, Init) 146 | 147 | } // namespace vscode_keyboard 148 | -------------------------------------------------------------------------------- /src/keymapping.h: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | #ifndef KEYMAPPING_H_ 7 | #define KEYMAPPING_H_ 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | #include "../deps/chromium/keyboard_codes.h" 14 | 15 | #if defined(__unix__) 16 | #include 17 | #endif 18 | 19 | namespace vscode_keyboard { 20 | 21 | // This structure is used to define the keycode mapping table. 22 | // It is defined here because the unittests need access to it. 23 | typedef struct { 24 | // USB keycode: 25 | // Upper 16-bits: USB Usage Page. 26 | // Lower 16-bits: USB Usage Id: Assigned ID within this usage page. 27 | uint32_t usb_keycode; 28 | 29 | // Contains one of the following: 30 | // On Linux: XKB scancode 31 | // On Windows: Windows OEM scancode 32 | // On Mac: Mac keycode 33 | int native_keycode; 34 | 35 | // The UIEvents (aka: DOM4Events) |code| value as defined in: 36 | // http://www.w3.org/TR/DOM-Level-3-Events-code/ 37 | const char* code; 38 | } KeycodeMapEntry; 39 | 40 | typedef struct { 41 | #if defined(_WIN32) 42 | void* listener; 43 | #endif 44 | #if defined(__unix__) 45 | pthread_t tid; 46 | #endif 47 | volatile napi_threadsafe_function tsfn; 48 | } NotificationCallbackData; 49 | 50 | napi_value GetKeyMapImpl(napi_env env, napi_callback_info info); 51 | napi_value GetCurrentKeyboardLayoutImpl(napi_env env, napi_callback_info info); 52 | void RegisterKeyboardLayoutChangeListenerImpl(NotificationCallbackData *data); 53 | void DisposeKeyboardLayoutChangeListenerImpl(NotificationCallbackData *data); 54 | napi_value IsISOKeyboardImpl(napi_env env, napi_callback_info info); 55 | 56 | void InvokeNotificationCallback(NotificationCallbackData *data); 57 | napi_status napi_set_named_property_string_utf8(napi_env env, napi_value object, const char *utf8_name, const char *value); 58 | napi_status napi_set_named_property_int32(napi_env env, napi_value object, const char *utf8_name, int value); 59 | napi_value napi_fetch_null(napi_env env); 60 | napi_value napi_fetch_undefined(napi_env env); 61 | napi_value napi_fetch_boolean(napi_env env, bool value); 62 | 63 | } // namespace vscode_keyboard 64 | 65 | #endif // KEYMAPPING_H_ 66 | -------------------------------------------------------------------------------- /src/string_conversion.cc: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | #include "string_conversion.h" 7 | 8 | namespace vscode_keyboard { 9 | 10 | wchar_t conversion_buffer[10]; 11 | 12 | std::string UTF16toUTF8(const wchar_t * in, int length) { 13 | if (length < 10) { 14 | for (int i = 0; i < length; ++i) { 15 | conversion_buffer[i] = in[i]; 16 | } 17 | conversion_buffer[length] = 0; 18 | return UTF16to8(conversion_buffer); 19 | } 20 | 21 | wchar_t *t = new wchar_t[length + 1]; 22 | for (int i = 0; i < length; ++i) { 23 | t[i] = in[i]; 24 | } 25 | t[length] = 0; 26 | std::string result = UTF16to8(t); 27 | delete []t; 28 | 29 | return result; 30 | } 31 | 32 | // http://stackoverflow.com/a/148766 33 | std::string UTF16to8(const wchar_t * in) { 34 | std::string out; 35 | unsigned int codepoint = 0; 36 | for (; *in != 0; ++in) { 37 | if (*in >= 0xd800 && *in <= 0xdbff) { 38 | codepoint = ((*in - 0xd800) << 10) + 0x10000; 39 | } else { 40 | if (*in >= 0xdc00 && *in <= 0xdfff) { 41 | codepoint |= *in - 0xdc00; 42 | } else { 43 | codepoint = *in; 44 | } 45 | 46 | if (codepoint <= 0x7f) { 47 | out.append(1, static_cast(codepoint)); 48 | } else if (codepoint <= 0x7ff) { 49 | out.append(1, static_cast(0xc0 | ((codepoint >> 6) & 0x1f))); 50 | out.append(1, static_cast(0x80 | (codepoint & 0x3f))); 51 | } else if (codepoint <= 0xffff) { 52 | out.append(1, static_cast(0xe0 | ((codepoint >> 12) & 0x0f))); 53 | out.append(1, static_cast(0x80 | ((codepoint >> 6) & 0x3f))); 54 | out.append(1, static_cast(0x80 | (codepoint & 0x3f))); 55 | } else { 56 | out.append(1, static_cast(0xf0 | ((codepoint >> 18) & 0x07))); 57 | out.append(1, static_cast(0x80 | ((codepoint >> 12) & 0x3f))); 58 | out.append(1, static_cast(0x80 | ((codepoint >> 6) & 0x3f))); 59 | out.append(1, static_cast(0x80 | (codepoint & 0x3f))); 60 | } 61 | codepoint = 0; 62 | } 63 | } 64 | return out; 65 | } 66 | 67 | } // namespace vscode_keyboard 68 | -------------------------------------------------------------------------------- /src/string_conversion.h: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | #ifndef STRING_CONVERSION_H_ 7 | #define STRING_CONVERSION_H_ 8 | 9 | #include 10 | 11 | namespace vscode_keyboard { 12 | 13 | std::string UTF16to8(const wchar_t * in); 14 | std::string UTF16toUTF8(const wchar_t * in, int length); 15 | 16 | } // namespace vscode_keyboard 17 | 18 | #endif // STRING_CONVERSION_H_ 19 | -------------------------------------------------------------------------------- /test/linux/de_ch.txt: -------------------------------------------------------------------------------- 1 | 2 | > native-keymap@2.2.0 test /home/max/dev/node-native-keymap 3 | > node test/test.js 4 | 5 | getCurrentKeyboardLayout: { model: 'pc105', 6 | layout: 'ch', 7 | variant: '', 8 | options: '', 9 | rules: 'evdev' } 10 | ------------- 11 | getKeyMap: { Sleep: 12 | { value: '', 13 | withShift: '', 14 | withAltGr: '', 15 | withShiftAltGr: '', 16 | withLevel5: '', 17 | withLevel3Level5: '' }, 18 | WakeUp: 19 | { value: '', 20 | withShift: '', 21 | withAltGr: '', 22 | withShiftAltGr: '', 23 | withLevel5: '', 24 | withLevel3Level5: '' }, 25 | KeyA: 26 | { value: 'a', 27 | withShift: 'A', 28 | withAltGr: 'æ', 29 | withShiftAltGr: 'Æ', 30 | withLevel5: 'a', 31 | withLevel3Level5: 'æ' }, 32 | KeyB: 33 | { value: 'b', 34 | withShift: 'B', 35 | withAltGr: '”', 36 | withShiftAltGr: '’', 37 | withLevel5: 'b', 38 | withLevel3Level5: '”' }, 39 | KeyC: 40 | { value: 'c', 41 | withShift: 'C', 42 | withAltGr: '¢', 43 | withShiftAltGr: '©', 44 | withLevel5: 'c', 45 | withLevel3Level5: '¢' }, 46 | KeyD: 47 | { value: 'd', 48 | withShift: 'D', 49 | withAltGr: 'ð', 50 | withShiftAltGr: 'Ð', 51 | withLevel5: 'd', 52 | withLevel3Level5: 'ð' }, 53 | KeyE: 54 | { value: 'e', 55 | withShift: 'E', 56 | withAltGr: '€', 57 | withShiftAltGr: 'E', 58 | withLevel5: 'e', 59 | withLevel3Level5: '€' }, 60 | KeyF: 61 | { value: 'f', 62 | withShift: 'F', 63 | withAltGr: 'đ', 64 | withShiftAltGr: 'ª', 65 | withLevel5: 'f', 66 | withLevel3Level5: 'đ' }, 67 | KeyG: 68 | { value: 'g', 69 | withShift: 'G', 70 | withAltGr: 'ŋ', 71 | withShiftAltGr: 'Ŋ', 72 | withLevel5: 'g', 73 | withLevel3Level5: 'ŋ' }, 74 | KeyH: 75 | { value: 'h', 76 | withShift: 'H', 77 | withAltGr: 'ħ', 78 | withShiftAltGr: 'Ħ', 79 | withLevel5: 'h', 80 | withLevel3Level5: 'ħ' }, 81 | KeyI: 82 | { value: 'i', 83 | withShift: 'I', 84 | withAltGr: '→', 85 | withShiftAltGr: 'ı', 86 | withLevel5: 'i', 87 | withLevel3Level5: '→' }, 88 | KeyJ: 89 | { value: 'j', 90 | withShift: 'J', 91 | withAltGr: '̉', 92 | withShiftAltGr: '̛', 93 | withLevel5: 'j', 94 | withLevel3Level5: '̉' }, 95 | KeyK: 96 | { value: 'k', 97 | withShift: 'K', 98 | withAltGr: 'ĸ', 99 | withShiftAltGr: '&', 100 | withLevel5: 'k', 101 | withLevel3Level5: 'ĸ' }, 102 | KeyL: 103 | { value: 'l', 104 | withShift: 'L', 105 | withAltGr: 'ł', 106 | withShiftAltGr: 'Ł', 107 | withLevel5: 'l', 108 | withLevel3Level5: 'ł' }, 109 | KeyM: 110 | { value: 'm', 111 | withShift: 'M', 112 | withAltGr: 'µ', 113 | withShiftAltGr: 'º', 114 | withLevel5: 'm', 115 | withLevel3Level5: 'µ' }, 116 | KeyN: 117 | { value: 'n', 118 | withShift: 'N', 119 | withAltGr: 'n', 120 | withShiftAltGr: 'N', 121 | withLevel5: 'n', 122 | withLevel3Level5: 'n' }, 123 | KeyO: 124 | { value: 'o', 125 | withShift: 'O', 126 | withAltGr: 'œ', 127 | withShiftAltGr: 'Œ', 128 | withLevel5: 'o', 129 | withLevel3Level5: 'œ' }, 130 | KeyP: 131 | { value: 'p', 132 | withShift: 'P', 133 | withAltGr: 'þ', 134 | withShiftAltGr: 'Þ', 135 | withLevel5: 'p', 136 | withLevel3Level5: 'þ' }, 137 | KeyQ: 138 | { value: 'q', 139 | withShift: 'Q', 140 | withAltGr: '@', 141 | withShiftAltGr: 'Ω', 142 | withLevel5: 'q', 143 | withLevel3Level5: '@' }, 144 | KeyR: 145 | { value: 'r', 146 | withShift: 'R', 147 | withAltGr: '¶', 148 | withShiftAltGr: '®', 149 | withLevel5: 'r', 150 | withLevel3Level5: '¶' }, 151 | KeyS: 152 | { value: 's', 153 | withShift: 'S', 154 | withAltGr: 'ß', 155 | withShiftAltGr: '§', 156 | withLevel5: 's', 157 | withLevel3Level5: 'ß' }, 158 | KeyT: 159 | { value: 't', 160 | withShift: 'T', 161 | withAltGr: 'ŧ', 162 | withShiftAltGr: 'Ŧ', 163 | withLevel5: 't', 164 | withLevel3Level5: 'ŧ' }, 165 | KeyU: 166 | { value: 'u', 167 | withShift: 'U', 168 | withAltGr: '↓', 169 | withShiftAltGr: '↑', 170 | withLevel5: 'u', 171 | withLevel3Level5: '↓' }, 172 | KeyV: 173 | { value: 'v', 174 | withShift: 'V', 175 | withAltGr: '“', 176 | withShiftAltGr: '‘', 177 | withLevel5: 'v', 178 | withLevel3Level5: '“' }, 179 | KeyW: 180 | { value: 'w', 181 | withShift: 'W', 182 | withAltGr: 'ł', 183 | withShiftAltGr: 'Ł', 184 | withLevel5: 'w', 185 | withLevel3Level5: 'ł' }, 186 | KeyX: 187 | { value: 'x', 188 | withShift: 'X', 189 | withAltGr: '»', 190 | withShiftAltGr: '>', 191 | withLevel5: 'x', 192 | withLevel3Level5: '»' }, 193 | KeyY: 194 | { value: 'z', 195 | withShift: 'Z', 196 | withAltGr: '←', 197 | withShiftAltGr: '¥', 198 | withLevel5: 'z', 199 | withLevel3Level5: '←' }, 200 | KeyZ: 201 | { value: 'y', 202 | withShift: 'Y', 203 | withAltGr: '«', 204 | withShiftAltGr: '<', 205 | withLevel5: 'y', 206 | withLevel3Level5: '«' }, 207 | Digit1: 208 | { value: '1', 209 | withShift: '+', 210 | withAltGr: '|', 211 | withShiftAltGr: '¡', 212 | withLevel5: '1', 213 | withLevel3Level5: '|' }, 214 | Digit2: 215 | { value: '2', 216 | withShift: '"', 217 | withAltGr: '@', 218 | withShiftAltGr: '⅛', 219 | withLevel5: '2', 220 | withLevel3Level5: '@' }, 221 | Digit3: 222 | { value: '3', 223 | withShift: '*', 224 | withAltGr: '#', 225 | withShiftAltGr: '£', 226 | withLevel5: '3', 227 | withLevel3Level5: '#' }, 228 | Digit4: 229 | { value: '4', 230 | withShift: 'ç', 231 | withAltGr: '¼', 232 | withShiftAltGr: '$', 233 | withLevel5: '4', 234 | withLevel3Level5: '¼' }, 235 | Digit5: 236 | { value: '5', 237 | withShift: '%', 238 | withAltGr: '½', 239 | withShiftAltGr: '⅜', 240 | withLevel5: '5', 241 | withLevel3Level5: '½' }, 242 | Digit6: 243 | { value: '6', 244 | withShift: '&', 245 | withAltGr: '¬', 246 | withShiftAltGr: '⅝', 247 | withLevel5: '6', 248 | withLevel3Level5: '¬' }, 249 | Digit7: 250 | { value: '7', 251 | withShift: '/', 252 | withAltGr: '|', 253 | withShiftAltGr: '⅞', 254 | withLevel5: '7', 255 | withLevel3Level5: '|' }, 256 | Digit8: 257 | { value: '8', 258 | withShift: '(', 259 | withAltGr: '¢', 260 | withShiftAltGr: '™', 261 | withLevel5: '8', 262 | withLevel3Level5: '¢' }, 263 | Digit9: 264 | { value: '9', 265 | withShift: ')', 266 | withAltGr: ']', 267 | withShiftAltGr: '±', 268 | withLevel5: '9', 269 | withLevel3Level5: ']' }, 270 | Digit0: 271 | { value: '0', 272 | withShift: '=', 273 | withAltGr: '}', 274 | withShiftAltGr: '°', 275 | withLevel5: '0', 276 | withLevel3Level5: '}' }, 277 | Enter: 278 | { value: '\r', 279 | withShift: '\r', 280 | withAltGr: '\r', 281 | withShiftAltGr: '\r', 282 | withLevel5: '\r', 283 | withLevel3Level5: '\r' }, 284 | Escape: 285 | { value: '\u001b', 286 | withShift: '\u001b', 287 | withAltGr: '\u001b', 288 | withShiftAltGr: '\u001b', 289 | withLevel5: '\u001b', 290 | withLevel3Level5: '\u001b' }, 291 | Backspace: 292 | { value: '\b', 293 | withShift: '\b', 294 | withAltGr: '\b', 295 | withShiftAltGr: '\b', 296 | withLevel5: '\b', 297 | withLevel3Level5: '\b' }, 298 | Tab: 299 | { value: '\t', 300 | withShift: '', 301 | withAltGr: '\t', 302 | withShiftAltGr: '', 303 | withLevel5: '\t', 304 | withLevel3Level5: '\t' }, 305 | Space: 306 | { value: ' ', 307 | withShift: ' ', 308 | withAltGr: ' ', 309 | withShiftAltGr: ' ', 310 | withLevel5: ' ', 311 | withLevel3Level5: ' ' }, 312 | Minus: 313 | { value: '\'', 314 | withShift: '?', 315 | withAltGr: '́', 316 | withShiftAltGr: '¿', 317 | withLevel5: '\'', 318 | withLevel3Level5: '́' }, 319 | Equal: 320 | { value: '̂', 321 | withShift: '̀', 322 | withAltGr: '̃', 323 | withShiftAltGr: '̨', 324 | withLevel5: '̂', 325 | withLevel3Level5: '̃' }, 326 | BracketLeft: 327 | { value: 'ü', 328 | withShift: 'è', 329 | withAltGr: '[', 330 | withShiftAltGr: '̊', 331 | withLevel5: 'ü', 332 | withLevel3Level5: '[' }, 333 | BracketRight: 334 | { value: '̈', 335 | withShift: '!', 336 | withAltGr: ']', 337 | withShiftAltGr: '̄', 338 | withLevel5: '̈', 339 | withLevel3Level5: ']' }, 340 | Backslash: 341 | { value: '$', 342 | withShift: '£', 343 | withAltGr: '}', 344 | withShiftAltGr: '̆', 345 | withLevel5: '$', 346 | withLevel3Level5: '}' }, 347 | Semicolon: 348 | { value: 'ö', 349 | withShift: 'é', 350 | withAltGr: '́', 351 | withShiftAltGr: '̋', 352 | withLevel5: 'ö', 353 | withLevel3Level5: '́' }, 354 | Quote: 355 | { value: 'ä', 356 | withShift: 'à', 357 | withAltGr: '{', 358 | withShiftAltGr: '̌', 359 | withLevel5: 'ä', 360 | withLevel3Level5: '{' }, 361 | Backquote: 362 | { value: '§', 363 | withShift: '°', 364 | withAltGr: '¬', 365 | withShiftAltGr: '¬', 366 | withLevel5: '§', 367 | withLevel3Level5: '¬' }, 368 | Comma: 369 | { value: ',', 370 | withShift: ';', 371 | withAltGr: '─', 372 | withShiftAltGr: '×', 373 | withLevel5: ',', 374 | withLevel3Level5: '─' }, 375 | Period: 376 | { value: '.', 377 | withShift: ':', 378 | withAltGr: '·', 379 | withShiftAltGr: '÷', 380 | withLevel5: '.', 381 | withLevel3Level5: '·' }, 382 | Slash: 383 | { value: '-', 384 | withShift: '_', 385 | withAltGr: '̣', 386 | withShiftAltGr: '̇', 387 | withLevel5: '-', 388 | withLevel3Level5: '̣' }, 389 | CapsLock: 390 | { value: '', 391 | withShift: '', 392 | withAltGr: '', 393 | withShiftAltGr: '', 394 | withLevel5: '', 395 | withLevel3Level5: '' }, 396 | F1: 397 | { value: '', 398 | withShift: '', 399 | withAltGr: '', 400 | withShiftAltGr: '', 401 | withLevel5: '', 402 | withLevel3Level5: '' }, 403 | F2: 404 | { value: '', 405 | withShift: '', 406 | withAltGr: '', 407 | withShiftAltGr: '', 408 | withLevel5: '', 409 | withLevel3Level5: '' }, 410 | F3: 411 | { value: '', 412 | withShift: '', 413 | withAltGr: '', 414 | withShiftAltGr: '', 415 | withLevel5: '', 416 | withLevel3Level5: '' }, 417 | F4: 418 | { value: '', 419 | withShift: '', 420 | withAltGr: '', 421 | withShiftAltGr: '', 422 | withLevel5: '', 423 | withLevel3Level5: '' }, 424 | F5: 425 | { value: '', 426 | withShift: '', 427 | withAltGr: '', 428 | withShiftAltGr: '', 429 | withLevel5: '', 430 | withLevel3Level5: '' }, 431 | F6: 432 | { value: '', 433 | withShift: '', 434 | withAltGr: '', 435 | withShiftAltGr: '', 436 | withLevel5: '', 437 | withLevel3Level5: '' }, 438 | F7: 439 | { value: '', 440 | withShift: '', 441 | withAltGr: '', 442 | withShiftAltGr: '', 443 | withLevel5: '', 444 | withLevel3Level5: '' }, 445 | F8: 446 | { value: '', 447 | withShift: '', 448 | withAltGr: '', 449 | withShiftAltGr: '', 450 | withLevel5: '', 451 | withLevel3Level5: '' }, 452 | F9: 453 | { value: '', 454 | withShift: '', 455 | withAltGr: '', 456 | withShiftAltGr: '', 457 | withLevel5: '', 458 | withLevel3Level5: '' }, 459 | F10: 460 | { value: '', 461 | withShift: '', 462 | withAltGr: '', 463 | withShiftAltGr: '', 464 | withLevel5: '', 465 | withLevel3Level5: '' }, 466 | F11: 467 | { value: '', 468 | withShift: '', 469 | withAltGr: '', 470 | withShiftAltGr: '', 471 | withLevel5: '', 472 | withLevel3Level5: '' }, 473 | F12: 474 | { value: '', 475 | withShift: '', 476 | withAltGr: '', 477 | withShiftAltGr: '', 478 | withLevel5: '', 479 | withLevel3Level5: '' }, 480 | PrintScreen: 481 | { value: '', 482 | withShift: '', 483 | withAltGr: '', 484 | withShiftAltGr: '', 485 | withLevel5: '', 486 | withLevel3Level5: '' }, 487 | ScrollLock: 488 | { value: '', 489 | withShift: '', 490 | withAltGr: '', 491 | withShiftAltGr: '', 492 | withLevel5: '', 493 | withLevel3Level5: '' }, 494 | Pause: 495 | { value: '', 496 | withShift: '', 497 | withAltGr: '', 498 | withShiftAltGr: '', 499 | withLevel5: '', 500 | withLevel3Level5: '' }, 501 | Insert: 502 | { value: '', 503 | withShift: '', 504 | withAltGr: '', 505 | withShiftAltGr: '', 506 | withLevel5: '', 507 | withLevel3Level5: '' }, 508 | Home: 509 | { value: '', 510 | withShift: '', 511 | withAltGr: '', 512 | withShiftAltGr: '', 513 | withLevel5: '', 514 | withLevel3Level5: '' }, 515 | PageUp: 516 | { value: '', 517 | withShift: '', 518 | withAltGr: '', 519 | withShiftAltGr: '', 520 | withLevel5: '', 521 | withLevel3Level5: '' }, 522 | Delete: 523 | { value: '', 524 | withShift: '', 525 | withAltGr: '', 526 | withShiftAltGr: '', 527 | withLevel5: '', 528 | withLevel3Level5: '' }, 529 | End: 530 | { value: '', 531 | withShift: '', 532 | withAltGr: '', 533 | withShiftAltGr: '', 534 | withLevel5: '', 535 | withLevel3Level5: '' }, 536 | PageDown: 537 | { value: '', 538 | withShift: '', 539 | withAltGr: '', 540 | withShiftAltGr: '', 541 | withLevel5: '', 542 | withLevel3Level5: '' }, 543 | ArrowRight: 544 | { value: '', 545 | withShift: '', 546 | withAltGr: '', 547 | withShiftAltGr: '', 548 | withLevel5: '', 549 | withLevel3Level5: '' }, 550 | ArrowLeft: 551 | { value: '', 552 | withShift: '', 553 | withAltGr: '', 554 | withShiftAltGr: '', 555 | withLevel5: '', 556 | withLevel3Level5: '' }, 557 | ArrowDown: 558 | { value: '', 559 | withShift: '', 560 | withAltGr: '', 561 | withShiftAltGr: '', 562 | withLevel5: '', 563 | withLevel3Level5: '' }, 564 | ArrowUp: 565 | { value: '', 566 | withShift: '', 567 | withAltGr: '', 568 | withShiftAltGr: '', 569 | withLevel5: '', 570 | withLevel3Level5: '' }, 571 | NumLock: 572 | { value: '', 573 | withShift: '', 574 | withAltGr: '', 575 | withShiftAltGr: '', 576 | withLevel5: '', 577 | withLevel3Level5: '' }, 578 | NumpadDivide: 579 | { value: '/', 580 | withShift: '/', 581 | withAltGr: '/', 582 | withShiftAltGr: '/', 583 | withLevel5: '/', 584 | withLevel3Level5: '/' }, 585 | NumpadMultiply: 586 | { value: '*', 587 | withShift: '*', 588 | withAltGr: '*', 589 | withShiftAltGr: '*', 590 | withLevel5: '*', 591 | withLevel3Level5: '*' }, 592 | NumpadSubtract: 593 | { value: '-', 594 | withShift: '-', 595 | withAltGr: '-', 596 | withShiftAltGr: '-', 597 | withLevel5: '-', 598 | withLevel3Level5: '-' }, 599 | NumpadAdd: 600 | { value: '+', 601 | withShift: '+', 602 | withAltGr: '+', 603 | withShiftAltGr: '+', 604 | withLevel5: '+', 605 | withLevel3Level5: '+' }, 606 | NumpadEnter: 607 | { value: '\r', 608 | withShift: '\r', 609 | withAltGr: '\r', 610 | withShiftAltGr: '\r', 611 | withLevel5: '\r', 612 | withLevel3Level5: '\r' }, 613 | Numpad1: 614 | { value: '', 615 | withShift: '1', 616 | withAltGr: '', 617 | withShiftAltGr: '1', 618 | withLevel5: '', 619 | withLevel3Level5: '' }, 620 | Numpad2: 621 | { value: '', 622 | withShift: '2', 623 | withAltGr: '', 624 | withShiftAltGr: '2', 625 | withLevel5: '', 626 | withLevel3Level5: '' }, 627 | Numpad3: 628 | { value: '', 629 | withShift: '3', 630 | withAltGr: '', 631 | withShiftAltGr: '3', 632 | withLevel5: '', 633 | withLevel3Level5: '' }, 634 | Numpad4: 635 | { value: '', 636 | withShift: '4', 637 | withAltGr: '', 638 | withShiftAltGr: '4', 639 | withLevel5: '', 640 | withLevel3Level5: '' }, 641 | Numpad5: 642 | { value: '', 643 | withShift: '5', 644 | withAltGr: '', 645 | withShiftAltGr: '5', 646 | withLevel5: '', 647 | withLevel3Level5: '' }, 648 | Numpad6: 649 | { value: '', 650 | withShift: '6', 651 | withAltGr: '', 652 | withShiftAltGr: '6', 653 | withLevel5: '', 654 | withLevel3Level5: '' }, 655 | Numpad7: 656 | { value: '', 657 | withShift: '7', 658 | withAltGr: '', 659 | withShiftAltGr: '7', 660 | withLevel5: '', 661 | withLevel3Level5: '' }, 662 | Numpad8: 663 | { value: '', 664 | withShift: '8', 665 | withAltGr: '', 666 | withShiftAltGr: '8', 667 | withLevel5: '', 668 | withLevel3Level5: '' }, 669 | Numpad9: 670 | { value: '', 671 | withShift: '9', 672 | withAltGr: '', 673 | withShiftAltGr: '9', 674 | withLevel5: '', 675 | withLevel3Level5: '' }, 676 | Numpad0: 677 | { value: '', 678 | withShift: '0', 679 | withAltGr: '', 680 | withShiftAltGr: '0', 681 | withLevel5: '', 682 | withLevel3Level5: '' }, 683 | NumpadDecimal: 684 | { value: '', 685 | withShift: '.', 686 | withAltGr: '', 687 | withShiftAltGr: '.', 688 | withLevel5: '', 689 | withLevel3Level5: '' }, 690 | IntlBackslash: 691 | { value: '<', 692 | withShift: '>', 693 | withAltGr: '\\', 694 | withShiftAltGr: '¦', 695 | withLevel5: '<', 696 | withLevel3Level5: '\\' }, 697 | ContextMenu: 698 | { value: '', 699 | withShift: '', 700 | withAltGr: '', 701 | withShiftAltGr: '', 702 | withLevel5: '', 703 | withLevel3Level5: '' }, 704 | Power: 705 | { value: '', 706 | withShift: '', 707 | withAltGr: '', 708 | withShiftAltGr: '', 709 | withLevel5: '', 710 | withLevel3Level5: '' }, 711 | NumpadEqual: 712 | { value: '=', 713 | withShift: '=', 714 | withAltGr: '=', 715 | withShiftAltGr: '=', 716 | withLevel5: '=', 717 | withLevel3Level5: '=' }, 718 | F13: 719 | { value: '', 720 | withShift: '', 721 | withAltGr: '', 722 | withShiftAltGr: '', 723 | withLevel5: '', 724 | withLevel3Level5: '' }, 725 | F14: 726 | { value: '', 727 | withShift: '', 728 | withAltGr: '', 729 | withShiftAltGr: '', 730 | withLevel5: '', 731 | withLevel3Level5: '' }, 732 | F15: 733 | { value: '', 734 | withShift: '', 735 | withAltGr: '', 736 | withShiftAltGr: '', 737 | withLevel5: '', 738 | withLevel3Level5: '' }, 739 | F16: 740 | { value: '', 741 | withShift: '', 742 | withAltGr: '', 743 | withShiftAltGr: '', 744 | withLevel5: '', 745 | withLevel3Level5: '' }, 746 | F17: 747 | { value: '', 748 | withShift: '', 749 | withAltGr: '', 750 | withShiftAltGr: '', 751 | withLevel5: '', 752 | withLevel3Level5: '' }, 753 | F18: 754 | { value: '', 755 | withShift: '', 756 | withAltGr: '', 757 | withShiftAltGr: '', 758 | withLevel5: '', 759 | withLevel3Level5: '' }, 760 | F19: 761 | { value: '', 762 | withShift: '', 763 | withAltGr: '', 764 | withShiftAltGr: '', 765 | withLevel5: '', 766 | withLevel3Level5: '' }, 767 | F20: 768 | { value: '', 769 | withShift: '', 770 | withAltGr: '', 771 | withShiftAltGr: '', 772 | withLevel5: '', 773 | withLevel3Level5: '' }, 774 | F21: 775 | { value: '', 776 | withShift: '', 777 | withAltGr: '', 778 | withShiftAltGr: '', 779 | withLevel5: '', 780 | withLevel3Level5: '' }, 781 | F22: 782 | { value: '', 783 | withShift: '', 784 | withAltGr: '', 785 | withShiftAltGr: '', 786 | withLevel5: '', 787 | withLevel3Level5: '' }, 788 | F23: 789 | { value: '', 790 | withShift: '', 791 | withAltGr: '', 792 | withShiftAltGr: '', 793 | withLevel5: '', 794 | withLevel3Level5: '' }, 795 | F24: 796 | { value: '', 797 | withShift: '', 798 | withAltGr: '', 799 | withShiftAltGr: '', 800 | withLevel5: '', 801 | withLevel3Level5: '' }, 802 | Open: 803 | { value: '', 804 | withShift: '', 805 | withAltGr: '', 806 | withShiftAltGr: '', 807 | withLevel5: '', 808 | withLevel3Level5: '' }, 809 | Help: 810 | { value: '', 811 | withShift: '', 812 | withAltGr: '', 813 | withShiftAltGr: '', 814 | withLevel5: '', 815 | withLevel3Level5: '' }, 816 | Select: 817 | { value: '', 818 | withShift: '', 819 | withAltGr: '', 820 | withShiftAltGr: '', 821 | withLevel5: '', 822 | withLevel3Level5: '' }, 823 | Again: 824 | { value: '', 825 | withShift: '', 826 | withAltGr: '', 827 | withShiftAltGr: '', 828 | withLevel5: '', 829 | withLevel3Level5: '' }, 830 | Undo: 831 | { value: '', 832 | withShift: '', 833 | withAltGr: '', 834 | withShiftAltGr: '', 835 | withLevel5: '', 836 | withLevel3Level5: '' }, 837 | Cut: 838 | { value: '', 839 | withShift: '', 840 | withAltGr: '', 841 | withShiftAltGr: '', 842 | withLevel5: '', 843 | withLevel3Level5: '' }, 844 | Copy: 845 | { value: '', 846 | withShift: '', 847 | withAltGr: '', 848 | withShiftAltGr: '', 849 | withLevel5: '', 850 | withLevel3Level5: '' }, 851 | Paste: 852 | { value: '', 853 | withShift: '', 854 | withAltGr: '', 855 | withShiftAltGr: '', 856 | withLevel5: '', 857 | withLevel3Level5: '' }, 858 | Find: 859 | { value: '', 860 | withShift: '', 861 | withAltGr: '', 862 | withShiftAltGr: '', 863 | withLevel5: '', 864 | withLevel3Level5: '' }, 865 | AudioVolumeMute: 866 | { value: '', 867 | withShift: '', 868 | withAltGr: '', 869 | withShiftAltGr: '', 870 | withLevel5: '', 871 | withLevel3Level5: '' }, 872 | AudioVolumeUp: 873 | { value: '', 874 | withShift: '', 875 | withAltGr: '', 876 | withShiftAltGr: '', 877 | withLevel5: '', 878 | withLevel3Level5: '' }, 879 | AudioVolumeDown: 880 | { value: '', 881 | withShift: '', 882 | withAltGr: '', 883 | withShiftAltGr: '', 884 | withLevel5: '', 885 | withLevel3Level5: '' }, 886 | NumpadComma: 887 | { value: '.', 888 | withShift: '.', 889 | withAltGr: '.', 890 | withShiftAltGr: '.', 891 | withLevel5: '.', 892 | withLevel3Level5: '.' }, 893 | IntlRo: 894 | { value: '', 895 | withShift: '', 896 | withAltGr: '', 897 | withShiftAltGr: '', 898 | withLevel5: '', 899 | withLevel3Level5: '' }, 900 | KanaMode: 901 | { value: '', 902 | withShift: '', 903 | withAltGr: '', 904 | withShiftAltGr: '', 905 | withLevel5: '', 906 | withLevel3Level5: '' }, 907 | IntlYen: 908 | { value: '', 909 | withShift: '', 910 | withAltGr: '', 911 | withShiftAltGr: '', 912 | withLevel5: '', 913 | withLevel3Level5: '' }, 914 | Convert: 915 | { value: '', 916 | withShift: '', 917 | withAltGr: '', 918 | withShiftAltGr: '', 919 | withLevel5: '', 920 | withLevel3Level5: '' }, 921 | NonConvert: 922 | { value: '', 923 | withShift: '', 924 | withAltGr: '', 925 | withShiftAltGr: '', 926 | withLevel5: '', 927 | withLevel3Level5: '' }, 928 | Lang1: 929 | { value: '', 930 | withShift: '', 931 | withAltGr: '', 932 | withShiftAltGr: '', 933 | withLevel5: '', 934 | withLevel3Level5: '' }, 935 | Lang2: 936 | { value: '', 937 | withShift: '', 938 | withAltGr: '', 939 | withShiftAltGr: '', 940 | withLevel5: '', 941 | withLevel3Level5: '' }, 942 | Lang3: 943 | { value: '', 944 | withShift: '', 945 | withAltGr: '', 946 | withShiftAltGr: '', 947 | withLevel5: '', 948 | withLevel3Level5: '' }, 949 | Lang4: 950 | { value: '', 951 | withShift: '', 952 | withAltGr: '', 953 | withShiftAltGr: '', 954 | withLevel5: '', 955 | withLevel3Level5: '' }, 956 | Lang5: 957 | { value: '', 958 | withShift: '', 959 | withAltGr: '', 960 | withShiftAltGr: '', 961 | withLevel5: '', 962 | withLevel3Level5: '' }, 963 | NumpadParenLeft: 964 | { value: '(', 965 | withShift: '(', 966 | withAltGr: '(', 967 | withShiftAltGr: '(', 968 | withLevel5: '(', 969 | withLevel3Level5: '(' }, 970 | NumpadParenRight: 971 | { value: ')', 972 | withShift: ')', 973 | withAltGr: ')', 974 | withShiftAltGr: ')', 975 | withLevel5: ')', 976 | withLevel3Level5: ')' }, 977 | ControlLeft: 978 | { value: '', 979 | withShift: '', 980 | withAltGr: '', 981 | withShiftAltGr: '', 982 | withLevel5: '', 983 | withLevel3Level5: '' }, 984 | ShiftLeft: 985 | { value: '', 986 | withShift: '', 987 | withAltGr: '', 988 | withShiftAltGr: '', 989 | withLevel5: '', 990 | withLevel3Level5: '' }, 991 | AltLeft: 992 | { value: '', 993 | withShift: '', 994 | withAltGr: '', 995 | withShiftAltGr: '', 996 | withLevel5: '', 997 | withLevel3Level5: '' }, 998 | MetaLeft: 999 | { value: '', 1000 | withShift: '', 1001 | withAltGr: '', 1002 | withShiftAltGr: '', 1003 | withLevel5: '', 1004 | withLevel3Level5: '' }, 1005 | ControlRight: 1006 | { value: '', 1007 | withShift: '', 1008 | withAltGr: '', 1009 | withShiftAltGr: '', 1010 | withLevel5: '', 1011 | withLevel3Level5: '' }, 1012 | ShiftRight: 1013 | { value: '', 1014 | withShift: '', 1015 | withAltGr: '', 1016 | withShiftAltGr: '', 1017 | withLevel5: '', 1018 | withLevel3Level5: '' }, 1019 | AltRight: 1020 | { value: '', 1021 | withShift: '', 1022 | withAltGr: '', 1023 | withShiftAltGr: '', 1024 | withLevel5: '', 1025 | withLevel3Level5: '' }, 1026 | MetaRight: 1027 | { value: '', 1028 | withShift: '', 1029 | withAltGr: '', 1030 | withShiftAltGr: '', 1031 | withLevel5: '', 1032 | withLevel3Level5: '' }, 1033 | BrightnessUp: 1034 | { value: '', 1035 | withShift: '', 1036 | withAltGr: '', 1037 | withShiftAltGr: '', 1038 | withLevel5: '', 1039 | withLevel3Level5: '' }, 1040 | BrightnessDown: 1041 | { value: '', 1042 | withShift: '', 1043 | withAltGr: '', 1044 | withShiftAltGr: '', 1045 | withLevel5: '', 1046 | withLevel3Level5: '' }, 1047 | MediaPlay: 1048 | { value: '', 1049 | withShift: '', 1050 | withAltGr: '', 1051 | withShiftAltGr: '', 1052 | withLevel5: '', 1053 | withLevel3Level5: '' }, 1054 | MediaRecord: 1055 | { value: '', 1056 | withShift: '', 1057 | withAltGr: '', 1058 | withShiftAltGr: '', 1059 | withLevel5: '', 1060 | withLevel3Level5: '' }, 1061 | MediaFastForward: 1062 | { value: '', 1063 | withShift: '', 1064 | withAltGr: '', 1065 | withShiftAltGr: '', 1066 | withLevel5: '', 1067 | withLevel3Level5: '' }, 1068 | MediaRewind: 1069 | { value: '', 1070 | withShift: '', 1071 | withAltGr: '', 1072 | withShiftAltGr: '', 1073 | withLevel5: '', 1074 | withLevel3Level5: '' }, 1075 | MediaTrackNext: 1076 | { value: '', 1077 | withShift: '', 1078 | withAltGr: '', 1079 | withShiftAltGr: '', 1080 | withLevel5: '', 1081 | withLevel3Level5: '' }, 1082 | MediaTrackPrevious: 1083 | { value: '', 1084 | withShift: '', 1085 | withAltGr: '', 1086 | withShiftAltGr: '', 1087 | withLevel5: '', 1088 | withLevel3Level5: '' }, 1089 | MediaStop: 1090 | { value: '', 1091 | withShift: '', 1092 | withAltGr: '', 1093 | withShiftAltGr: '', 1094 | withLevel5: '', 1095 | withLevel3Level5: '' }, 1096 | Eject: 1097 | { value: '', 1098 | withShift: '', 1099 | withAltGr: '', 1100 | withShiftAltGr: '', 1101 | withLevel5: '', 1102 | withLevel3Level5: '' }, 1103 | MediaPlayPause: 1104 | { value: '', 1105 | withShift: '', 1106 | withAltGr: '', 1107 | withShiftAltGr: '', 1108 | withLevel5: '', 1109 | withLevel3Level5: '' }, 1110 | MediaSelect: 1111 | { value: '', 1112 | withShift: '', 1113 | withAltGr: '', 1114 | withShiftAltGr: '', 1115 | withLevel5: '', 1116 | withLevel3Level5: '' }, 1117 | LaunchMail: 1118 | { value: '', 1119 | withShift: '', 1120 | withAltGr: '', 1121 | withShiftAltGr: '', 1122 | withLevel5: '', 1123 | withLevel3Level5: '' }, 1124 | LaunchApp2: 1125 | { value: '', 1126 | withShift: '', 1127 | withAltGr: '', 1128 | withShiftAltGr: '', 1129 | withLevel5: '', 1130 | withLevel3Level5: '' }, 1131 | LaunchApp1: 1132 | { value: '', 1133 | withShift: '', 1134 | withAltGr: '', 1135 | withShiftAltGr: '', 1136 | withLevel5: '', 1137 | withLevel3Level5: '' }, 1138 | SelectTask: 1139 | { value: '', 1140 | withShift: '', 1141 | withAltGr: '', 1142 | withShiftAltGr: '', 1143 | withLevel5: '', 1144 | withLevel3Level5: '' }, 1145 | LaunchScreenSaver: 1146 | { value: '', 1147 | withShift: '', 1148 | withAltGr: '', 1149 | withShiftAltGr: '', 1150 | withLevel5: '', 1151 | withLevel3Level5: '' }, 1152 | BrowserSearch: 1153 | { value: '', 1154 | withShift: '', 1155 | withAltGr: '', 1156 | withShiftAltGr: '', 1157 | withLevel5: '', 1158 | withLevel3Level5: '' }, 1159 | BrowserHome: 1160 | { value: '', 1161 | withShift: '', 1162 | withAltGr: '', 1163 | withShiftAltGr: '', 1164 | withLevel5: '', 1165 | withLevel3Level5: '' }, 1166 | BrowserBack: 1167 | { value: '', 1168 | withShift: '', 1169 | withAltGr: '', 1170 | withShiftAltGr: '', 1171 | withLevel5: '', 1172 | withLevel3Level5: '' }, 1173 | BrowserForward: 1174 | { value: '', 1175 | withShift: '', 1176 | withAltGr: '', 1177 | withShiftAltGr: '', 1178 | withLevel5: '', 1179 | withLevel3Level5: '' }, 1180 | BrowserStop: 1181 | { value: '', 1182 | withShift: '', 1183 | withAltGr: '', 1184 | withShiftAltGr: '', 1185 | withLevel5: '', 1186 | withLevel3Level5: '' }, 1187 | BrowserRefresh: 1188 | { value: '', 1189 | withShift: '', 1190 | withAltGr: '', 1191 | withShiftAltGr: '', 1192 | withLevel5: '', 1193 | withLevel3Level5: '' }, 1194 | BrowserFavorites: 1195 | { value: '', 1196 | withShift: '', 1197 | withAltGr: '', 1198 | withShiftAltGr: '', 1199 | withLevel5: '', 1200 | withLevel3Level5: '' }, 1201 | MailReply: 1202 | { value: '', 1203 | withShift: '', 1204 | withAltGr: '', 1205 | withShiftAltGr: '', 1206 | withLevel5: '', 1207 | withLevel3Level5: '' }, 1208 | MailForward: 1209 | { value: '', 1210 | withShift: '', 1211 | withAltGr: '', 1212 | withShiftAltGr: '', 1213 | withLevel5: '', 1214 | withLevel3Level5: '' }, 1215 | MailSend: 1216 | { value: '', 1217 | withShift: '', 1218 | withAltGr: '', 1219 | withShiftAltGr: '', 1220 | withLevel5: '', 1221 | withLevel3Level5: '' } } 1222 | -------------------------------------------------------------------------------- /test/linux/de_neo.txt: -------------------------------------------------------------------------------- 1 | 2 | > native-keymap@2.2.0 test /home/max/dev/node-native-keymap 3 | > node test/test.js 4 | 5 | getCurrentKeyboardLayout: { model: 'pc105', 6 | layout: 'de', 7 | variant: 'neo', 8 | options: '', 9 | rules: 'evdev' } 10 | ------------- 11 | getKeyMap: { Sleep: 12 | { value: '', 13 | withShift: '', 14 | withAltGr: '', 15 | withShiftAltGr: '', 16 | withLevel5: '', 17 | withLevel3Level5: '' }, 18 | WakeUp: 19 | { value: '', 20 | withShift: '', 21 | withAltGr: '', 22 | withShiftAltGr: '', 23 | withLevel5: '', 24 | withLevel3Level5: '' }, 25 | KeyA: 26 | { value: 'u', 27 | withShift: 'U', 28 | withAltGr: '\\', 29 | withShiftAltGr: '', 30 | withLevel5: '', 31 | withLevel3Level5: '⊂' }, 32 | KeyB: 33 | { value: 'z', 34 | withShift: 'Z', 35 | withAltGr: '`', 36 | withShiftAltGr: 'ζ', 37 | withLevel5: '', 38 | withLevel3Level5: 'ℤ' }, 39 | KeyC: 40 | { value: 'ä', 41 | withShift: 'Ä', 42 | withAltGr: '|', 43 | withShiftAltGr: 'η', 44 | withLevel5: '', 45 | withLevel3Level5: 'ℵ' }, 46 | KeyD: 47 | { value: 'a', 48 | withShift: 'A', 49 | withAltGr: '{', 50 | withShiftAltGr: 'α', 51 | withLevel5: '', 52 | withLevel3Level5: '∀' }, 53 | KeyE: 54 | { value: 'l', 55 | withShift: 'L', 56 | withAltGr: '[', 57 | withShiftAltGr: 'λ', 58 | withLevel5: '', 59 | withLevel3Level5: 'Λ' }, 60 | KeyF: 61 | { value: 'e', 62 | withShift: 'E', 63 | withAltGr: '}', 64 | withShiftAltGr: 'ε', 65 | withLevel5: '', 66 | withLevel3Level5: '∃' }, 67 | KeyG: 68 | { value: 'o', 69 | withShift: 'O', 70 | withAltGr: '*', 71 | withShiftAltGr: 'ο', 72 | withLevel5: '', 73 | withLevel3Level5: '∈' }, 74 | KeyH: 75 | { value: 's', 76 | withShift: 'S', 77 | withAltGr: '?', 78 | withShiftAltGr: 'σ', 79 | withLevel5: '¿', 80 | withLevel3Level5: 'Σ' }, 81 | KeyI: 82 | { value: 'g', 83 | withShift: 'G', 84 | withAltGr: '>', 85 | withShiftAltGr: 'γ', 86 | withLevel5: '8', 87 | withLevel3Level5: 'Γ' }, 88 | KeyJ: 89 | { value: 'n', 90 | withShift: 'N', 91 | withAltGr: '(', 92 | withShiftAltGr: 'ν', 93 | withLevel5: '4', 94 | withLevel3Level5: 'ℕ' }, 95 | KeyK: 96 | { value: 'r', 97 | withShift: 'R', 98 | withAltGr: ')', 99 | withShiftAltGr: 'ρ', 100 | withLevel5: '5', 101 | withLevel3Level5: 'ℝ' }, 102 | KeyL: 103 | { value: 't', 104 | withShift: 'T', 105 | withAltGr: '-', 106 | withShiftAltGr: 'τ', 107 | withLevel5: '6', 108 | withLevel3Level5: '∂' }, 109 | KeyM: 110 | { value: 'm', 111 | withShift: 'M', 112 | withAltGr: '%', 113 | withShiftAltGr: 'μ', 114 | withLevel5: '1', 115 | withLevel3Level5: '⇔' }, 116 | KeyN: 117 | { value: 'b', 118 | withShift: 'B', 119 | withAltGr: '+', 120 | withShiftAltGr: 'β', 121 | withLevel5: ':', 122 | withLevel3Level5: '⇐' }, 123 | KeyO: 124 | { value: 'f', 125 | withShift: 'F', 126 | withAltGr: '=', 127 | withShiftAltGr: 'φ', 128 | withLevel5: '9', 129 | withLevel3Level5: 'Φ' }, 130 | KeyP: 131 | { value: 'q', 132 | withShift: 'Q', 133 | withAltGr: '&', 134 | withShiftAltGr: 'ϕ', 135 | withLevel5: '+', 136 | withLevel3Level5: 'ℚ' }, 137 | KeyQ: 138 | { value: 'x', 139 | withShift: 'X', 140 | withAltGr: '…', 141 | withShiftAltGr: 'ξ', 142 | withLevel5: '', 143 | withLevel3Level5: 'Ξ' }, 144 | KeyR: 145 | { value: 'c', 146 | withShift: 'C', 147 | withAltGr: ']', 148 | withShiftAltGr: 'χ', 149 | withLevel5: '', 150 | withLevel3Level5: 'ℂ' }, 151 | KeyS: 152 | { value: 'i', 153 | withShift: 'I', 154 | withAltGr: '/', 155 | withShiftAltGr: 'ι', 156 | withLevel5: '', 157 | withLevel3Level5: '∫' }, 158 | KeyT: 159 | { value: 'w', 160 | withShift: 'W', 161 | withAltGr: '^', 162 | withShiftAltGr: 'ω', 163 | withLevel5: '', 164 | withLevel3Level5: 'Ω' }, 165 | KeyU: 166 | { value: 'h', 167 | withShift: 'H', 168 | withAltGr: '<', 169 | withShiftAltGr: 'ψ', 170 | withLevel5: '7', 171 | withLevel3Level5: 'Ψ' }, 172 | KeyV: 173 | { value: 'p', 174 | withShift: 'P', 175 | withAltGr: '~', 176 | withShiftAltGr: 'π', 177 | withLevel5: '\r', 178 | withLevel3Level5: 'Π' }, 179 | KeyW: 180 | { value: 'v', 181 | withShift: 'V', 182 | withAltGr: '_', 183 | withShiftAltGr: '', 184 | withLevel5: '\b', 185 | withLevel3Level5: '√' }, 186 | KeyX: 187 | { value: 'ö', 188 | withShift: 'Ö', 189 | withAltGr: '$', 190 | withShiftAltGr: 'ϵ', 191 | withLevel5: '\t', 192 | withLevel3Level5: '∩' }, 193 | KeyY: 194 | { value: 'k', 195 | withShift: 'K', 196 | withAltGr: '!', 197 | withShiftAltGr: 'κ', 198 | withLevel5: '¡', 199 | withLevel3Level5: '×' }, 200 | KeyZ: 201 | { value: 'ü', 202 | withShift: 'Ü', 203 | withAltGr: '#', 204 | withShiftAltGr: '', 205 | withLevel5: '\u001b', 206 | withLevel3Level5: '∪' }, 207 | Digit1: 208 | { value: '1', 209 | withShift: '°', 210 | withAltGr: '¹', 211 | withShiftAltGr: '₁', 212 | withLevel5: 'ª', 213 | withLevel3Level5: '¬' }, 214 | Digit2: 215 | { value: '2', 216 | withShift: '§', 217 | withAltGr: '²', 218 | withShiftAltGr: '₂', 219 | withLevel5: 'º', 220 | withLevel3Level5: '∨' }, 221 | Digit3: 222 | { value: '3', 223 | withShift: 'ℓ', 224 | withAltGr: '³', 225 | withShiftAltGr: '₃', 226 | withLevel5: '№', 227 | withLevel3Level5: '∧' }, 228 | Digit4: 229 | { value: '4', 230 | withShift: '»', 231 | withAltGr: '›', 232 | withShiftAltGr: '♀', 233 | withLevel5: '', 234 | withLevel3Level5: '⊥' }, 235 | Digit5: 236 | { value: '5', 237 | withShift: '«', 238 | withAltGr: '‹', 239 | withShiftAltGr: '♂', 240 | withLevel5: '·', 241 | withLevel3Level5: '∡' }, 242 | Digit6: 243 | { value: '6', 244 | withShift: '$', 245 | withAltGr: '¢', 246 | withShiftAltGr: '⚥', 247 | withLevel5: '£', 248 | withLevel3Level5: '∥' }, 249 | Digit7: 250 | { value: '7', 251 | withShift: '€', 252 | withAltGr: '¥', 253 | withShiftAltGr: 'ϰ', 254 | withLevel5: '¤', 255 | withLevel3Level5: '→' }, 256 | Digit8: 257 | { value: '8', 258 | withShift: '„', 259 | withAltGr: '‚', 260 | withShiftAltGr: '⟨', 261 | withLevel5: '\t', 262 | withLevel3Level5: '∞' }, 263 | Digit9: 264 | { value: '9', 265 | withShift: '“', 266 | withAltGr: '‘', 267 | withShiftAltGr: '⟩', 268 | withLevel5: '/', 269 | withLevel3Level5: '∝' }, 270 | Digit0: 271 | { value: '0', 272 | withShift: '”', 273 | withAltGr: '’', 274 | withShiftAltGr: '₀', 275 | withLevel5: '*', 276 | withLevel3Level5: '∅' }, 277 | Enter: 278 | { value: '\r', 279 | withShift: '\r', 280 | withAltGr: '\r', 281 | withShiftAltGr: '\r', 282 | withLevel5: '\r', 283 | withLevel3Level5: '\r' }, 284 | Escape: 285 | { value: '\u001b', 286 | withShift: '\u001b', 287 | withAltGr: '\u001b', 288 | withShiftAltGr: '\u001b', 289 | withLevel5: '\u001b', 290 | withLevel3Level5: '\u001b' }, 291 | Backspace: 292 | { value: '\b', 293 | withShift: '\b', 294 | withAltGr: '\b', 295 | withShiftAltGr: '\b', 296 | withLevel5: '\b', 297 | withLevel3Level5: '\b' }, 298 | Tab: 299 | { value: '\t', 300 | withShift: '', 301 | withAltGr: '', 302 | withShiftAltGr: '', 303 | withLevel5: '', 304 | withLevel3Level5: '' }, 305 | Space: 306 | { value: ' ', 307 | withShift: ' ', 308 | withAltGr: ' ', 309 | withShiftAltGr: ' ', 310 | withLevel5: '0', 311 | withLevel3Level5: ' ' }, 312 | Minus: 313 | { value: '-', 314 | withShift: '—', 315 | withAltGr: '', 316 | withShiftAltGr: '‑', 317 | withLevel5: '-', 318 | withLevel3Level5: '­' }, 319 | Equal: 320 | { value: '̀', 321 | withShift: '̧', 322 | withAltGr: '̊', 323 | withShiftAltGr: '̔', 324 | withLevel5: '̈', 325 | withLevel3Level5: '̄' }, 326 | BracketLeft: 327 | { value: 'ß', 328 | withShift: 'ẞ', 329 | withAltGr: 'ſ', 330 | withShiftAltGr: 'ς', 331 | withLevel5: '−', 332 | withLevel3Level5: '∘' }, 333 | BracketRight: 334 | { value: '́', 335 | withShift: '̃', 336 | withAltGr: '̸', 337 | withShiftAltGr: '̓', 338 | withLevel5: '̋', 339 | withLevel3Level5: '̆' }, 340 | Backslash: 341 | { value: '', 342 | withShift: '', 343 | withAltGr: '', 344 | withShiftAltGr: '', 345 | withLevel5: '', 346 | withLevel3Level5: '' }, 347 | Semicolon: 348 | { value: 'd', 349 | withShift: 'D', 350 | withAltGr: ':', 351 | withShiftAltGr: 'δ', 352 | withLevel5: ',', 353 | withLevel3Level5: 'Δ' }, 354 | Quote: 355 | { value: 'y', 356 | withShift: 'Y', 357 | withAltGr: '@', 358 | withShiftAltGr: 'υ', 359 | withLevel5: '.', 360 | withLevel3Level5: '∇' }, 361 | Backquote: 362 | { value: '̂', 363 | withShift: '̌', 364 | withAltGr: '↻', 365 | withShiftAltGr: '˞', 366 | withLevel5: '̇', 367 | withLevel3Level5: '̣' }, 368 | Comma: 369 | { value: ',', 370 | withShift: '–', 371 | withAltGr: '"', 372 | withShiftAltGr: 'ϱ', 373 | withLevel5: '2', 374 | withLevel3Level5: '⇒' }, 375 | Period: 376 | { value: '.', 377 | withShift: '•', 378 | withAltGr: '\'', 379 | withShiftAltGr: 'ϑ', 380 | withLevel5: '3', 381 | withLevel3Level5: '↦' }, 382 | Slash: 383 | { value: 'j', 384 | withShift: 'J', 385 | withAltGr: ';', 386 | withShiftAltGr: 'θ', 387 | withLevel5: ';', 388 | withLevel3Level5: 'Θ' }, 389 | CapsLock: 390 | { value: '', 391 | withShift: '', 392 | withAltGr: '', 393 | withShiftAltGr: '', 394 | withLevel5: '', 395 | withLevel3Level5: '' }, 396 | F1: 397 | { value: '', 398 | withShift: '', 399 | withAltGr: '', 400 | withShiftAltGr: '', 401 | withLevel5: '', 402 | withLevel3Level5: '' }, 403 | F2: 404 | { value: '', 405 | withShift: '', 406 | withAltGr: '', 407 | withShiftAltGr: '', 408 | withLevel5: '', 409 | withLevel3Level5: '' }, 410 | F3: 411 | { value: '', 412 | withShift: '', 413 | withAltGr: '', 414 | withShiftAltGr: '', 415 | withLevel5: '', 416 | withLevel3Level5: '' }, 417 | F4: 418 | { value: '', 419 | withShift: '', 420 | withAltGr: '', 421 | withShiftAltGr: '', 422 | withLevel5: '', 423 | withLevel3Level5: '' }, 424 | F5: 425 | { value: '', 426 | withShift: '', 427 | withAltGr: '', 428 | withShiftAltGr: '', 429 | withLevel5: '', 430 | withLevel3Level5: '' }, 431 | F6: 432 | { value: '', 433 | withShift: '', 434 | withAltGr: '', 435 | withShiftAltGr: '', 436 | withLevel5: '', 437 | withLevel3Level5: '' }, 438 | F7: 439 | { value: '', 440 | withShift: '', 441 | withAltGr: '', 442 | withShiftAltGr: '', 443 | withLevel5: '', 444 | withLevel3Level5: '' }, 445 | F8: 446 | { value: '', 447 | withShift: '', 448 | withAltGr: '', 449 | withShiftAltGr: '', 450 | withLevel5: '', 451 | withLevel3Level5: '' }, 452 | F9: 453 | { value: '', 454 | withShift: '', 455 | withAltGr: '', 456 | withShiftAltGr: '', 457 | withLevel5: '', 458 | withLevel3Level5: '' }, 459 | F10: 460 | { value: '', 461 | withShift: '', 462 | withAltGr: '', 463 | withShiftAltGr: '', 464 | withLevel5: '', 465 | withLevel3Level5: '' }, 466 | F11: 467 | { value: '', 468 | withShift: '', 469 | withAltGr: '', 470 | withShiftAltGr: '', 471 | withLevel5: '', 472 | withLevel3Level5: '' }, 473 | F12: 474 | { value: '', 475 | withShift: '', 476 | withAltGr: '', 477 | withShiftAltGr: '', 478 | withLevel5: '', 479 | withLevel3Level5: '' }, 480 | PrintScreen: 481 | { value: '', 482 | withShift: '', 483 | withAltGr: '', 484 | withShiftAltGr: '', 485 | withLevel5: '', 486 | withLevel3Level5: '' }, 487 | ScrollLock: 488 | { value: '', 489 | withShift: '', 490 | withAltGr: '', 491 | withShiftAltGr: '', 492 | withLevel5: '', 493 | withLevel3Level5: '' }, 494 | Pause: 495 | { value: '', 496 | withShift: '', 497 | withAltGr: '', 498 | withShiftAltGr: '', 499 | withLevel5: '', 500 | withLevel3Level5: '' }, 501 | Insert: 502 | { value: '', 503 | withShift: '', 504 | withAltGr: '', 505 | withShiftAltGr: '', 506 | withLevel5: '', 507 | withLevel3Level5: '' }, 508 | Home: 509 | { value: '', 510 | withShift: '', 511 | withAltGr: '', 512 | withShiftAltGr: '', 513 | withLevel5: '', 514 | withLevel3Level5: '' }, 515 | PageUp: 516 | { value: '', 517 | withShift: '', 518 | withAltGr: '', 519 | withShiftAltGr: '', 520 | withLevel5: '', 521 | withLevel3Level5: '' }, 522 | Delete: 523 | { value: '', 524 | withShift: '', 525 | withAltGr: '', 526 | withShiftAltGr: '', 527 | withLevel5: '', 528 | withLevel3Level5: '' }, 529 | End: 530 | { value: '', 531 | withShift: '', 532 | withAltGr: '', 533 | withShiftAltGr: '', 534 | withLevel5: '', 535 | withLevel3Level5: '' }, 536 | PageDown: 537 | { value: '', 538 | withShift: '', 539 | withAltGr: '', 540 | withShiftAltGr: '', 541 | withLevel5: '', 542 | withLevel3Level5: '' }, 543 | ArrowRight: 544 | { value: '', 545 | withShift: '', 546 | withAltGr: '', 547 | withShiftAltGr: '', 548 | withLevel5: '', 549 | withLevel3Level5: '' }, 550 | ArrowLeft: 551 | { value: '', 552 | withShift: '', 553 | withAltGr: '', 554 | withShiftAltGr: '', 555 | withLevel5: '', 556 | withLevel3Level5: '' }, 557 | ArrowDown: 558 | { value: '', 559 | withShift: '', 560 | withAltGr: '', 561 | withShiftAltGr: '', 562 | withLevel5: '', 563 | withLevel3Level5: '' }, 564 | ArrowUp: 565 | { value: '', 566 | withShift: '', 567 | withAltGr: '', 568 | withShiftAltGr: '', 569 | withLevel5: '', 570 | withLevel3Level5: '' }, 571 | NumLock: 572 | { value: '\t', 573 | withShift: '', 574 | withAltGr: '=', 575 | withShiftAltGr: '≈', 576 | withLevel5: '≠', 577 | withLevel3Level5: '≡' }, 578 | NumpadDivide: 579 | { value: '/', 580 | withShift: '/', 581 | withAltGr: '÷', 582 | withShiftAltGr: '⌀', 583 | withLevel5: '∕', 584 | withLevel3Level5: '∣' }, 585 | NumpadMultiply: 586 | { value: '*', 587 | withShift: '*', 588 | withAltGr: '⋅', 589 | withShiftAltGr: '⊙', 590 | withLevel5: '×', 591 | withLevel3Level5: '⊗' }, 592 | NumpadSubtract: 593 | { value: '-', 594 | withShift: '-', 595 | withAltGr: '−', 596 | withShiftAltGr: '⊖', 597 | withLevel5: '∖', 598 | withLevel3Level5: '∸' }, 599 | NumpadAdd: 600 | { value: '+', 601 | withShift: '+', 602 | withAltGr: '±', 603 | withShiftAltGr: '⊕', 604 | withLevel5: '∓', 605 | withLevel3Level5: '∔' }, 606 | NumpadEnter: 607 | { value: '\r', 608 | withShift: '\r', 609 | withAltGr: '\r', 610 | withShiftAltGr: '\r', 611 | withLevel5: '\r', 612 | withLevel3Level5: '\r' }, 613 | Numpad1: 614 | { value: '1', 615 | withShift: '♦', 616 | withAltGr: '↔', 617 | withShiftAltGr: '≤', 618 | withLevel5: '', 619 | withLevel3Level5: '⌊' }, 620 | Numpad2: 621 | { value: '2', 622 | withShift: '♥', 623 | withAltGr: '↓', 624 | withShiftAltGr: '∪', 625 | withLevel5: '', 626 | withLevel3Level5: '⋃' }, 627 | Numpad3: 628 | { value: '3', 629 | withShift: '♠', 630 | withAltGr: '⇌', 631 | withShiftAltGr: '≥', 632 | withLevel5: '', 633 | withLevel3Level5: '⌋' }, 634 | Numpad4: 635 | { value: '4', 636 | withShift: '♣', 637 | withAltGr: '←', 638 | withShiftAltGr: '⊂', 639 | withLevel5: '', 640 | withLevel3Level5: '⊆' }, 641 | Numpad5: 642 | { value: '5', 643 | withShift: '€', 644 | withAltGr: ':', 645 | withShiftAltGr: '⊶', 646 | withLevel5: '', 647 | withLevel3Level5: '⊷' }, 648 | Numpad6: 649 | { value: '6', 650 | withShift: '‣', 651 | withAltGr: '→', 652 | withShiftAltGr: '⊃', 653 | withLevel5: '', 654 | withLevel3Level5: '⊇' }, 655 | Numpad7: 656 | { value: '7', 657 | withShift: '✔', 658 | withAltGr: '↕', 659 | withShiftAltGr: '≪', 660 | withLevel5: '', 661 | withLevel3Level5: '⌈' }, 662 | Numpad8: 663 | { value: '8', 664 | withShift: '✘', 665 | withAltGr: '↑', 666 | withShiftAltGr: '∩', 667 | withLevel5: '', 668 | withLevel3Level5: '⋂' }, 669 | Numpad9: 670 | { value: '9', 671 | withShift: '†', 672 | withAltGr: '⃗', 673 | withShiftAltGr: '≫', 674 | withLevel5: '', 675 | withLevel3Level5: '⌉' }, 676 | Numpad0: 677 | { value: '0', 678 | withShift: '␣', 679 | withAltGr: '%', 680 | withShiftAltGr: '‰', 681 | withLevel5: '', 682 | withLevel3Level5: '□' }, 683 | NumpadDecimal: 684 | { value: ',', 685 | withShift: '.', 686 | withAltGr: ',', 687 | withShiftAltGr: '′', 688 | withLevel5: '', 689 | withLevel3Level5: '″' }, 690 | IntlBackslash: 691 | { value: '', 692 | withShift: '', 693 | withAltGr: '', 694 | withShiftAltGr: '', 695 | withLevel5: '', 696 | withLevel3Level5: '' }, 697 | ContextMenu: 698 | { value: '', 699 | withShift: '', 700 | withAltGr: '', 701 | withShiftAltGr: '', 702 | withLevel5: '', 703 | withLevel3Level5: '' }, 704 | Power: 705 | { value: '', 706 | withShift: '', 707 | withAltGr: '', 708 | withShiftAltGr: '', 709 | withLevel5: '', 710 | withLevel3Level5: '' }, 711 | NumpadEqual: 712 | { value: '=', 713 | withShift: '', 714 | withAltGr: '', 715 | withShiftAltGr: '', 716 | withLevel5: '', 717 | withLevel3Level5: '' }, 718 | F13: 719 | { value: '', 720 | withShift: '', 721 | withAltGr: '', 722 | withShiftAltGr: '', 723 | withLevel5: '', 724 | withLevel3Level5: '' }, 725 | F14: 726 | { value: '', 727 | withShift: '', 728 | withAltGr: '', 729 | withShiftAltGr: '', 730 | withLevel5: '', 731 | withLevel3Level5: '' }, 732 | F15: 733 | { value: '', 734 | withShift: '', 735 | withAltGr: '', 736 | withShiftAltGr: '', 737 | withLevel5: '', 738 | withLevel3Level5: '' }, 739 | F16: 740 | { value: '', 741 | withShift: '', 742 | withAltGr: '', 743 | withShiftAltGr: '', 744 | withLevel5: '', 745 | withLevel3Level5: '' }, 746 | F17: 747 | { value: '', 748 | withShift: '', 749 | withAltGr: '', 750 | withShiftAltGr: '', 751 | withLevel5: '', 752 | withLevel3Level5: '' }, 753 | F18: 754 | { value: '', 755 | withShift: '', 756 | withAltGr: '', 757 | withShiftAltGr: '', 758 | withLevel5: '', 759 | withLevel3Level5: '' }, 760 | F19: 761 | { value: '', 762 | withShift: '', 763 | withAltGr: '', 764 | withShiftAltGr: '', 765 | withLevel5: '', 766 | withLevel3Level5: '' }, 767 | F20: 768 | { value: '', 769 | withShift: '', 770 | withAltGr: '', 771 | withShiftAltGr: '', 772 | withLevel5: '', 773 | withLevel3Level5: '' }, 774 | F21: 775 | { value: '', 776 | withShift: '', 777 | withAltGr: '', 778 | withShiftAltGr: '', 779 | withLevel5: '', 780 | withLevel3Level5: '' }, 781 | F22: 782 | { value: '', 783 | withShift: '', 784 | withAltGr: '', 785 | withShiftAltGr: '', 786 | withLevel5: '', 787 | withLevel3Level5: '' }, 788 | F23: 789 | { value: '', 790 | withShift: '', 791 | withAltGr: '', 792 | withShiftAltGr: '', 793 | withLevel5: '', 794 | withLevel3Level5: '' }, 795 | F24: 796 | { value: '', 797 | withShift: '', 798 | withAltGr: '', 799 | withShiftAltGr: '', 800 | withLevel5: '', 801 | withLevel3Level5: '' }, 802 | Open: 803 | { value: '', 804 | withShift: '', 805 | withAltGr: '', 806 | withShiftAltGr: '', 807 | withLevel5: '', 808 | withLevel3Level5: '' }, 809 | Help: 810 | { value: '', 811 | withShift: '', 812 | withAltGr: '', 813 | withShiftAltGr: '', 814 | withLevel5: '', 815 | withLevel3Level5: '' }, 816 | Select: 817 | { value: '', 818 | withShift: '', 819 | withAltGr: '', 820 | withShiftAltGr: '', 821 | withLevel5: '', 822 | withLevel3Level5: '' }, 823 | Again: 824 | { value: '', 825 | withShift: '', 826 | withAltGr: '', 827 | withShiftAltGr: '', 828 | withLevel5: '', 829 | withLevel3Level5: '' }, 830 | Undo: 831 | { value: '', 832 | withShift: '', 833 | withAltGr: '', 834 | withShiftAltGr: '', 835 | withLevel5: '', 836 | withLevel3Level5: '' }, 837 | Cut: 838 | { value: '', 839 | withShift: '', 840 | withAltGr: '', 841 | withShiftAltGr: '', 842 | withLevel5: '', 843 | withLevel3Level5: '' }, 844 | Copy: 845 | { value: '', 846 | withShift: '', 847 | withAltGr: '', 848 | withShiftAltGr: '', 849 | withLevel5: '', 850 | withLevel3Level5: '' }, 851 | Paste: 852 | { value: '', 853 | withShift: '', 854 | withAltGr: '', 855 | withShiftAltGr: '', 856 | withLevel5: '', 857 | withLevel3Level5: '' }, 858 | Find: 859 | { value: '', 860 | withShift: '', 861 | withAltGr: '', 862 | withShiftAltGr: '', 863 | withLevel5: '', 864 | withLevel3Level5: '' }, 865 | AudioVolumeMute: 866 | { value: '', 867 | withShift: '', 868 | withAltGr: '', 869 | withShiftAltGr: '', 870 | withLevel5: '', 871 | withLevel3Level5: '' }, 872 | AudioVolumeUp: 873 | { value: '', 874 | withShift: '', 875 | withAltGr: '', 876 | withShiftAltGr: '', 877 | withLevel5: '', 878 | withLevel3Level5: '' }, 879 | AudioVolumeDown: 880 | { value: '', 881 | withShift: '', 882 | withAltGr: '', 883 | withShiftAltGr: '', 884 | withLevel5: '', 885 | withLevel3Level5: '' }, 886 | NumpadComma: 887 | { value: '.', 888 | withShift: '.', 889 | withAltGr: '.', 890 | withShiftAltGr: '.', 891 | withLevel5: '.', 892 | withLevel3Level5: '.' }, 893 | IntlRo: 894 | { value: '', 895 | withShift: '', 896 | withAltGr: '', 897 | withShiftAltGr: '', 898 | withLevel5: '', 899 | withLevel3Level5: '' }, 900 | KanaMode: 901 | { value: '', 902 | withShift: '', 903 | withAltGr: '', 904 | withShiftAltGr: '', 905 | withLevel5: '', 906 | withLevel3Level5: '' }, 907 | IntlYen: 908 | { value: '', 909 | withShift: '', 910 | withAltGr: '', 911 | withShiftAltGr: '', 912 | withLevel5: '', 913 | withLevel3Level5: '' }, 914 | Convert: 915 | { value: '', 916 | withShift: '', 917 | withAltGr: '', 918 | withShiftAltGr: '', 919 | withLevel5: '', 920 | withLevel3Level5: '' }, 921 | NonConvert: 922 | { value: '', 923 | withShift: '', 924 | withAltGr: '', 925 | withShiftAltGr: '', 926 | withLevel5: '', 927 | withLevel3Level5: '' }, 928 | Lang1: 929 | { value: '', 930 | withShift: '', 931 | withAltGr: '', 932 | withShiftAltGr: '', 933 | withLevel5: '', 934 | withLevel3Level5: '' }, 935 | Lang2: 936 | { value: '', 937 | withShift: '', 938 | withAltGr: '', 939 | withShiftAltGr: '', 940 | withLevel5: '', 941 | withLevel3Level5: '' }, 942 | Lang3: 943 | { value: '', 944 | withShift: '', 945 | withAltGr: '', 946 | withShiftAltGr: '', 947 | withLevel5: '', 948 | withLevel3Level5: '' }, 949 | Lang4: 950 | { value: '', 951 | withShift: '', 952 | withAltGr: '', 953 | withShiftAltGr: '', 954 | withLevel5: '', 955 | withLevel3Level5: '' }, 956 | Lang5: 957 | { value: '', 958 | withShift: '', 959 | withAltGr: '', 960 | withShiftAltGr: '', 961 | withLevel5: '', 962 | withLevel3Level5: '' }, 963 | NumpadParenLeft: 964 | { value: '(', 965 | withShift: '(', 966 | withAltGr: '(', 967 | withShiftAltGr: '(', 968 | withLevel5: '(', 969 | withLevel3Level5: '(' }, 970 | NumpadParenRight: 971 | { value: ')', 972 | withShift: ')', 973 | withAltGr: ')', 974 | withShiftAltGr: ')', 975 | withLevel5: ')', 976 | withLevel3Level5: ')' }, 977 | ControlLeft: 978 | { value: '', 979 | withShift: '', 980 | withAltGr: '', 981 | withShiftAltGr: '', 982 | withLevel5: '', 983 | withLevel3Level5: '' }, 984 | ShiftLeft: 985 | { value: '', 986 | withShift: '', 987 | withAltGr: '', 988 | withShiftAltGr: '', 989 | withLevel5: '', 990 | withLevel3Level5: '' }, 991 | AltLeft: 992 | { value: '', 993 | withShift: '', 994 | withAltGr: '', 995 | withShiftAltGr: '', 996 | withLevel5: '', 997 | withLevel3Level5: '' }, 998 | MetaLeft: 999 | { value: '', 1000 | withShift: '', 1001 | withAltGr: '', 1002 | withShiftAltGr: '', 1003 | withLevel5: '', 1004 | withLevel3Level5: '' }, 1005 | ControlRight: 1006 | { value: '', 1007 | withShift: '', 1008 | withAltGr: '', 1009 | withShiftAltGr: '', 1010 | withLevel5: '', 1011 | withLevel3Level5: '' }, 1012 | ShiftRight: 1013 | { value: '', 1014 | withShift: '', 1015 | withAltGr: '', 1016 | withShiftAltGr: '', 1017 | withLevel5: '', 1018 | withLevel3Level5: '' }, 1019 | AltRight: 1020 | { value: '', 1021 | withShift: '', 1022 | withAltGr: '', 1023 | withShiftAltGr: '', 1024 | withLevel5: '', 1025 | withLevel3Level5: '' }, 1026 | MetaRight: 1027 | { value: '', 1028 | withShift: '', 1029 | withAltGr: '', 1030 | withShiftAltGr: '', 1031 | withLevel5: '', 1032 | withLevel3Level5: '' }, 1033 | BrightnessUp: 1034 | { value: '', 1035 | withShift: '', 1036 | withAltGr: '', 1037 | withShiftAltGr: '', 1038 | withLevel5: '', 1039 | withLevel3Level5: '' }, 1040 | BrightnessDown: 1041 | { value: '', 1042 | withShift: '', 1043 | withAltGr: '', 1044 | withShiftAltGr: '', 1045 | withLevel5: '', 1046 | withLevel3Level5: '' }, 1047 | MediaPlay: 1048 | { value: '', 1049 | withShift: '', 1050 | withAltGr: '', 1051 | withShiftAltGr: '', 1052 | withLevel5: '', 1053 | withLevel3Level5: '' }, 1054 | MediaRecord: 1055 | { value: '', 1056 | withShift: '', 1057 | withAltGr: '', 1058 | withShiftAltGr: '', 1059 | withLevel5: '', 1060 | withLevel3Level5: '' }, 1061 | MediaFastForward: 1062 | { value: '', 1063 | withShift: '', 1064 | withAltGr: '', 1065 | withShiftAltGr: '', 1066 | withLevel5: '', 1067 | withLevel3Level5: '' }, 1068 | MediaRewind: 1069 | { value: '', 1070 | withShift: '', 1071 | withAltGr: '', 1072 | withShiftAltGr: '', 1073 | withLevel5: '', 1074 | withLevel3Level5: '' }, 1075 | MediaTrackNext: 1076 | { value: '', 1077 | withShift: '', 1078 | withAltGr: '', 1079 | withShiftAltGr: '', 1080 | withLevel5: '', 1081 | withLevel3Level5: '' }, 1082 | MediaTrackPrevious: 1083 | { value: '', 1084 | withShift: '', 1085 | withAltGr: '', 1086 | withShiftAltGr: '', 1087 | withLevel5: '', 1088 | withLevel3Level5: '' }, 1089 | MediaStop: 1090 | { value: '', 1091 | withShift: '', 1092 | withAltGr: '', 1093 | withShiftAltGr: '', 1094 | withLevel5: '', 1095 | withLevel3Level5: '' }, 1096 | Eject: 1097 | { value: '', 1098 | withShift: '', 1099 | withAltGr: '', 1100 | withShiftAltGr: '', 1101 | withLevel5: '', 1102 | withLevel3Level5: '' }, 1103 | MediaPlayPause: 1104 | { value: '', 1105 | withShift: '', 1106 | withAltGr: '', 1107 | withShiftAltGr: '', 1108 | withLevel5: '', 1109 | withLevel3Level5: '' }, 1110 | MediaSelect: 1111 | { value: '', 1112 | withShift: '', 1113 | withAltGr: '', 1114 | withShiftAltGr: '', 1115 | withLevel5: '', 1116 | withLevel3Level5: '' }, 1117 | LaunchMail: 1118 | { value: '', 1119 | withShift: '', 1120 | withAltGr: '', 1121 | withShiftAltGr: '', 1122 | withLevel5: '', 1123 | withLevel3Level5: '' }, 1124 | LaunchApp2: 1125 | { value: '', 1126 | withShift: '', 1127 | withAltGr: '', 1128 | withShiftAltGr: '', 1129 | withLevel5: '', 1130 | withLevel3Level5: '' }, 1131 | LaunchApp1: 1132 | { value: '', 1133 | withShift: '', 1134 | withAltGr: '', 1135 | withShiftAltGr: '', 1136 | withLevel5: '', 1137 | withLevel3Level5: '' }, 1138 | SelectTask: 1139 | { value: '', 1140 | withShift: '', 1141 | withAltGr: '', 1142 | withShiftAltGr: '', 1143 | withLevel5: '', 1144 | withLevel3Level5: '' }, 1145 | LaunchScreenSaver: 1146 | { value: '\t', 1147 | withShift: '', 1148 | withAltGr: '=', 1149 | withShiftAltGr: '≈', 1150 | withLevel5: '≠', 1151 | withLevel3Level5: '≡' }, 1152 | BrowserSearch: 1153 | { value: '', 1154 | withShift: '', 1155 | withAltGr: '', 1156 | withShiftAltGr: '', 1157 | withLevel5: '', 1158 | withLevel3Level5: '' }, 1159 | BrowserHome: 1160 | { value: '', 1161 | withShift: '', 1162 | withAltGr: '', 1163 | withShiftAltGr: '', 1164 | withLevel5: '', 1165 | withLevel3Level5: '' }, 1166 | BrowserBack: 1167 | { value: '', 1168 | withShift: '', 1169 | withAltGr: '', 1170 | withShiftAltGr: '', 1171 | withLevel5: '', 1172 | withLevel3Level5: '' }, 1173 | BrowserForward: 1174 | { value: '', 1175 | withShift: '', 1176 | withAltGr: '', 1177 | withShiftAltGr: '', 1178 | withLevel5: '', 1179 | withLevel3Level5: '' }, 1180 | BrowserStop: 1181 | { value: '', 1182 | withShift: '', 1183 | withAltGr: '', 1184 | withShiftAltGr: '', 1185 | withLevel5: '', 1186 | withLevel3Level5: '' }, 1187 | BrowserRefresh: 1188 | { value: '', 1189 | withShift: '', 1190 | withAltGr: '', 1191 | withShiftAltGr: '', 1192 | withLevel5: '', 1193 | withLevel3Level5: '' }, 1194 | BrowserFavorites: 1195 | { value: '', 1196 | withShift: '', 1197 | withAltGr: '', 1198 | withShiftAltGr: '', 1199 | withLevel5: '', 1200 | withLevel3Level5: '' }, 1201 | MailReply: 1202 | { value: '', 1203 | withShift: '', 1204 | withAltGr: '', 1205 | withShiftAltGr: '', 1206 | withLevel5: '', 1207 | withLevel3Level5: '' }, 1208 | MailForward: 1209 | { value: '', 1210 | withShift: '', 1211 | withAltGr: '', 1212 | withShiftAltGr: '', 1213 | withLevel5: '', 1214 | withLevel3Level5: '' }, 1215 | MailSend: 1216 | { value: '', 1217 | withShift: '', 1218 | withAltGr: '', 1219 | withShiftAltGr: '', 1220 | withLevel5: '', 1221 | withLevel3Level5: '' } } 1222 | -------------------------------------------------------------------------------- /test/linux/en.txt: -------------------------------------------------------------------------------- 1 | 2 | > native-keymap@2.2.0 test /home/max/dev/node-native-keymap 3 | > node test/test.js 4 | 5 | getCurrentKeyboardLayout: { model: 'pc105', 6 | layout: 'us', 7 | variant: '', 8 | options: '', 9 | rules: 'evdev' } 10 | ------------- 11 | getKeyMap: { Sleep: 12 | { value: '', 13 | withShift: '', 14 | withAltGr: '', 15 | withShiftAltGr: '', 16 | withLevel5: '', 17 | withLevel3Level5: '' }, 18 | WakeUp: 19 | { value: '', 20 | withShift: '', 21 | withAltGr: '', 22 | withShiftAltGr: '', 23 | withLevel5: '', 24 | withLevel3Level5: '' }, 25 | KeyA: 26 | { value: 'a', 27 | withShift: 'A', 28 | withAltGr: 'a', 29 | withShiftAltGr: 'A', 30 | withLevel5: 'a', 31 | withLevel3Level5: 'a' }, 32 | KeyB: 33 | { value: 'b', 34 | withShift: 'B', 35 | withAltGr: 'b', 36 | withShiftAltGr: 'B', 37 | withLevel5: 'b', 38 | withLevel3Level5: 'b' }, 39 | KeyC: 40 | { value: 'c', 41 | withShift: 'C', 42 | withAltGr: 'c', 43 | withShiftAltGr: 'C', 44 | withLevel5: 'c', 45 | withLevel3Level5: 'c' }, 46 | KeyD: 47 | { value: 'd', 48 | withShift: 'D', 49 | withAltGr: 'd', 50 | withShiftAltGr: 'D', 51 | withLevel5: 'd', 52 | withLevel3Level5: 'd' }, 53 | KeyE: 54 | { value: 'e', 55 | withShift: 'E', 56 | withAltGr: 'e', 57 | withShiftAltGr: 'E', 58 | withLevel5: 'e', 59 | withLevel3Level5: 'e' }, 60 | KeyF: 61 | { value: 'f', 62 | withShift: 'F', 63 | withAltGr: 'f', 64 | withShiftAltGr: 'F', 65 | withLevel5: 'f', 66 | withLevel3Level5: 'f' }, 67 | KeyG: 68 | { value: 'g', 69 | withShift: 'G', 70 | withAltGr: 'g', 71 | withShiftAltGr: 'G', 72 | withLevel5: 'g', 73 | withLevel3Level5: 'g' }, 74 | KeyH: 75 | { value: 'h', 76 | withShift: 'H', 77 | withAltGr: 'h', 78 | withShiftAltGr: 'H', 79 | withLevel5: 'h', 80 | withLevel3Level5: 'h' }, 81 | KeyI: 82 | { value: 'i', 83 | withShift: 'I', 84 | withAltGr: 'i', 85 | withShiftAltGr: 'I', 86 | withLevel5: 'i', 87 | withLevel3Level5: 'i' }, 88 | KeyJ: 89 | { value: 'j', 90 | withShift: 'J', 91 | withAltGr: 'j', 92 | withShiftAltGr: 'J', 93 | withLevel5: 'j', 94 | withLevel3Level5: 'j' }, 95 | KeyK: 96 | { value: 'k', 97 | withShift: 'K', 98 | withAltGr: 'k', 99 | withShiftAltGr: 'K', 100 | withLevel5: 'k', 101 | withLevel3Level5: 'k' }, 102 | KeyL: 103 | { value: 'l', 104 | withShift: 'L', 105 | withAltGr: 'l', 106 | withShiftAltGr: 'L', 107 | withLevel5: 'l', 108 | withLevel3Level5: 'l' }, 109 | KeyM: 110 | { value: 'm', 111 | withShift: 'M', 112 | withAltGr: 'm', 113 | withShiftAltGr: 'M', 114 | withLevel5: 'm', 115 | withLevel3Level5: 'm' }, 116 | KeyN: 117 | { value: 'n', 118 | withShift: 'N', 119 | withAltGr: 'n', 120 | withShiftAltGr: 'N', 121 | withLevel5: 'n', 122 | withLevel3Level5: 'n' }, 123 | KeyO: 124 | { value: 'o', 125 | withShift: 'O', 126 | withAltGr: 'o', 127 | withShiftAltGr: 'O', 128 | withLevel5: 'o', 129 | withLevel3Level5: 'o' }, 130 | KeyP: 131 | { value: 'p', 132 | withShift: 'P', 133 | withAltGr: 'p', 134 | withShiftAltGr: 'P', 135 | withLevel5: 'p', 136 | withLevel3Level5: 'p' }, 137 | KeyQ: 138 | { value: 'q', 139 | withShift: 'Q', 140 | withAltGr: 'q', 141 | withShiftAltGr: 'Q', 142 | withLevel5: 'q', 143 | withLevel3Level5: 'q' }, 144 | KeyR: 145 | { value: 'r', 146 | withShift: 'R', 147 | withAltGr: 'r', 148 | withShiftAltGr: 'R', 149 | withLevel5: 'r', 150 | withLevel3Level5: 'r' }, 151 | KeyS: 152 | { value: 's', 153 | withShift: 'S', 154 | withAltGr: 's', 155 | withShiftAltGr: 'S', 156 | withLevel5: 's', 157 | withLevel3Level5: 's' }, 158 | KeyT: 159 | { value: 't', 160 | withShift: 'T', 161 | withAltGr: 't', 162 | withShiftAltGr: 'T', 163 | withLevel5: 't', 164 | withLevel3Level5: 't' }, 165 | KeyU: 166 | { value: 'u', 167 | withShift: 'U', 168 | withAltGr: 'u', 169 | withShiftAltGr: 'U', 170 | withLevel5: 'u', 171 | withLevel3Level5: 'u' }, 172 | KeyV: 173 | { value: 'v', 174 | withShift: 'V', 175 | withAltGr: 'v', 176 | withShiftAltGr: 'V', 177 | withLevel5: 'v', 178 | withLevel3Level5: 'v' }, 179 | KeyW: 180 | { value: 'w', 181 | withShift: 'W', 182 | withAltGr: 'w', 183 | withShiftAltGr: 'W', 184 | withLevel5: 'w', 185 | withLevel3Level5: 'w' }, 186 | KeyX: 187 | { value: 'x', 188 | withShift: 'X', 189 | withAltGr: 'x', 190 | withShiftAltGr: 'X', 191 | withLevel5: 'x', 192 | withLevel3Level5: 'x' }, 193 | KeyY: 194 | { value: 'y', 195 | withShift: 'Y', 196 | withAltGr: 'y', 197 | withShiftAltGr: 'Y', 198 | withLevel5: 'y', 199 | withLevel3Level5: 'y' }, 200 | KeyZ: 201 | { value: 'z', 202 | withShift: 'Z', 203 | withAltGr: 'z', 204 | withShiftAltGr: 'Z', 205 | withLevel5: 'z', 206 | withLevel3Level5: 'z' }, 207 | Digit1: 208 | { value: '1', 209 | withShift: '!', 210 | withAltGr: '1', 211 | withShiftAltGr: '!', 212 | withLevel5: '1', 213 | withLevel3Level5: '1' }, 214 | Digit2: 215 | { value: '2', 216 | withShift: '@', 217 | withAltGr: '2', 218 | withShiftAltGr: '@', 219 | withLevel5: '2', 220 | withLevel3Level5: '2' }, 221 | Digit3: 222 | { value: '3', 223 | withShift: '#', 224 | withAltGr: '3', 225 | withShiftAltGr: '#', 226 | withLevel5: '3', 227 | withLevel3Level5: '3' }, 228 | Digit4: 229 | { value: '4', 230 | withShift: '$', 231 | withAltGr: '4', 232 | withShiftAltGr: '$', 233 | withLevel5: '4', 234 | withLevel3Level5: '4' }, 235 | Digit5: 236 | { value: '5', 237 | withShift: '%', 238 | withAltGr: '5', 239 | withShiftAltGr: '%', 240 | withLevel5: '5', 241 | withLevel3Level5: '5' }, 242 | Digit6: 243 | { value: '6', 244 | withShift: '^', 245 | withAltGr: '6', 246 | withShiftAltGr: '^', 247 | withLevel5: '6', 248 | withLevel3Level5: '6' }, 249 | Digit7: 250 | { value: '7', 251 | withShift: '&', 252 | withAltGr: '7', 253 | withShiftAltGr: '&', 254 | withLevel5: '7', 255 | withLevel3Level5: '7' }, 256 | Digit8: 257 | { value: '8', 258 | withShift: '*', 259 | withAltGr: '8', 260 | withShiftAltGr: '*', 261 | withLevel5: '8', 262 | withLevel3Level5: '8' }, 263 | Digit9: 264 | { value: '9', 265 | withShift: '(', 266 | withAltGr: '9', 267 | withShiftAltGr: '(', 268 | withLevel5: '9', 269 | withLevel3Level5: '9' }, 270 | Digit0: 271 | { value: '0', 272 | withShift: ')', 273 | withAltGr: '0', 274 | withShiftAltGr: ')', 275 | withLevel5: '0', 276 | withLevel3Level5: '0' }, 277 | Enter: 278 | { value: '\r', 279 | withShift: '\r', 280 | withAltGr: '\r', 281 | withShiftAltGr: '\r', 282 | withLevel5: '\r', 283 | withLevel3Level5: '\r' }, 284 | Escape: 285 | { value: '\u001b', 286 | withShift: '\u001b', 287 | withAltGr: '\u001b', 288 | withShiftAltGr: '\u001b', 289 | withLevel5: '\u001b', 290 | withLevel3Level5: '\u001b' }, 291 | Backspace: 292 | { value: '\b', 293 | withShift: '\b', 294 | withAltGr: '\b', 295 | withShiftAltGr: '\b', 296 | withLevel5: '\b', 297 | withLevel3Level5: '\b' }, 298 | Tab: 299 | { value: '\t', 300 | withShift: '', 301 | withAltGr: '\t', 302 | withShiftAltGr: '', 303 | withLevel5: '\t', 304 | withLevel3Level5: '\t' }, 305 | Space: 306 | { value: ' ', 307 | withShift: ' ', 308 | withAltGr: ' ', 309 | withShiftAltGr: ' ', 310 | withLevel5: ' ', 311 | withLevel3Level5: ' ' }, 312 | Minus: 313 | { value: '-', 314 | withShift: '_', 315 | withAltGr: '-', 316 | withShiftAltGr: '_', 317 | withLevel5: '-', 318 | withLevel3Level5: '-' }, 319 | Equal: 320 | { value: '=', 321 | withShift: '+', 322 | withAltGr: '=', 323 | withShiftAltGr: '+', 324 | withLevel5: '=', 325 | withLevel3Level5: '=' }, 326 | BracketLeft: 327 | { value: '[', 328 | withShift: '{', 329 | withAltGr: '[', 330 | withShiftAltGr: '{', 331 | withLevel5: '[', 332 | withLevel3Level5: '[' }, 333 | BracketRight: 334 | { value: ']', 335 | withShift: '}', 336 | withAltGr: ']', 337 | withShiftAltGr: '}', 338 | withLevel5: ']', 339 | withLevel3Level5: ']' }, 340 | Backslash: 341 | { value: '\\', 342 | withShift: '|', 343 | withAltGr: '\\', 344 | withShiftAltGr: '|', 345 | withLevel5: '\\', 346 | withLevel3Level5: '\\' }, 347 | Semicolon: 348 | { value: ';', 349 | withShift: ':', 350 | withAltGr: ';', 351 | withShiftAltGr: ':', 352 | withLevel5: ';', 353 | withLevel3Level5: ';' }, 354 | Quote: 355 | { value: '\'', 356 | withShift: '"', 357 | withAltGr: '\'', 358 | withShiftAltGr: '"', 359 | withLevel5: '\'', 360 | withLevel3Level5: '\'' }, 361 | Backquote: 362 | { value: '`', 363 | withShift: '~', 364 | withAltGr: '`', 365 | withShiftAltGr: '~', 366 | withLevel5: '`', 367 | withLevel3Level5: '`' }, 368 | Comma: 369 | { value: ',', 370 | withShift: '<', 371 | withAltGr: ',', 372 | withShiftAltGr: '<', 373 | withLevel5: ',', 374 | withLevel3Level5: ',' }, 375 | Period: 376 | { value: '.', 377 | withShift: '>', 378 | withAltGr: '.', 379 | withShiftAltGr: '>', 380 | withLevel5: '.', 381 | withLevel3Level5: '.' }, 382 | Slash: 383 | { value: '/', 384 | withShift: '?', 385 | withAltGr: '/', 386 | withShiftAltGr: '?', 387 | withLevel5: '/', 388 | withLevel3Level5: '/' }, 389 | CapsLock: 390 | { value: '', 391 | withShift: '', 392 | withAltGr: '', 393 | withShiftAltGr: '', 394 | withLevel5: '', 395 | withLevel3Level5: '' }, 396 | F1: 397 | { value: '', 398 | withShift: '', 399 | withAltGr: '', 400 | withShiftAltGr: '', 401 | withLevel5: '', 402 | withLevel3Level5: '' }, 403 | F2: 404 | { value: '', 405 | withShift: '', 406 | withAltGr: '', 407 | withShiftAltGr: '', 408 | withLevel5: '', 409 | withLevel3Level5: '' }, 410 | F3: 411 | { value: '', 412 | withShift: '', 413 | withAltGr: '', 414 | withShiftAltGr: '', 415 | withLevel5: '', 416 | withLevel3Level5: '' }, 417 | F4: 418 | { value: '', 419 | withShift: '', 420 | withAltGr: '', 421 | withShiftAltGr: '', 422 | withLevel5: '', 423 | withLevel3Level5: '' }, 424 | F5: 425 | { value: '', 426 | withShift: '', 427 | withAltGr: '', 428 | withShiftAltGr: '', 429 | withLevel5: '', 430 | withLevel3Level5: '' }, 431 | F6: 432 | { value: '', 433 | withShift: '', 434 | withAltGr: '', 435 | withShiftAltGr: '', 436 | withLevel5: '', 437 | withLevel3Level5: '' }, 438 | F7: 439 | { value: '', 440 | withShift: '', 441 | withAltGr: '', 442 | withShiftAltGr: '', 443 | withLevel5: '', 444 | withLevel3Level5: '' }, 445 | F8: 446 | { value: '', 447 | withShift: '', 448 | withAltGr: '', 449 | withShiftAltGr: '', 450 | withLevel5: '', 451 | withLevel3Level5: '' }, 452 | F9: 453 | { value: '', 454 | withShift: '', 455 | withAltGr: '', 456 | withShiftAltGr: '', 457 | withLevel5: '', 458 | withLevel3Level5: '' }, 459 | F10: 460 | { value: '', 461 | withShift: '', 462 | withAltGr: '', 463 | withShiftAltGr: '', 464 | withLevel5: '', 465 | withLevel3Level5: '' }, 466 | F11: 467 | { value: '', 468 | withShift: '', 469 | withAltGr: '', 470 | withShiftAltGr: '', 471 | withLevel5: '', 472 | withLevel3Level5: '' }, 473 | F12: 474 | { value: '', 475 | withShift: '', 476 | withAltGr: '', 477 | withShiftAltGr: '', 478 | withLevel5: '', 479 | withLevel3Level5: '' }, 480 | PrintScreen: 481 | { value: '', 482 | withShift: '', 483 | withAltGr: '', 484 | withShiftAltGr: '', 485 | withLevel5: '', 486 | withLevel3Level5: '' }, 487 | ScrollLock: 488 | { value: '', 489 | withShift: '', 490 | withAltGr: '', 491 | withShiftAltGr: '', 492 | withLevel5: '', 493 | withLevel3Level5: '' }, 494 | Pause: 495 | { value: '', 496 | withShift: '', 497 | withAltGr: '', 498 | withShiftAltGr: '', 499 | withLevel5: '', 500 | withLevel3Level5: '' }, 501 | Insert: 502 | { value: '', 503 | withShift: '', 504 | withAltGr: '', 505 | withShiftAltGr: '', 506 | withLevel5: '', 507 | withLevel3Level5: '' }, 508 | Home: 509 | { value: '', 510 | withShift: '', 511 | withAltGr: '', 512 | withShiftAltGr: '', 513 | withLevel5: '', 514 | withLevel3Level5: '' }, 515 | PageUp: 516 | { value: '', 517 | withShift: '', 518 | withAltGr: '', 519 | withShiftAltGr: '', 520 | withLevel5: '', 521 | withLevel3Level5: '' }, 522 | Delete: 523 | { value: '', 524 | withShift: '', 525 | withAltGr: '', 526 | withShiftAltGr: '', 527 | withLevel5: '', 528 | withLevel3Level5: '' }, 529 | End: 530 | { value: '', 531 | withShift: '', 532 | withAltGr: '', 533 | withShiftAltGr: '', 534 | withLevel5: '', 535 | withLevel3Level5: '' }, 536 | PageDown: 537 | { value: '', 538 | withShift: '', 539 | withAltGr: '', 540 | withShiftAltGr: '', 541 | withLevel5: '', 542 | withLevel3Level5: '' }, 543 | ArrowRight: 544 | { value: '', 545 | withShift: '', 546 | withAltGr: '', 547 | withShiftAltGr: '', 548 | withLevel5: '', 549 | withLevel3Level5: '' }, 550 | ArrowLeft: 551 | { value: '', 552 | withShift: '', 553 | withAltGr: '', 554 | withShiftAltGr: '', 555 | withLevel5: '', 556 | withLevel3Level5: '' }, 557 | ArrowDown: 558 | { value: '', 559 | withShift: '', 560 | withAltGr: '', 561 | withShiftAltGr: '', 562 | withLevel5: '', 563 | withLevel3Level5: '' }, 564 | ArrowUp: 565 | { value: '', 566 | withShift: '', 567 | withAltGr: '', 568 | withShiftAltGr: '', 569 | withLevel5: '', 570 | withLevel3Level5: '' }, 571 | NumLock: 572 | { value: '', 573 | withShift: '', 574 | withAltGr: '', 575 | withShiftAltGr: '', 576 | withLevel5: '', 577 | withLevel3Level5: '' }, 578 | NumpadDivide: 579 | { value: '/', 580 | withShift: '/', 581 | withAltGr: '/', 582 | withShiftAltGr: '/', 583 | withLevel5: '/', 584 | withLevel3Level5: '/' }, 585 | NumpadMultiply: 586 | { value: '*', 587 | withShift: '*', 588 | withAltGr: '*', 589 | withShiftAltGr: '*', 590 | withLevel5: '*', 591 | withLevel3Level5: '*' }, 592 | NumpadSubtract: 593 | { value: '-', 594 | withShift: '-', 595 | withAltGr: '-', 596 | withShiftAltGr: '-', 597 | withLevel5: '-', 598 | withLevel3Level5: '-' }, 599 | NumpadAdd: 600 | { value: '+', 601 | withShift: '+', 602 | withAltGr: '+', 603 | withShiftAltGr: '+', 604 | withLevel5: '+', 605 | withLevel3Level5: '+' }, 606 | NumpadEnter: 607 | { value: '\r', 608 | withShift: '\r', 609 | withAltGr: '\r', 610 | withShiftAltGr: '\r', 611 | withLevel5: '\r', 612 | withLevel3Level5: '\r' }, 613 | Numpad1: 614 | { value: '', 615 | withShift: '1', 616 | withAltGr: '', 617 | withShiftAltGr: '1', 618 | withLevel5: '', 619 | withLevel3Level5: '' }, 620 | Numpad2: 621 | { value: '', 622 | withShift: '2', 623 | withAltGr: '', 624 | withShiftAltGr: '2', 625 | withLevel5: '', 626 | withLevel3Level5: '' }, 627 | Numpad3: 628 | { value: '', 629 | withShift: '3', 630 | withAltGr: '', 631 | withShiftAltGr: '3', 632 | withLevel5: '', 633 | withLevel3Level5: '' }, 634 | Numpad4: 635 | { value: '', 636 | withShift: '4', 637 | withAltGr: '', 638 | withShiftAltGr: '4', 639 | withLevel5: '', 640 | withLevel3Level5: '' }, 641 | Numpad5: 642 | { value: '', 643 | withShift: '5', 644 | withAltGr: '', 645 | withShiftAltGr: '5', 646 | withLevel5: '', 647 | withLevel3Level5: '' }, 648 | Numpad6: 649 | { value: '', 650 | withShift: '6', 651 | withAltGr: '', 652 | withShiftAltGr: '6', 653 | withLevel5: '', 654 | withLevel3Level5: '' }, 655 | Numpad7: 656 | { value: '', 657 | withShift: '7', 658 | withAltGr: '', 659 | withShiftAltGr: '7', 660 | withLevel5: '', 661 | withLevel3Level5: '' }, 662 | Numpad8: 663 | { value: '', 664 | withShift: '8', 665 | withAltGr: '', 666 | withShiftAltGr: '8', 667 | withLevel5: '', 668 | withLevel3Level5: '' }, 669 | Numpad9: 670 | { value: '', 671 | withShift: '9', 672 | withAltGr: '', 673 | withShiftAltGr: '9', 674 | withLevel5: '', 675 | withLevel3Level5: '' }, 676 | Numpad0: 677 | { value: '', 678 | withShift: '0', 679 | withAltGr: '', 680 | withShiftAltGr: '0', 681 | withLevel5: '', 682 | withLevel3Level5: '' }, 683 | NumpadDecimal: 684 | { value: '', 685 | withShift: '.', 686 | withAltGr: '', 687 | withShiftAltGr: '.', 688 | withLevel5: '', 689 | withLevel3Level5: '' }, 690 | IntlBackslash: 691 | { value: '<', 692 | withShift: '>', 693 | withAltGr: '|', 694 | withShiftAltGr: '¦', 695 | withLevel5: '<', 696 | withLevel3Level5: '|' }, 697 | ContextMenu: 698 | { value: '', 699 | withShift: '', 700 | withAltGr: '', 701 | withShiftAltGr: '', 702 | withLevel5: '', 703 | withLevel3Level5: '' }, 704 | Power: 705 | { value: '', 706 | withShift: '', 707 | withAltGr: '', 708 | withShiftAltGr: '', 709 | withLevel5: '', 710 | withLevel3Level5: '' }, 711 | NumpadEqual: 712 | { value: '=', 713 | withShift: '=', 714 | withAltGr: '=', 715 | withShiftAltGr: '=', 716 | withLevel5: '=', 717 | withLevel3Level5: '=' }, 718 | F13: 719 | { value: '', 720 | withShift: '', 721 | withAltGr: '', 722 | withShiftAltGr: '', 723 | withLevel5: '', 724 | withLevel3Level5: '' }, 725 | F14: 726 | { value: '', 727 | withShift: '', 728 | withAltGr: '', 729 | withShiftAltGr: '', 730 | withLevel5: '', 731 | withLevel3Level5: '' }, 732 | F15: 733 | { value: '', 734 | withShift: '', 735 | withAltGr: '', 736 | withShiftAltGr: '', 737 | withLevel5: '', 738 | withLevel3Level5: '' }, 739 | F16: 740 | { value: '', 741 | withShift: '', 742 | withAltGr: '', 743 | withShiftAltGr: '', 744 | withLevel5: '', 745 | withLevel3Level5: '' }, 746 | F17: 747 | { value: '', 748 | withShift: '', 749 | withAltGr: '', 750 | withShiftAltGr: '', 751 | withLevel5: '', 752 | withLevel3Level5: '' }, 753 | F18: 754 | { value: '', 755 | withShift: '', 756 | withAltGr: '', 757 | withShiftAltGr: '', 758 | withLevel5: '', 759 | withLevel3Level5: '' }, 760 | F19: 761 | { value: '', 762 | withShift: '', 763 | withAltGr: '', 764 | withShiftAltGr: '', 765 | withLevel5: '', 766 | withLevel3Level5: '' }, 767 | F20: 768 | { value: '', 769 | withShift: '', 770 | withAltGr: '', 771 | withShiftAltGr: '', 772 | withLevel5: '', 773 | withLevel3Level5: '' }, 774 | F21: 775 | { value: '', 776 | withShift: '', 777 | withAltGr: '', 778 | withShiftAltGr: '', 779 | withLevel5: '', 780 | withLevel3Level5: '' }, 781 | F22: 782 | { value: '', 783 | withShift: '', 784 | withAltGr: '', 785 | withShiftAltGr: '', 786 | withLevel5: '', 787 | withLevel3Level5: '' }, 788 | F23: 789 | { value: '', 790 | withShift: '', 791 | withAltGr: '', 792 | withShiftAltGr: '', 793 | withLevel5: '', 794 | withLevel3Level5: '' }, 795 | F24: 796 | { value: '', 797 | withShift: '', 798 | withAltGr: '', 799 | withShiftAltGr: '', 800 | withLevel5: '', 801 | withLevel3Level5: '' }, 802 | Open: 803 | { value: '', 804 | withShift: '', 805 | withAltGr: '', 806 | withShiftAltGr: '', 807 | withLevel5: '', 808 | withLevel3Level5: '' }, 809 | Help: 810 | { value: '', 811 | withShift: '', 812 | withAltGr: '', 813 | withShiftAltGr: '', 814 | withLevel5: '', 815 | withLevel3Level5: '' }, 816 | Select: 817 | { value: '', 818 | withShift: '', 819 | withAltGr: '', 820 | withShiftAltGr: '', 821 | withLevel5: '', 822 | withLevel3Level5: '' }, 823 | Again: 824 | { value: '', 825 | withShift: '', 826 | withAltGr: '', 827 | withShiftAltGr: '', 828 | withLevel5: '', 829 | withLevel3Level5: '' }, 830 | Undo: 831 | { value: '', 832 | withShift: '', 833 | withAltGr: '', 834 | withShiftAltGr: '', 835 | withLevel5: '', 836 | withLevel3Level5: '' }, 837 | Cut: 838 | { value: '', 839 | withShift: '', 840 | withAltGr: '', 841 | withShiftAltGr: '', 842 | withLevel5: '', 843 | withLevel3Level5: '' }, 844 | Copy: 845 | { value: '', 846 | withShift: '', 847 | withAltGr: '', 848 | withShiftAltGr: '', 849 | withLevel5: '', 850 | withLevel3Level5: '' }, 851 | Paste: 852 | { value: '', 853 | withShift: '', 854 | withAltGr: '', 855 | withShiftAltGr: '', 856 | withLevel5: '', 857 | withLevel3Level5: '' }, 858 | Find: 859 | { value: '', 860 | withShift: '', 861 | withAltGr: '', 862 | withShiftAltGr: '', 863 | withLevel5: '', 864 | withLevel3Level5: '' }, 865 | AudioVolumeMute: 866 | { value: '', 867 | withShift: '', 868 | withAltGr: '', 869 | withShiftAltGr: '', 870 | withLevel5: '', 871 | withLevel3Level5: '' }, 872 | AudioVolumeUp: 873 | { value: '', 874 | withShift: '', 875 | withAltGr: '', 876 | withShiftAltGr: '', 877 | withLevel5: '', 878 | withLevel3Level5: '' }, 879 | AudioVolumeDown: 880 | { value: '', 881 | withShift: '', 882 | withAltGr: '', 883 | withShiftAltGr: '', 884 | withLevel5: '', 885 | withLevel3Level5: '' }, 886 | NumpadComma: 887 | { value: '.', 888 | withShift: '.', 889 | withAltGr: '.', 890 | withShiftAltGr: '.', 891 | withLevel5: '.', 892 | withLevel3Level5: '.' }, 893 | IntlRo: 894 | { value: '', 895 | withShift: '', 896 | withAltGr: '', 897 | withShiftAltGr: '', 898 | withLevel5: '', 899 | withLevel3Level5: '' }, 900 | KanaMode: 901 | { value: '', 902 | withShift: '', 903 | withAltGr: '', 904 | withShiftAltGr: '', 905 | withLevel5: '', 906 | withLevel3Level5: '' }, 907 | IntlYen: 908 | { value: '', 909 | withShift: '', 910 | withAltGr: '', 911 | withShiftAltGr: '', 912 | withLevel5: '', 913 | withLevel3Level5: '' }, 914 | Convert: 915 | { value: '', 916 | withShift: '', 917 | withAltGr: '', 918 | withShiftAltGr: '', 919 | withLevel5: '', 920 | withLevel3Level5: '' }, 921 | NonConvert: 922 | { value: '', 923 | withShift: '', 924 | withAltGr: '', 925 | withShiftAltGr: '', 926 | withLevel5: '', 927 | withLevel3Level5: '' }, 928 | Lang1: 929 | { value: '', 930 | withShift: '', 931 | withAltGr: '', 932 | withShiftAltGr: '', 933 | withLevel5: '', 934 | withLevel3Level5: '' }, 935 | Lang2: 936 | { value: '', 937 | withShift: '', 938 | withAltGr: '', 939 | withShiftAltGr: '', 940 | withLevel5: '', 941 | withLevel3Level5: '' }, 942 | Lang3: 943 | { value: '', 944 | withShift: '', 945 | withAltGr: '', 946 | withShiftAltGr: '', 947 | withLevel5: '', 948 | withLevel3Level5: '' }, 949 | Lang4: 950 | { value: '', 951 | withShift: '', 952 | withAltGr: '', 953 | withShiftAltGr: '', 954 | withLevel5: '', 955 | withLevel3Level5: '' }, 956 | Lang5: 957 | { value: '', 958 | withShift: '', 959 | withAltGr: '', 960 | withShiftAltGr: '', 961 | withLevel5: '', 962 | withLevel3Level5: '' }, 963 | NumpadParenLeft: 964 | { value: '(', 965 | withShift: '(', 966 | withAltGr: '(', 967 | withShiftAltGr: '(', 968 | withLevel5: '(', 969 | withLevel3Level5: '(' }, 970 | NumpadParenRight: 971 | { value: ')', 972 | withShift: ')', 973 | withAltGr: ')', 974 | withShiftAltGr: ')', 975 | withLevel5: ')', 976 | withLevel3Level5: ')' }, 977 | ControlLeft: 978 | { value: '', 979 | withShift: '', 980 | withAltGr: '', 981 | withShiftAltGr: '', 982 | withLevel5: '', 983 | withLevel3Level5: '' }, 984 | ShiftLeft: 985 | { value: '', 986 | withShift: '', 987 | withAltGr: '', 988 | withShiftAltGr: '', 989 | withLevel5: '', 990 | withLevel3Level5: '' }, 991 | AltLeft: 992 | { value: '', 993 | withShift: '', 994 | withAltGr: '', 995 | withShiftAltGr: '', 996 | withLevel5: '', 997 | withLevel3Level5: '' }, 998 | MetaLeft: 999 | { value: '', 1000 | withShift: '', 1001 | withAltGr: '', 1002 | withShiftAltGr: '', 1003 | withLevel5: '', 1004 | withLevel3Level5: '' }, 1005 | ControlRight: 1006 | { value: '', 1007 | withShift: '', 1008 | withAltGr: '', 1009 | withShiftAltGr: '', 1010 | withLevel5: '', 1011 | withLevel3Level5: '' }, 1012 | ShiftRight: 1013 | { value: '', 1014 | withShift: '', 1015 | withAltGr: '', 1016 | withShiftAltGr: '', 1017 | withLevel5: '', 1018 | withLevel3Level5: '' }, 1019 | AltRight: 1020 | { value: '', 1021 | withShift: '', 1022 | withAltGr: '', 1023 | withShiftAltGr: '', 1024 | withLevel5: '', 1025 | withLevel3Level5: '' }, 1026 | MetaRight: 1027 | { value: '', 1028 | withShift: '', 1029 | withAltGr: '', 1030 | withShiftAltGr: '', 1031 | withLevel5: '', 1032 | withLevel3Level5: '' }, 1033 | BrightnessUp: 1034 | { value: '', 1035 | withShift: '', 1036 | withAltGr: '', 1037 | withShiftAltGr: '', 1038 | withLevel5: '', 1039 | withLevel3Level5: '' }, 1040 | BrightnessDown: 1041 | { value: '', 1042 | withShift: '', 1043 | withAltGr: '', 1044 | withShiftAltGr: '', 1045 | withLevel5: '', 1046 | withLevel3Level5: '' }, 1047 | MediaPlay: 1048 | { value: '', 1049 | withShift: '', 1050 | withAltGr: '', 1051 | withShiftAltGr: '', 1052 | withLevel5: '', 1053 | withLevel3Level5: '' }, 1054 | MediaRecord: 1055 | { value: '', 1056 | withShift: '', 1057 | withAltGr: '', 1058 | withShiftAltGr: '', 1059 | withLevel5: '', 1060 | withLevel3Level5: '' }, 1061 | MediaFastForward: 1062 | { value: '', 1063 | withShift: '', 1064 | withAltGr: '', 1065 | withShiftAltGr: '', 1066 | withLevel5: '', 1067 | withLevel3Level5: '' }, 1068 | MediaRewind: 1069 | { value: '', 1070 | withShift: '', 1071 | withAltGr: '', 1072 | withShiftAltGr: '', 1073 | withLevel5: '', 1074 | withLevel3Level5: '' }, 1075 | MediaTrackNext: 1076 | { value: '', 1077 | withShift: '', 1078 | withAltGr: '', 1079 | withShiftAltGr: '', 1080 | withLevel5: '', 1081 | withLevel3Level5: '' }, 1082 | MediaTrackPrevious: 1083 | { value: '', 1084 | withShift: '', 1085 | withAltGr: '', 1086 | withShiftAltGr: '', 1087 | withLevel5: '', 1088 | withLevel3Level5: '' }, 1089 | MediaStop: 1090 | { value: '', 1091 | withShift: '', 1092 | withAltGr: '', 1093 | withShiftAltGr: '', 1094 | withLevel5: '', 1095 | withLevel3Level5: '' }, 1096 | Eject: 1097 | { value: '', 1098 | withShift: '', 1099 | withAltGr: '', 1100 | withShiftAltGr: '', 1101 | withLevel5: '', 1102 | withLevel3Level5: '' }, 1103 | MediaPlayPause: 1104 | { value: '', 1105 | withShift: '', 1106 | withAltGr: '', 1107 | withShiftAltGr: '', 1108 | withLevel5: '', 1109 | withLevel3Level5: '' }, 1110 | MediaSelect: 1111 | { value: '', 1112 | withShift: '', 1113 | withAltGr: '', 1114 | withShiftAltGr: '', 1115 | withLevel5: '', 1116 | withLevel3Level5: '' }, 1117 | LaunchMail: 1118 | { value: '', 1119 | withShift: '', 1120 | withAltGr: '', 1121 | withShiftAltGr: '', 1122 | withLevel5: '', 1123 | withLevel3Level5: '' }, 1124 | LaunchApp2: 1125 | { value: '', 1126 | withShift: '', 1127 | withAltGr: '', 1128 | withShiftAltGr: '', 1129 | withLevel5: '', 1130 | withLevel3Level5: '' }, 1131 | LaunchApp1: 1132 | { value: '', 1133 | withShift: '', 1134 | withAltGr: '', 1135 | withShiftAltGr: '', 1136 | withLevel5: '', 1137 | withLevel3Level5: '' }, 1138 | SelectTask: 1139 | { value: '', 1140 | withShift: '', 1141 | withAltGr: '', 1142 | withShiftAltGr: '', 1143 | withLevel5: '', 1144 | withLevel3Level5: '' }, 1145 | LaunchScreenSaver: 1146 | { value: '', 1147 | withShift: '', 1148 | withAltGr: '', 1149 | withShiftAltGr: '', 1150 | withLevel5: '', 1151 | withLevel3Level5: '' }, 1152 | BrowserSearch: 1153 | { value: '', 1154 | withShift: '', 1155 | withAltGr: '', 1156 | withShiftAltGr: '', 1157 | withLevel5: '', 1158 | withLevel3Level5: '' }, 1159 | BrowserHome: 1160 | { value: '', 1161 | withShift: '', 1162 | withAltGr: '', 1163 | withShiftAltGr: '', 1164 | withLevel5: '', 1165 | withLevel3Level5: '' }, 1166 | BrowserBack: 1167 | { value: '', 1168 | withShift: '', 1169 | withAltGr: '', 1170 | withShiftAltGr: '', 1171 | withLevel5: '', 1172 | withLevel3Level5: '' }, 1173 | BrowserForward: 1174 | { value: '', 1175 | withShift: '', 1176 | withAltGr: '', 1177 | withShiftAltGr: '', 1178 | withLevel5: '', 1179 | withLevel3Level5: '' }, 1180 | BrowserStop: 1181 | { value: '', 1182 | withShift: '', 1183 | withAltGr: '', 1184 | withShiftAltGr: '', 1185 | withLevel5: '', 1186 | withLevel3Level5: '' }, 1187 | BrowserRefresh: 1188 | { value: '', 1189 | withShift: '', 1190 | withAltGr: '', 1191 | withShiftAltGr: '', 1192 | withLevel5: '', 1193 | withLevel3Level5: '' }, 1194 | BrowserFavorites: 1195 | { value: '', 1196 | withShift: '', 1197 | withAltGr: '', 1198 | withShiftAltGr: '', 1199 | withLevel5: '', 1200 | withLevel3Level5: '' }, 1201 | MailReply: 1202 | { value: '', 1203 | withShift: '', 1204 | withAltGr: '', 1205 | withShiftAltGr: '', 1206 | withLevel5: '', 1207 | withLevel3Level5: '' }, 1208 | MailForward: 1209 | { value: '', 1210 | withShift: '', 1211 | withAltGr: '', 1212 | withShiftAltGr: '', 1213 | withLevel5: '', 1214 | withLevel3Level5: '' }, 1215 | MailSend: 1216 | { value: '', 1217 | withShift: '', 1218 | withAltGr: '', 1219 | withShiftAltGr: '', 1220 | withLevel5: '', 1221 | withLevel3Level5: '' } } 1222 | -------------------------------------------------------------------------------- /test/linux/es.txt: -------------------------------------------------------------------------------- 1 | 2 | > native-keymap@2.2.0 test /home/max/dev/node-native-keymap 3 | > node test/test.js 4 | 5 | getCurrentKeyboardLayout: { model: 'pc105', 6 | layout: 'es', 7 | variant: '', 8 | options: '', 9 | rules: 'evdev' } 10 | ------------- 11 | getKeyMap: { Sleep: 12 | { value: '', 13 | withShift: '', 14 | withAltGr: '', 15 | withShiftAltGr: '', 16 | withLevel5: '', 17 | withLevel3Level5: '' }, 18 | WakeUp: 19 | { value: '', 20 | withShift: '', 21 | withAltGr: '', 22 | withShiftAltGr: '', 23 | withLevel5: '', 24 | withLevel3Level5: '' }, 25 | KeyA: 26 | { value: 'a', 27 | withShift: 'A', 28 | withAltGr: 'æ', 29 | withShiftAltGr: 'Æ', 30 | withLevel5: 'a', 31 | withLevel3Level5: 'æ' }, 32 | KeyB: 33 | { value: 'b', 34 | withShift: 'B', 35 | withAltGr: '”', 36 | withShiftAltGr: '’', 37 | withLevel5: 'b', 38 | withLevel3Level5: '”' }, 39 | KeyC: 40 | { value: 'c', 41 | withShift: 'C', 42 | withAltGr: '¢', 43 | withShiftAltGr: '©', 44 | withLevel5: 'c', 45 | withLevel3Level5: '¢' }, 46 | KeyD: 47 | { value: 'd', 48 | withShift: 'D', 49 | withAltGr: 'ð', 50 | withShiftAltGr: 'Ð', 51 | withLevel5: 'd', 52 | withLevel3Level5: 'ð' }, 53 | KeyE: 54 | { value: 'e', 55 | withShift: 'E', 56 | withAltGr: '€', 57 | withShiftAltGr: '¢', 58 | withLevel5: 'e', 59 | withLevel3Level5: '€' }, 60 | KeyF: 61 | { value: 'f', 62 | withShift: 'F', 63 | withAltGr: 'đ', 64 | withShiftAltGr: 'ª', 65 | withLevel5: 'f', 66 | withLevel3Level5: 'đ' }, 67 | KeyG: 68 | { value: 'g', 69 | withShift: 'G', 70 | withAltGr: 'ŋ', 71 | withShiftAltGr: 'Ŋ', 72 | withLevel5: 'g', 73 | withLevel3Level5: 'ŋ' }, 74 | KeyH: 75 | { value: 'h', 76 | withShift: 'H', 77 | withAltGr: 'ħ', 78 | withShiftAltGr: 'Ħ', 79 | withLevel5: 'h', 80 | withLevel3Level5: 'ħ' }, 81 | KeyI: 82 | { value: 'i', 83 | withShift: 'I', 84 | withAltGr: '→', 85 | withShiftAltGr: 'ı', 86 | withLevel5: 'i', 87 | withLevel3Level5: '→' }, 88 | KeyJ: 89 | { value: 'j', 90 | withShift: 'J', 91 | withAltGr: '̉', 92 | withShiftAltGr: '̛', 93 | withLevel5: 'j', 94 | withLevel3Level5: '̉' }, 95 | KeyK: 96 | { value: 'k', 97 | withShift: 'K', 98 | withAltGr: 'ĸ', 99 | withShiftAltGr: '&', 100 | withLevel5: 'k', 101 | withLevel3Level5: 'ĸ' }, 102 | KeyL: 103 | { value: 'l', 104 | withShift: 'L', 105 | withAltGr: 'ł', 106 | withShiftAltGr: 'Ł', 107 | withLevel5: 'l', 108 | withLevel3Level5: 'ł' }, 109 | KeyM: 110 | { value: 'm', 111 | withShift: 'M', 112 | withAltGr: 'µ', 113 | withShiftAltGr: 'º', 114 | withLevel5: 'm', 115 | withLevel3Level5: 'µ' }, 116 | KeyN: 117 | { value: 'n', 118 | withShift: 'N', 119 | withAltGr: 'n', 120 | withShiftAltGr: 'N', 121 | withLevel5: 'n', 122 | withLevel3Level5: 'n' }, 123 | KeyO: 124 | { value: 'o', 125 | withShift: 'O', 126 | withAltGr: 'ø', 127 | withShiftAltGr: 'Ø', 128 | withLevel5: 'o', 129 | withLevel3Level5: 'ø' }, 130 | KeyP: 131 | { value: 'p', 132 | withShift: 'P', 133 | withAltGr: 'þ', 134 | withShiftAltGr: 'Þ', 135 | withLevel5: 'p', 136 | withLevel3Level5: 'þ' }, 137 | KeyQ: 138 | { value: 'q', 139 | withShift: 'Q', 140 | withAltGr: '@', 141 | withShiftAltGr: 'Ω', 142 | withLevel5: 'q', 143 | withLevel3Level5: '@' }, 144 | KeyR: 145 | { value: 'r', 146 | withShift: 'R', 147 | withAltGr: '¶', 148 | withShiftAltGr: '®', 149 | withLevel5: 'r', 150 | withLevel3Level5: '¶' }, 151 | KeyS: 152 | { value: 's', 153 | withShift: 'S', 154 | withAltGr: 'ß', 155 | withShiftAltGr: '§', 156 | withLevel5: 's', 157 | withLevel3Level5: 'ß' }, 158 | KeyT: 159 | { value: 't', 160 | withShift: 'T', 161 | withAltGr: 'ŧ', 162 | withShiftAltGr: 'Ŧ', 163 | withLevel5: 't', 164 | withLevel3Level5: 'ŧ' }, 165 | KeyU: 166 | { value: 'u', 167 | withShift: 'U', 168 | withAltGr: '↓', 169 | withShiftAltGr: '↑', 170 | withLevel5: 'u', 171 | withLevel3Level5: '↓' }, 172 | KeyV: 173 | { value: 'v', 174 | withShift: 'V', 175 | withAltGr: '“', 176 | withShiftAltGr: '‘', 177 | withLevel5: 'v', 178 | withLevel3Level5: '“' }, 179 | KeyW: 180 | { value: 'w', 181 | withShift: 'W', 182 | withAltGr: 'ł', 183 | withShiftAltGr: 'Ł', 184 | withLevel5: 'w', 185 | withLevel3Level5: 'ł' }, 186 | KeyX: 187 | { value: 'x', 188 | withShift: 'X', 189 | withAltGr: '»', 190 | withShiftAltGr: '>', 191 | withLevel5: 'x', 192 | withLevel3Level5: '»' }, 193 | KeyY: 194 | { value: 'y', 195 | withShift: 'Y', 196 | withAltGr: '←', 197 | withShiftAltGr: '¥', 198 | withLevel5: 'y', 199 | withLevel3Level5: '←' }, 200 | KeyZ: 201 | { value: 'z', 202 | withShift: 'Z', 203 | withAltGr: '«', 204 | withShiftAltGr: '<', 205 | withLevel5: 'z', 206 | withLevel3Level5: '«' }, 207 | Digit1: 208 | { value: '1', 209 | withShift: '!', 210 | withAltGr: '|', 211 | withShiftAltGr: '¡', 212 | withLevel5: '1', 213 | withLevel3Level5: '|' }, 214 | Digit2: 215 | { value: '2', 216 | withShift: '"', 217 | withAltGr: '@', 218 | withShiftAltGr: '⅛', 219 | withLevel5: '2', 220 | withLevel3Level5: '@' }, 221 | Digit3: 222 | { value: '3', 223 | withShift: '·', 224 | withAltGr: '#', 225 | withShiftAltGr: '£', 226 | withLevel5: '3', 227 | withLevel3Level5: '#' }, 228 | Digit4: 229 | { value: '4', 230 | withShift: '$', 231 | withAltGr: '~', 232 | withShiftAltGr: '$', 233 | withLevel5: '4', 234 | withLevel3Level5: '~' }, 235 | Digit5: 236 | { value: '5', 237 | withShift: '%', 238 | withAltGr: '½', 239 | withShiftAltGr: '⅜', 240 | withLevel5: '5', 241 | withLevel3Level5: '½' }, 242 | Digit6: 243 | { value: '6', 244 | withShift: '&', 245 | withAltGr: '¬', 246 | withShiftAltGr: '⅝', 247 | withLevel5: '6', 248 | withLevel3Level5: '¬' }, 249 | Digit7: 250 | { value: '7', 251 | withShift: '/', 252 | withAltGr: '{', 253 | withShiftAltGr: '⅞', 254 | withLevel5: '7', 255 | withLevel3Level5: '{' }, 256 | Digit8: 257 | { value: '8', 258 | withShift: '(', 259 | withAltGr: '[', 260 | withShiftAltGr: '™', 261 | withLevel5: '8', 262 | withLevel3Level5: '[' }, 263 | Digit9: 264 | { value: '9', 265 | withShift: ')', 266 | withAltGr: ']', 267 | withShiftAltGr: '±', 268 | withLevel5: '9', 269 | withLevel3Level5: ']' }, 270 | Digit0: 271 | { value: '0', 272 | withShift: '=', 273 | withAltGr: '}', 274 | withShiftAltGr: '°', 275 | withLevel5: '0', 276 | withLevel3Level5: '}' }, 277 | Enter: 278 | { value: '\r', 279 | withShift: '\r', 280 | withAltGr: '\r', 281 | withShiftAltGr: '\r', 282 | withLevel5: '\r', 283 | withLevel3Level5: '\r' }, 284 | Escape: 285 | { value: '\u001b', 286 | withShift: '\u001b', 287 | withAltGr: '\u001b', 288 | withShiftAltGr: '\u001b', 289 | withLevel5: '\u001b', 290 | withLevel3Level5: '\u001b' }, 291 | Backspace: 292 | { value: '\b', 293 | withShift: '\b', 294 | withAltGr: '\b', 295 | withShiftAltGr: '\b', 296 | withLevel5: '\b', 297 | withLevel3Level5: '\b' }, 298 | Tab: 299 | { value: '\t', 300 | withShift: '', 301 | withAltGr: '\t', 302 | withShiftAltGr: '', 303 | withLevel5: '\t', 304 | withLevel3Level5: '\t' }, 305 | Space: 306 | { value: ' ', 307 | withShift: ' ', 308 | withAltGr: ' ', 309 | withShiftAltGr: ' ', 310 | withLevel5: ' ', 311 | withLevel3Level5: ' ' }, 312 | Minus: 313 | { value: '\'', 314 | withShift: '?', 315 | withAltGr: '\\', 316 | withShiftAltGr: '¿', 317 | withLevel5: '\'', 318 | withLevel3Level5: '\\' }, 319 | Equal: 320 | { value: '¡', 321 | withShift: '¿', 322 | withAltGr: '̃', 323 | withShiftAltGr: '~', 324 | withLevel5: '¡', 325 | withLevel3Level5: '̃' }, 326 | BracketLeft: 327 | { value: '̀', 328 | withShift: '̂', 329 | withAltGr: '[', 330 | withShiftAltGr: '̊', 331 | withLevel5: '̀', 332 | withLevel3Level5: '[' }, 333 | BracketRight: 334 | { value: '+', 335 | withShift: '*', 336 | withAltGr: ']', 337 | withShiftAltGr: '̄', 338 | withLevel5: '+', 339 | withLevel3Level5: ']' }, 340 | Backslash: 341 | { value: 'ç', 342 | withShift: 'Ç', 343 | withAltGr: '}', 344 | withShiftAltGr: '̆', 345 | withLevel5: 'ç', 346 | withLevel3Level5: '}' }, 347 | Semicolon: 348 | { value: 'ñ', 349 | withShift: 'Ñ', 350 | withAltGr: '~', 351 | withShiftAltGr: '̋', 352 | withLevel5: 'ñ', 353 | withLevel3Level5: '~' }, 354 | Quote: 355 | { value: '́', 356 | withShift: '̈', 357 | withAltGr: '{', 358 | withShiftAltGr: '{', 359 | withLevel5: '́', 360 | withLevel3Level5: '{' }, 361 | Backquote: 362 | { value: 'º', 363 | withShift: 'ª', 364 | withAltGr: '\\', 365 | withShiftAltGr: '\\', 366 | withLevel5: 'º', 367 | withLevel3Level5: '\\' }, 368 | Comma: 369 | { value: ',', 370 | withShift: ';', 371 | withAltGr: '─', 372 | withShiftAltGr: '×', 373 | withLevel5: ',', 374 | withLevel3Level5: '─' }, 375 | Period: 376 | { value: '.', 377 | withShift: ':', 378 | withAltGr: '·', 379 | withShiftAltGr: '÷', 380 | withLevel5: '.', 381 | withLevel3Level5: '·' }, 382 | Slash: 383 | { value: '-', 384 | withShift: '_', 385 | withAltGr: '̣', 386 | withShiftAltGr: '̇', 387 | withLevel5: '-', 388 | withLevel3Level5: '̣' }, 389 | CapsLock: 390 | { value: '', 391 | withShift: '', 392 | withAltGr: '', 393 | withShiftAltGr: '', 394 | withLevel5: '', 395 | withLevel3Level5: '' }, 396 | F1: 397 | { value: '', 398 | withShift: '', 399 | withAltGr: '', 400 | withShiftAltGr: '', 401 | withLevel5: '', 402 | withLevel3Level5: '' }, 403 | F2: 404 | { value: '', 405 | withShift: '', 406 | withAltGr: '', 407 | withShiftAltGr: '', 408 | withLevel5: '', 409 | withLevel3Level5: '' }, 410 | F3: 411 | { value: '', 412 | withShift: '', 413 | withAltGr: '', 414 | withShiftAltGr: '', 415 | withLevel5: '', 416 | withLevel3Level5: '' }, 417 | F4: 418 | { value: '', 419 | withShift: '', 420 | withAltGr: '', 421 | withShiftAltGr: '', 422 | withLevel5: '', 423 | withLevel3Level5: '' }, 424 | F5: 425 | { value: '', 426 | withShift: '', 427 | withAltGr: '', 428 | withShiftAltGr: '', 429 | withLevel5: '', 430 | withLevel3Level5: '' }, 431 | F6: 432 | { value: '', 433 | withShift: '', 434 | withAltGr: '', 435 | withShiftAltGr: '', 436 | withLevel5: '', 437 | withLevel3Level5: '' }, 438 | F7: 439 | { value: '', 440 | withShift: '', 441 | withAltGr: '', 442 | withShiftAltGr: '', 443 | withLevel5: '', 444 | withLevel3Level5: '' }, 445 | F8: 446 | { value: '', 447 | withShift: '', 448 | withAltGr: '', 449 | withShiftAltGr: '', 450 | withLevel5: '', 451 | withLevel3Level5: '' }, 452 | F9: 453 | { value: '', 454 | withShift: '', 455 | withAltGr: '', 456 | withShiftAltGr: '', 457 | withLevel5: '', 458 | withLevel3Level5: '' }, 459 | F10: 460 | { value: '', 461 | withShift: '', 462 | withAltGr: '', 463 | withShiftAltGr: '', 464 | withLevel5: '', 465 | withLevel3Level5: '' }, 466 | F11: 467 | { value: '', 468 | withShift: '', 469 | withAltGr: '', 470 | withShiftAltGr: '', 471 | withLevel5: '', 472 | withLevel3Level5: '' }, 473 | F12: 474 | { value: '', 475 | withShift: '', 476 | withAltGr: '', 477 | withShiftAltGr: '', 478 | withLevel5: '', 479 | withLevel3Level5: '' }, 480 | PrintScreen: 481 | { value: '', 482 | withShift: '', 483 | withAltGr: '', 484 | withShiftAltGr: '', 485 | withLevel5: '', 486 | withLevel3Level5: '' }, 487 | ScrollLock: 488 | { value: '', 489 | withShift: '', 490 | withAltGr: '', 491 | withShiftAltGr: '', 492 | withLevel5: '', 493 | withLevel3Level5: '' }, 494 | Pause: 495 | { value: '', 496 | withShift: '', 497 | withAltGr: '', 498 | withShiftAltGr: '', 499 | withLevel5: '', 500 | withLevel3Level5: '' }, 501 | Insert: 502 | { value: '', 503 | withShift: '', 504 | withAltGr: '', 505 | withShiftAltGr: '', 506 | withLevel5: '', 507 | withLevel3Level5: '' }, 508 | Home: 509 | { value: '', 510 | withShift: '', 511 | withAltGr: '', 512 | withShiftAltGr: '', 513 | withLevel5: '', 514 | withLevel3Level5: '' }, 515 | PageUp: 516 | { value: '', 517 | withShift: '', 518 | withAltGr: '', 519 | withShiftAltGr: '', 520 | withLevel5: '', 521 | withLevel3Level5: '' }, 522 | Delete: 523 | { value: '', 524 | withShift: '', 525 | withAltGr: '', 526 | withShiftAltGr: '', 527 | withLevel5: '', 528 | withLevel3Level5: '' }, 529 | End: 530 | { value: '', 531 | withShift: '', 532 | withAltGr: '', 533 | withShiftAltGr: '', 534 | withLevel5: '', 535 | withLevel3Level5: '' }, 536 | PageDown: 537 | { value: '', 538 | withShift: '', 539 | withAltGr: '', 540 | withShiftAltGr: '', 541 | withLevel5: '', 542 | withLevel3Level5: '' }, 543 | ArrowRight: 544 | { value: '', 545 | withShift: '', 546 | withAltGr: '', 547 | withShiftAltGr: '', 548 | withLevel5: '', 549 | withLevel3Level5: '' }, 550 | ArrowLeft: 551 | { value: '', 552 | withShift: '', 553 | withAltGr: '', 554 | withShiftAltGr: '', 555 | withLevel5: '', 556 | withLevel3Level5: '' }, 557 | ArrowDown: 558 | { value: '', 559 | withShift: '', 560 | withAltGr: '', 561 | withShiftAltGr: '', 562 | withLevel5: '', 563 | withLevel3Level5: '' }, 564 | ArrowUp: 565 | { value: '', 566 | withShift: '', 567 | withAltGr: '', 568 | withShiftAltGr: '', 569 | withLevel5: '', 570 | withLevel3Level5: '' }, 571 | NumLock: 572 | { value: '', 573 | withShift: '', 574 | withAltGr: '', 575 | withShiftAltGr: '', 576 | withLevel5: '', 577 | withLevel3Level5: '' }, 578 | NumpadDivide: 579 | { value: '/', 580 | withShift: '/', 581 | withAltGr: '/', 582 | withShiftAltGr: '/', 583 | withLevel5: '/', 584 | withLevel3Level5: '/' }, 585 | NumpadMultiply: 586 | { value: '*', 587 | withShift: '*', 588 | withAltGr: '*', 589 | withShiftAltGr: '*', 590 | withLevel5: '*', 591 | withLevel3Level5: '*' }, 592 | NumpadSubtract: 593 | { value: '-', 594 | withShift: '-', 595 | withAltGr: '-', 596 | withShiftAltGr: '-', 597 | withLevel5: '-', 598 | withLevel3Level5: '-' }, 599 | NumpadAdd: 600 | { value: '+', 601 | withShift: '+', 602 | withAltGr: '+', 603 | withShiftAltGr: '+', 604 | withLevel5: '+', 605 | withLevel3Level5: '+' }, 606 | NumpadEnter: 607 | { value: '\r', 608 | withShift: '\r', 609 | withAltGr: '\r', 610 | withShiftAltGr: '\r', 611 | withLevel5: '\r', 612 | withLevel3Level5: '\r' }, 613 | Numpad1: 614 | { value: '', 615 | withShift: '1', 616 | withAltGr: '', 617 | withShiftAltGr: '1', 618 | withLevel5: '', 619 | withLevel3Level5: '' }, 620 | Numpad2: 621 | { value: '', 622 | withShift: '2', 623 | withAltGr: '', 624 | withShiftAltGr: '2', 625 | withLevel5: '', 626 | withLevel3Level5: '' }, 627 | Numpad3: 628 | { value: '', 629 | withShift: '3', 630 | withAltGr: '', 631 | withShiftAltGr: '3', 632 | withLevel5: '', 633 | withLevel3Level5: '' }, 634 | Numpad4: 635 | { value: '', 636 | withShift: '4', 637 | withAltGr: '', 638 | withShiftAltGr: '4', 639 | withLevel5: '', 640 | withLevel3Level5: '' }, 641 | Numpad5: 642 | { value: '', 643 | withShift: '5', 644 | withAltGr: '', 645 | withShiftAltGr: '5', 646 | withLevel5: '', 647 | withLevel3Level5: '' }, 648 | Numpad6: 649 | { value: '', 650 | withShift: '6', 651 | withAltGr: '', 652 | withShiftAltGr: '6', 653 | withLevel5: '', 654 | withLevel3Level5: '' }, 655 | Numpad7: 656 | { value: '', 657 | withShift: '7', 658 | withAltGr: '', 659 | withShiftAltGr: '7', 660 | withLevel5: '', 661 | withLevel3Level5: '' }, 662 | Numpad8: 663 | { value: '', 664 | withShift: '8', 665 | withAltGr: '', 666 | withShiftAltGr: '8', 667 | withLevel5: '', 668 | withLevel3Level5: '' }, 669 | Numpad9: 670 | { value: '', 671 | withShift: '9', 672 | withAltGr: '', 673 | withShiftAltGr: '9', 674 | withLevel5: '', 675 | withLevel3Level5: '' }, 676 | Numpad0: 677 | { value: '', 678 | withShift: '0', 679 | withAltGr: '', 680 | withShiftAltGr: '0', 681 | withLevel5: '', 682 | withLevel3Level5: '' }, 683 | NumpadDecimal: 684 | { value: '', 685 | withShift: '.', 686 | withAltGr: '', 687 | withShiftAltGr: '.', 688 | withLevel5: '', 689 | withLevel3Level5: '' }, 690 | IntlBackslash: 691 | { value: '<', 692 | withShift: '>', 693 | withAltGr: '|', 694 | withShiftAltGr: '¦', 695 | withLevel5: '<', 696 | withLevel3Level5: '|' }, 697 | ContextMenu: 698 | { value: '', 699 | withShift: '', 700 | withAltGr: '', 701 | withShiftAltGr: '', 702 | withLevel5: '', 703 | withLevel3Level5: '' }, 704 | Power: 705 | { value: '', 706 | withShift: '', 707 | withAltGr: '', 708 | withShiftAltGr: '', 709 | withLevel5: '', 710 | withLevel3Level5: '' }, 711 | NumpadEqual: 712 | { value: '=', 713 | withShift: '=', 714 | withAltGr: '=', 715 | withShiftAltGr: '=', 716 | withLevel5: '=', 717 | withLevel3Level5: '=' }, 718 | F13: 719 | { value: '', 720 | withShift: '', 721 | withAltGr: '', 722 | withShiftAltGr: '', 723 | withLevel5: '', 724 | withLevel3Level5: '' }, 725 | F14: 726 | { value: '', 727 | withShift: '', 728 | withAltGr: '', 729 | withShiftAltGr: '', 730 | withLevel5: '', 731 | withLevel3Level5: '' }, 732 | F15: 733 | { value: '', 734 | withShift: '', 735 | withAltGr: '', 736 | withShiftAltGr: '', 737 | withLevel5: '', 738 | withLevel3Level5: '' }, 739 | F16: 740 | { value: '', 741 | withShift: '', 742 | withAltGr: '', 743 | withShiftAltGr: '', 744 | withLevel5: '', 745 | withLevel3Level5: '' }, 746 | F17: 747 | { value: '', 748 | withShift: '', 749 | withAltGr: '', 750 | withShiftAltGr: '', 751 | withLevel5: '', 752 | withLevel3Level5: '' }, 753 | F18: 754 | { value: '', 755 | withShift: '', 756 | withAltGr: '', 757 | withShiftAltGr: '', 758 | withLevel5: '', 759 | withLevel3Level5: '' }, 760 | F19: 761 | { value: '', 762 | withShift: '', 763 | withAltGr: '', 764 | withShiftAltGr: '', 765 | withLevel5: '', 766 | withLevel3Level5: '' }, 767 | F20: 768 | { value: '', 769 | withShift: '', 770 | withAltGr: '', 771 | withShiftAltGr: '', 772 | withLevel5: '', 773 | withLevel3Level5: '' }, 774 | F21: 775 | { value: '', 776 | withShift: '', 777 | withAltGr: '', 778 | withShiftAltGr: '', 779 | withLevel5: '', 780 | withLevel3Level5: '' }, 781 | F22: 782 | { value: '', 783 | withShift: '', 784 | withAltGr: '', 785 | withShiftAltGr: '', 786 | withLevel5: '', 787 | withLevel3Level5: '' }, 788 | F23: 789 | { value: '', 790 | withShift: '', 791 | withAltGr: '', 792 | withShiftAltGr: '', 793 | withLevel5: '', 794 | withLevel3Level5: '' }, 795 | F24: 796 | { value: '', 797 | withShift: '', 798 | withAltGr: '', 799 | withShiftAltGr: '', 800 | withLevel5: '', 801 | withLevel3Level5: '' }, 802 | Open: 803 | { value: '', 804 | withShift: '', 805 | withAltGr: '', 806 | withShiftAltGr: '', 807 | withLevel5: '', 808 | withLevel3Level5: '' }, 809 | Help: 810 | { value: '', 811 | withShift: '', 812 | withAltGr: '', 813 | withShiftAltGr: '', 814 | withLevel5: '', 815 | withLevel3Level5: '' }, 816 | Select: 817 | { value: '', 818 | withShift: '', 819 | withAltGr: '', 820 | withShiftAltGr: '', 821 | withLevel5: '', 822 | withLevel3Level5: '' }, 823 | Again: 824 | { value: '', 825 | withShift: '', 826 | withAltGr: '', 827 | withShiftAltGr: '', 828 | withLevel5: '', 829 | withLevel3Level5: '' }, 830 | Undo: 831 | { value: '', 832 | withShift: '', 833 | withAltGr: '', 834 | withShiftAltGr: '', 835 | withLevel5: '', 836 | withLevel3Level5: '' }, 837 | Cut: 838 | { value: '', 839 | withShift: '', 840 | withAltGr: '', 841 | withShiftAltGr: '', 842 | withLevel5: '', 843 | withLevel3Level5: '' }, 844 | Copy: 845 | { value: '', 846 | withShift: '', 847 | withAltGr: '', 848 | withShiftAltGr: '', 849 | withLevel5: '', 850 | withLevel3Level5: '' }, 851 | Paste: 852 | { value: '', 853 | withShift: '', 854 | withAltGr: '', 855 | withShiftAltGr: '', 856 | withLevel5: '', 857 | withLevel3Level5: '' }, 858 | Find: 859 | { value: '', 860 | withShift: '', 861 | withAltGr: '', 862 | withShiftAltGr: '', 863 | withLevel5: '', 864 | withLevel3Level5: '' }, 865 | AudioVolumeMute: 866 | { value: '', 867 | withShift: '', 868 | withAltGr: '', 869 | withShiftAltGr: '', 870 | withLevel5: '', 871 | withLevel3Level5: '' }, 872 | AudioVolumeUp: 873 | { value: '', 874 | withShift: '', 875 | withAltGr: '', 876 | withShiftAltGr: '', 877 | withLevel5: '', 878 | withLevel3Level5: '' }, 879 | AudioVolumeDown: 880 | { value: '', 881 | withShift: '', 882 | withAltGr: '', 883 | withShiftAltGr: '', 884 | withLevel5: '', 885 | withLevel3Level5: '' }, 886 | NumpadComma: 887 | { value: '.', 888 | withShift: '.', 889 | withAltGr: '.', 890 | withShiftAltGr: '.', 891 | withLevel5: '.', 892 | withLevel3Level5: '.' }, 893 | IntlRo: 894 | { value: '', 895 | withShift: '', 896 | withAltGr: '', 897 | withShiftAltGr: '', 898 | withLevel5: '', 899 | withLevel3Level5: '' }, 900 | KanaMode: 901 | { value: '', 902 | withShift: '', 903 | withAltGr: '', 904 | withShiftAltGr: '', 905 | withLevel5: '', 906 | withLevel3Level5: '' }, 907 | IntlYen: 908 | { value: '', 909 | withShift: '', 910 | withAltGr: '', 911 | withShiftAltGr: '', 912 | withLevel5: '', 913 | withLevel3Level5: '' }, 914 | Convert: 915 | { value: '', 916 | withShift: '', 917 | withAltGr: '', 918 | withShiftAltGr: '', 919 | withLevel5: '', 920 | withLevel3Level5: '' }, 921 | NonConvert: 922 | { value: '', 923 | withShift: '', 924 | withAltGr: '', 925 | withShiftAltGr: '', 926 | withLevel5: '', 927 | withLevel3Level5: '' }, 928 | Lang1: 929 | { value: '', 930 | withShift: '', 931 | withAltGr: '', 932 | withShiftAltGr: '', 933 | withLevel5: '', 934 | withLevel3Level5: '' }, 935 | Lang2: 936 | { value: '', 937 | withShift: '', 938 | withAltGr: '', 939 | withShiftAltGr: '', 940 | withLevel5: '', 941 | withLevel3Level5: '' }, 942 | Lang3: 943 | { value: '', 944 | withShift: '', 945 | withAltGr: '', 946 | withShiftAltGr: '', 947 | withLevel5: '', 948 | withLevel3Level5: '' }, 949 | Lang4: 950 | { value: '', 951 | withShift: '', 952 | withAltGr: '', 953 | withShiftAltGr: '', 954 | withLevel5: '', 955 | withLevel3Level5: '' }, 956 | Lang5: 957 | { value: '', 958 | withShift: '', 959 | withAltGr: '', 960 | withShiftAltGr: '', 961 | withLevel5: '', 962 | withLevel3Level5: '' }, 963 | NumpadParenLeft: 964 | { value: '(', 965 | withShift: '(', 966 | withAltGr: '(', 967 | withShiftAltGr: '(', 968 | withLevel5: '(', 969 | withLevel3Level5: '(' }, 970 | NumpadParenRight: 971 | { value: ')', 972 | withShift: ')', 973 | withAltGr: ')', 974 | withShiftAltGr: ')', 975 | withLevel5: ')', 976 | withLevel3Level5: ')' }, 977 | ControlLeft: 978 | { value: '', 979 | withShift: '', 980 | withAltGr: '', 981 | withShiftAltGr: '', 982 | withLevel5: '', 983 | withLevel3Level5: '' }, 984 | ShiftLeft: 985 | { value: '', 986 | withShift: '', 987 | withAltGr: '', 988 | withShiftAltGr: '', 989 | withLevel5: '', 990 | withLevel3Level5: '' }, 991 | AltLeft: 992 | { value: '', 993 | withShift: '', 994 | withAltGr: '', 995 | withShiftAltGr: '', 996 | withLevel5: '', 997 | withLevel3Level5: '' }, 998 | MetaLeft: 999 | { value: '', 1000 | withShift: '', 1001 | withAltGr: '', 1002 | withShiftAltGr: '', 1003 | withLevel5: '', 1004 | withLevel3Level5: '' }, 1005 | ControlRight: 1006 | { value: '', 1007 | withShift: '', 1008 | withAltGr: '', 1009 | withShiftAltGr: '', 1010 | withLevel5: '', 1011 | withLevel3Level5: '' }, 1012 | ShiftRight: 1013 | { value: '', 1014 | withShift: '', 1015 | withAltGr: '', 1016 | withShiftAltGr: '', 1017 | withLevel5: '', 1018 | withLevel3Level5: '' }, 1019 | AltRight: 1020 | { value: '', 1021 | withShift: '', 1022 | withAltGr: '', 1023 | withShiftAltGr: '', 1024 | withLevel5: '', 1025 | withLevel3Level5: '' }, 1026 | MetaRight: 1027 | { value: '', 1028 | withShift: '', 1029 | withAltGr: '', 1030 | withShiftAltGr: '', 1031 | withLevel5: '', 1032 | withLevel3Level5: '' }, 1033 | BrightnessUp: 1034 | { value: '', 1035 | withShift: '', 1036 | withAltGr: '', 1037 | withShiftAltGr: '', 1038 | withLevel5: '', 1039 | withLevel3Level5: '' }, 1040 | BrightnessDown: 1041 | { value: '', 1042 | withShift: '', 1043 | withAltGr: '', 1044 | withShiftAltGr: '', 1045 | withLevel5: '', 1046 | withLevel3Level5: '' }, 1047 | MediaPlay: 1048 | { value: '', 1049 | withShift: '', 1050 | withAltGr: '', 1051 | withShiftAltGr: '', 1052 | withLevel5: '', 1053 | withLevel3Level5: '' }, 1054 | MediaRecord: 1055 | { value: '', 1056 | withShift: '', 1057 | withAltGr: '', 1058 | withShiftAltGr: '', 1059 | withLevel5: '', 1060 | withLevel3Level5: '' }, 1061 | MediaFastForward: 1062 | { value: '', 1063 | withShift: '', 1064 | withAltGr: '', 1065 | withShiftAltGr: '', 1066 | withLevel5: '', 1067 | withLevel3Level5: '' }, 1068 | MediaRewind: 1069 | { value: '', 1070 | withShift: '', 1071 | withAltGr: '', 1072 | withShiftAltGr: '', 1073 | withLevel5: '', 1074 | withLevel3Level5: '' }, 1075 | MediaTrackNext: 1076 | { value: '', 1077 | withShift: '', 1078 | withAltGr: '', 1079 | withShiftAltGr: '', 1080 | withLevel5: '', 1081 | withLevel3Level5: '' }, 1082 | MediaTrackPrevious: 1083 | { value: '', 1084 | withShift: '', 1085 | withAltGr: '', 1086 | withShiftAltGr: '', 1087 | withLevel5: '', 1088 | withLevel3Level5: '' }, 1089 | MediaStop: 1090 | { value: '', 1091 | withShift: '', 1092 | withAltGr: '', 1093 | withShiftAltGr: '', 1094 | withLevel5: '', 1095 | withLevel3Level5: '' }, 1096 | Eject: 1097 | { value: '', 1098 | withShift: '', 1099 | withAltGr: '', 1100 | withShiftAltGr: '', 1101 | withLevel5: '', 1102 | withLevel3Level5: '' }, 1103 | MediaPlayPause: 1104 | { value: '', 1105 | withShift: '', 1106 | withAltGr: '', 1107 | withShiftAltGr: '', 1108 | withLevel5: '', 1109 | withLevel3Level5: '' }, 1110 | MediaSelect: 1111 | { value: '', 1112 | withShift: '', 1113 | withAltGr: '', 1114 | withShiftAltGr: '', 1115 | withLevel5: '', 1116 | withLevel3Level5: '' }, 1117 | LaunchMail: 1118 | { value: '', 1119 | withShift: '', 1120 | withAltGr: '', 1121 | withShiftAltGr: '', 1122 | withLevel5: '', 1123 | withLevel3Level5: '' }, 1124 | LaunchApp2: 1125 | { value: '', 1126 | withShift: '', 1127 | withAltGr: '', 1128 | withShiftAltGr: '', 1129 | withLevel5: '', 1130 | withLevel3Level5: '' }, 1131 | LaunchApp1: 1132 | { value: '', 1133 | withShift: '', 1134 | withAltGr: '', 1135 | withShiftAltGr: '', 1136 | withLevel5: '', 1137 | withLevel3Level5: '' }, 1138 | SelectTask: 1139 | { value: '', 1140 | withShift: '', 1141 | withAltGr: '', 1142 | withShiftAltGr: '', 1143 | withLevel5: '', 1144 | withLevel3Level5: '' }, 1145 | LaunchScreenSaver: 1146 | { value: '', 1147 | withShift: '', 1148 | withAltGr: '', 1149 | withShiftAltGr: '', 1150 | withLevel5: '', 1151 | withLevel3Level5: '' }, 1152 | BrowserSearch: 1153 | { value: '', 1154 | withShift: '', 1155 | withAltGr: '', 1156 | withShiftAltGr: '', 1157 | withLevel5: '', 1158 | withLevel3Level5: '' }, 1159 | BrowserHome: 1160 | { value: '', 1161 | withShift: '', 1162 | withAltGr: '', 1163 | withShiftAltGr: '', 1164 | withLevel5: '', 1165 | withLevel3Level5: '' }, 1166 | BrowserBack: 1167 | { value: '', 1168 | withShift: '', 1169 | withAltGr: '', 1170 | withShiftAltGr: '', 1171 | withLevel5: '', 1172 | withLevel3Level5: '' }, 1173 | BrowserForward: 1174 | { value: '', 1175 | withShift: '', 1176 | withAltGr: '', 1177 | withShiftAltGr: '', 1178 | withLevel5: '', 1179 | withLevel3Level5: '' }, 1180 | BrowserStop: 1181 | { value: '', 1182 | withShift: '', 1183 | withAltGr: '', 1184 | withShiftAltGr: '', 1185 | withLevel5: '', 1186 | withLevel3Level5: '' }, 1187 | BrowserRefresh: 1188 | { value: '', 1189 | withShift: '', 1190 | withAltGr: '', 1191 | withShiftAltGr: '', 1192 | withLevel5: '', 1193 | withLevel3Level5: '' }, 1194 | BrowserFavorites: 1195 | { value: '', 1196 | withShift: '', 1197 | withAltGr: '', 1198 | withShiftAltGr: '', 1199 | withLevel5: '', 1200 | withLevel3Level5: '' }, 1201 | MailReply: 1202 | { value: '', 1203 | withShift: '', 1204 | withAltGr: '', 1205 | withShiftAltGr: '', 1206 | withLevel5: '', 1207 | withLevel3Level5: '' }, 1208 | MailForward: 1209 | { value: '', 1210 | withShift: '', 1211 | withAltGr: '', 1212 | withShiftAltGr: '', 1213 | withLevel5: '', 1214 | withLevel3Level5: '' }, 1215 | MailSend: 1216 | { value: '', 1217 | withShift: '', 1218 | withAltGr: '', 1219 | withShiftAltGr: '', 1220 | withLevel5: '', 1221 | withLevel3Level5: '' } } 1222 | -------------------------------------------------------------------------------- /test/mac/chinese-pinyin.txt: -------------------------------------------------------------------------------- 1 | 2 | > native-keymap@1.1.0 test /Users/code/Alex/src/node-native-keymap 3 | > node test/test.js 4 | 5 | getCurrentKeyboardLayout: { id: 'com.apple.inputmethod.SCIM.ITABC', lang: 'zh-Hans' } 6 | ------------- 7 | getKeyMap: {} 8 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | var index = require('../index'); 7 | 8 | console.log('getCurrentKeyboardLayout: ', index.getCurrentKeyboardLayout()); 9 | console.log('-------------') 10 | console.log('getKeyMap: ', index.getKeyMap()); 11 | --------------------------------------------------------------------------------