windowsKeyboardMapper.ts ×34

Frontier kind: Code frontier

unlabeled · c_f1597732c512

33 tests · 8657 LOC · 40 files · introduces 0 tests · 190 LOC · 1 file

Introduces — evidence that enters the hierarchy at this concept

Code
34 ranges190 lines · 1 files
Tests
0 tests

Contains — complete concept membership

All code (extent)
1131 ranges8657 lines · 40 files · Browse complete extent
All tests (intent)
33 testsBrowse complete intent

Neighbourhood graph

The orange circle is the focus. Violet and green circles are every ancestor and descendant, broader and narrower, at any distance; blue squares and pink diamonds are the introduced files and exact introduced tests of every visible concept, not only the focus's. Arrows point from broader to narrower concepts and bridge only concepts omitted from this view. Undirected links show source or test introduction. Concept and file size follows LOC; exact test nodes use test-count units.

Introduced files, introduced tests, and structurally relevant concept specialization

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the native relationship evidence on this page.

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the native relationship evidence on this page while the interactive map is unavailable.

Native relationship evidence

Every exact file and test below is linked only from the concept that introduces it.

Introduced tests

Every collected test enters the hierarchy at exactly one concept.

No tests are introduced at this concept. Its intent tests are introduced by other concepts.

Introduced code

Every collected source range enters the hierarchy at exactly one concept.

1 file ranked by introduced lines: 190 introduced LOC across 34 ranges. Expand a file to inspect source; the > gutter marks introduced lines.

src/vs/workbench/services/keybinding/common/windowsKeyboardMapper.ts 190 introduced LOC · 34 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- windowsKeyboardMapper.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { CharCode } from '../../../../base/common/charCode.js';
7 > import { KeyCode, KeyCodeUtils, IMMUTABLE_CODE_TO_KEY_CODE, ScanCode, ScanCodeUtils, NATIVE_WINDOWS_KEY_CODE_TO_KEY_CODE } from '../../../../base/common/keyCodes.js';
8 > import { ResolvedKeybinding, KeyCodeChord, SingleModifierChord, ScanCodeChord, Keybinding, Chord } from '../../../../base/common/keybindings.js';
9 > import { UILabelProvider } from '../../../../base/common/keybindingLabels.js';
10 > import { OperatingSystem } from '../../../../base/common/platform.js';
11 > import { IKeyboardEvent } from '../../../../platform/keybinding/common/keybinding.js';
12 > import { IKeyboardMapper } from '../../../../platform/keyboardLayout/common/keyboardMapper.js';
13 > import { BaseResolvedKeybinding } from '../../../../platform/keybinding/common/baseResolvedKeybinding.js';
14 > import { toEmptyArrayIfContainsNull } from '../../../../platform/keybinding/common/resolvedKeybindingItem.js';
15 > import { IWindowsKeyboardMapping } from '../../../../platform/keyboardLayout/common/keyboardLayout.js';
16 >
17 > const LOG = false;
18 function log(str: string): void {
19 if (LOG) {
21 }
22 }
24 >
25 > export interface IScanCodeMapping {
26 > scanCode: ScanCode;
27 > keyCode: KeyCode;
28 > value: string;
29 > withShift: string;
30 > withAltGr: string;
31 > withShiftAltGr: string;
32 > }
33 >
34 > export class WindowsNativeResolvedKeybinding extends BaseResolvedKeybinding<KeyCodeChord> {
35 >
36 > private readonly _mapper: WindowsKeyboardMapper;
37 >
38 > constructor(mapper: WindowsKeyboardMapper, chords: KeyCodeChord[]) {
39 super(OperatingSystem.Windows, chords);
40 this._mapper = mapper;
41 }
43 > protected _getLabel(chord: KeyCodeChord): string | null {
44 if (chord.isDuplicateModifierCase()) {
45 return '';
47 return this._mapper.getUILabelForKeyCode(chord.keyCode);
48 }
50 > private _getUSLabelForKeybinding(chord: KeyCodeChord): string | null {
51 if (chord.isDuplicateModifierCase()) {
52 return '';
54 return KeyCodeUtils.toString(chord.keyCode);
55 }
57 > public getUSLabel(): string | null {
58 return UILabelProvider.toLabel(this._os, this._chords, (keybinding) => this._getUSLabelForKeybinding(keybinding));
59 }
61 > protected _getAriaLabel(chord: KeyCodeChord): string | null {
62 if (chord.isDuplicateModifierCase()) {
63 return '';
65 return this._mapper.getAriaLabelForKeyCode(chord.keyCode);
66 }
68 > protected _getElectronAccelerator(chord: KeyCodeChord): string | null {
69 return this._mapper.getElectronAcceleratorForKeyBinding(chord);
70 }
72 > protected _getUserSettingsLabel(chord: KeyCodeChord): string | null {
73 if (chord.isDuplicateModifierCase()) {
74 return '';
77 return (result ? result.toLowerCase() : result);
78 }
80 > protected _isWYSIWYG(chord: KeyCodeChord): boolean {
81 return this.__isWYSIWYG(chord.keyCode);
82 }
84 > private __isWYSIWYG(keyCode: KeyCode): boolean {
85 if (
86 keyCode === KeyCode.LeftArrow
95 return (ariaLabel === userSettingsLabel);
96 }
98 > protected _getChordDispatch(chord: KeyCodeChord): string | null {
99 if (chord.isModifierKey()) {
100 return null;
118 return result;
119 }
121 > protected _getSingleModifierChordDispatch(chord: KeyCodeChord): SingleModifierChord | null {
122 if (chord.keyCode === KeyCode.Ctrl && !chord.shiftKey && !chord.altKey && !chord.metaKey) {
123 return 'ctrl';
134 return null;
135 }
137 > private static getProducedCharCode(chord: ScanCodeChord, mapping: IScanCodeMapping): string | null {
138 if (!mapping) {
139 return null;
150 return mapping.value;
151 }
153 > public static getProducedChar(chord: ScanCodeChord, mapping: IScanCodeMapping): string {
154 const char = this.getProducedCharCode(chord, mapping);
155 if (char === null || char.length === 0) {
158 return ' ' + char + ' ';
159 }
161 >
162 > export class WindowsKeyboardMapper implements IKeyboardMapper {
163 >
164 > private readonly _codeInfo: IScanCodeMapping[];
165 > private readonly _scanCodeToKeyCode: KeyCode[];
166 > private readonly _keyCodeToLabel: Array<string | null> = [];
167 > private readonly _keyCodeExists: boolean[];
168 >
169 > constructor(
170 > private readonly _isUSStandard: boolean,
171 > rawMappings: IWindowsKeyboardMapping,
172 > private readonly _mapAltGrToCtrlAlt: boolean
173 > ) {
174 > this._scanCodeToKeyCode = [];
175 > this._keyCodeToLabel = [];
176 > this._keyCodeExists = [];
177 > this._keyCodeToLabel[KeyCode.Unknown] = KeyCodeUtils.toString(KeyCode.Unknown);
178 >
179 > for (let scanCode = ScanCode.None; scanCode < ScanCode.MAX_VALUE; scanCode++) {
180 > const immutableKeyCode = IMMUTABLE_CODE_TO_KEY_CODE[scanCode];
181 > if (immutableKeyCode !== KeyCode.DependsOnKbLayout) {
182 > this._scanCodeToKeyCode[scanCode] = immutableKeyCode;
183 > this._keyCodeToLabel[immutableKeyCode] = KeyCodeUtils.toString(immutableKeyCode);
184 > this._keyCodeExists[immutableKeyCode] = true;
185 > }
186 > }
187 >
188 > const producesLetter: boolean[] = [];
189 > let producesLetters = false;
190 >
191 > this._codeInfo = [];
192 > for (const strCode in rawMappings) {
193 > if (rawMappings.hasOwnProperty(strCode)) {
194 > const scanCode = ScanCodeUtils.toEnum(strCode);
195 > if (scanCode === ScanCode.None) {
196 log(`Unknown scanCode ${strCode} in mapping.`);
197 continue;
198 }
199 > const rawMapping = rawMappings[strCode]; windowsKeyboardMapper.ts
200 >
201 > const immutableKeyCode = IMMUTABLE_CODE_TO_KEY_CODE[scanCode];
202 > if (immutableKeyCode !== KeyCode.DependsOnKbLayout) {
203 const keyCode = NATIVE_WINDOWS_KEY_CODE_TO_KEY_CODE[rawMapping.vkey] || KeyCode.Unknown;
204 if (keyCode === KeyCode.Unknown || immutableKeyCode === keyCode) {
211 }
212 }
214 > const value = rawMapping.value;
215 > const withShift = rawMapping.withShift;
216 > const withAltGr = rawMapping.withAltGr;
217 > const withShiftAltGr = rawMapping.withShiftAltGr;
218 > const keyCode = NATIVE_WINDOWS_KEY_CODE_TO_KEY_CODE[rawMapping.vkey] || KeyCode.Unknown;
219 >
220 > const mapping: IScanCodeMapping = {
221 > scanCode: scanCode,
222 > keyCode: keyCode,
223 > value: value,
224 > withShift: withShift,
225 > withAltGr: withAltGr,
226 > withShiftAltGr: withShiftAltGr,
227 > };
228 > this._codeInfo[scanCode] = mapping;
229 > this._scanCodeToKeyCode[scanCode] = keyCode;
230 >
231 > if (keyCode === KeyCode.Unknown) {
232 continue;
233 }
234 > this._keyCodeExists[keyCode] = true; windowsKeyboardMapper.ts
235 >
236 > if (value.length === 0) {
237 // This key does not produce strings
238 this._keyCodeToLabel[keyCode] = null;
239 }
241 > else if (value.length > 1) {
242 // This key produces a letter representable with multiple UTF-16 code units.
243 this._keyCodeToLabel[keyCode] = value;
244 }
246 > else {
247 > const charCode = value.charCodeAt(0);
248 >
249 > if (charCode >= CharCode.a && charCode <= CharCode.z) {
250 const upperCaseValue = CharCode.A + (charCode - CharCode.a);
251 producesLetter[upperCaseValue] = true;
253 this._keyCodeToLabel[keyCode] = String.fromCharCode(CharCode.A + (charCode - CharCode.a));
254 }
256 > else if (charCode >= CharCode.A && charCode <= CharCode.Z) {
257 producesLetter[charCode] = true;
258 producesLetters = true;
259 this._keyCodeToLabel[keyCode] = value;
260 }
262 > else {
263 > this._keyCodeToLabel[keyCode] = value;
264 > }
265 > }
266 > }
267 > }
268 >
269 > // Handle keyboard layouts where latin characters are not produced e.g. Cyrillic
270 > const _registerLetterIfMissing = (charCode: CharCode, keyCode: KeyCode): void => {
271 > if (!producesLetter[charCode]) {
272 this._keyCodeToLabel[keyCode] = String.fromCharCode(charCode);
273 }
275 > _registerLetterIfMissing(CharCode.A, KeyCode.KeyA);
276 > _registerLetterIfMissing(CharCode.B, KeyCode.KeyB);
277 > _registerLetterIfMissing(CharCode.C, KeyCode.KeyC);
278 > _registerLetterIfMissing(CharCode.D, KeyCode.KeyD);
279 > _registerLetterIfMissing(CharCode.E, KeyCode.KeyE);
280 > _registerLetterIfMissing(CharCode.F, KeyCode.KeyF);
281 > _registerLetterIfMissing(CharCode.G, KeyCode.KeyG);
282 > _registerLetterIfMissing(CharCode.H, KeyCode.KeyH);
283 > _registerLetterIfMissing(CharCode.I, KeyCode.KeyI);
284 > _registerLetterIfMissing(CharCode.J, KeyCode.KeyJ);
285 > _registerLetterIfMissing(CharCode.K, KeyCode.KeyK);
286 > _registerLetterIfMissing(CharCode.L, KeyCode.KeyL);
287 > _registerLetterIfMissing(CharCode.M, KeyCode.KeyM);
288 > _registerLetterIfMissing(CharCode.N, KeyCode.KeyN);
289 > _registerLetterIfMissing(CharCode.O, KeyCode.KeyO);
290 > _registerLetterIfMissing(CharCode.P, KeyCode.KeyP);
291 > _registerLetterIfMissing(CharCode.Q, KeyCode.KeyQ);
292 > _registerLetterIfMissing(CharCode.R, KeyCode.KeyR);
293 > _registerLetterIfMissing(CharCode.S, KeyCode.KeyS);
294 > _registerLetterIfMissing(CharCode.T, KeyCode.KeyT);
295 > _registerLetterIfMissing(CharCode.U, KeyCode.KeyU);
296 > _registerLetterIfMissing(CharCode.V, KeyCode.KeyV);
297 > _registerLetterIfMissing(CharCode.W, KeyCode.KeyW);
298 > _registerLetterIfMissing(CharCode.X, KeyCode.KeyX);
299 > _registerLetterIfMissing(CharCode.Y, KeyCode.KeyY);
300 > _registerLetterIfMissing(CharCode.Z, KeyCode.KeyZ);
301 >
302 > if (!producesLetters) {
303 // Since this keyboard layout produces no latin letters at all, most of the UI will use the
304 // US kb layout equivalent for UI labels, so also try to render other keys with the US labels
323 _registerLabel(KeyCode.Quote, CharCode.SingleQuote);
324 }
326 >
327 > public dumpDebugInfo(): string {
328 const result: string[] = [];
329
377 return result.join('\n');
378 }
380 > private _leftPad(str: string | null, cnt: number): string {
381 if (str === null) {
382 str = 'null';
387 return str;
388 }
390 > public getUILabelForKeyCode(keyCode: KeyCode): string {
391 return this._getLabelForKeyCode(keyCode);
392 }
394 > public getAriaLabelForKeyCode(keyCode: KeyCode): string {
395 return this._getLabelForKeyCode(keyCode);
396 }
398 > public getUserSettingsLabelForKeyCode(keyCode: KeyCode): string {
399 if (this._isUSStandard) {
400 return KeyCodeUtils.toUserSettingsUS(keyCode);
402 return KeyCodeUtils.toUserSettingsGeneral(keyCode);
403 }
405 > public getElectronAcceleratorForKeyBinding(chord: KeyCodeChord): string | null {
406 return KeyCodeUtils.toElectronAccelerator(chord.keyCode);
407 }
409 > private _getLabelForKeyCode(keyCode: KeyCode): string {
410 return this._keyCodeToLabel[keyCode] || KeyCodeUtils.toString(KeyCode.Unknown);
411 }
413 > public resolveKeyboardEvent(keyboardEvent: IKeyboardEvent): WindowsNativeResolvedKeybinding {
414 const ctrlKey = keyboardEvent.ctrlKey || (this._mapAltGrToCtrlAlt && keyboardEvent.altGraphKey);
415 const altKey = keyboardEvent.altKey || (this._mapAltGrToCtrlAlt && keyboardEvent.altGraphKey);
417 return new WindowsNativeResolvedKeybinding(this, [chord]);
418 }
420 > private _resolveChord(chord: Chord | null): KeyCodeChord | null {
421 if (!chord) {
422 return null;
434 return new KeyCodeChord(chord.ctrlKey, chord.shiftKey, chord.altKey, chord.metaKey, keyCode);
435 }
437 > public resolveKeybinding(keybinding: Keybinding): ResolvedKeybinding[] {
438 const chords: KeyCodeChord[] = toEmptyArrayIfContainsNull(keybinding.chords.map(chord => this._resolveChord(chord)));
439 if (chords.length > 0) {