diff --git a/src/vs/base/browser/keyboardEvent.ts b/src/vs/base/browser/keyboardEvent.ts index a15c16108c8..bf2d8bb800b 100644 --- a/src/vs/base/browser/keyboardEvent.ts +++ b/src/vs/base/browser/keyboardEvent.ts @@ -123,6 +123,9 @@ let KEY_CODE_MAP: {[keyCode:number]:KeyCode} = {}; KEY_CODE_MAP[220] = KeyCode.US_BACKSLASH; KEY_CODE_MAP[221] = KeyCode.US_CLOSE_SQUARE_BRACKET; KEY_CODE_MAP[222] = KeyCode.US_QUOTE; + KEY_CODE_MAP[223] = KeyCode.OEM_8; + + KEY_CODE_MAP[226] = KeyCode.OEM_102; if (Browser.isIE11orEarlier) { KEY_CODE_MAP[91] = KeyCode.Meta; diff --git a/src/vs/base/common/keyCodes.ts b/src/vs/base/common/keyCodes.ts index f0fce658f76..f3c75f9aa8a 100644 --- a/src/vs/base/common/keyCodes.ts +++ b/src/vs/base/common/keyCodes.ts @@ -111,49 +111,68 @@ export enum KeyCode { ScrollLock, /** + * Used for miscellaneous characters; it can vary by keyboard. * For the US standard keyboard, the ';:' key */ US_SEMICOLON, /** + * For any country/region, the '+' key * For the US standard keyboard, the '=+' key */ US_EQUAL, /** + * For any country/region, the ',' key * For the US standard keyboard, the ',<' key */ US_COMMA, /** + * For any country/region, the '-' key * For the US standard keyboard, the '-_' key */ US_MINUS, /** + * For any country/region, the '.' key * For the US standard keyboard, the '.>' key */ US_DOT, /** + * Used for miscellaneous characters; it can vary by keyboard. * For the US standard keyboard, the '/?' key */ US_SLASH, /** + * Used for miscellaneous characters; it can vary by keyboard. * For the US standard keyboard, the '`~' key */ US_BACKTICK, /** + * Used for miscellaneous characters; it can vary by keyboard. * For the US standard keyboard, the '[{' key */ US_OPEN_SQUARE_BRACKET, /** + * Used for miscellaneous characters; it can vary by keyboard. * For the US standard keyboard, the '\|' key */ US_BACKSLASH, /** + * Used for miscellaneous characters; it can vary by keyboard. * For the US standard keyboard, the ']}' key */ US_CLOSE_SQUARE_BRACKET, /** + * Used for miscellaneous characters; it can vary by keyboard. * For the US standard keyboard, the ''"' key */ US_QUOTE, + /** + * Used for miscellaneous characters; it can vary by keyboard. + */ + OEM_8, + /** + * Either the angle bracket key or the backslash key on the RT 102-key keyboard. + */ + OEM_102, NUMPAD_0, // VK_NUMPAD0, 0x60, Numeric keypad 0 key NUMPAD_1, // VK_NUMPAD1, 0x61, Numeric keypad 1 key @@ -329,6 +348,8 @@ let STRING = createMapping((TO_STRING_MAP) => { TO_STRING_MAP[KeyCode.US_BACKSLASH] = '\\'; TO_STRING_MAP[KeyCode.US_CLOSE_SQUARE_BRACKET] = ']'; TO_STRING_MAP[KeyCode.US_QUOTE] = '\''; + TO_STRING_MAP[KeyCode.OEM_8] = 'OEM_8'; + TO_STRING_MAP[KeyCode.OEM_102] = 'OEM_102'; TO_STRING_MAP[KeyCode.NUMPAD_0] = 'NumPad0'; TO_STRING_MAP[KeyCode.NUMPAD_1] = 'NumPad1'; @@ -378,8 +399,8 @@ let USER_SETTINGS = createMapping((TO_USER_SETTINGS_MAP) => { FROM_USER_SETTINGS_MAP['OEM_5'] = KeyCode.US_BACKSLASH; FROM_USER_SETTINGS_MAP['OEM_6'] = KeyCode.US_CLOSE_SQUARE_BRACKET; FROM_USER_SETTINGS_MAP['OEM_7'] = KeyCode.US_QUOTE; - // FROM_USER_SETTINGS_MAP['OEM_8'] = KeyCode.Unknown; // MISSING - // FROM_USER_SETTINGS_MAP['OEM_102'] = KeyCode.Unknown; // MISSING + FROM_USER_SETTINGS_MAP['OEM_8'] = KeyCode.OEM_8; + FROM_USER_SETTINGS_MAP['OEM_102'] = KeyCode.OEM_102; }); export namespace KeyCode { @@ -536,6 +557,22 @@ export class Keybinding { return _asString(value, ElectronAcceleratorLabelProvider.INSTANCE, Platform); } + private static _cachedKeybindingRegex: string = null; + public static getUserSettingsKeybindingRegex(): string { + if (!this._cachedKeybindingRegex) { + let numpadKey = "numpad(0|1|2|3|4|5|6|7|8|9|_multiply|_add|_subtract|_decimal|_divide|_separator)"; + let oemKey = "`|\\-|=|\\[|\\]|\\\\\\\\|;|'|,|\\.|\\/|oem_8|oem_102"; + let specialKey = "left|up|right|down|pageup|pagedown|end|home|tab|enter|escape|space|backspace|delete|pausebreak|capslock|insert|contextmenu|numlock|scrolllock"; + let casualKey = "[a-z]|[0-9]|f(1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19)"; + let key = '((' + [numpadKey, oemKey, specialKey, casualKey].join(')|(') + '))'; + let mod = '((ctrl|shift|alt|cmd|win|meta)\\+)*'; + let keybinding = '(' + mod + key + ')'; + + this._cachedKeybindingRegex = '"\\s*(' + keybinding + '(\\s+' + keybinding +')?' + ')\\s*"'; + } + return this._cachedKeybindingRegex; + } + /** * Format the binding to a format appropiate for the user settings file. */ diff --git a/src/vs/base/test/common/keyCodes.test.ts b/src/vs/base/test/common/keyCodes.test.ts index 4cfd2dbcaf3..202df661e3e 100644 --- a/src/vs/base/test/common/keyCodes.test.ts +++ b/src/vs/base/test/common/keyCodes.test.ts @@ -5,7 +5,8 @@ 'use strict'; import * as assert from 'assert'; -import {KeyCode, KeyMod, BinaryKeybindings} from 'vs/base/common/keyCodes'; +import {KeyCode, KeyMod, BinaryKeybindings, Keybinding} from 'vs/base/common/keyCodes'; +import * as Strings from 'vs/base/common/strings'; interface ITestKeybinding { ctrlCmd?: boolean; @@ -65,4 +66,44 @@ suite('keyCodes', () => { assert.equal(encodedFirstPart, KeyMod.CtrlCmd | KeyCode.KEY_Y, 'first part'); assert.equal(encodedSecondPart, encodedSecondPart, 'chord part'); }); + + test('getUserSettingsKeybindingRegex', () => { + let regex = new RegExp(Keybinding.getUserSettingsKeybindingRegex()); + + function testIsGood(userSettingsLabel:string, message:string = userSettingsLabel): void { + let userSettings = '"' + userSettingsLabel.replace(/\\/g, '\\\\') + '"'; + let isGood = regex.test(userSettings); + assert.ok(isGood, message); + } + + // check that all key codes are covered by the regex + let ignore: boolean[] = []; + ignore[KeyCode.Shift] = true; + ignore[KeyCode.Ctrl] = true; + ignore[KeyCode.Alt] = true; + ignore[KeyCode.Meta] = true; + for (let keyCode = KeyCode.Unknown + 1; keyCode < KeyCode.MAX_VALUE; keyCode++) { + if (ignore[keyCode]) { + continue; + } + let userSettings = Keybinding.toUserSettingsLabel(keyCode); + testIsGood(userSettings, keyCode + ' - ' + KeyCode[keyCode] + ' - ' + userSettings); + } + + // one modifier + testIsGood('ctrl+a'); + testIsGood('shift+a'); + testIsGood('alt+a'); + testIsGood('cmd+a'); + testIsGood('meta+a'); + testIsGood('win+a'); + + // more modifiers + testIsGood('ctrl+shift+a'); + testIsGood('shift+alt+a'); + testIsGood('ctrl+shift+alt+a'); + + // chords + testIsGood('ctrl+a ctrl+a'); + }) }); diff --git a/src/vs/editor/contrib/defineKeybinding/browser/defineKeybinding.ts b/src/vs/editor/contrib/defineKeybinding/browser/defineKeybinding.ts index 787627f5803..dc80982c258 100644 --- a/src/vs/editor/contrib/defineKeybinding/browser/defineKeybinding.ts +++ b/src/vs/editor/contrib/defineKeybinding/browser/defineKeybinding.ts @@ -137,26 +137,10 @@ export class DefineKeybindingController implements EditorCommon.IEditorContribut this._updateDecorations.schedule(); } - private static _cachedKeybindingRegex: string = null; - private static _getKeybindingRegex(): string { - if (!this._cachedKeybindingRegex) { - let numpadKey = "numpad(0|1|2|3|4|5|6|7|8|9|_multiply|_add|_subtract|_decimal|_divide)"; - let punctKey = "`|\\-|=|\\[|\\]|\\\\\\\\|;|'|,|\\.|\\/"; - let specialKey = "left|up|right|down|pageup|pagedown|end|home|tab|enter|escape|space|backspace|delete|pausebreak|capslock|insert"; - let casualKey = "[a-z]|[0-9]|f(1|2|3|4|5|6|7|8|9|10|11|12|13|14|15)"; - let key = '((' + [numpadKey, punctKey, specialKey, casualKey].join(')|(') + '))'; - let mod = '((ctrl|shift|alt|cmd|win|meta)\\+)*'; - let keybinding = '(' + mod + key + ')'; - - this._cachedKeybindingRegex = '"\\s*(' + keybinding + '(\\s+' + keybinding +')?' + ')\\s*"'; - } - return this._cachedKeybindingRegex; - } - private _dec:string[] = []; private _updateDecorationsNow(): void { let model = this._editor.getModel(); - let regex = DefineKeybindingController._getKeybindingRegex(); + let regex = Keybinding.getUserSettingsKeybindingRegex(); var m = model.findMatches(regex, false, true, false, false); diff --git a/src/vs/platform/keybinding/test/common/keybindingIO.test.ts b/src/vs/platform/keybinding/test/common/keybindingIO.test.ts index 27ccc72d664..30b2b28cd51 100644 --- a/src/vs/platform/keybinding/test/common/keybindingIO.test.ts +++ b/src/vs/platform/keybinding/test/common/keybindingIO.test.ts @@ -85,6 +85,8 @@ suite('Keybinding IO', () => { testRoundtrip(KeyCode.US_BACKSLASH, '\\', '\\', '\\'); testRoundtrip(KeyCode.US_CLOSE_SQUARE_BRACKET, ']', ']', ']'); testRoundtrip(KeyCode.US_QUOTE, '\'', '\'', '\''); + testRoundtrip(KeyCode.OEM_8, 'oem_8', 'oem_8', 'oem_8'); + testRoundtrip(KeyCode.OEM_102, 'oem_102', 'oem_102', 'oem_102'); // OEM aliases testDeserialization('OEM_1', 'OEM_1', 'OEM_1', KeyCode.US_SEMICOLON); @@ -98,8 +100,8 @@ suite('Keybinding IO', () => { testDeserialization('OEM_5', 'OEM_5', 'OEM_5', KeyCode.US_BACKSLASH); testDeserialization('OEM_6', 'OEM_6', 'OEM_6', KeyCode.US_CLOSE_SQUARE_BRACKET); testDeserialization('OEM_7', 'OEM_7', 'OEM_7', KeyCode.US_QUOTE); - testDeserialization('OEM_8', 'OEM_8', 'OEM_8', KeyCode.Unknown); // MISSING - testDeserialization('OEM_102', 'OEM_102', 'OEM_102', KeyCode.Unknown); // MISSING + testDeserialization('OEM_8', 'OEM_8', 'OEM_8', KeyCode.OEM_8); + testDeserialization('OEM_102', 'OEM_102', 'OEM_102', KeyCode.OEM_102); // accepts '-' as separator testDeserialization('ctrl-shift-alt-win-a', 'ctrl-shift-alt-cmd-a', 'ctrl-shift-alt-meta-a', KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyMod.WinCtrl | KeyCode.KEY_A); diff --git a/src/vs/workbench/services/keybinding/electron-browser/nativeKeymap.ts b/src/vs/workbench/services/keybinding/electron-browser/nativeKeymap.ts index 208dbddd709..cf35f7ea885 100644 --- a/src/vs/workbench/services/keybinding/electron-browser/nativeKeymap.ts +++ b/src/vs/workbench/services/keybinding/electron-browser/nativeKeymap.ts @@ -179,8 +179,8 @@ const NATIVE_KEY_CODE_TO_KEY_CODE: {[nativeKeyCode:string]:KeyCode;} = { VKEY_OEM_5: KeyCode.US_BACKSLASH, VKEY_OEM_6: KeyCode.US_CLOSE_SQUARE_BRACKET, VKEY_OEM_7: KeyCode.US_QUOTE, - VKEY_OEM_8: KeyCode.Unknown, // MISSING - VKEY_OEM_102: KeyCode.Unknown, // MISSING + VKEY_OEM_8: KeyCode.OEM_8, + VKEY_OEM_102: KeyCode.OEM_102, VKEY_PROCESSKEY: KeyCode.Unknown, // MISSING VKEY_PACKET: KeyCode.Unknown, // MISSING VKEY_DBE_SBCSCHAR: KeyCode.Unknown, // MISSING @@ -348,6 +348,8 @@ export function getNativeLabelProvider(): IKeyBindingLabelProvider { VKEY_OEM_5: true, VKEY_OEM_6: true, VKEY_OEM_7: true, + VKEY_OEM_8: true, + VKEY_OEM_102: true, }; let remaps:string[] = [];