Path: blob/main/src/vs/workbench/services/keybinding/test/browser/keybindingIO.test.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/4import assert from 'assert';5import { KeyChord, KeyCode, KeyMod, ScanCode } from '../../../../../base/common/keyCodes.js';6import { KeyCodeChord, decodeKeybinding, ScanCodeChord, Keybinding } from '../../../../../base/common/keybindings.js';7import { KeybindingParser } from '../../../../../base/common/keybindingParser.js';8import { OperatingSystem } from '../../../../../base/common/platform.js';9import { KeybindingIO } from '../../common/keybindingIO.js';10import { createUSLayoutResolvedKeybinding } from '../../../../../platform/keybinding/test/common/keybindingsTestUtils.js';11import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js';1213suite('keybindingIO', () => {14ensureNoDisposablesAreLeakedInTestSuite();1516test('serialize/deserialize', () => {1718function testOneSerialization(keybinding: number, expected: string, msg: string, OS: OperatingSystem): void {19const usLayoutResolvedKeybinding = createUSLayoutResolvedKeybinding(keybinding, OS)!;20const actualSerialized = usLayoutResolvedKeybinding.getUserSettingsLabel();21assert.strictEqual(actualSerialized, expected, expected + ' - ' + msg);22}23function testSerialization(keybinding: number, expectedWin: string, expectedMac: string, expectedLinux: string): void {24testOneSerialization(keybinding, expectedWin, 'win', OperatingSystem.Windows);25testOneSerialization(keybinding, expectedMac, 'mac', OperatingSystem.Macintosh);26testOneSerialization(keybinding, expectedLinux, 'linux', OperatingSystem.Linux);27}2829function testOneDeserialization(keybinding: string, _expected: number, msg: string, OS: OperatingSystem): void {30const actualDeserialized = KeybindingParser.parseKeybinding(keybinding);31const expected = decodeKeybinding(_expected, OS);32assert.deepStrictEqual(actualDeserialized, expected, keybinding + ' - ' + msg);33}34function testDeserialization(inWin: string, inMac: string, inLinux: string, expected: number): void {35testOneDeserialization(inWin, expected, 'win', OperatingSystem.Windows);36testOneDeserialization(inMac, expected, 'mac', OperatingSystem.Macintosh);37testOneDeserialization(inLinux, expected, 'linux', OperatingSystem.Linux);38}3940function testRoundtrip(keybinding: number, expectedWin: string, expectedMac: string, expectedLinux: string): void {41testSerialization(keybinding, expectedWin, expectedMac, expectedLinux);42testDeserialization(expectedWin, expectedMac, expectedLinux, keybinding);43}4445testRoundtrip(KeyCode.Digit0, '0', '0', '0');46testRoundtrip(KeyCode.KeyA, 'a', 'a', 'a');47testRoundtrip(KeyCode.UpArrow, 'up', 'up', 'up');48testRoundtrip(KeyCode.RightArrow, 'right', 'right', 'right');49testRoundtrip(KeyCode.DownArrow, 'down', 'down', 'down');50testRoundtrip(KeyCode.LeftArrow, 'left', 'left', 'left');5152// one modifier53testRoundtrip(KeyMod.Alt | KeyCode.KeyA, 'alt+a', 'alt+a', 'alt+a');54testRoundtrip(KeyMod.CtrlCmd | KeyCode.KeyA, 'ctrl+a', 'cmd+a', 'ctrl+a');55testRoundtrip(KeyMod.Shift | KeyCode.KeyA, 'shift+a', 'shift+a', 'shift+a');56testRoundtrip(KeyMod.WinCtrl | KeyCode.KeyA, 'win+a', 'ctrl+a', 'meta+a');5758// two modifiers59testRoundtrip(KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KeyA, 'ctrl+alt+a', 'alt+cmd+a', 'ctrl+alt+a');60testRoundtrip(KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyA, 'ctrl+shift+a', 'shift+cmd+a', 'ctrl+shift+a');61testRoundtrip(KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.KeyA, 'ctrl+win+a', 'ctrl+cmd+a', 'ctrl+meta+a');62testRoundtrip(KeyMod.Shift | KeyMod.Alt | KeyCode.KeyA, 'shift+alt+a', 'shift+alt+a', 'shift+alt+a');63testRoundtrip(KeyMod.Shift | KeyMod.WinCtrl | KeyCode.KeyA, 'shift+win+a', 'ctrl+shift+a', 'shift+meta+a');64testRoundtrip(KeyMod.Alt | KeyMod.WinCtrl | KeyCode.KeyA, 'alt+win+a', 'ctrl+alt+a', 'alt+meta+a');6566// three modifiers67testRoundtrip(KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyCode.KeyA, 'ctrl+shift+alt+a', 'shift+alt+cmd+a', 'ctrl+shift+alt+a');68testRoundtrip(KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.WinCtrl | KeyCode.KeyA, 'ctrl+shift+win+a', 'ctrl+shift+cmd+a', 'ctrl+shift+meta+a');69testRoundtrip(KeyMod.Shift | KeyMod.Alt | KeyMod.WinCtrl | KeyCode.KeyA, 'shift+alt+win+a', 'ctrl+shift+alt+a', 'shift+alt+meta+a');7071// all modifiers72testRoundtrip(KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyMod.WinCtrl | KeyCode.KeyA, 'ctrl+shift+alt+win+a', 'ctrl+shift+alt+cmd+a', 'ctrl+shift+alt+meta+a');7374// chords75testRoundtrip(KeyChord(KeyMod.CtrlCmd | KeyCode.KeyA, KeyMod.CtrlCmd | KeyCode.KeyA), 'ctrl+a ctrl+a', 'cmd+a cmd+a', 'ctrl+a ctrl+a');76testRoundtrip(KeyChord(KeyMod.CtrlCmd | KeyCode.UpArrow, KeyMod.CtrlCmd | KeyCode.UpArrow), 'ctrl+up ctrl+up', 'cmd+up cmd+up', 'ctrl+up ctrl+up');7778// OEM keys79testRoundtrip(KeyCode.Semicolon, ';', ';', ';');80testRoundtrip(KeyCode.Equal, '=', '=', '=');81testRoundtrip(KeyCode.Comma, ',', ',', ',');82testRoundtrip(KeyCode.Minus, '-', '-', '-');83testRoundtrip(KeyCode.Period, '.', '.', '.');84testRoundtrip(KeyCode.Slash, '/', '/', '/');85testRoundtrip(KeyCode.Backquote, '`', '`', '`');86testRoundtrip(KeyCode.ABNT_C1, 'abnt_c1', 'abnt_c1', 'abnt_c1');87testRoundtrip(KeyCode.ABNT_C2, 'abnt_c2', 'abnt_c2', 'abnt_c2');88testRoundtrip(KeyCode.BracketLeft, '[', '[', '[');89testRoundtrip(KeyCode.Backslash, '\\', '\\', '\\');90testRoundtrip(KeyCode.BracketRight, ']', ']', ']');91testRoundtrip(KeyCode.Quote, '\'', '\'', '\'');92testRoundtrip(KeyCode.OEM_8, 'oem_8', 'oem_8', 'oem_8');93testRoundtrip(KeyCode.IntlBackslash, 'oem_102', 'oem_102', 'oem_102');9495// OEM aliases96testDeserialization('OEM_1', 'OEM_1', 'OEM_1', KeyCode.Semicolon);97testDeserialization('OEM_PLUS', 'OEM_PLUS', 'OEM_PLUS', KeyCode.Equal);98testDeserialization('OEM_COMMA', 'OEM_COMMA', 'OEM_COMMA', KeyCode.Comma);99testDeserialization('OEM_MINUS', 'OEM_MINUS', 'OEM_MINUS', KeyCode.Minus);100testDeserialization('OEM_PERIOD', 'OEM_PERIOD', 'OEM_PERIOD', KeyCode.Period);101testDeserialization('OEM_2', 'OEM_2', 'OEM_2', KeyCode.Slash);102testDeserialization('OEM_3', 'OEM_3', 'OEM_3', KeyCode.Backquote);103testDeserialization('ABNT_C1', 'ABNT_C1', 'ABNT_C1', KeyCode.ABNT_C1);104testDeserialization('ABNT_C2', 'ABNT_C2', 'ABNT_C2', KeyCode.ABNT_C2);105testDeserialization('OEM_4', 'OEM_4', 'OEM_4', KeyCode.BracketLeft);106testDeserialization('OEM_5', 'OEM_5', 'OEM_5', KeyCode.Backslash);107testDeserialization('OEM_6', 'OEM_6', 'OEM_6', KeyCode.BracketRight);108testDeserialization('OEM_7', 'OEM_7', 'OEM_7', KeyCode.Quote);109testDeserialization('OEM_8', 'OEM_8', 'OEM_8', KeyCode.OEM_8);110testDeserialization('OEM_102', 'OEM_102', 'OEM_102', KeyCode.IntlBackslash);111112// accepts '-' as separator113testDeserialization('ctrl-shift-alt-win-a', 'ctrl-shift-alt-cmd-a', 'ctrl-shift-alt-meta-a', KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyMod.WinCtrl | KeyCode.KeyA);114115// various input mistakes116testDeserialization(' ctrl-shift-alt-win-A ', ' shift-alt-cmd-Ctrl-A ', ' ctrl-shift-alt-META-A ', KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyMod.WinCtrl | KeyCode.KeyA);117});118119test('deserialize scan codes', () => {120assert.deepStrictEqual(121KeybindingParser.parseKeybinding('ctrl+shift+[comma] ctrl+/'),122new Keybinding([new ScanCodeChord(true, true, false, false, ScanCode.Comma), new KeyCodeChord(true, false, false, false, KeyCode.Slash)])123);124});125126test('issue #10452 - invalid command', () => {127const strJSON = `[{ "key": "ctrl+k ctrl+f", "command": ["firstcommand", "seccondcommand"] }]`;128const userKeybinding = <Object>JSON.parse(strJSON)[0];129const keybindingItem = KeybindingIO.readUserKeybindingItem(userKeybinding);130assert.strictEqual(keybindingItem.command, null);131});132133test('issue #10452 - invalid when', () => {134const strJSON = `[{ "key": "ctrl+k ctrl+f", "command": "firstcommand", "when": [] }]`;135const userKeybinding = <Object>JSON.parse(strJSON)[0];136const keybindingItem = KeybindingIO.readUserKeybindingItem(userKeybinding);137assert.strictEqual(keybindingItem.when, undefined);138});139140test('issue #10452 - invalid key', () => {141const strJSON = `[{ "key": [], "command": "firstcommand" }]`;142const userKeybinding = <Object>JSON.parse(strJSON)[0];143const keybindingItem = KeybindingIO.readUserKeybindingItem(userKeybinding);144assert.deepStrictEqual(keybindingItem.keybinding, null);145});146147test('issue #10452 - invalid key 2', () => {148const strJSON = `[{ "key": "", "command": "firstcommand" }]`;149const userKeybinding = <Object>JSON.parse(strJSON)[0];150const keybindingItem = KeybindingIO.readUserKeybindingItem(userKeybinding);151assert.deepStrictEqual(keybindingItem.keybinding, null);152});153154test('test commands args', () => {155const strJSON = `[{ "key": "ctrl+k ctrl+f", "command": "firstcommand", "when": [], "args": { "text": "theText" } }]`;156const userKeybinding = <Object>JSON.parse(strJSON)[0];157const keybindingItem = KeybindingIO.readUserKeybindingItem(userKeybinding);158assert.strictEqual(keybindingItem.commandArgs.text, 'theText');159});160});161162163