diff --git a/package.json b/package.json index 1d683c6..450a182 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,11 @@ { "name": "atom-keymap", - "version": "6.3.2", + "version": "6.3.3-beta1", "description": "Atom's DOM-aware keymap module", "main": "./lib/keymap-manager", "scripts": { "prepublish": "npm run clean && npm run compile && npm run lint && npm run atomdoc", - "clean": "rm -rf lib && rm -rf api.json", + "clean": "rimraf lib && rimraf api.json", "compile": "coffee --no-header --output lib --compile src && babel src --out-dir lib", "lint": "coffeelint -r src spec && eslint src spec", "test": "devtool --quit --console node_modules/mocha/bin/_mocha --colors spec/helpers/setup.js spec/*", @@ -27,7 +27,7 @@ "event-kit": "^1.0.0", "fs-plus": "^2.0.4", "grim": "^1.2.1", - "keyboard-layout": "^1.0", + "keyboard-layout": "^1.2.0", "pathwatcher": "^6.2", "property-accessors": "^1", "season": "^5.0.2" @@ -39,12 +39,11 @@ "babel-preset-stage-0": "6.5.0", "babel-register": "6.5.2", "chai": "3.5.0", - "coffee-cache": "0.2.0", "coffee-script": "1.7.0", "coffeelint": "1.14.2", "debounce": "1.0.0", - "devtool": "1.9.1", - "electron-rebuild": "1.1.3", + "devtool": "2.2.0", + "electron-rebuild": "1.2.1", "eslint": "2.2.0", "eslint-config-standard": "5.1.0", "eslint-plugin-promise": "1.0.8", @@ -55,7 +54,6 @@ "grunt-coffeelint": "0.0.6", "grunt-contrib-coffee": "0.9.0", "grunt-shell": "0.2.2", - "jasmine-focused": "1.0.4", "lolex": "1.4.0", "mocha": "2.4.5", "rimraf": "2.2.2", diff --git a/spec/helpers/helpers.js b/spec/helpers/helpers.js index 76825ee..6d3be54 100644 --- a/spec/helpers/helpers.js +++ b/spec/helpers/helpers.js @@ -5,7 +5,11 @@ import lolex from 'lolex' import sinon from 'sinon' -let sinonSandbox, fakeClock +let sinonSandbox, fakeClock, processPlatform, originalProcessPlatform + +originalProcessPlatform = process.platform +processPlatform = process.platform +Object.defineProperty(process, 'platform', {get: () => processPlatform}) beforeEach(function () { document.body.innerHTML = '' @@ -16,6 +20,7 @@ beforeEach(function () { afterEach(function () { fakeClock.uninstall() sinonSandbox.restore() + processPlatform = originalProcessPlatform }) export function appendContent (element) { @@ -30,3 +35,7 @@ export function stub () { export function getFakeClock () { return fakeClock } + +export function mockProcessPlatform (platform) { + processPlatform = platform +} diff --git a/spec/helpers/keymaps/mac-dvorak-qwerty-cmd.json b/spec/helpers/keymaps/mac-dvorak-qwerty-cmd.json new file mode 100644 index 0000000..c9c6893 --- /dev/null +++ b/spec/helpers/keymaps/mac-dvorak-qwerty-cmd.json @@ -0,0 +1,398 @@ +{ + "KeyA": { + "unmodified": "a", + "withShift": "A", + "withAltGraph": "å", + "withAltGraphShift": "Å" + }, + "KeyB": { + "unmodified": "x", + "withShift": "X", + "withAltGraph": "≈", + "withAltGraphShift": "˛" + }, + "KeyC": { + "unmodified": "j", + "withShift": "J", + "withAltGraph": "∆", + "withAltGraphShift": "Ô" + }, + "KeyD": { + "unmodified": "e", + "withShift": "E", + "withAltGraph": null, + "withAltGraphShift": "´" + }, + "KeyE": { + "unmodified": ".", + "withShift": ">", + "withAltGraph": "≥", + "withAltGraphShift": "˘" + }, + "KeyF": { + "unmodified": "u", + "withShift": "U", + "withAltGraph": null, + "withAltGraphShift": "¨" + }, + "KeyG": { + "unmodified": "i", + "withShift": "I", + "withAltGraph": null, + "withAltGraphShift": "ˆ" + }, + "KeyH": { + "unmodified": "d", + "withShift": "D", + "withAltGraph": "∂", + "withAltGraphShift": "Î" + }, + "KeyI": { + "unmodified": "c", + "withShift": "C", + "withAltGraph": "ç", + "withAltGraphShift": "Ç" + }, + "KeyJ": { + "unmodified": "h", + "withShift": "H", + "withAltGraph": "˙", + "withAltGraphShift": "Ó" + }, + "KeyK": { + "unmodified": "t", + "withShift": "T", + "withAltGraph": "†", + "withAltGraphShift": "ˇ" + }, + "KeyL": { + "unmodified": "n", + "withShift": "N", + "withAltGraph": null, + "withAltGraphShift": "˜" + }, + "KeyM": { + "unmodified": "m", + "withShift": "M", + "withAltGraph": "µ", + "withAltGraphShift": "Â" + }, + "KeyN": { + "unmodified": "b", + "withShift": "B", + "withAltGraph": "∫", + "withAltGraphShift": "ı" + }, + "KeyO": { + "unmodified": "r", + "withShift": "R", + "withAltGraph": "®", + "withAltGraphShift": "‰" + }, + "KeyP": { + "unmodified": "l", + "withShift": "L", + "withAltGraph": "¬", + "withAltGraphShift": "Ò" + }, + "KeyQ": { + "unmodified": "'", + "withShift": "\"", + "withAltGraph": "æ", + "withAltGraphShift": "Æ" + }, + "KeyR": { + "unmodified": "p", + "withShift": "P", + "withAltGraph": "π", + "withAltGraphShift": "∏" + }, + "KeyS": { + "unmodified": "o", + "withShift": "O", + "withAltGraph": "ø", + "withAltGraphShift": "Ø" + }, + "KeyT": { + "unmodified": "y", + "withShift": "Y", + "withAltGraph": "¥", + "withAltGraphShift": "Á" + }, + "KeyU": { + "unmodified": "g", + "withShift": "G", + "withAltGraph": "©", + "withAltGraphShift": "˝" + }, + "KeyV": { + "unmodified": "k", + "withShift": "K", + "withAltGraph": "˚", + "withAltGraphShift": "" + }, + "KeyW": { + "unmodified": ",", + "withShift": "<", + "withAltGraph": "≤", + "withAltGraphShift": "¯" + }, + "KeyX": { + "unmodified": "q", + "withShift": "Q", + "withAltGraph": "œ", + "withAltGraphShift": "Œ" + }, + "KeyY": { + "unmodified": "f", + "withShift": "F", + "withAltGraph": "ƒ", + "withAltGraphShift": "Ï" + }, + "KeyZ": { + "unmodified": ";", + "withShift": ":", + "withAltGraph": "…", + "withAltGraphShift": "Ú" + }, + "Digit1": { + "unmodified": "1", + "withShift": "!", + "withAltGraph": "¡", + "withAltGraphShift": "⁄" + }, + "Digit2": { + "unmodified": "2", + "withShift": "@", + "withAltGraph": "™", + "withAltGraphShift": "€" + }, + "Digit3": { + "unmodified": "3", + "withShift": "#", + "withAltGraph": "£", + "withAltGraphShift": "‹" + }, + "Digit4": { + "unmodified": "4", + "withShift": "$", + "withAltGraph": "¢", + "withAltGraphShift": "›" + }, + "Digit5": { + "unmodified": "5", + "withShift": "%", + "withAltGraph": "∞", + "withAltGraphShift": "fi" + }, + "Digit6": { + "unmodified": "6", + "withShift": "^", + "withAltGraph": "§", + "withAltGraphShift": "fl" + }, + "Digit7": { + "unmodified": "7", + "withShift": "&", + "withAltGraph": "¶", + "withAltGraphShift": "‡" + }, + "Digit8": { + "unmodified": "8", + "withShift": "*", + "withAltGraph": "•", + "withAltGraphShift": "°" + }, + "Digit9": { + "unmodified": "9", + "withShift": "(", + "withAltGraph": "ª", + "withAltGraphShift": "·" + }, + "Digit0": { + "unmodified": "0", + "withShift": ")", + "withAltGraph": "º", + "withAltGraphShift": "‚" + }, + "Space": { + "unmodified": " ", + "withShift": " ", + "withAltGraph": " ", + "withAltGraphShift": " " + }, + "Minus": { + "unmodified": "[", + "withShift": "{", + "withAltGraph": "“", + "withAltGraphShift": "”" + }, + "Equal": { + "unmodified": "]", + "withShift": "}", + "withAltGraph": "‘", + "withAltGraphShift": "’" + }, + "BracketLeft": { + "unmodified": "/", + "withShift": "?", + "withAltGraph": "÷", + "withAltGraphShift": "¿" + }, + "BracketRight": { + "unmodified": "=", + "withShift": "+", + "withAltGraph": "≠", + "withAltGraphShift": "±" + }, + "Backslash": { + "unmodified": "\\", + "withShift": "|", + "withAltGraph": "«", + "withAltGraphShift": "»" + }, + "Semicolon": { + "unmodified": "s", + "withShift": "S", + "withAltGraph": "ß", + "withAltGraphShift": "Í" + }, + "Quote": { + "unmodified": "-", + "withShift": "_", + "withAltGraph": "–", + "withAltGraphShift": "—" + }, + "Backquote": { + "unmodified": "`", + "withShift": "~", + "withAltGraph": null, + "withAltGraphShift": "`" + }, + "Comma": { + "unmodified": "w", + "withShift": "W", + "withAltGraph": "∑", + "withAltGraphShift": "„" + }, + "Period": { + "unmodified": "v", + "withShift": "V", + "withAltGraph": "√", + "withAltGraphShift": "◊" + }, + "Slash": { + "unmodified": "z", + "withShift": "Z", + "withAltGraph": "Ω", + "withAltGraphShift": "¸" + }, + "NumpadDivide": { + "unmodified": "/", + "withShift": "/", + "withAltGraph": "/", + "withAltGraphShift": "/" + }, + "NumpadMultiply": { + "unmodified": "*", + "withShift": "*", + "withAltGraph": "*", + "withAltGraphShift": "*" + }, + "NumpadSubtract": { + "unmodified": "-", + "withShift": "-", + "withAltGraph": "-", + "withAltGraphShift": "-" + }, + "NumpadAdd": { + "unmodified": "+", + "withShift": "+", + "withAltGraph": "+", + "withAltGraphShift": "+" + }, + "Numpad1": { + "unmodified": "1", + "withShift": "1", + "withAltGraph": "1", + "withAltGraphShift": "1" + }, + "Numpad2": { + "unmodified": "2", + "withShift": "2", + "withAltGraph": "2", + "withAltGraphShift": "2" + }, + "Numpad3": { + "unmodified": "3", + "withShift": "3", + "withAltGraph": "3", + "withAltGraphShift": "3" + }, + "Numpad4": { + "unmodified": "4", + "withShift": "4", + "withAltGraph": "4", + "withAltGraphShift": "4" + }, + "Numpad5": { + "unmodified": "5", + "withShift": "5", + "withAltGraph": "5", + "withAltGraphShift": "5" + }, + "Numpad6": { + "unmodified": "6", + "withShift": "6", + "withAltGraph": "6", + "withAltGraphShift": "6" + }, + "Numpad7": { + "unmodified": "7", + "withShift": "7", + "withAltGraph": "7", + "withAltGraphShift": "7" + }, + "Numpad8": { + "unmodified": "8", + "withShift": "8", + "withAltGraph": "8", + "withAltGraphShift": "8" + }, + "Numpad9": { + "unmodified": "9", + "withShift": "9", + "withAltGraph": "9", + "withAltGraphShift": "9" + }, + "Numpad0": { + "unmodified": "0", + "withShift": "0", + "withAltGraph": "0", + "withAltGraphShift": "0" + }, + "NumpadDecimal": { + "unmodified": ".", + "withShift": ".", + "withAltGraph": ".", + "withAltGraphShift": "." + }, + "IntlBackslash": { + "unmodified": "§", + "withShift": "±", + "withAltGraph": "§", + "withAltGraphShift": "±" + }, + "NumpadEqual": { + "unmodified": "=", + "withShift": "=", + "withAltGraph": "=", + "withAltGraphShift": "=" + }, + "AudioVolumeUp": { + "unmodified": null, + "withShift": "=", + "withAltGraph": null, + "withAltGraphShift": "=" + } +} diff --git a/spec/helpers/keymaps/mac-greek.json b/spec/helpers/keymaps/mac-greek.json new file mode 100644 index 0000000..591fc47 --- /dev/null +++ b/spec/helpers/keymaps/mac-greek.json @@ -0,0 +1,398 @@ +{ + "KeyA": { + "unmodified": "α", + "withShift": "Α", + "withAltGraph": "…", + "withAltGraphShift": "ά" + }, + "KeyB": { + "unmodified": "β", + "withShift": "Β", + "withAltGraph": null, + "withAltGraphShift": null + }, + "KeyC": { + "unmodified": "ψ", + "withShift": "Ψ", + "withAltGraph": "ç", + "withAltGraphShift": "Χ" + }, + "KeyD": { + "unmodified": "δ", + "withShift": "Δ", + "withAltGraph": "÷", + "withAltGraphShift": null + }, + "KeyE": { + "unmodified": "ε", + "withShift": "Ε", + "withAltGraph": "€", + "withAltGraphShift": "Έ" + }, + "KeyF": { + "unmodified": "φ", + "withShift": "Φ", + "withAltGraph": "≠", + "withAltGraphShift": "Π" + }, + "KeyG": { + "unmodified": "γ", + "withShift": "Γ", + "withAltGraph": "©", + "withAltGraphShift": "Ϊ" + }, + "KeyH": { + "unmodified": "η", + "withShift": "Η", + "withAltGraph": "½", + "withAltGraphShift": "≠" + }, + "KeyI": { + "unmodified": "ι", + "withShift": "Ι", + "withAltGraph": "†", + "withAltGraphShift": "Ν" + }, + "KeyJ": { + "unmodified": "ξ", + "withShift": "Ξ", + "withAltGraph": "≤", + "withAltGraphShift": "§" + }, + "KeyK": { + "unmodified": "κ", + "withShift": "Κ", + "withAltGraph": "≥", + "withAltGraphShift": "°" + }, + "KeyL": { + "unmodified": "λ", + "withShift": "Λ", + "withAltGraph": "¬", + "withAltGraphShift": "·" + }, + "KeyM": { + "unmodified": "μ", + "withShift": "Μ", + "withAltGraph": "’", + "withAltGraphShift": "Ύ" + }, + "KeyN": { + "unmodified": "ν", + "withShift": "Ν", + "withAltGraph": "‘", + "withAltGraphShift": "Ό" + }, + "KeyO": { + "unmodified": "ο", + "withShift": "Ο", + "withAltGraph": "œ", + "withAltGraphShift": "Τ" + }, + "KeyP": { + "unmodified": "π", + "withShift": "Π", + "withAltGraph": "≈", + "withAltGraphShift": null + }, + "KeyQ": { + "unmodified": ";", + "withShift": ":", + "withAltGraph": "·", + "withAltGraphShift": "―" + }, + "KeyR": { + "unmodified": "ρ", + "withShift": "Ρ", + "withAltGraph": "®", + "withAltGraphShift": "Δ" + }, + "KeyS": { + "unmodified": "σ", + "withShift": "Σ", + "withAltGraph": "ß", + "withAltGraphShift": "ρ" + }, + "KeyT": { + "unmodified": "τ", + "withShift": "Τ", + "withAltGraph": "™", + "withAltGraphShift": null + }, + "KeyU": { + "unmodified": "θ", + "withShift": "Θ", + "withAltGraph": "­", + "withAltGraphShift": "Ξ" + }, + "KeyV": { + "unmodified": "ω", + "withShift": "Ω", + "withAltGraph": "±", + "withAltGraphShift": "Ά" + }, + "KeyW": { + "unmodified": "ς", + "withShift": null, + "withAltGraph": "―", + "withAltGraphShift": "Β" + }, + "KeyX": { + "unmodified": "χ", + "withShift": "Χ", + "withAltGraph": null, + "withAltGraphShift": null + }, + "KeyY": { + "unmodified": "υ", + "withShift": "Υ", + "withAltGraph": "¥", + "withAltGraphShift": null + }, + "KeyZ": { + "unmodified": "ζ", + "withShift": "Ζ", + "withAltGraph": "§", + "withAltGraphShift": null + }, + "Digit1": { + "unmodified": "1", + "withShift": "!", + "withAltGraph": "¹", + "withAltGraphShift": "έ" + }, + "Digit2": { + "unmodified": "2", + "withShift": "@", + "withAltGraph": "²", + "withAltGraphShift": "ί" + }, + "Digit3": { + "unmodified": "3", + "withShift": "#", + "withAltGraph": "³", + "withAltGraphShift": "ή" + }, + "Digit4": { + "unmodified": "4", + "withShift": "$", + "withAltGraph": "£", + "withAltGraphShift": "ό" + }, + "Digit5": { + "unmodified": "5", + "withShift": "%", + "withAltGraph": "§", + "withAltGraphShift": "Ώ" + }, + "Digit6": { + "unmodified": "6", + "withShift": "^", + "withAltGraph": "¶", + "withAltGraphShift": "^" + }, + "Digit7": { + "unmodified": "7", + "withShift": "&", + "withAltGraph": "°", + "withAltGraphShift": null + }, + "Digit8": { + "unmodified": "8", + "withShift": "*", + "withAltGraph": "•", + "withAltGraphShift": "Ρ" + }, + "Digit9": { + "unmodified": "9", + "withShift": "(", + "withAltGraph": "“", + "withAltGraphShift": "Κ" + }, + "Digit0": { + "unmodified": "0", + "withShift": ")", + "withAltGraph": "°", + "withAltGraphShift": "ύ" + }, + "Space": { + "unmodified": " ", + "withShift": " ", + "withAltGraph": " ", + "withAltGraphShift": " " + }, + "Minus": { + "unmodified": "-", + "withShift": "_", + "withAltGraph": "±", + "withAltGraphShift": "_" + }, + "Equal": { + "unmodified": "=", + "withShift": "+", + "withAltGraph": "½", + "withAltGraphShift": "+" + }, + "BracketLeft": { + "unmodified": "[", + "withShift": "{", + "withAltGraph": "«", + "withAltGraphShift": "{" + }, + "BracketRight": { + "unmodified": "]", + "withShift": "}", + "withAltGraph": "»", + "withAltGraphShift": "}" + }, + "Backslash": { + "unmodified": "\\", + "withShift": "|", + "withAltGraph": "¦", + "withAltGraphShift": "Ζ" + }, + "Semicolon": { + "unmodified": null, + "withShift": null, + "withAltGraph": null, + "withAltGraphShift": ":" + }, + "Quote": { + "unmodified": "'", + "withShift": "\"", + "withAltGraph": "'", + "withAltGraphShift": "\"" + }, + "Backquote": { + "unmodified": "`", + "withShift": "~", + "withAltGraph": "`", + "withAltGraphShift": "Μ" + }, + "Comma": { + "unmodified": ",", + "withShift": "<", + "withAltGraph": "«", + "withAltGraphShift": null + }, + "Period": { + "unmodified": ".", + "withShift": ">", + "withAltGraph": "»", + "withAltGraphShift": "ώ" + }, + "Slash": { + "unmodified": "/", + "withShift": "?", + "withAltGraph": "/", + "withAltGraphShift": "?" + }, + "NumpadDivide": { + "unmodified": "/", + "withShift": "/", + "withAltGraph": "/", + "withAltGraphShift": "/" + }, + "NumpadMultiply": { + "unmodified": "*", + "withShift": "*", + "withAltGraph": "*", + "withAltGraphShift": "*" + }, + "NumpadSubtract": { + "unmodified": "-", + "withShift": "-", + "withAltGraph": "-", + "withAltGraphShift": "-" + }, + "NumpadAdd": { + "unmodified": "+", + "withShift": "+", + "withAltGraph": "+", + "withAltGraphShift": "+" + }, + "Numpad1": { + "unmodified": "1", + "withShift": "1", + "withAltGraph": "1", + "withAltGraphShift": "1" + }, + "Numpad2": { + "unmodified": "2", + "withShift": "2", + "withAltGraph": "2", + "withAltGraphShift": "2" + }, + "Numpad3": { + "unmodified": "3", + "withShift": "3", + "withAltGraph": "3", + "withAltGraphShift": "3" + }, + "Numpad4": { + "unmodified": "4", + "withShift": "4", + "withAltGraph": "4", + "withAltGraphShift": "4" + }, + "Numpad5": { + "unmodified": "5", + "withShift": "5", + "withAltGraph": "5", + "withAltGraphShift": "5" + }, + "Numpad6": { + "unmodified": "6", + "withShift": "6", + "withAltGraph": "6", + "withAltGraphShift": "6" + }, + "Numpad7": { + "unmodified": "7", + "withShift": "7", + "withAltGraph": "7", + "withAltGraphShift": "7" + }, + "Numpad8": { + "unmodified": "8", + "withShift": "8", + "withAltGraph": "8", + "withAltGraphShift": "8" + }, + "Numpad9": { + "unmodified": "9", + "withShift": "9", + "withAltGraph": "9", + "withAltGraphShift": "9" + }, + "Numpad0": { + "unmodified": "0", + "withShift": "0", + "withAltGraph": "0", + "withAltGraphShift": "0" + }, + "NumpadDecimal": { + "unmodified": ".", + "withShift": ".", + "withAltGraph": ".", + "withAltGraphShift": "." + }, + "IntlBackslash": { + "unmodified": "§", + "withShift": "±", + "withAltGraph": null, + "withAltGraphShift": null + }, + "NumpadEqual": { + "unmodified": "=", + "withShift": "=", + "withAltGraph": "=", + "withAltGraphShift": "=" + }, + "AudioVolumeUp": { + "unmodified": null, + "withShift": "=", + "withAltGraph": null, + "withAltGraphShift": "=" + } +} diff --git a/spec/helpers/keymaps/mac-swiss-german.json b/spec/helpers/keymaps/mac-swiss-german.json new file mode 100644 index 0000000..f137aa0 --- /dev/null +++ b/spec/helpers/keymaps/mac-swiss-german.json @@ -0,0 +1,398 @@ +{ + "KeyA": { + "unmodified": "a", + "withShift": "A", + "withAltGraph": "å", + "withAltGraphShift": "Å" + }, + "KeyB": { + "unmodified": "b", + "withShift": "B", + "withAltGraph": "∫", + "withAltGraphShift": null + }, + "KeyC": { + "unmodified": "c", + "withShift": "C", + "withAltGraph": "©", + "withAltGraphShift": null + }, + "KeyD": { + "unmodified": "d", + "withShift": "D", + "withAltGraph": "∂", + "withAltGraphShift": "fl" + }, + "KeyE": { + "unmodified": "e", + "withShift": "E", + "withAltGraph": "€", + "withAltGraphShift": "Ë" + }, + "KeyF": { + "unmodified": "f", + "withShift": "F", + "withAltGraph": "ƒ", + "withAltGraphShift": "‡" + }, + "KeyG": { + "unmodified": "g", + "withShift": "G", + "withAltGraph": "@", + "withAltGraphShift": "‚" + }, + "KeyH": { + "unmodified": "h", + "withShift": "H", + "withAltGraph": "ª", + "withAltGraphShift": "·" + }, + "KeyI": { + "unmodified": "i", + "withShift": "I", + "withAltGraph": "¡", + "withAltGraphShift": "ı" + }, + "KeyJ": { + "unmodified": "j", + "withShift": "J", + "withAltGraph": "º", + "withAltGraphShift": "˜" + }, + "KeyK": { + "unmodified": "k", + "withShift": "K", + "withAltGraph": "∆", + "withAltGraphShift": "¯" + }, + "KeyL": { + "unmodified": "l", + "withShift": "L", + "withAltGraph": "¬", + "withAltGraphShift": "ˆ" + }, + "KeyM": { + "unmodified": "m", + "withShift": "M", + "withAltGraph": "µ", + "withAltGraphShift": "˚" + }, + "KeyN": { + "unmodified": "n", + "withShift": "N", + "withAltGraph": null, + "withAltGraphShift": "˙" + }, + "KeyO": { + "unmodified": "o", + "withShift": "O", + "withAltGraph": "ø", + "withAltGraphShift": "Ø" + }, + "KeyP": { + "unmodified": "p", + "withShift": "P", + "withAltGraph": "π", + "withAltGraphShift": "∏" + }, + "KeyQ": { + "unmodified": "q", + "withShift": "Q", + "withAltGraph": "œ", + "withAltGraphShift": "Œ" + }, + "KeyR": { + "unmodified": "r", + "withShift": "R", + "withAltGraph": "®", + "withAltGraphShift": "È" + }, + "KeyS": { + "unmodified": "s", + "withShift": "S", + "withAltGraph": "ß", + "withAltGraphShift": "fi" + }, + "KeyT": { + "unmodified": "t", + "withShift": "T", + "withAltGraph": "†", + "withAltGraphShift": "Î" + }, + "KeyU": { + "unmodified": "u", + "withShift": "U", + "withAltGraph": "°", + "withAltGraphShift": "Ù" + }, + "KeyV": { + "unmodified": "v", + "withShift": "V", + "withAltGraph": "√", + "withAltGraphShift": "◊" + }, + "KeyW": { + "unmodified": "w", + "withShift": "W", + "withAltGraph": "∑", + "withAltGraphShift": "Á" + }, + "KeyX": { + "unmodified": "x", + "withShift": "X", + "withAltGraph": "≈", + "withAltGraphShift": "™" + }, + "KeyY": { + "unmodified": "z", + "withShift": "Z", + "withAltGraph": "Ω", + "withAltGraphShift": "Í" + }, + "KeyZ": { + "unmodified": "y", + "withShift": "Y", + "withAltGraph": "¥", + "withAltGraphShift": "Ÿ" + }, + "Digit1": { + "unmodified": "1", + "withShift": "+", + "withAltGraph": "±", + "withAltGraphShift": "∞" + }, + "Digit2": { + "unmodified": "2", + "withShift": "\"", + "withAltGraph": "“", + "withAltGraphShift": "”" + }, + "Digit3": { + "unmodified": "3", + "withShift": "*", + "withAltGraph": "#", + "withAltGraphShift": "‹" + }, + "Digit4": { + "unmodified": "4", + "withShift": "ç", + "withAltGraph": "Ç", + "withAltGraphShift": "⁄" + }, + "Digit5": { + "unmodified": "5", + "withShift": "%", + "withAltGraph": "[", + "withAltGraphShift": "[" + }, + "Digit6": { + "unmodified": "6", + "withShift": "&", + "withAltGraph": "]", + "withAltGraphShift": "]" + }, + "Digit7": { + "unmodified": "7", + "withShift": "/", + "withAltGraph": "|", + "withAltGraphShift": "\\" + }, + "Digit8": { + "unmodified": "8", + "withShift": "(", + "withAltGraph": "{", + "withAltGraphShift": "Ò" + }, + "Digit9": { + "unmodified": "9", + "withShift": ")", + "withAltGraph": "}", + "withAltGraphShift": "Ô" + }, + "Digit0": { + "unmodified": "0", + "withShift": "=", + "withAltGraph": "≠", + "withAltGraphShift": "Ú" + }, + "Space": { + "unmodified": " ", + "withShift": " ", + "withAltGraph": " ", + "withAltGraphShift": " " + }, + "Minus": { + "unmodified": "'", + "withShift": "?", + "withAltGraph": "¿", + "withAltGraphShift": "" + }, + "Equal": { + "unmodified": null, + "withShift": null, + "withAltGraph": null, + "withAltGraphShift": "^" + }, + "BracketLeft": { + "unmodified": "ü", + "withShift": "è", + "withAltGraph": "§", + "withAltGraphShift": "ÿ" + }, + "BracketRight": { + "unmodified": null, + "withShift": "!", + "withAltGraph": "‘", + "withAltGraphShift": "’" + }, + "Backslash": { + "unmodified": "$", + "withShift": "£", + "withAltGraph": "¶", + "withAltGraphShift": "•" + }, + "Semicolon": { + "unmodified": "ö", + "withShift": "é", + "withAltGraph": "¢", + "withAltGraphShift": "˘" + }, + "Quote": { + "unmodified": "ä", + "withShift": "à", + "withAltGraph": "æ", + "withAltGraphShift": "Æ" + }, + "Backquote": { + "unmodified": "<", + "withShift": ">", + "withAltGraph": "≤", + "withAltGraphShift": "≥" + }, + "Comma": { + "unmodified": ",", + "withShift": ";", + "withAltGraph": "«", + "withAltGraphShift": "»" + }, + "Period": { + "unmodified": ".", + "withShift": ":", + "withAltGraph": "…", + "withAltGraphShift": "÷" + }, + "Slash": { + "unmodified": "-", + "withShift": "_", + "withAltGraph": "–", + "withAltGraphShift": "—" + }, + "NumpadDivide": { + "unmodified": "/", + "withShift": "/", + "withAltGraph": "/", + "withAltGraphShift": "/" + }, + "NumpadMultiply": { + "unmodified": "*", + "withShift": "*", + "withAltGraph": "*", + "withAltGraphShift": "*" + }, + "NumpadSubtract": { + "unmodified": "-", + "withShift": "-", + "withAltGraph": "-", + "withAltGraphShift": "-" + }, + "NumpadAdd": { + "unmodified": "+", + "withShift": "+", + "withAltGraph": "+", + "withAltGraphShift": "+" + }, + "Numpad1": { + "unmodified": "1", + "withShift": "1", + "withAltGraph": "1", + "withAltGraphShift": "1" + }, + "Numpad2": { + "unmodified": "2", + "withShift": "2", + "withAltGraph": "2", + "withAltGraphShift": "2" + }, + "Numpad3": { + "unmodified": "3", + "withShift": "3", + "withAltGraph": "3", + "withAltGraphShift": "3" + }, + "Numpad4": { + "unmodified": "4", + "withShift": "4", + "withAltGraph": "4", + "withAltGraphShift": "4" + }, + "Numpad5": { + "unmodified": "5", + "withShift": "5", + "withAltGraph": "5", + "withAltGraphShift": "5" + }, + "Numpad6": { + "unmodified": "6", + "withShift": "6", + "withAltGraph": "6", + "withAltGraphShift": "6" + }, + "Numpad7": { + "unmodified": "7", + "withShift": "7", + "withAltGraph": "7", + "withAltGraphShift": "7" + }, + "Numpad8": { + "unmodified": "8", + "withShift": "8", + "withAltGraph": "8", + "withAltGraphShift": "8" + }, + "Numpad9": { + "unmodified": "9", + "withShift": "9", + "withAltGraph": "9", + "withAltGraphShift": "9" + }, + "Numpad0": { + "unmodified": "0", + "withShift": "0", + "withAltGraph": "0", + "withAltGraphShift": "0" + }, + "NumpadDecimal": { + "unmodified": ".", + "withShift": ",", + "withAltGraph": ".", + "withAltGraphShift": "." + }, + "IntlBackslash": { + "unmodified": "§", + "withShift": "°", + "withAltGraph": "fi", + "withAltGraphShift": "‰" + }, + "NumpadEqual": { + "unmodified": "=", + "withShift": "=", + "withAltGraph": "=", + "withAltGraphShift": "=" + }, + "AudioVolumeUp": { + "unmodified": null, + "withShift": "=", + "withAltGraph": null, + "withAltGraphShift": "=" + } +} diff --git a/spec/helpers/keymaps/mac-turkish.json b/spec/helpers/keymaps/mac-turkish.json new file mode 100644 index 0000000..1dff3c2 --- /dev/null +++ b/spec/helpers/keymaps/mac-turkish.json @@ -0,0 +1,398 @@ +{ + "KeyA": { + "unmodified": "u", + "withShift": "U", + "withAltGraph": "", + "withAltGraphShift": "Ë" + }, + "KeyB": { + "unmodified": "ç", + "withShift": "Ç", + "withAltGraph": "¯", + "withAltGraphShift": "˙" + }, + "KeyC": { + "unmodified": "v", + "withShift": "V", + "withAltGraph": "√", + "withAltGraphShift": "◊" + }, + "KeyD": { + "unmodified": "e", + "withShift": "E", + "withAltGraph": null, + "withAltGraphShift": "‰" + }, + "KeyE": { + "unmodified": "ğ", + "withShift": "Ğ", + "withAltGraph": "#", + "withAltGraphShift": "´" + }, + "KeyF": { + "unmodified": "a", + "withShift": "A", + "withAltGraph": "å", + "withAltGraphShift": "Å" + }, + "KeyG": { + "unmodified": "ü", + "withShift": "Ü", + "withAltGraph": "@", + "withAltGraphShift": "ª" + }, + "KeyH": { + "unmodified": "t", + "withShift": "T", + "withAltGraph": "₺", + "withAltGraphShift": "Ê" + }, + "KeyI": { + "unmodified": "n", + "withShift": "N", + "withAltGraph": null, + "withAltGraphShift": "ˆ" + }, + "KeyJ": { + "unmodified": "k", + "withShift": "K", + "withAltGraph": null, + "withAltGraphShift": "©" + }, + "KeyK": { + "unmodified": "m", + "withShift": "M", + "withAltGraph": "µ", + "withAltGraphShift": "˜" + }, + "KeyL": { + "unmodified": "l", + "withShift": "L", + "withAltGraph": "¬", + "withAltGraphShift": "£" + }, + "KeyM": { + "unmodified": "s", + "withShift": "S", + "withAltGraph": "§", + "withAltGraphShift": "~" + }, + "KeyN": { + "unmodified": "z", + "withShift": "Z", + "withAltGraph": "Ω", + "withAltGraphShift": "Û" + }, + "KeyO": { + "unmodified": "h", + "withShift": "H", + "withAltGraph": null, + "withAltGraphShift": "Ó" + }, + "KeyP": { + "unmodified": "p", + "withShift": "P", + "withAltGraph": "π", + "withAltGraphShift": "∏" + }, + "KeyQ": { + "unmodified": "f", + "withShift": "F", + "withAltGraph": "ƒ", + "withAltGraphShift": "Ï" + }, + "KeyR": { + "unmodified": "ı", + "withShift": "I", + "withAltGraph": "^", + "withAltGraphShift": "È" + }, + "KeyS": { + "unmodified": "i", + "withShift": "İ", + "withAltGraph": null, + "withAltGraphShift": "∞" + }, + "KeyT": { + "unmodified": "o", + "withShift": "O", + "withAltGraph": "ø", + "withAltGraphShift": "Ø" + }, + "KeyU": { + "unmodified": "r", + "withShift": "R", + "withAltGraph": "®", + "withAltGraphShift": "Â" + }, + "KeyV": { + "unmodified": "c", + "withShift": "C", + "withAltGraph": "ç", + "withAltGraphShift": "˚" + }, + "KeyW": { + "unmodified": "g", + "withShift": "G", + "withAltGraph": "¶", + "withAltGraphShift": "`" + }, + "KeyX": { + "unmodified": "ö", + "withShift": "Ö", + "withAltGraph": "¨", + "withAltGraphShift": "Ÿ" + }, + "KeyY": { + "unmodified": "d", + "withShift": "D", + "withAltGraph": "∂", + "withAltGraphShift": "Î" + }, + "KeyZ": { + "unmodified": "j", + "withShift": "J", + "withAltGraph": "∆", + "withAltGraphShift": "Ô" + }, + "Digit1": { + "unmodified": "1", + "withShift": "!", + "withAltGraph": "¡", + "withAltGraphShift": "·" + }, + "Digit2": { + "unmodified": "2", + "withShift": "*", + "withAltGraph": "™", + "withAltGraphShift": "€" + }, + "Digit3": { + "unmodified": "3", + "withShift": "\"", + "withAltGraph": "“", + "withAltGraphShift": "”" + }, + "Digit4": { + "unmodified": "4", + "withShift": "'", + "withAltGraph": "‘", + "withAltGraphShift": "’" + }, + "Digit5": { + "unmodified": "5", + "withShift": "(", + "withAltGraph": "[", + "withAltGraphShift": "{" + }, + "Digit6": { + "unmodified": "6", + "withShift": "/", + "withAltGraph": "|", + "withAltGraphShift": "\\" + }, + "Digit7": { + "unmodified": "7", + "withShift": ")", + "withAltGraph": "]", + "withAltGraphShift": "}" + }, + "Digit8": { + "unmodified": "8", + "withShift": "_", + "withAltGraph": "•", + "withAltGraphShift": "°" + }, + "Digit9": { + "unmodified": "9", + "withShift": "%", + "withAltGraph": "«", + "withAltGraphShift": "»" + }, + "Digit0": { + "unmodified": "0", + "withShift": ":", + "withAltGraph": "º", + "withAltGraphShift": "÷" + }, + "Space": { + "unmodified": " ", + "withShift": " ", + "withAltGraph": " ", + "withAltGraphShift": " " + }, + "Minus": { + "unmodified": "x", + "withShift": "X", + "withAltGraph": "≈", + "withAltGraphShift": "Ù" + }, + "Equal": { + "unmodified": "q", + "withShift": "Q", + "withAltGraph": "œ", + "withAltGraphShift": "Œ" + }, + "BracketLeft": { + "unmodified": ";", + "withShift": "$", + "withAltGraph": "…", + "withAltGraphShift": "¢" + }, + "BracketRight": { + "unmodified": ">", + "withShift": "<", + "withAltGraph": "≥", + "withAltGraphShift": "≤" + }, + "Backslash": { + "unmodified": "=", + "withShift": "+", + "withAltGraph": "≠", + "withAltGraphShift": "±" + }, + "Semicolon": { + "unmodified": "y", + "withShift": "Y", + "withAltGraph": "¥", + "withAltGraphShift": "Á" + }, + "Quote": { + "unmodified": "ş", + "withShift": "Ş", + "withAltGraph": "æ", + "withAltGraphShift": "Æ" + }, + "Backquote": { + "unmodified": "w", + "withShift": "W", + "withAltGraph": "∑", + "withAltGraphShift": "„" + }, + "Comma": { + "unmodified": "b", + "withShift": "B", + "withAltGraph": "∫", + "withAltGraphShift": "ß" + }, + "Period": { + "unmodified": ".", + "withShift": "?", + "withAltGraph": "&", + "withAltGraphShift": "¿" + }, + "Slash": { + "unmodified": ",", + "withShift": "-", + "withAltGraph": "–", + "withAltGraphShift": "—" + }, + "NumpadDivide": { + "unmodified": "/", + "withShift": "/", + "withAltGraph": "/", + "withAltGraphShift": "/" + }, + "NumpadMultiply": { + "unmodified": "*", + "withShift": "*", + "withAltGraph": "*", + "withAltGraphShift": "*" + }, + "NumpadSubtract": { + "unmodified": "-", + "withShift": "-", + "withAltGraph": "-", + "withAltGraphShift": "-" + }, + "NumpadAdd": { + "unmodified": "+", + "withShift": "+", + "withAltGraph": "+", + "withAltGraphShift": "+" + }, + "Numpad1": { + "unmodified": "1", + "withShift": "1", + "withAltGraph": "1", + "withAltGraphShift": "1" + }, + "Numpad2": { + "unmodified": "2", + "withShift": "2", + "withAltGraph": "2", + "withAltGraphShift": "2" + }, + "Numpad3": { + "unmodified": "3", + "withShift": "3", + "withAltGraph": "3", + "withAltGraphShift": "3" + }, + "Numpad4": { + "unmodified": "4", + "withShift": "4", + "withAltGraph": "4", + "withAltGraphShift": "4" + }, + "Numpad5": { + "unmodified": "5", + "withShift": "5", + "withAltGraph": "5", + "withAltGraphShift": "5" + }, + "Numpad6": { + "unmodified": "6", + "withShift": "6", + "withAltGraph": "6", + "withAltGraphShift": "6" + }, + "Numpad7": { + "unmodified": "7", + "withShift": "7", + "withAltGraph": "7", + "withAltGraphShift": "7" + }, + "Numpad8": { + "unmodified": "8", + "withShift": "8", + "withAltGraph": "8", + "withAltGraphShift": "8" + }, + "Numpad9": { + "unmodified": "9", + "withShift": "9", + "withAltGraph": "9", + "withAltGraphShift": "9" + }, + "Numpad0": { + "unmodified": "0", + "withShift": "0", + "withAltGraph": "0", + "withAltGraphShift": "0" + }, + "NumpadDecimal": { + "unmodified": ",", + "withShift": ",", + "withAltGraph": ",", + "withAltGraphShift": "," + }, + "IntlBackslash": { + "unmodified": "§", + "withShift": "±", + "withAltGraph": null, + "withAltGraphShift": null + }, + "NumpadEqual": { + "unmodified": "=", + "withShift": "=", + "withAltGraph": "=", + "withAltGraphShift": "=" + }, + "AudioVolumeUp": { + "unmodified": null, + "withShift": "=", + "withAltGraph": null, + "withAltGraphShift": "=" + } +} diff --git a/spec/helpers/keymaps/windows-swiss-german.json b/spec/helpers/keymaps/windows-swiss-german.json new file mode 100644 index 0000000..32194af --- /dev/null +++ b/spec/helpers/keymaps/windows-swiss-german.json @@ -0,0 +1,314 @@ +{ + "KeyA": { + "unmodified": "a", + "withShift": "A", + "withAltGraph": null, + "withAltGraphShift": null + }, + "KeyB": { + "unmodified": "b", + "withShift": "B", + "withAltGraph": null, + "withAltGraphShift": null + }, + "KeyC": { + "unmodified": "c", + "withShift": "C", + "withAltGraph": null, + "withAltGraphShift": null + }, + "KeyD": { + "unmodified": "d", + "withShift": "D", + "withAltGraph": null, + "withAltGraphShift": null + }, + "KeyE": { + "unmodified": "e", + "withShift": "E", + "withAltGraph": null, + "withAltGraphShift": null + }, + "KeyF": { + "unmodified": "f", + "withShift": "F", + "withAltGraph": null, + "withAltGraphShift": null + }, + "KeyG": { + "unmodified": "g", + "withShift": "G", + "withAltGraph": null, + "withAltGraphShift": null + }, + "KeyH": { + "unmodified": "h", + "withShift": "H", + "withAltGraph": null, + "withAltGraphShift": null + }, + "KeyI": { + "unmodified": "i", + "withShift": "I", + "withAltGraph": null, + "withAltGraphShift": null + }, + "KeyJ": { + "unmodified": "j", + "withShift": "J", + "withAltGraph": null, + "withAltGraphShift": null + }, + "KeyK": { + "unmodified": "k", + "withShift": "K", + "withAltGraph": null, + "withAltGraphShift": null + }, + "KeyL": { + "unmodified": "l", + "withShift": "L", + "withAltGraph": null, + "withAltGraphShift": null + }, + "KeyM": { + "unmodified": "m", + "withShift": "M", + "withAltGraph": null, + "withAltGraphShift": null + }, + "KeyN": { + "unmodified": "n", + "withShift": "N", + "withAltGraph": null, + "withAltGraphShift": null + }, + "KeyO": { + "unmodified": "o", + "withShift": "O", + "withAltGraph": null, + "withAltGraphShift": null + }, + "KeyP": { + "unmodified": "p", + "withShift": "P", + "withAltGraph": null, + "withAltGraphShift": null + }, + "KeyQ": { + "unmodified": "q", + "withShift": "Q", + "withAltGraph": null, + "withAltGraphShift": null + }, + "KeyR": { + "unmodified": "r", + "withShift": "R", + "withAltGraph": null, + "withAltGraphShift": null + }, + "KeyS": { + "unmodified": "s", + "withShift": "S", + "withAltGraph": null, + "withAltGraphShift": null + }, + "KeyT": { + "unmodified": "t", + "withShift": "T", + "withAltGraph": null, + "withAltGraphShift": null + }, + "KeyU": { + "unmodified": "u", + "withShift": "U", + "withAltGraph": null, + "withAltGraphShift": null + }, + "KeyV": { + "unmodified": "v", + "withShift": "V", + "withAltGraph": null, + "withAltGraphShift": null + }, + "KeyW": { + "unmodified": "w", + "withShift": "W", + "withAltGraph": null, + "withAltGraphShift": null + }, + "KeyX": { + "unmodified": "x", + "withShift": "X", + "withAltGraph": null, + "withAltGraphShift": null + }, + "KeyY": { + "unmodified": "z", + "withShift": "Z", + "withAltGraph": null, + "withAltGraphShift": null + }, + "KeyZ": { + "unmodified": "y", + "withShift": "Y", + "withAltGraph": null, + "withAltGraphShift": null + }, + "Digit1": { + "unmodified": "1", + "withShift": "+", + "withAltGraph": "¦", + "withAltGraphShift": null + }, + "Digit2": { + "unmodified": "2", + "withShift": "\"", + "withAltGraph": "@", + "withAltGraphShift": null + }, + "Digit3": { + "unmodified": "3", + "withShift": "*", + "withAltGraph": "#", + "withAltGraphShift": null + }, + "Digit4": { + "unmodified": "4", + "withShift": "ç", + "withAltGraph": "°", + "withAltGraphShift": null + }, + "Digit5": { + "unmodified": "5", + "withShift": "%", + "withAltGraph": "§", + "withAltGraphShift": null + }, + "Digit6": { + "unmodified": "6", + "withShift": "&", + "withAltGraph": "¬", + "withAltGraphShift": null + }, + "Digit7": { + "unmodified": "7", + "withShift": "/", + "withAltGraph": "|", + "withAltGraphShift": null + }, + "Digit8": { + "unmodified": "8", + "withShift": "(", + "withAltGraph": "¢", + "withAltGraphShift": null + }, + "Digit9": { + "unmodified": "9", + "withShift": ")", + "withAltGraph": null, + "withAltGraphShift": null + }, + "Digit0": { + "unmodified": "0", + "withShift": "=", + "withAltGraph": null, + "withAltGraphShift": null + }, + "Space": { + "unmodified": " ", + "withShift": " ", + "withAltGraph": null, + "withAltGraphShift": null + }, + "Minus": { + "unmodified": "'", + "withShift": "?", + "withAltGraph": null, + "withAltGraphShift": null + }, + "Equal": { + "unmodified": "´^", + "withShift": null, + "withAltGraph": "`~", + "withAltGraphShift": null + }, + "BracketLeft": { + "unmodified": "ü", + "withShift": "è", + "withAltGraph": "[", + "withAltGraphShift": null + }, + "BracketRight": { + "unmodified": null, + "withShift": "¨!", + "withAltGraph": "]", + "withAltGraphShift": null + }, + "Backslash": { + "unmodified": "$", + "withShift": "£", + "withAltGraph": "}", + "withAltGraphShift": null + }, + "Semicolon": { + "unmodified": "ö", + "withShift": "é", + "withAltGraph": null, + "withAltGraphShift": null + }, + "Quote": { + "unmodified": "ä", + "withShift": "à", + "withAltGraph": "{", + "withAltGraphShift": null + }, + "Backquote": { + "unmodified": "§", + "withShift": "°", + "withAltGraph": null, + "withAltGraphShift": null + }, + "Comma": { + "unmodified": ",", + "withShift": ";", + "withAltGraph": null, + "withAltGraphShift": null + }, + "Period": { + "unmodified": ".", + "withShift": ":", + "withAltGraph": null, + "withAltGraphShift": null + }, + "Slash": { + "unmodified": "-", + "withShift": "_", + "withAltGraph": null, + "withAltGraphShift": null + }, + "NumpadMultiply": { + "unmodified": "*", + "withShift": "*", + "withAltGraph": null, + "withAltGraphShift": null + }, + "NumpadSubtract": { + "unmodified": "-", + "withShift": "-", + "withAltGraph": null, + "withAltGraphShift": null + }, + "NumpadAdd": { + "unmodified": "+", + "withShift": "+", + "withAltGraph": null, + "withAltGraphShift": null + }, + "IntlBackslash": { + "unmodified": "<", + "withShift": ">", + "withAltGraph": "\\", + "withAltGraphShift": null + } +} diff --git a/spec/helpers/keymaps/windows-us-international.json b/spec/helpers/keymaps/windows-us-international.json new file mode 100644 index 0000000..4d426c4 --- /dev/null +++ b/spec/helpers/keymaps/windows-us-international.json @@ -0,0 +1,314 @@ +{ + "KeyA": { + "unmodified": "a", + "withShift": "A", + "withAltGraph": "á", + "withAltGraphShift": "Á" + }, + "KeyB": { + "unmodified": "b", + "withShift": "B", + "withAltGraph": null, + "withAltGraphShift": null + }, + "KeyC": { + "unmodified": "c", + "withShift": "C", + "withAltGraph": "©", + "withAltGraphShift": "¢" + }, + "KeyD": { + "unmodified": "d", + "withShift": "D", + "withAltGraph": "ð", + "withAltGraphShift": "Ð" + }, + "KeyE": { + "unmodified": "e", + "withShift": "E", + "withAltGraph": "é", + "withAltGraphShift": "É" + }, + "KeyF": { + "unmodified": "f", + "withShift": "F", + "withAltGraph": null, + "withAltGraphShift": null + }, + "KeyG": { + "unmodified": "g", + "withShift": "G", + "withAltGraph": null, + "withAltGraphShift": null + }, + "KeyH": { + "unmodified": "h", + "withShift": "H", + "withAltGraph": null, + "withAltGraphShift": null + }, + "KeyI": { + "unmodified": "i", + "withShift": "I", + "withAltGraph": "í", + "withAltGraphShift": "Í" + }, + "KeyJ": { + "unmodified": "j", + "withShift": "J", + "withAltGraph": null, + "withAltGraphShift": null + }, + "KeyK": { + "unmodified": "k", + "withShift": "K", + "withAltGraph": null, + "withAltGraphShift": null + }, + "KeyL": { + "unmodified": "l", + "withShift": "L", + "withAltGraph": "ø", + "withAltGraphShift": "Ø" + }, + "KeyM": { + "unmodified": "m", + "withShift": "M", + "withAltGraph": "µ", + "withAltGraphShift": null + }, + "KeyN": { + "unmodified": "n", + "withShift": "N", + "withAltGraph": "ñ", + "withAltGraphShift": "Ñ" + }, + "KeyO": { + "unmodified": "o", + "withShift": "O", + "withAltGraph": "ó", + "withAltGraphShift": "Ó" + }, + "KeyP": { + "unmodified": "p", + "withShift": "P", + "withAltGraph": "ö", + "withAltGraphShift": "Ö" + }, + "KeyQ": { + "unmodified": "q", + "withShift": "Q", + "withAltGraph": "ä", + "withAltGraphShift": "Ä" + }, + "KeyR": { + "unmodified": "r", + "withShift": "R", + "withAltGraph": "®", + "withAltGraphShift": null + }, + "KeyS": { + "unmodified": "s", + "withShift": "S", + "withAltGraph": "ß", + "withAltGraphShift": "§" + }, + "KeyT": { + "unmodified": "t", + "withShift": "T", + "withAltGraph": "þ", + "withAltGraphShift": "Þ" + }, + "KeyU": { + "unmodified": "u", + "withShift": "U", + "withAltGraph": "ú", + "withAltGraphShift": "Ú" + }, + "KeyV": { + "unmodified": "v", + "withShift": "V", + "withAltGraph": null, + "withAltGraphShift": null + }, + "KeyW": { + "unmodified": "w", + "withShift": "W", + "withAltGraph": "å", + "withAltGraphShift": "Å" + }, + "KeyX": { + "unmodified": "x", + "withShift": "X", + "withAltGraph": null, + "withAltGraphShift": null + }, + "KeyY": { + "unmodified": "y", + "withShift": "Y", + "withAltGraph": "ü", + "withAltGraphShift": "Ü" + }, + "KeyZ": { + "unmodified": "z", + "withShift": "Z", + "withAltGraph": "æ", + "withAltGraphShift": "Æ" + }, + "Digit1": { + "unmodified": "1", + "withShift": "!", + "withAltGraph": "¡", + "withAltGraphShift": "¹" + }, + "Digit2": { + "unmodified": "2", + "withShift": "@", + "withAltGraph": "²", + "withAltGraphShift": null + }, + "Digit3": { + "unmodified": "3", + "withShift": "#", + "withAltGraph": "³", + "withAltGraphShift": null + }, + "Digit4": { + "unmodified": "4", + "withShift": "$", + "withAltGraph": "¤", + "withAltGraphShift": "£" + }, + "Digit5": { + "unmodified": "5", + "withShift": "%", + "withAltGraph": null, + "withAltGraphShift": null + }, + "Digit6": { + "unmodified": "6", + "withShift": null, + "withAltGraph": "^¼", + "withAltGraphShift": null + }, + "Digit7": { + "unmodified": "7", + "withShift": "&", + "withAltGraph": "½", + "withAltGraphShift": null + }, + "Digit8": { + "unmodified": "8", + "withShift": "*", + "withAltGraph": "¾", + "withAltGraphShift": null + }, + "Digit9": { + "unmodified": "9", + "withShift": "(", + "withAltGraph": "‘", + "withAltGraphShift": null + }, + "Digit0": { + "unmodified": "0", + "withShift": ")", + "withAltGraph": null, + "withAltGraphShift": null + }, + "Space": { + "unmodified": " ", + "withShift": " ", + "withAltGraph": null, + "withAltGraphShift": null + }, + "Minus": { + "unmodified": "-", + "withShift": "_", + "withAltGraph": "¥", + "withAltGraphShift": null + }, + "Equal": { + "unmodified": "=", + "withShift": "+", + "withAltGraph": "×", + "withAltGraphShift": "÷" + }, + "BracketLeft": { + "unmodified": "[", + "withShift": "{", + "withAltGraph": "«", + "withAltGraphShift": null + }, + "BracketRight": { + "unmodified": "]", + "withShift": "}", + "withAltGraph": "»", + "withAltGraphShift": null + }, + "Backslash": { + "unmodified": "\\", + "withShift": "|", + "withAltGraph": "¬", + "withAltGraphShift": "¦" + }, + "Semicolon": { + "unmodified": ";", + "withShift": ":", + "withAltGraph": "¶", + "withAltGraphShift": "°" + }, + "Quote": { + "unmodified": null, + "withShift": "'\"", + "withAltGraph": "´", + "withAltGraphShift": "¨" + }, + "Backquote": { + "unmodified": null, + "withShift": "`~", + "withAltGraph": null, + "withAltGraphShift": null + }, + "Comma": { + "unmodified": ",", + "withShift": "<", + "withAltGraph": "ç", + "withAltGraphShift": "Ç" + }, + "Period": { + "unmodified": ".", + "withShift": ">", + "withAltGraph": null, + "withAltGraphShift": null + }, + "Slash": { + "unmodified": "/", + "withShift": "?", + "withAltGraph": "¿", + "withAltGraphShift": null + }, + "NumpadMultiply": { + "unmodified": "*", + "withShift": "*", + "withAltGraph": null, + "withAltGraphShift": null + }, + "NumpadSubtract": { + "unmodified": "-", + "withShift": "-", + "withAltGraph": null, + "withAltGraphShift": null + }, + "NumpadAdd": { + "unmodified": "+", + "withShift": "+", + "withAltGraph": null, + "withAltGraphShift": null + }, + "IntlBackslash": { + "unmodified": "\\", + "withShift": "|", + "withAltGraph": null, + "withAltGraphShift": null + } +} diff --git a/spec/helpers/setup.js b/spec/helpers/setup.js index ac4b496..f66d58b 100644 --- a/spec/helpers/setup.js +++ b/spec/helpers/setup.js @@ -1,5 +1,5 @@ require('babel-register') -require('coffee-cache') +require('coffee-script/register') global.assert = require('chai').assert diff --git a/spec/keymap-manager-spec.coffee b/spec/keymap-manager-spec.coffee index bdf2dca..b368816 100644 --- a/spec/keymap-manager-spec.coffee +++ b/spec/keymap-manager-spec.coffee @@ -3,14 +3,16 @@ debounce = require 'debounce' fs = require 'fs-plus' path = require 'path' temp = require 'temp' -{appendContent, stub, getFakeClock} = require './helpers/helpers' +KeyboardLayout = require('keyboard-layout') KeymapManager = require '../src/keymap-manager' {buildKeydownEvent, buildKeyupEvent} = KeymapManager +{appendContent, stub, getFakeClock, mockProcessPlatform} = require './helpers/helpers' describe "KeymapManager", -> keymapManager = null beforeEach -> + mockProcessPlatform('darwin') keymapManager = new KeymapManager afterEach -> @@ -316,7 +318,7 @@ describe "KeymapManager", -> workspace.addEventListener 'control-dog', -> events.push('control-dog') - keymapManager.handleKeyboardEvent(buildKeydownEvent('ctrl-d', target: editor)) + keymapManager.handleKeyboardEvent(buildKeydownEvent('d', ctrl: true, target: editor)) keymapManager.handleKeyboardEvent(buildKeydownEvent('o', target: editor)) getFakeClock().tick(keymapManager.getPartialMatchTimeout()) @@ -580,120 +582,102 @@ describe "KeymapManager", -> assert.equal(keymapManager.findKeyBindings(command: 'z').length, 0) describe "::keystrokeForKeyboardEvent(event)", -> - describe "when no modifiers are pressed", -> + describe "when no extra modifiers are pressed", -> it "returns a string that identifies the unmodified keystroke", -> - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('a')), 'a') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('[')), '[') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('*')), '*') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('left')), 'left') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('\b')), 'backspace') + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: 'a'}), 'a') + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: 'A', shiftKey: true}), 'shift-A') + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: '['}), '[') + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: '*', shiftKey: true}), '*') + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: 'ArrowLeft'}), 'left') + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: 'Backspace'}), 'backspace') + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: 'Delete'}), 'delete') + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: 'PageUp'}), 'pageup') describe "when a modifier key is combined with a non-modifier key", -> it "returns a string that identifies the modified keystroke", -> - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('a', alt: true)), 'alt-a') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('[', cmd: true)), 'cmd-[') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('*', ctrl: true)), 'ctrl-*') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('left', ctrl: true, alt: true, cmd: true)), 'ctrl-alt-cmd-left') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('A', shift: true)), 'shift-A') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('a', ctrl: true, shift: true)), 'ctrl-shift-A') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('{', shift: true)), '{') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('left', shift: true)), 'shift-left') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('Left', shift: true)), 'shift-left') - - describe "when a numpad key is pressed", -> - it "returns a string that identifies the key as the appropriate num-key", -> - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+0041', keyCode: 97, location: 3)), '1') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+0045', keyCode: 101, location: 3)), '5') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+0049', keyCode: 105, location: 3)), '9') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('PageDown', keyCode: 34, location: 3)), 'pagedown') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('PageUp', keyCode: 33, location: 3)), 'pageup') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+004B', keyCode: 107, location: 3)), '+') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+007F', keyCode: 46, location: 3)), 'delete') - - describe "when a non-English keyboard language is used", -> - it "uses the physical character pressed instead of the character it maps to in the current language", -> - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+03B6', cmd: true, keyCode: 122)), 'cmd-z') - - describe "when KeymapManager::dvorakQwertyWorkaroundEnabled is true", -> - it "uses event.keyCode instead of event.keyIdentifier when event.keyIdentifier is numeric", -> - keymapManager.dvorakQwertyWorkaroundEnabled = true - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+004A', cmd: true, keyCode: 67)), 'cmd-c') - - it "maps the keyCode for delete (46) to the ASCII code for delete (127)", -> - keymapManager.dvorakQwertyWorkaroundEnabled = true - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+007F', keyCode: 46)), 'delete') - - describe "on Windows and Linux", -> - originalPlatform = null + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: 'a', altKey: true}), 'alt-a') + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: '[', metaKey: true}), 'cmd-[') + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: '*', ctrlKey: true, shiftKey: true}), 'ctrl-*') + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: 'ArrowLeft', ctrlKey: true, altKey: true, metaKey: true}), 'ctrl-alt-cmd-left') + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: 'A', shiftKey: true}), 'shift-A') + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: 'A', ctrlKey: true, shiftKey: true}), 'ctrl-shift-A') + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: '{', shiftKey: true}), '{') + + describe "when the Dvorak QWERTY-⌘ layout is in use on macOS", -> + it "uses the US layout equivalent when the command key is held down", -> + mockProcessPlatform('darwin') + stub(KeyboardLayout, 'getCurrentKeymap', -> require('./helpers/keymaps/mac-dvorak-qwerty-cmd')) + stub(KeyboardLayout, 'getCurrentKeyboardLayout', -> 'com.apple.keylayout.DVORAK-QWERTYCMD') + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: 'l', code: 'KeyP', altKey: true}), 'alt-l') + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: 'l', code: 'KeyP', ctrlKey: true, altKey: true}), 'ctrl-alt-l') + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: 'l', code: 'KeyP', metaKey: true}), 'cmd-p') + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: 'L', code: 'KeyP', metaKey: true, shiftKey: true}), 'shift-cmd-P') + + describe "international layouts", -> + currentKeymap = null beforeEach -> - originalPlatform = process.platform - - afterEach -> - Object.defineProperty process, 'platform', value: originalPlatform - - it "corrects a Chromium bug where the keyIdentifier is incorrect for certain keypress events", -> - testTranslations = -> - # Number row - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+0030', ctrl: true)), 'ctrl-0') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+0031', ctrl: true)), 'ctrl-1') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+0032', ctrl: true)), 'ctrl-2') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+0033', ctrl: true)), 'ctrl-3') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+0034', ctrl: true)), 'ctrl-4') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+0035', ctrl: true)), 'ctrl-5') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+0036', ctrl: true)), 'ctrl-6') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+0037', ctrl: true)), 'ctrl-7') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+0038', ctrl: true)), 'ctrl-8') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+0039', ctrl: true)), 'ctrl-9') - - # Number row shifted - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+0030', ctrl: true, shift: true)), 'ctrl-)') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+0031', ctrl: true, shift: true)), 'ctrl-!') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+0032', ctrl: true, shift: true)), 'ctrl-@') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+0033', ctrl: true, shift: true)), 'ctrl-#') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+0034', ctrl: true, shift: true)), 'ctrl-$') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+0035', ctrl: true, shift: true)), 'ctrl-%') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+0036', ctrl: true, shift: true)), 'ctrl-^') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+0037', ctrl: true, shift: true)), 'ctrl-&') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+0038', ctrl: true, shift: true)), 'ctrl-*') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+0039', ctrl: true, shift: true)), 'ctrl-(') - - # Other symbols - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+00ba', ctrl: true)), 'ctrl-;') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+00bb', ctrl: true)), 'ctrl-=') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+00bc', ctrl: true)), 'ctrl-,') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+00bd', ctrl: true)), 'ctrl--') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+00be', ctrl: true)), 'ctrl-.') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+00bf', ctrl: true)), 'ctrl-/') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+00db', ctrl: true)), 'ctrl-[') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+00dc', ctrl: true)), 'ctrl-\\') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+00dd', ctrl: true)), 'ctrl-]') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+00de', ctrl: true)), 'ctrl-\'') - - # Other symbols shifted - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+00ba', ctrl: true, shift: true)), 'ctrl-:') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+00bb', ctrl: true, shift: true)), 'ctrl-+') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+00bc', ctrl: true, shift: true)), 'ctrl-<') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+00bd', ctrl: true, shift: true)), 'ctrl-_') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+00be', ctrl: true, shift: true)), 'ctrl->') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+00bf', ctrl: true, shift: true)), 'ctrl-?') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+00db', ctrl: true, shift: true)), 'ctrl-{') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+00dc', ctrl: true, shift: true)), 'ctrl-|') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+00dd', ctrl: true, shift: true)), 'ctrl-}') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+00de', ctrl: true, shift: true)), 'ctrl-"') - - # Single modifiers - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+00A0', shift: true)), 'shift') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+00A1', shift: true)), 'shift') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+00A2', ctrl: true)), 'ctrl') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+00A3', ctrl: true)), 'ctrl') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+00A4', alt: true)), 'alt') - assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent('U+00A5', alt: true)), 'alt') - - Object.defineProperty process, 'platform', value: 'win32' - testTranslations() - Object.defineProperty process, 'platform', value: 'linux' - testTranslations() + currentKeymap = null + stub(KeyboardLayout, 'getCurrentKeymap', -> currentKeymap) + + it "allows ASCII characters (<= 127) to be typed via an option modifier on macOS", -> + mockProcessPlatform('darwin') + + currentKeymap = require('./helpers/keymaps/mac-swiss-german') + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: '@', code: 'KeyG', altKey: true}), '@') + # Does not use alt variant characters outside of basic ASCII range + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: '‚', code: 'KeyG', altKey: true, shiftKey: true}), 'alt-shift-G') + # Does not use alt variant character if ctrl modifier is used + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: '@', code: 'KeyG', ctrlKey: true, altKey: true}), 'ctrl-alt-g') + + it "allows ASCII characters to be typed via an altgraph modifier on Windows", -> + mockProcessPlatform('win32') + + currentKeymap = require('./helpers/keymaps/windows-swiss-german') + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: '@', code: 'Digit2', ctrlKey: true, altKey: true}), '@') + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: '°', code: 'Digit4', ctrlKey: true, altKey: true}), 'ctrl-alt-4') + + currentKeymap = require('./helpers/keymaps/windows-us-international') + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: '¢', code: 'KeyC', ctrlKey: true, altKey: true, shiftKey: true}), 'ctrl-alt-shift-C') + + it "allows arbitrary characters to be typed via an altgraph modifier on Linux", -> + mockProcessPlatform('linux') + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: '@', altKey: true, getModifierState: (key) -> key is 'AltGraph'}), '@') + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: '€', altKey: true, getModifierState: (key) -> key is 'AltGraph'}), '€') + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: 'Ë', altKey: true, shiftKey: true, getModifierState: (key) -> key is 'AltGraph'}), 'shift-Ë') + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: 'g', altKey: true, getModifierState: (key) -> false}), 'alt-g') + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: 'e', altKey: true, getModifierState: (key) -> false}), 'alt-e') + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: 'E', altKey: true, shiftKey: true, getModifierState: (key) -> false}), 'alt-shift-E') + + it "converts non-latin keycaps to their U.S. counterpart for purposes of binding", -> + mockProcessPlatform('darwin') + currentKeymap = require('./helpers/keymaps/mac-greek') + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: 'δ', code: 'KeyD'}), 'δ') + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: 'Δ', code: 'KeyD', shiftKey: true}), 'Δ') + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: '÷', altKey: true, code: 'KeyD'}), 'alt-d') + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: 'δ', code: 'KeyD', metaKey: true}), 'cmd-d') + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: 'Δ', code: 'KeyD', metaKey: true, shiftKey: true}), 'shift-cmd-D') + + # Don't use U.S. counterpart for latin characters + currentKeymap = require('./helpers/keymaps/mac-turkish') + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: 'ö', code: 'KeyX', metaKey: true}), 'cmd-ö') + + currentKeymap = null + mockProcessPlatform('windows') + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: 'δ', code: 'KeyD'}), 'δ') + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: 'Δ', code: 'KeyD', shiftKey: true}), 'Δ') + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: 'δ', code: 'KeyD', ctrlKey: true}), 'ctrl-d') + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: 'Δ', code: 'KeyD', ctrlKey: true, shiftKey: true}), 'ctrl-shift-D') + # Don't use U.S. counterpart for latin characters + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: 'ö', code: 'KeyX', metaKey: true}), 'cmd-ö') + + mockProcessPlatform('linux') + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: 'δ', code: 'KeyD'}), 'δ') + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: 'Δ', code: 'KeyD', shiftKey: true}), 'Δ') + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: 'δ', code: 'KeyD', ctrlKey: true}), 'ctrl-d') + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: 'Δ', code: 'KeyD', ctrlKey: true, shiftKey: true}), 'ctrl-shift-D') + # Don't use U.S. counterpart for latin characters + assert.equal(keymapManager.keystrokeForKeyboardEvent({key: 'ö', code: 'KeyX', metaKey: true}), 'cmd-ö') describe "::findKeyBindings({command, target, keystrokes})", -> [elementA, elementB] = [] diff --git a/src/helpers.coffee b/src/helpers.coffee index 570ef05..b3338ac 100644 --- a/src/helpers.coffee +++ b/src/helpers.coffee @@ -1,192 +1,200 @@ {calculateSpecificity} = require 'clear-cut' - -AtomModifiers = new Set -AtomModifiers.add(modifier) for modifier in ['ctrl', 'alt', 'shift', 'cmd'] - -AtomModifierRegex = /(ctrl|alt|shift|cmd)$/ -WhitespaceRegex = /\s+/ -LowerCaseLetterRegex = /^[a-z]$/ -UpperCaseLetterRegex = /^[A-Z]$/ -ExactMatch = 'exact' -KeydownExactMatch = 'keydownExact' -PartialMatch = 'partial' - -KeyboardEventModifiers = new Set -KeyboardEventModifiers.add(modifier) for modifier in ['Control', 'Alt', 'Shift', 'Meta'] - -WindowsAndLinuxKeyIdentifierTranslations = - 'U+00A0': 'Shift' - 'U+00A1': 'Shift' - 'U+00A2': 'Control' - 'U+00A3': 'Control' - 'U+00A4': 'Alt' - 'U+00A5': 'Alt' - 'Win': 'Meta' - -WindowsAndLinuxCharCodeTranslations = - 48: - shifted: 41 # ")" - unshifted: 48 # "0" - 49: - shifted: 33 # "!" - unshifted: 49 # "1" - 50: - shifted: 64 # "@" - unshifted: 50 # "2" - 51: - shifted: 35 # "#" - unshifted: 51 # "3" - 52: - shifted: 36 # "$" - unshifted: 52 # "4" - 53: - shifted: 37 # "%" - unshifted: 53 # "5" - 54: - shifted: 94 # "^" - unshifted: 54 # "6" - 55: - shifted: 38 # "&" - unshifted: 55 # "7" - 56: - shifted: 42 # "*" - unshifted: 56 # "8" - 57: - shifted: 40 # "(" - unshifted: 57 # "9" - 186: - shifted: 58 # ":" - unshifted: 59 # ";" - 187: - shifted: 43 # "+" - unshifted: 61 # "=" - 188: - shifted: 60 # "<" - unshifted: 44 # "," - 189: - shifted: 95 # "_" - unshifted: 45 # "-" - 190: - shifted: 62 # ">" - unshifted: 46 # "." - 191: - shifted: 63 # "?" - unshifted: 47 # "/" - 192: - shifted: 126 # "~" - unshifted: 96 # "`" - 219: - shifted: 123 # "{" - unshifted: 91 # "[" - 220: - shifted: 124 # "|" - unshifted: 92 # "\" - 221: - shifted: 125 # "}" - unshifted: 93 # "]" - 222: - shifted: 34 # '"' - unshifted: 39 # "'" - -NumPadToASCII = - 79: 47 # "/" - 74: 42 # "*" - 77: 45 # "-" - 75: 43 # "+" - 78: 46 # "." - 96: 48 # "0" - 65: 49 # "1" - 66: 50 # "2" - 67: 51 # "3" - 68: 52 # "4" - 69: 53 # "5" - 70: 54 # "6" - 71: 55 # "7" - 72: 56 # "8" - 73: 57 # "9" +KeyboardLayout = require 'keyboard-layout' + +MODIFIERS = new Set(['ctrl', 'alt', 'shift', 'cmd']) +ENDS_IN_MODIFIER_REGEX = /(ctrl|alt|shift|cmd)$/ +WHITESPACE_REGEX = /\s+/ +NON_CHARACTER_KEY_NAMES_BY_KEYBOARD_EVENT_KEY = { + 'Control': 'ctrl', + 'Meta': 'cmd', + 'ArrowDown': 'down', + 'ArrowUp': 'up', + 'ArrowLeft': 'left', + 'ArrowRight': 'right' +} +MATCH_TYPES = { + EXACT: 'exact' + KEYDOWN_EXACT: 'keydownExact' + PARTIAL: 'partial' +} + +isASCIICharacter = (character) -> + character? and character.length is 1 and character.charCodeAt(0) <= 127 + +isLatinCharacter = (character) -> + character? and character.length is 1 and character.charCodeAt(0) <= 0x024F + +isUpperCaseCharacter = (character) -> + character? and character.length is 1 and character.toLowerCase() isnt character + +isLowerCaseCharacter = (character) -> + character? and character.length is 1 and character.toUpperCase() isnt character + +usKeymap = null +usCharactersForKeyCode = (code) -> + usKeymap ?= require('./us-keymap') + usKeymap[code] exports.normalizeKeystrokes = (keystrokes) -> normalizedKeystrokes = [] - for keystroke in keystrokes.split(WhitespaceRegex) + for keystroke in keystrokes.split(WHITESPACE_REGEX) if normalizedKeystroke = normalizeKeystroke(keystroke) normalizedKeystrokes.push(normalizedKeystroke) else return false normalizedKeystrokes.join(' ') -exports.keystrokeForKeyboardEvent = (event, dvorakQwertyWorkaroundEnabled) -> - key = keyForKeyboardEvent(event, dvorakQwertyWorkaroundEnabled) +normalizeKeystroke = (keystroke) -> + if isKeyup = keystroke.startsWith('^') + keystroke = keystroke.slice(1) + keys = parseKeystroke(keystroke) + return false unless keys + + primaryKey = null + modifiers = new Set + + for key, i in keys + if MODIFIERS.has(key) + modifiers.add(key) + else + # only the last key can be a non-modifier + if i is keys.length - 1 + primaryKey = key + else + return false + + if isKeyup + primaryKey = primaryKey.toLowerCase() if primaryKey? + else + modifiers.add('shift') if isUpperCaseCharacter(primaryKey) + if modifiers.has('shift') and isLowerCaseCharacter(primaryKey) + primaryKey = primaryKey.toUpperCase() + + keystroke = [] + if not isKeyup or (isKeyup and not primaryKey?) + keystroke.push('ctrl') if modifiers.has('ctrl') + keystroke.push('alt') if modifiers.has('alt') + keystroke.push('shift') if modifiers.has('shift') + keystroke.push('cmd') if modifiers.has('cmd') + keystroke.push(primaryKey) if primaryKey? + keystroke = keystroke.join('-') + keystroke = "^#{keystroke}" if isKeyup + keystroke + +parseKeystroke = (keystroke) -> + keys = [] + keyStart = 0 + for character, index in keystroke when character is '-' + if index > keyStart + keys.push(keystroke.substring(keyStart, index)) + keyStart = index + 1 + + # The keystroke has a trailing - and is invalid + return false if keyStart is keystroke.length + keys.push(keystroke.substring(keyStart)) if keyStart < keystroke.length + keys + +exports.keystrokeForKeyboardEvent = (event) -> + {ctrlKey, altKey, shiftKey, metaKey} = event + isNonCharacterKey = event.key.length > 1 + + if isNonCharacterKey + key = NON_CHARACTER_KEY_NAMES_BY_KEYBOARD_EVENT_KEY[event.key] ? event.key.toLowerCase() + else + key = event.key + + # When the option key is down on macOS, we need to determine whether the + # the user intends to type an ASCII character that is only reachable by use + # of the option key (such as option-g to type @ on a Swiss-German layout) + # or used as a modifier to match against an alt-* binding. + # + # We check for event.code because test helpers produce events without it. + if altKey + if process.platform is 'darwin' and event.code + nonAltModifiedKey = nonAltModifiedKeyForKeyboardEvent(event) + if ctrlKey or metaKey or not isASCIICharacter(key) or key is nonAltModifiedKey + key = nonAltModifiedKey + else + altKey = false + else if process.platform is 'win32' and ctrlKey and event.code + nonAltModifiedKey = nonAltModifiedKeyForKeyboardEvent(event) + if metaKey or not isASCIICharacter(key) or key is nonAltModifiedKey + key = nonAltModifiedKey + else + ctrlKey = false + altKey = false + else if process.platform is 'linux' + if event.getModifierState('AltGraph') + altKey = false + + # Use US equivalent character for non-latin characters in keystrokes with modifiers + # or when using the dvorak-qwertycmd layout and holding down the command key. + if (not isLatinCharacter(key) and (ctrlKey or altKey or metaKey)) or + (metaKey and KeyboardLayout.getCurrentKeyboardLayout() is 'com.apple.keylayout.DVORAK-QWERTYCMD') + if characters = usCharactersForKeyCode(event.code) + if event.shiftKey + key = characters.withShift + else + key = characters.unmodified keystroke = '' - if event.ctrlKey or key is 'Control' + if key is 'ctrl' or ctrlKey keystroke += 'ctrl' - if event.altKey or key is 'Alt' - keystroke += '-' if keystroke + + if key is 'alt' or altKey + keystroke += '-' if keystroke.length > 0 keystroke += 'alt' - if event.shiftKey or key is 'Shift' - # Don't push 'shift' when modifying symbolic characters like '{' - unless /^[^A-Za-z]$/.test(key) - keystroke += '-' if keystroke - keystroke += 'shift' - if event.metaKey or key is 'Meta' + + if key is 'shift' or (shiftKey and (isNonCharacterKey or (isLatinCharacter(key) and isUpperCaseCharacter(key)))) + keystroke += '-' if keystroke + keystroke += 'shift' + + if key is 'cmd' or metaKey keystroke += '-' if keystroke keystroke += 'cmd' - if key? and not KeyboardEventModifiers.has(key) + + unless MODIFIERS.has(key) keystroke += '-' if keystroke keystroke += key keystroke = normalizeKeystroke("^#{keystroke}") if event.type is 'keyup' keystroke -exports.characterForKeyboardEvent = (event, dvorakQwertyWorkaroundEnabled) -> - unless event.ctrlKey or event.altKey or event.metaKey - if key = keyForKeyboardEvent(event, dvorakQwertyWorkaroundEnabled) - key if key.length is 1 +nonAltModifiedKeyForKeyboardEvent = (event) -> + if event.code and (characters = KeyboardLayout.getCurrentKeymap()[event.code]) + if event.shiftKey + characters.withShift + else + characters.unmodified + +exports.characterForKeyboardEvent = (event) -> + event.key unless event.ctrlKey or event.metaKey exports.calculateSpecificity = calculateSpecificity -exports.isAtomModifier = (keystroke) -> - AtomModifiers.has(keystroke) or AtomModifierRegex.test(keystroke) +exports.isBareModifier = (keystroke) -> ENDS_IN_MODIFIER_REGEX.test(keystroke) exports.keydownEvent = (key, options) -> - return keyboardEvent(key, 'keydown', options) + return buildKeyboardEvent(key, 'keydown', options) exports.keyupEvent = (key, options) -> - return keyboardEvent(key, 'keyup', options) + return buildKeyboardEvent(key, 'keyup', options) -keyboardEvent = (key, eventType, {ctrl, shift, alt, cmd, keyCode, target, location}={}) -> - event = document.createEvent('KeyboardEvent') +buildKeyboardEvent = (key, eventType, {ctrl, shift, alt, cmd, keyCode, target, location}={}) -> + ctrlKey = ctrl ? false + altKey = alt ? false + shiftKey = shift ? false + metaKey = cmd ? false bubbles = true cancelable = true - view = null - key = key.toUpperCase() if LowerCaseLetterRegex.test(key) - if key.length is 1 - keyIdentifier = "U+#{key.charCodeAt(0).toString(16)}" - else - switch key - when 'ctrl' - keyIdentifier = 'Control' - ctrl = true if eventType isnt 'keyup' - when 'alt' - keyIdentifier = 'Alt' - alt = true if eventType isnt 'keyup' - when 'shift' - keyIdentifier = 'Shift' - shift = true if eventType isnt 'keyup' - when 'cmd' - keyIdentifier = 'Meta' - cmd = true if eventType isnt 'keyup' - else - keyIdentifier = key[0].toUpperCase() + key[1..] + event = new KeyboardEvent(eventType, { + key, ctrlKey, altKey, shiftKey, metaKey, bubbles, cancelable + }) - location ?= KeyboardEvent.DOM_KEY_LOCATION_STANDARD - event.initKeyboardEvent(eventType, bubbles, cancelable, view, keyIdentifier, location, ctrl, alt, shift, cmd) if target? Object.defineProperty(event, 'target', get: -> target) Object.defineProperty(event, 'path', get: -> [target]) - Object.defineProperty(event, 'keyCode', get: -> keyCode) - Object.defineProperty(event, 'which', get: -> keyCode) event # bindingKeystrokes and userKeystrokes are arrays of keystrokes @@ -231,127 +239,8 @@ exports.keystrokesMatch = (bindingKeystrokes, userKeystrokes) -> return false if userKeystrokeIndex < userKeystrokes.length - 1 if isPartialMatch and bindingRemainderContainsOnlyKeyups - KeydownExactMatch + MATCH_TYPES.KEYDOWN_EXACT else if isPartialMatch - PartialMatch - else - ExactMatch - -normalizeKeystroke = (keystroke) -> - if isKeyup = keystroke.startsWith('^') - keystroke = keystroke.slice(1) - keys = parseKeystroke(keystroke) - return false unless keys - - primaryKey = null - modifiers = new Set - - for key, i in keys - if AtomModifiers.has(key) - modifiers.add(key) - else - # only the last key can be a non-modifier - if i is keys.length - 1 - primaryKey = key - else - return false - - if isKeyup - primaryKey = primaryKey.toLowerCase() if primaryKey? - else - modifiers.add('shift') if UpperCaseLetterRegex.test(primaryKey) - if modifiers.has('shift') and LowerCaseLetterRegex.test(primaryKey) - primaryKey = primaryKey.toUpperCase() - - keystroke = [] - if not isKeyup or (isKeyup and not primaryKey?) - keystroke.push('ctrl') if modifiers.has('ctrl') - keystroke.push('alt') if modifiers.has('alt') - keystroke.push('shift') if modifiers.has('shift') - keystroke.push('cmd') if modifiers.has('cmd') - keystroke.push(primaryKey) if primaryKey? - keystroke = keystroke.join('-') - keystroke = "^#{keystroke}" if isKeyup - keystroke - -parseKeystroke = (keystroke) -> - keys = [] - keyStart = 0 - for character, index in keystroke when character is '-' - if index > keyStart - keys.push(keystroke.substring(keyStart, index)) - keyStart = index + 1 - - # The keystroke has a trailing - and is invalid - return false if keyStart is keystroke.length - keys.push(keystroke.substring(keyStart)) if keyStart < keystroke.length - keys - -keyForKeyboardEvent = (event, dvorakQwertyWorkaroundEnabled) -> - keyIdentifier = event.keyIdentifier - if process.platform in ['linux', 'win32'] - keyIdentifier = translateKeyIdentifierForWindowsAndLinuxChromiumBug(keyIdentifier) - - return keyIdentifier if KeyboardEventModifiers.has(keyIdentifier) - - charCode = charCodeFromKeyIdentifier(keyIdentifier) - - if dvorakQwertyWorkaroundEnabled and typeof charCode is 'number' - if event.keyCode is 46 # key code for 'delete' - charCode = 127 # ASCII character code for 'delete' - else - charCode = event.keyCode - - if charCode? - if process.platform in ['linux', 'win32'] - charCode = translateCharCodeForWindowsAndLinuxChromiumBug(charCode, event.shiftKey) - - if event.location is KeyboardEvent.DOM_KEY_LOCATION_NUMPAD - # This is a numpad number - charCode = numpadToASCII(charCode) - - charCode = event.which if not isASCII(charCode) and isASCII(event.keyCode) - key = keyFromCharCode(charCode) - else - key = keyIdentifier.toLowerCase() - - # Only upper case alphabetic characters like 'a' - if event.shiftKey - key = key.toUpperCase() if LowerCaseLetterRegex.test(key) - else - key = key.toLowerCase() if UpperCaseLetterRegex.test(key) - - key - -charCodeFromKeyIdentifier = (keyIdentifier) -> - parseInt(keyIdentifier[2..], 16) if keyIdentifier.indexOf('U+') is 0 - -# Chromium includes incorrect keyIdentifier values on keypress events for -# certain symbols keys on Window and Linux. -# -# See https://code.google.com/p/chromium/issues/detail?id=51024 -# See https://bugs.webkit.org/show_bug.cgi?id=19906 -translateKeyIdentifierForWindowsAndLinuxChromiumBug = (keyIdentifier) -> - WindowsAndLinuxKeyIdentifierTranslations[keyIdentifier] ? keyIdentifier - -translateCharCodeForWindowsAndLinuxChromiumBug = (charCode, shift) -> - if translation = WindowsAndLinuxCharCodeTranslations[charCode] - if shift then translation.shifted else translation.unshifted + MATCH_TYPES.PARTIAL else - charCode - -keyFromCharCode = (charCode) -> - switch charCode - when 8 then 'backspace' - when 9 then 'tab' - when 13 then 'enter' - when 27 then 'escape' - when 32 then 'space' - when 127 then 'delete' - else String.fromCharCode(charCode) - -isASCII = (charCode) -> - 0 <= charCode <= 127 - -numpadToASCII = (charCode) -> - NumPadToASCII[charCode] ? charCode + MATCH_TYPES.EXACT diff --git a/src/keymap-manager.coffee b/src/keymap-manager.coffee index a5b18db..3b5ce24 100644 --- a/src/keymap-manager.coffee +++ b/src/keymap-manager.coffee @@ -7,7 +7,7 @@ path = require 'path' {Emitter, Disposable, CompositeDisposable} = require 'event-kit' KeyBinding = require './key-binding' CommandEvent = require './command-event' -{normalizeKeystrokes, keystrokeForKeyboardEvent, isAtomModifier, keydownEvent, keyupEvent, characterForKeyboardEvent, keystrokesMatch} = require './helpers' +{normalizeKeystrokes, keystrokeForKeyboardEvent, isBareModifier, keydownEvent, keyupEvent, characterForKeyboardEvent, keystrokesMatch} = require './helpers' Platforms = ['darwin', 'freebsd', 'linux', 'sunos', 'win32'] OtherPlatforms = Platforms.filter (platform) -> platform isnt process.platform @@ -493,7 +493,7 @@ class KeymapManager keystroke = @keystrokeForKeyboardEvent(event) # We dont care about bare modifier keys in the bindings. e.g. `ctrl y` isnt going to work. - if event.type is 'keydown' and @queuedKeystrokes.length > 0 and isAtomModifier(keystroke) + if event.type is 'keydown' and @queuedKeystrokes.length > 0 and isBareModifier(keystroke) event.preventDefault() return diff --git a/src/us-keymap.coffee b/src/us-keymap.coffee new file mode 100644 index 0000000..e0e3dc3 --- /dev/null +++ b/src/us-keymap.coffee @@ -0,0 +1,254 @@ +module.exports = { + "Space": { + "unmodified": " ", + "withShift": " " + }, + "Digit0": { + "unmodified": "0", + "withShift": ")" + }, + "Digit1": { + "unmodified": "1", + "withShift": "!" + }, + "Digit2": { + "unmodified": "2", + "withShift": "@" + }, + "Digit3": { + "unmodified": "3", + "withShift": "#" + }, + "Digit4": { + "unmodified": "4", + "withShift": "$" + }, + "Digit5": { + "unmodified": "5", + "withShift": "%" + }, + "Digit6": { + "unmodified": "6", + "withShift": "^" + }, + "Digit7": { + "unmodified": "7", + "withShift": "&" + }, + "Digit8": { + "unmodified": "8", + "withShift": "*" + }, + "Digit9": { + "unmodified": "9", + "withShift": "(" + }, + "KeyA": { + "unmodified": "a", + "withShift": "A" + }, + "KeyB": { + "unmodified": "b", + "withShift": "B" + }, + "KeyC": { + "unmodified": "c", + "withShift": "C" + }, + "KeyD": { + "unmodified": "d", + "withShift": "D" + }, + "KeyE": { + "unmodified": "e", + "withShift": "E" + }, + "KeyF": { + "unmodified": "f", + "withShift": "F" + }, + "KeyG": { + "unmodified": "g", + "withShift": "G" + }, + "KeyH": { + "unmodified": "h", + "withShift": "H" + }, + "KeyI": { + "unmodified": "i", + "withShift": "I" + }, + "KeyJ": { + "unmodified": "j", + "withShift": "J" + }, + "KeyK": { + "unmodified": "k", + "withShift": "K" + }, + "KeyL": { + "unmodified": "l", + "withShift": "L" + }, + "KeyM": { + "unmodified": "m", + "withShift": "M" + }, + "KeyN": { + "unmodified": "n", + "withShift": "N" + }, + "KeyO": { + "unmodified": "o", + "withShift": "O" + }, + "KeyP": { + "unmodified": "p", + "withShift": "P" + }, + "KeyQ": { + "unmodified": "q", + "withShift": "Q" + }, + "KeyR": { + "unmodified": "r", + "withShift": "R" + }, + "KeyS": { + "unmodified": "s", + "withShift": "S" + }, + "KeyT": { + "unmodified": "t", + "withShift": "T" + }, + "KeyU": { + "unmodified": "u", + "withShift": "U" + }, + "KeyV": { + "unmodified": "v", + "withShift": "V" + }, + "KeyW": { + "unmodified": "w", + "withShift": "W" + }, + "KeyX": { + "unmodified": "x", + "withShift": "X" + }, + "KeyY": { + "unmodified": "y", + "withShift": "Y" + }, + "KeyZ": { + "unmodified": "z", + "withShift": "Z" + }, + "Numpad0": { + "unmodified": "0", + "withShift": "0" + }, + "Numpad1": { + "unmodified": "1", + "withShift": "1" + }, + "Numpad2": { + "unmodified": "2", + "withShift": "2" + }, + "Numpad3": { + "unmodified": "3", + "withShift": "3" + }, + "Numpad4": { + "unmodified": "4", + "withShift": "4" + }, + "Numpad5": { + "unmodified": "5", + "withShift": "5" + }, + "Numpad6": { + "unmodified": "6", + "withShift": "6" + }, + "Numpad7": { + "unmodified": "7", + "withShift": "7" + }, + "Numpad8": { + "unmodified": "8", + "withShift": "8" + }, + "Numpad9": { + "unmodified": "9", + "withShift": "9" + }, + "NumpadMultiply": { + "unmodified": "*", + "withShift": "*" + }, + "NumpadAdd": { + "unmodified": "+", + "withShift": "+" + }, + "NumpadSubtract": { + "unmodified": "-", + "withShift": "-" + }, + "NumpadDecimal": { + "unmodified": ".", + "withShift": "." + }, + "NumpadDivide": { + "unmodified": "/", + "withShift": "/" + }, + "Semicolon": { + "unmodified": ";", + "withShift": ":" + }, + "Equal": { + "unmodified": "=", + "withShift": "+" + }, + "NumpadComma": { + "unmodified": ",", + "withShift": "<" + }, + "Minus": { + "unmodified": "-", + "withShift": "_" + }, + "Period": { + "unmodified": ".", + "withShift": ">" + }, + "Slash": { + "unmodified": "/", + "withShift": "?" + }, + "Backquote": { + "unmodified": "`", + "withShift": "~" + }, + "BracketLeft": { + "unmodified": "[", + "withShift": "{" + }, + "IntlYen": { + "unmodified": "\\", + "withShift": "|" + }, + "BracketRight": { + "unmodified": "]", + "withShift": "}" + }, + "Quote": { + "unmodified": "'", + "withShift": "\"" + } +}