Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/services/keybinding/test/browser/keybindingIO.test.ts
3296 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
import assert from 'assert';
6
import { KeyChord, KeyCode, KeyMod, ScanCode } from '../../../../../base/common/keyCodes.js';
7
import { KeyCodeChord, decodeKeybinding, ScanCodeChord, Keybinding } from '../../../../../base/common/keybindings.js';
8
import { KeybindingParser } from '../../../../../base/common/keybindingParser.js';
9
import { OperatingSystem } from '../../../../../base/common/platform.js';
10
import { KeybindingIO } from '../../common/keybindingIO.js';
11
import { createUSLayoutResolvedKeybinding } from '../../../../../platform/keybinding/test/common/keybindingsTestUtils.js';
12
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js';
13
14
suite('keybindingIO', () => {
15
ensureNoDisposablesAreLeakedInTestSuite();
16
17
test('serialize/deserialize', () => {
18
19
function testOneSerialization(keybinding: number, expected: string, msg: string, OS: OperatingSystem): void {
20
const usLayoutResolvedKeybinding = createUSLayoutResolvedKeybinding(keybinding, OS)!;
21
const actualSerialized = usLayoutResolvedKeybinding.getUserSettingsLabel();
22
assert.strictEqual(actualSerialized, expected, expected + ' - ' + msg);
23
}
24
function testSerialization(keybinding: number, expectedWin: string, expectedMac: string, expectedLinux: string): void {
25
testOneSerialization(keybinding, expectedWin, 'win', OperatingSystem.Windows);
26
testOneSerialization(keybinding, expectedMac, 'mac', OperatingSystem.Macintosh);
27
testOneSerialization(keybinding, expectedLinux, 'linux', OperatingSystem.Linux);
28
}
29
30
function testOneDeserialization(keybinding: string, _expected: number, msg: string, OS: OperatingSystem): void {
31
const actualDeserialized = KeybindingParser.parseKeybinding(keybinding);
32
const expected = decodeKeybinding(_expected, OS);
33
assert.deepStrictEqual(actualDeserialized, expected, keybinding + ' - ' + msg);
34
}
35
function testDeserialization(inWin: string, inMac: string, inLinux: string, expected: number): void {
36
testOneDeserialization(inWin, expected, 'win', OperatingSystem.Windows);
37
testOneDeserialization(inMac, expected, 'mac', OperatingSystem.Macintosh);
38
testOneDeserialization(inLinux, expected, 'linux', OperatingSystem.Linux);
39
}
40
41
function testRoundtrip(keybinding: number, expectedWin: string, expectedMac: string, expectedLinux: string): void {
42
testSerialization(keybinding, expectedWin, expectedMac, expectedLinux);
43
testDeserialization(expectedWin, expectedMac, expectedLinux, keybinding);
44
}
45
46
testRoundtrip(KeyCode.Digit0, '0', '0', '0');
47
testRoundtrip(KeyCode.KeyA, 'a', 'a', 'a');
48
testRoundtrip(KeyCode.UpArrow, 'up', 'up', 'up');
49
testRoundtrip(KeyCode.RightArrow, 'right', 'right', 'right');
50
testRoundtrip(KeyCode.DownArrow, 'down', 'down', 'down');
51
testRoundtrip(KeyCode.LeftArrow, 'left', 'left', 'left');
52
53
// one modifier
54
testRoundtrip(KeyMod.Alt | KeyCode.KeyA, 'alt+a', 'alt+a', 'alt+a');
55
testRoundtrip(KeyMod.CtrlCmd | KeyCode.KeyA, 'ctrl+a', 'cmd+a', 'ctrl+a');
56
testRoundtrip(KeyMod.Shift | KeyCode.KeyA, 'shift+a', 'shift+a', 'shift+a');
57
testRoundtrip(KeyMod.WinCtrl | KeyCode.KeyA, 'win+a', 'ctrl+a', 'meta+a');
58
59
// two modifiers
60
testRoundtrip(KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KeyA, 'ctrl+alt+a', 'alt+cmd+a', 'ctrl+alt+a');
61
testRoundtrip(KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyA, 'ctrl+shift+a', 'shift+cmd+a', 'ctrl+shift+a');
62
testRoundtrip(KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.KeyA, 'ctrl+win+a', 'ctrl+cmd+a', 'ctrl+meta+a');
63
testRoundtrip(KeyMod.Shift | KeyMod.Alt | KeyCode.KeyA, 'shift+alt+a', 'shift+alt+a', 'shift+alt+a');
64
testRoundtrip(KeyMod.Shift | KeyMod.WinCtrl | KeyCode.KeyA, 'shift+win+a', 'ctrl+shift+a', 'shift+meta+a');
65
testRoundtrip(KeyMod.Alt | KeyMod.WinCtrl | KeyCode.KeyA, 'alt+win+a', 'ctrl+alt+a', 'alt+meta+a');
66
67
// three modifiers
68
testRoundtrip(KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyCode.KeyA, 'ctrl+shift+alt+a', 'shift+alt+cmd+a', 'ctrl+shift+alt+a');
69
testRoundtrip(KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.WinCtrl | KeyCode.KeyA, 'ctrl+shift+win+a', 'ctrl+shift+cmd+a', 'ctrl+shift+meta+a');
70
testRoundtrip(KeyMod.Shift | KeyMod.Alt | KeyMod.WinCtrl | KeyCode.KeyA, 'shift+alt+win+a', 'ctrl+shift+alt+a', 'shift+alt+meta+a');
71
72
// all modifiers
73
testRoundtrip(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');
74
75
// chords
76
testRoundtrip(KeyChord(KeyMod.CtrlCmd | KeyCode.KeyA, KeyMod.CtrlCmd | KeyCode.KeyA), 'ctrl+a ctrl+a', 'cmd+a cmd+a', 'ctrl+a ctrl+a');
77
testRoundtrip(KeyChord(KeyMod.CtrlCmd | KeyCode.UpArrow, KeyMod.CtrlCmd | KeyCode.UpArrow), 'ctrl+up ctrl+up', 'cmd+up cmd+up', 'ctrl+up ctrl+up');
78
79
// OEM keys
80
testRoundtrip(KeyCode.Semicolon, ';', ';', ';');
81
testRoundtrip(KeyCode.Equal, '=', '=', '=');
82
testRoundtrip(KeyCode.Comma, ',', ',', ',');
83
testRoundtrip(KeyCode.Minus, '-', '-', '-');
84
testRoundtrip(KeyCode.Period, '.', '.', '.');
85
testRoundtrip(KeyCode.Slash, '/', '/', '/');
86
testRoundtrip(KeyCode.Backquote, '`', '`', '`');
87
testRoundtrip(KeyCode.ABNT_C1, 'abnt_c1', 'abnt_c1', 'abnt_c1');
88
testRoundtrip(KeyCode.ABNT_C2, 'abnt_c2', 'abnt_c2', 'abnt_c2');
89
testRoundtrip(KeyCode.BracketLeft, '[', '[', '[');
90
testRoundtrip(KeyCode.Backslash, '\\', '\\', '\\');
91
testRoundtrip(KeyCode.BracketRight, ']', ']', ']');
92
testRoundtrip(KeyCode.Quote, '\'', '\'', '\'');
93
testRoundtrip(KeyCode.OEM_8, 'oem_8', 'oem_8', 'oem_8');
94
testRoundtrip(KeyCode.IntlBackslash, 'oem_102', 'oem_102', 'oem_102');
95
96
// OEM aliases
97
testDeserialization('OEM_1', 'OEM_1', 'OEM_1', KeyCode.Semicolon);
98
testDeserialization('OEM_PLUS', 'OEM_PLUS', 'OEM_PLUS', KeyCode.Equal);
99
testDeserialization('OEM_COMMA', 'OEM_COMMA', 'OEM_COMMA', KeyCode.Comma);
100
testDeserialization('OEM_MINUS', 'OEM_MINUS', 'OEM_MINUS', KeyCode.Minus);
101
testDeserialization('OEM_PERIOD', 'OEM_PERIOD', 'OEM_PERIOD', KeyCode.Period);
102
testDeserialization('OEM_2', 'OEM_2', 'OEM_2', KeyCode.Slash);
103
testDeserialization('OEM_3', 'OEM_3', 'OEM_3', KeyCode.Backquote);
104
testDeserialization('ABNT_C1', 'ABNT_C1', 'ABNT_C1', KeyCode.ABNT_C1);
105
testDeserialization('ABNT_C2', 'ABNT_C2', 'ABNT_C2', KeyCode.ABNT_C2);
106
testDeserialization('OEM_4', 'OEM_4', 'OEM_4', KeyCode.BracketLeft);
107
testDeserialization('OEM_5', 'OEM_5', 'OEM_5', KeyCode.Backslash);
108
testDeserialization('OEM_6', 'OEM_6', 'OEM_6', KeyCode.BracketRight);
109
testDeserialization('OEM_7', 'OEM_7', 'OEM_7', KeyCode.Quote);
110
testDeserialization('OEM_8', 'OEM_8', 'OEM_8', KeyCode.OEM_8);
111
testDeserialization('OEM_102', 'OEM_102', 'OEM_102', KeyCode.IntlBackslash);
112
113
// accepts '-' as separator
114
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.KeyA);
115
116
// various input mistakes
117
testDeserialization(' 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);
118
});
119
120
test('deserialize scan codes', () => {
121
assert.deepStrictEqual(
122
KeybindingParser.parseKeybinding('ctrl+shift+[comma] ctrl+/'),
123
new Keybinding([new ScanCodeChord(true, true, false, false, ScanCode.Comma), new KeyCodeChord(true, false, false, false, KeyCode.Slash)])
124
);
125
});
126
127
test('issue #10452 - invalid command', () => {
128
const strJSON = `[{ "key": "ctrl+k ctrl+f", "command": ["firstcommand", "seccondcommand"] }]`;
129
const userKeybinding = <Object>JSON.parse(strJSON)[0];
130
const keybindingItem = KeybindingIO.readUserKeybindingItem(userKeybinding);
131
assert.strictEqual(keybindingItem.command, null);
132
});
133
134
test('issue #10452 - invalid when', () => {
135
const strJSON = `[{ "key": "ctrl+k ctrl+f", "command": "firstcommand", "when": [] }]`;
136
const userKeybinding = <Object>JSON.parse(strJSON)[0];
137
const keybindingItem = KeybindingIO.readUserKeybindingItem(userKeybinding);
138
assert.strictEqual(keybindingItem.when, undefined);
139
});
140
141
test('issue #10452 - invalid key', () => {
142
const strJSON = `[{ "key": [], "command": "firstcommand" }]`;
143
const userKeybinding = <Object>JSON.parse(strJSON)[0];
144
const keybindingItem = KeybindingIO.readUserKeybindingItem(userKeybinding);
145
assert.deepStrictEqual(keybindingItem.keybinding, null);
146
});
147
148
test('issue #10452 - invalid key 2', () => {
149
const strJSON = `[{ "key": "", "command": "firstcommand" }]`;
150
const userKeybinding = <Object>JSON.parse(strJSON)[0];
151
const keybindingItem = KeybindingIO.readUserKeybindingItem(userKeybinding);
152
assert.deepStrictEqual(keybindingItem.keybinding, null);
153
});
154
155
test('test commands args', () => {
156
const strJSON = `[{ "key": "ctrl+k ctrl+f", "command": "firstcommand", "when": [], "args": { "text": "theText" } }]`;
157
const userKeybinding = <Object>JSON.parse(strJSON)[0];
158
const keybindingItem = KeybindingIO.readUserKeybindingItem(userKeybinding);
159
assert.strictEqual(keybindingItem.commandArgs.text, 'theText');
160
});
161
});
162
163