src/vs/workbench/services/keybinding/common/macLinuxKeyboardMapper.ts

1112 LOC · 1088 covered · 24 uncovered · 246 ranges · 145 concepts · 79 introducers · 85 tests

File neighbourhood

The centred file is linked to every concept that introduces one of its ranges, every test that runs code from the file, and the gray connector concepts standing between those tests and the file's own introducer concepts. Undirected links join concepts to every file where they introduce source and concepts to the tests they introduce; arrows show specialization between the displayed concepts and bridge only concepts omitted from this view. Concept colors match the source ranges below; connector concepts have no source color and are shown in gray.

Focused file, its introducer and connector concepts, their introduced files, and tests that run code from the file

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 related-file, concept, and source links on this page.

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the related-file, concept, and source links on this page while the interactive map is unavailable.

1 > /*--------------------------------------------------------------------------------------------- macLinuxKeyboardMapper.ts ×43
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, IMMUTABLE_KEY_CODE_TO_CODE, ScanCode, ScanCodeUtils, isModifierKey } from '../../../../base/common/keyCodes.js';
8 > import { ResolvedKeybinding, KeyCodeChord, SingleModifierChord, ScanCodeChord, Keybinding, Chord } from '../../../../base/common/keybindings.js';
9 > import { OperatingSystem } from '../../../../base/common/platform.js';
10 > import { IKeyboardEvent } from '../../../../platform/keybinding/common/keybinding.js';
11 > import { IKeyboardMapper } from '../../../../platform/keyboardLayout/common/keyboardMapper.js';
12 > import { BaseResolvedKeybinding } from '../../../../platform/keybinding/common/baseResolvedKeybinding.js';
13 > import { IMacLinuxKeyboardMapping, IMacLinuxKeyMapping } from '../../../../platform/keyboardLayout/common/keyboardLayout.js';
14 >
15 > /**
16 > * A map from character to key codes.
17 > * e.g. Contains entries such as:
18 > * - '/' => { keyCode: KeyCode.US_SLASH, shiftKey: false }
19 > * - '?' => { keyCode: KeyCode.US_SLASH, shiftKey: true }
20 > */
21 > const CHAR_CODE_TO_KEY_CODE: ({ keyCode: KeyCode; shiftKey: boolean } | null)[] = [];
22 >
23 > export class NativeResolvedKeybinding extends BaseResolvedKeybinding<ScanCodeChord> {
24 >
25 > private readonly _mapper: MacLinuxKeyboardMapper;
26 >
27 > constructor(mapper: MacLinuxKeyboardMapper, os: OperatingSystem, chords: ScanCodeChord[]) {
28 > super(os, chords); macLinuxKeyboardMapper.ts ×17
29 > this._mapper = mapper;
30 > }
32 > protected _getLabel(chord: ScanCodeChord): string | null {
33 > return this._mapper.getUILabelForScanCodeChord(chord); macLinuxKeyboardMapper.ts ×9
34 > }
36 > protected _getAriaLabel(chord: ScanCodeChord): string | null {
37 > return this._mapper.getAriaLabelForScanCodeChord(chord); macLinuxKeyboardMapper.ts ×17
38 > }
40 > protected _getElectronAccelerator(chord: ScanCodeChord): string | null {
41 > return this._mapper.getElectronAcceleratorLabelForScanCodeChord(chord); macLinuxKeyboardMapper.ts ×5
42 > }
44 > protected _getUserSettingsLabel(chord: ScanCodeChord): string | null {
45 > return this._mapper.getUserSettingsLabelForScanCodeChord(chord); macLinuxKeyboardMapper.ts ×17
46 > }
48 > protected _isWYSIWYG(binding: ScanCodeChord | null): boolean {
49 > if (!binding) { macLinuxKeyboardMapper.ts ×17
50 return true;
51 }
52 > if (IMMUTABLE_CODE_TO_KEY_CODE[binding.scanCode] !== KeyCode.DependsOnKbLayout) { macLinuxKeyboardMapper.ts ×17
53 > return true; macLinuxKeyboardMapper.ts ×1
54 > }
55 > const a = this._mapper.getAriaLabelForScanCodeChord(binding); macLinuxKeyboardMapper.ts ×6
56 > const b = this._mapper.getUserSettingsLabelForScanCodeChord(binding);
57 >
58 > if (!a && !b) { macLinuxKeyboardMapper.ts ×17
59 > return true; macLinuxKeyboardMapper.ts ×11
60 > }
61 > if (!a || !b) { macLinuxKeyboardMapper.ts ×17
62 > return false; macLinuxKeyboardMapper.ts ×11
63 > }
64 > return (a.toLowerCase() === b.toLowerCase()); macLinuxKeyboardMapper.ts ×6
67 > protected _getChordDispatch(chord: ScanCodeChord): string | null {
68 > return this._mapper.getDispatchStrForScanCodeChord(chord); macLinuxKeyboardMapper.ts ×17
69 > }
71 > protected _getSingleModifierChordDispatch(chord: ScanCodeChord): SingleModifierChord | null {
72 > if ((chord.scanCode === ScanCode.ControlLeft || chord.scanCode === ScanCode.ControlRight) && !chord.shiftKey && !chord.altKey && !chord.metaKey) { macLinuxKeyboardMapper.ts ×9
73 > return 'ctrl'; macLinuxKeyboardMapper.ts ×1
74 > }
75 > if ((chord.scanCode === ScanCode.AltLeft || chord.scanCode === ScanCode.AltRight) && !chord.ctrlKey && !chord.shiftKey && !chord.metaKey) { macLinuxKeyboardMapper.ts ×9
76 > return 'alt'; macLinuxKeyboardMapper.ts ×1
77 > }
78 > if ((chord.scanCode === ScanCode.ShiftLeft || chord.scanCode === ScanCode.ShiftRight) && !chord.ctrlKey && !chord.altKey && !chord.metaKey) { macLinuxKeyboardMapper.ts ×9
79 > return 'shift'; macLinuxKeyboardMapper.ts ×1
80 > }
81 > if ((chord.scanCode === ScanCode.MetaLeft || chord.scanCode === ScanCode.MetaRight) && !chord.ctrlKey && !chord.shiftKey && !chord.altKey) { macLinuxKeyboardMapper.ts ×9
82 > return 'meta'; macLinuxKeyboardMapper.ts ×1
83 > }
84 > return null; macLinuxKeyboardMapper.ts ×1
87 >
88 > interface IScanCodeMapping {
89 > scanCode: ScanCode;
90 > value: number;
91 > withShift: number;
92 > withAltGr: number;
93 > withShiftAltGr: number;
94 > }
95 >
96 > class ScanCodeCombo {
97 > public readonly ctrlKey: boolean;
98 > public readonly shiftKey: boolean;
99 > public readonly altKey: boolean;
100 > public readonly scanCode: ScanCode;
101 >
102 > constructor(ctrlKey: boolean, shiftKey: boolean, altKey: boolean, scanCode: ScanCode) {
103 > this.ctrlKey = ctrlKey;
104 > this.shiftKey = shiftKey;
105 > this.altKey = altKey;
106 > this.scanCode = scanCode;
107 > }
108 >
109 > public toString(): string {
110 > return `${this.ctrlKey ? 'Ctrl+' : ''}${this.shiftKey ? 'Shift+' : ''}${this.altKey ? 'Alt+' : ''}${ScanCodeUtils.toString(this.scanCode)}`; macLinuxKeyboardMapper.ts ×11
111 > }
113 > public equals(other: ScanCodeCombo): boolean {
115 > this.ctrlKey === other.ctrlKey
116 > && this.shiftKey === other.shiftKey
117 > && this.altKey === other.altKey
118 > && this.scanCode === other.scanCode
119 > );
120 > }
122 > private getProducedCharCode(mapping: IMacLinuxKeyMapping): string {
123 > if (!mapping) { macLinuxKeyboardMapper.ts ×11
124 > return '';
125 > }
126 > if (this.ctrlKey && this.shiftKey && this.altKey) {
127 > return mapping.withShiftAltGr;
128 > }
129 > if (this.ctrlKey && this.altKey) {
130 > return mapping.withAltGr;
131 > }
132 > if (this.shiftKey) {
133 > return mapping.withShift;
134 > }
135 > return mapping.value;
136 > }
138 > public getProducedChar(mapping: IMacLinuxKeyMapping): string {
139 > const charCode = MacLinuxKeyboardMapper.getCharCode(this.getProducedCharCode(mapping)); macLinuxKeyboardMapper.ts ×11
140 > if (charCode === 0) {
141 > return ' --- ';
142 > }
143 > if (charCode >= CharCode.U_Combining_Grave_Accent && charCode <= CharCode.U_Combining_Latin_Small_Letter_X) {
144 > // combining macLinuxKeyboardMapper.ts ×1
145 > return 'U+' + charCode.toString(16);
146 > }
147 > return ' ' + String.fromCharCode(charCode) + ' '; macLinuxKeyboardMapper.ts ×11
148 > }
150 >
151 > class KeyCodeCombo {
152 > public readonly ctrlKey: boolean;
153 > public readonly shiftKey: boolean;
154 > public readonly altKey: boolean;
155 > public readonly keyCode: KeyCode;
156 >
157 > constructor(ctrlKey: boolean, shiftKey: boolean, altKey: boolean, keyCode: KeyCode) {
158 > this.ctrlKey = ctrlKey;
159 > this.shiftKey = shiftKey;
160 > this.altKey = altKey;
161 > this.keyCode = keyCode;
162 > }
163 >
164 > public toString(): string {
165 > return `${this.ctrlKey ? 'Ctrl+' : ''}${this.shiftKey ? 'Shift+' : ''}${this.altKey ? 'Alt+' : ''}${KeyCodeUtils.toString(this.keyCode)}`; macLinuxKeyboardMapper.ts ×11
166 > }
168 >
169 > class ScanCodeKeyCodeMapper {
170 >
171 > /**
172 > * ScanCode combination => KeyCode combination.
173 > * Only covers relevant modifiers ctrl, shift, alt (since meta does not influence the mappings).
174 > */
175 > private readonly _scanCodeToKeyCode: number[][] = [];
176 > /**
177 > * inverse of `_scanCodeToKeyCode`.
178 > * KeyCode combination => ScanCode combination.
179 > * Only covers relevant modifiers ctrl, shift, alt (since meta does not influence the mappings).
180 > */
181 > private readonly _keyCodeToScanCode: number[][] = [];
182 >
183 > constructor() {
184 > this._scanCodeToKeyCode = [];
185 > this._keyCodeToScanCode = [];
186 > }
187 >
188 > public registrationComplete(): void {
189 > // IntlHash and IntlBackslash are rare keys, so ensure they don't end up being the preferred...
190 > this._moveToEnd(ScanCode.IntlHash);
191 > this._moveToEnd(ScanCode.IntlBackslash);
192 > }
193 >
194 > private _moveToEnd(scanCode: ScanCode): void {
195 > for (let mod = 0; mod < 8; mod++) {
196 > const encodedKeyCodeCombos = this._scanCodeToKeyCode[(scanCode << 3) + mod];
197 > if (!encodedKeyCodeCombos) {
198 > continue;
199 > }
200 > for (let i = 0, len = encodedKeyCodeCombos.length; i < len; i++) { macLinuxKeyboardMapper.ts ×2
201 > const encodedScanCodeCombos = this._keyCodeToScanCode[encodedKeyCodeCombos[i]];
202 > if (encodedScanCodeCombos.length === 1) {
204 > }
205 > for (let j = 0, len = encodedScanCodeCombos.length; j < len; j++) { macLinuxKeyboardMapper.ts ×2
206 > const entry = encodedScanCodeCombos[j];
207 > const entryScanCode = (entry >>> 3);
208 > if (entryScanCode === scanCode) {
209 > // Move this entry to the end
210 > for (let k = j + 1; k < len; k++) {
211 > encodedScanCodeCombos[k - 1] = encodedScanCodeCombos[k];
212 > }
213 > encodedScanCodeCombos[len - 1] = entry;
214 > }
215 > }
216 > }
217 > }
219 >
220 > public registerIfUnknown(scanCodeCombo: ScanCodeCombo, keyCodeCombo: KeyCodeCombo): void {
221 > if (keyCodeCombo.keyCode === KeyCode.Unknown) {
222 > return;
223 > }
224 > const scanCodeComboEncoded = this._encodeScanCodeCombo(scanCodeCombo);
225 > const keyCodeComboEncoded = this._encodeKeyCodeCombo(keyCodeCombo);
226 >
227 > const keyCodeIsDigit = (keyCodeCombo.keyCode >= KeyCode.Digit0 && keyCodeCombo.keyCode <= KeyCode.Digit9);
228 > const keyCodeIsLetter = (keyCodeCombo.keyCode >= KeyCode.KeyA && keyCodeCombo.keyCode <= KeyCode.KeyZ);
229 >
230 > const existingKeyCodeCombos = this._scanCodeToKeyCode[scanCodeComboEncoded];
231 >
232 > // Allow a scan code to map to multiple key codes if it is a digit or a letter key code
233 > if (keyCodeIsDigit || keyCodeIsLetter) {
234 > // Only check that we don't insert the same entry twice
235 > if (existingKeyCodeCombos) {
236 > for (let i = 0, len = existingKeyCodeCombos.length; i < len; i++) { macLinuxKeyboardMapper.ts ×11
237 > if (existingKeyCodeCombos[i] === keyCodeComboEncoded) {
238 > // avoid duplicates
239 > return;
240 > }
241 > }
244 > // Don't allow multiples
245 > if (existingKeyCodeCombos && existingKeyCodeCombos.length !== 0) {
247 > }
249 >
250 > this._scanCodeToKeyCode[scanCodeComboEncoded] = this._scanCodeToKeyCode[scanCodeComboEncoded] || [];
251 > this._scanCodeToKeyCode[scanCodeComboEncoded].unshift(keyCodeComboEncoded);
252 >
253 > this._keyCodeToScanCode[keyCodeComboEncoded] = this._keyCodeToScanCode[keyCodeComboEncoded] || [];
254 > this._keyCodeToScanCode[keyCodeComboEncoded].unshift(scanCodeComboEncoded);
255 > }
256 >
257 > public lookupKeyCodeCombo(keyCodeCombo: KeyCodeCombo): ScanCodeCombo[] {
258 > const keyCodeComboEncoded = this._encodeKeyCodeCombo(keyCodeCombo); macLinuxKeyboardMapper.ts ×4
259 > const scanCodeCombosEncoded = this._keyCodeToScanCode[keyCodeComboEncoded];
260 > if (!scanCodeCombosEncoded || scanCodeCombosEncoded.length === 0) {
262 > }
264 > const result: ScanCodeCombo[] = [];
265 > for (let i = 0, len = scanCodeCombosEncoded.length; i < len; i++) {
266 > const scanCodeComboEncoded = scanCodeCombosEncoded[i];
267 >
268 > const ctrlKey = (scanCodeComboEncoded & 0b001) ? true : false;
269 > const shiftKey = (scanCodeComboEncoded & 0b010) ? true : false;
270 > const altKey = (scanCodeComboEncoded & 0b100) ? true : false;
271 > const scanCode: ScanCode = (scanCodeComboEncoded >>> 3);
272 >
273 > result[i] = new ScanCodeCombo(ctrlKey, shiftKey, altKey, scanCode);
274 > }
275 > return result;
278 > public lookupScanCodeCombo(scanCodeCombo: ScanCodeCombo): KeyCodeCombo[] {
279 > const scanCodeComboEncoded = this._encodeScanCodeCombo(scanCodeCombo); macLinuxKeyboardMapper.ts ×3
280 > const keyCodeCombosEncoded = this._scanCodeToKeyCode[scanCodeComboEncoded];
281 > if (!keyCodeCombosEncoded || keyCodeCombosEncoded.length === 0) {
283 > }
285 > const result: KeyCodeCombo[] = [];
286 > for (let i = 0, len = keyCodeCombosEncoded.length; i < len; i++) {
287 > const keyCodeComboEncoded = keyCodeCombosEncoded[i];
288 >
289 > const ctrlKey = (keyCodeComboEncoded & 0b001) ? true : false;
290 > const shiftKey = (keyCodeComboEncoded & 0b010) ? true : false;
291 > const altKey = (keyCodeComboEncoded & 0b100) ? true : false;
292 > const keyCode: KeyCode = (keyCodeComboEncoded >>> 3);
293 >
294 > result[i] = new KeyCodeCombo(ctrlKey, shiftKey, altKey, keyCode);
295 > }
296 > return result;
299 > public guessStableKeyCode(scanCode: ScanCode): KeyCode {
300 > if (scanCode >= ScanCode.Digit1 && scanCode <= ScanCode.Digit0) { macLinuxKeyboardMapper.ts ×6
301 > // digits are ok macLinuxKeyboardMapper.ts ×1
302 > switch (scanCode) {
303 > case ScanCode.Digit1: return KeyCode.Digit1;
304 > case ScanCode.Digit2: return KeyCode.Digit2;
305 > case ScanCode.Digit3: return KeyCode.Digit3;
306 > case ScanCode.Digit4: return KeyCode.Digit4;
307 > case ScanCode.Digit5: return KeyCode.Digit5;
308 > case ScanCode.Digit6: return KeyCode.Digit6;
309 > case ScanCode.Digit7: return KeyCode.Digit7;
310 > case ScanCode.Digit8: return KeyCode.Digit8;
311 > case ScanCode.Digit9: return KeyCode.Digit9;
312 > case ScanCode.Digit0: return KeyCode.Digit0;
313 > }
314 > }
316 > // Lookup the scanCode with and without shift and see if the keyCode is stable
317 > const keyCodeCombos1 = this.lookupScanCodeCombo(new ScanCodeCombo(false, false, false, scanCode));
318 > const keyCodeCombos2 = this.lookupScanCodeCombo(new ScanCodeCombo(false, true, false, scanCode));
319 > if (keyCodeCombos1.length === 1 && keyCodeCombos2.length === 1) { macLinuxKeyboardMapper.ts ×6
320 > const shiftKey1 = keyCodeCombos1[0].shiftKey; macLinuxKeyboardMapper.ts ×3
321 > const keyCode1 = keyCodeCombos1[0].keyCode;
322 > const shiftKey2 = keyCodeCombos2[0].shiftKey;
323 > const keyCode2 = keyCodeCombos2[0].keyCode;
324 > if (keyCode1 === keyCode2 && shiftKey1 !== shiftKey2) {
325 > // This looks like a stable mapping macLinuxKeyboardMapper.ts ×1
326 > return keyCode1;
327 > }
330 > return KeyCode.DependsOnKbLayout;
333 > private _encodeScanCodeCombo(scanCodeCombo: ScanCodeCombo): number {
334 > return this._encode(scanCodeCombo.ctrlKey, scanCodeCombo.shiftKey, scanCodeCombo.altKey, scanCodeCombo.scanCode);
335 > }
336 >
337 > private _encodeKeyCodeCombo(keyCodeCombo: KeyCodeCombo): number {
338 > return this._encode(keyCodeCombo.ctrlKey, keyCodeCombo.shiftKey, keyCodeCombo.altKey, keyCodeCombo.keyCode);
339 > }
340 >
341 > private _encode(ctrlKey: boolean, shiftKey: boolean, altKey: boolean, principal: number): number {
342 > return (
343 > ((ctrlKey ? 1 : 0) << 0)
344 > | ((shiftKey ? 1 : 0) << 1)
345 > | ((altKey ? 1 : 0) << 2)
346 > | principal << 3
347 > ) >>> 0;
348 > }
349 > }
350 >
351 > export class MacLinuxKeyboardMapper implements IKeyboardMapper {
352 >
353 > /**
354 > * used only for debug purposes.
355 > */
356 > private readonly _codeInfo: IMacLinuxKeyMapping[];
357 > /**
358 > * Maps ScanCode combos <-> KeyCode combos.
359 > */
360 > private readonly _scanCodeKeyCodeMapper: ScanCodeKeyCodeMapper;
361 > /**
362 > * UI label for a ScanCode.
363 > */
364 > private readonly _scanCodeToLabel: Array<string | null> = [];
365 > /**
366 > * Dispatching string for a ScanCode.
367 > */
368 > private readonly _scanCodeToDispatch: Array<string | null> = [];
369 >
370 > constructor(
371 > private readonly _isUSStandard: boolean,
372 > rawMappings: IMacLinuxKeyboardMapping,
373 > private readonly _mapAltGrToCtrlAlt: boolean,
374 > private readonly _OS: OperatingSystem,
375 > ) {
376 > this._codeInfo = [];
377 > this._scanCodeKeyCodeMapper = new ScanCodeKeyCodeMapper();
378 > this._scanCodeToLabel = [];
379 > this._scanCodeToDispatch = [];
380 >
381 > const _registerIfUnknown = (
382 > hwCtrlKey: 0 | 1, hwShiftKey: 0 | 1, hwAltKey: 0 | 1, scanCode: ScanCode,
383 > kbCtrlKey: 0 | 1, kbShiftKey: 0 | 1, kbAltKey: 0 | 1, keyCode: KeyCode,
384 > ): void => {
385 > this._scanCodeKeyCodeMapper.registerIfUnknown(
386 > new ScanCodeCombo(hwCtrlKey ? true : false, hwShiftKey ? true : false, hwAltKey ? true : false, scanCode),
387 > new KeyCodeCombo(kbCtrlKey ? true : false, kbShiftKey ? true : false, kbAltKey ? true : false, keyCode)
388 > );
389 > };
390 >
391 > const _registerAllCombos = (_ctrlKey: 0 | 1, _shiftKey: 0 | 1, _altKey: 0 | 1, scanCode: ScanCode, keyCode: KeyCode): void => {
392 > for (let ctrlKey = _ctrlKey; ctrlKey <= 1; ctrlKey++) {
393 > for (let shiftKey = _shiftKey; shiftKey <= 1; shiftKey++) {
394 > for (let altKey = _altKey; altKey <= 1; altKey++) {
395 > _registerIfUnknown(
396 > ctrlKey, shiftKey, altKey, scanCode,
397 > ctrlKey, shiftKey, altKey, keyCode
398 > );
399 > }
400 > }
401 > }
402 > };
403 >
404 > // Initialize `_scanCodeToLabel`
405 > for (let scanCode = ScanCode.None; scanCode < ScanCode.MAX_VALUE; scanCode++) {
406 > this._scanCodeToLabel[scanCode] = null;
407 > }
408 >
409 > // Initialize `_scanCodeToDispatch`
410 > for (let scanCode = ScanCode.None; scanCode < ScanCode.MAX_VALUE; scanCode++) {
411 > this._scanCodeToDispatch[scanCode] = null;
412 > }
413 >
414 > // Handle immutable mappings
415 > for (let scanCode = ScanCode.None; scanCode < ScanCode.MAX_VALUE; scanCode++) {
416 > const keyCode = IMMUTABLE_CODE_TO_KEY_CODE[scanCode];
417 > if (keyCode !== KeyCode.DependsOnKbLayout) {
418 > _registerAllCombos(0, 0, 0, scanCode, keyCode);
419 > this._scanCodeToLabel[scanCode] = KeyCodeUtils.toString(keyCode);
420 >
421 > if (keyCode === KeyCode.Unknown || isModifierKey(keyCode)) {
422 > this._scanCodeToDispatch[scanCode] = null; // cannot dispatch on this ScanCode
423 > } else {
424 > this._scanCodeToDispatch[scanCode] = `[${ScanCodeUtils.toString(scanCode)}]`;
425 > }
426 > }
427 > }
428 >
429 > // Try to identify keyboard layouts where characters A-Z are missing
430 > // and forcibly map them to their corresponding scan codes if that is the case
431 > const missingLatinLettersOverride: { [scanCode: string]: IMacLinuxKeyMapping } = {};
432 >
433 > {
434 > const producesLatinLetter: boolean[] = [];
435 > for (const strScanCode in rawMappings) {
436 > if (rawMappings.hasOwnProperty(strScanCode)) { macLinuxKeyboardMapper.ts ×26
437 > const scanCode = ScanCodeUtils.toEnum(strScanCode);
438 > if (scanCode === ScanCode.None) {
439 continue;
440 }
441 > if (IMMUTABLE_CODE_TO_KEY_CODE[scanCode] !== KeyCode.DependsOnKbLayout) { macLinuxKeyboardMapper.ts ×26
443 > }
445 > const rawMapping = rawMappings[strScanCode];
446 > const value = MacLinuxKeyboardMapper.getCharCode(rawMapping.value);
447 >
448 > if (value >= CharCode.a && value <= CharCode.z) {
449 > const upperCaseValue = CharCode.A + (value - CharCode.a); macLinuxKeyboardMapper.ts ×1
450 > producesLatinLetter[upperCaseValue] = true;
451 > }
453 > }
455 > const _registerLetterIfMissing = (charCode: CharCode, scanCode: ScanCode, value: string, withShift: string): void => {
456 > if (!producesLatinLetter[charCode]) {
457 > missingLatinLettersOverride[ScanCodeUtils.toString(scanCode)] = { macLinuxKeyboardMapper.ts ×1
458 > value: value,
459 > withShift: withShift,
460 > withAltGr: '',
461 > withShiftAltGr: ''
462 > };
463 > }
465 >
466 > // Ensure letters are mapped
467 > _registerLetterIfMissing(CharCode.A, ScanCode.KeyA, 'a', 'A');
468 > _registerLetterIfMissing(CharCode.B, ScanCode.KeyB, 'b', 'B');
469 > _registerLetterIfMissing(CharCode.C, ScanCode.KeyC, 'c', 'C');
470 > _registerLetterIfMissing(CharCode.D, ScanCode.KeyD, 'd', 'D');
471 > _registerLetterIfMissing(CharCode.E, ScanCode.KeyE, 'e', 'E');
472 > _registerLetterIfMissing(CharCode.F, ScanCode.KeyF, 'f', 'F');
473 > _registerLetterIfMissing(CharCode.G, ScanCode.KeyG, 'g', 'G');
474 > _registerLetterIfMissing(CharCode.H, ScanCode.KeyH, 'h', 'H');
475 > _registerLetterIfMissing(CharCode.I, ScanCode.KeyI, 'i', 'I');
476 > _registerLetterIfMissing(CharCode.J, ScanCode.KeyJ, 'j', 'J');
477 > _registerLetterIfMissing(CharCode.K, ScanCode.KeyK, 'k', 'K');
478 > _registerLetterIfMissing(CharCode.L, ScanCode.KeyL, 'l', 'L');
479 > _registerLetterIfMissing(CharCode.M, ScanCode.KeyM, 'm', 'M');
480 > _registerLetterIfMissing(CharCode.N, ScanCode.KeyN, 'n', 'N');
481 > _registerLetterIfMissing(CharCode.O, ScanCode.KeyO, 'o', 'O');
482 > _registerLetterIfMissing(CharCode.P, ScanCode.KeyP, 'p', 'P');
483 > _registerLetterIfMissing(CharCode.Q, ScanCode.KeyQ, 'q', 'Q');
484 > _registerLetterIfMissing(CharCode.R, ScanCode.KeyR, 'r', 'R');
485 > _registerLetterIfMissing(CharCode.S, ScanCode.KeyS, 's', 'S');
486 > _registerLetterIfMissing(CharCode.T, ScanCode.KeyT, 't', 'T');
487 > _registerLetterIfMissing(CharCode.U, ScanCode.KeyU, 'u', 'U');
488 > _registerLetterIfMissing(CharCode.V, ScanCode.KeyV, 'v', 'V');
489 > _registerLetterIfMissing(CharCode.W, ScanCode.KeyW, 'w', 'W');
490 > _registerLetterIfMissing(CharCode.X, ScanCode.KeyX, 'x', 'X');
491 > _registerLetterIfMissing(CharCode.Y, ScanCode.KeyY, 'y', 'Y');
492 > _registerLetterIfMissing(CharCode.Z, ScanCode.KeyZ, 'z', 'Z');
493 > }
494 >
495 > const mappings: IScanCodeMapping[] = [];
496 > let mappingsLen = 0;
497 > for (const strScanCode in rawMappings) {
498 > if (rawMappings.hasOwnProperty(strScanCode)) { macLinuxKeyboardMapper.ts ×26
499 > const scanCode = ScanCodeUtils.toEnum(strScanCode);
500 > if (scanCode === ScanCode.None) {
501 continue;
502 }
503 > if (IMMUTABLE_CODE_TO_KEY_CODE[scanCode] !== KeyCode.DependsOnKbLayout) { macLinuxKeyboardMapper.ts ×26
505 > }
507 > this._codeInfo[scanCode] = rawMappings[strScanCode];
508 >
509 > const rawMapping = missingLatinLettersOverride[strScanCode] || rawMappings[strScanCode];
510 > const value = MacLinuxKeyboardMapper.getCharCode(rawMapping.value);
511 > const withShift = MacLinuxKeyboardMapper.getCharCode(rawMapping.withShift);
512 > const withAltGr = MacLinuxKeyboardMapper.getCharCode(rawMapping.withAltGr);
513 > const withShiftAltGr = MacLinuxKeyboardMapper.getCharCode(rawMapping.withShiftAltGr);
514 >
515 > const mapping: IScanCodeMapping = {
516 > scanCode: scanCode,
517 > value: value,
518 > withShift: withShift,
519 > withAltGr: withAltGr,
520 > withShiftAltGr: withShiftAltGr,
521 > };
522 > mappings[mappingsLen++] = mapping;
523 >
524 > this._scanCodeToDispatch[scanCode] = `[${ScanCodeUtils.toString(scanCode)}]`;
525 >
526 > if (value >= CharCode.a && value <= CharCode.z) {
527 > const upperCaseValue = CharCode.A + (value - CharCode.a); macLinuxKeyboardMapper.ts ×11
528 > this._scanCodeToLabel[scanCode] = String.fromCharCode(upperCaseValue);
529 > } else if (value >= CharCode.A && value <= CharCode.Z) { macLinuxKeyboardMapper.ts ×26
530 this._scanCodeToLabel[scanCode] = String.fromCharCode(value);
531 > } else if (value) { macLinuxKeyboardMapper.ts ×26
532 > this._scanCodeToLabel[scanCode] = String.fromCharCode(value);
533 > } else {
534 > this._scanCodeToLabel[scanCode] = null; macLinuxKeyboardMapper.ts ×11
535 > }
537 > }
539 > // Handle all `withShiftAltGr` entries
540 > for (let i = mappings.length - 1; i >= 0; i--) {
541 > const mapping = mappings[i]; macLinuxKeyboardMapper.ts ×26
542 > const scanCode = mapping.scanCode;
543 > const withShiftAltGr = mapping.withShiftAltGr;
544 > if (withShiftAltGr === mapping.withAltGr || withShiftAltGr === mapping.withShift || withShiftAltGr === mapping.value) {
545 > // handled below
546 > continue;
547 > }
548 > const kb = MacLinuxKeyboardMapper._charCodeToKb(withShiftAltGr); macLinuxKeyboardMapper.ts ×11
549 > if (!kb) {
551 > }
552 > const kbShiftKey = kb.shiftKey; macLinuxKeyboardMapper.ts ×3
553 > const keyCode = kb.keyCode;
554 >
555 > if (kbShiftKey) {
556 > // Ctrl+Shift+Alt+ScanCode => Shift+KeyCode macLinuxKeyboardMapper.ts ×1
557 > _registerIfUnknown(1, 1, 1, scanCode, 0, 1, 0, keyCode); // Ctrl+Alt+ScanCode => Shift+KeyCode
559 > // Ctrl+Shift+Alt+ScanCode => KeyCode macLinuxKeyboardMapper.ts ×1
560 > _registerIfUnknown(1, 1, 1, scanCode, 0, 0, 0, keyCode); // Ctrl+Alt+ScanCode => KeyCode
561 > }
563 > // Handle all `withAltGr` entries macLinuxKeyboardMapper.ts ×43
564 > for (let i = mappings.length - 1; i >= 0; i--) {
565 > const mapping = mappings[i]; macLinuxKeyboardMapper.ts ×26
566 > const scanCode = mapping.scanCode;
567 > const withAltGr = mapping.withAltGr;
568 > if (withAltGr === mapping.withShift || withAltGr === mapping.value) {
569 > // handled below macLinuxKeyboardMapper.ts ×11
570 > continue;
571 > }
572 > const kb = MacLinuxKeyboardMapper._charCodeToKb(withAltGr); macLinuxKeyboardMapper.ts ×26
573 > if (!kb) {
575 > }
576 > const kbShiftKey = kb.shiftKey; macLinuxKeyboardMapper.ts ×2
577 > const keyCode = kb.keyCode;
578 >
579 > if (kbShiftKey) {
580 > // Ctrl+Alt+ScanCode => Shift+KeyCode macLinuxKeyboardMapper.ts ×1
581 > _registerIfUnknown(1, 0, 1, scanCode, 0, 1, 0, keyCode); // Ctrl+Alt+ScanCode => Shift+KeyCode
583 > // Ctrl+Alt+ScanCode => KeyCode macLinuxKeyboardMapper.ts ×3
584 > _registerIfUnknown(1, 0, 1, scanCode, 0, 0, 0, keyCode); // Ctrl+Alt+ScanCode => KeyCode
585 > }
587 > // Handle all `withShift` entries macLinuxKeyboardMapper.ts ×43
588 > for (let i = mappings.length - 1; i >= 0; i--) {
589 > const mapping = mappings[i]; macLinuxKeyboardMapper.ts ×26
590 > const scanCode = mapping.scanCode;
591 > const withShift = mapping.withShift;
592 > if (withShift === mapping.value) {
593 > // handled below macLinuxKeyboardMapper.ts ×11
594 > continue;
595 > }
596 > const kb = MacLinuxKeyboardMapper._charCodeToKb(withShift); macLinuxKeyboardMapper.ts ×26
597 > if (!kb) {
598 > continue;
599 > }
600 > const kbShiftKey = kb.shiftKey; macLinuxKeyboardMapper.ts ×11
601 > const keyCode = kb.keyCode;
602 >
603 > if (kbShiftKey) {
604 > // Shift+ScanCode => Shift+KeyCode
605 > _registerIfUnknown(0, 1, 0, scanCode, 0, 1, 0, keyCode); // Shift+ScanCode => Shift+KeyCode
606 > _registerIfUnknown(0, 1, 1, scanCode, 0, 1, 1, keyCode); // Shift+Alt+ScanCode => Shift+Alt+KeyCode
607 > _registerIfUnknown(1, 1, 0, scanCode, 1, 1, 0, keyCode); // Ctrl+Shift+ScanCode => Ctrl+Shift+KeyCode
608 > _registerIfUnknown(1, 1, 1, scanCode, 1, 1, 1, keyCode); // Ctrl+Shift+Alt+ScanCode => Ctrl+Shift+Alt+KeyCode
609 > } else {
610 > // Shift+ScanCode => KeyCode macLinuxKeyboardMapper.ts ×1
611 > _registerIfUnknown(0, 1, 0, scanCode, 0, 0, 0, keyCode); // Shift+ScanCode => KeyCode
612 > _registerIfUnknown(0, 1, 0, scanCode, 0, 1, 0, keyCode); // Shift+ScanCode => Shift+KeyCode
613 > _registerIfUnknown(0, 1, 1, scanCode, 0, 0, 1, keyCode); // Shift+Alt+ScanCode => Alt+KeyCode
614 > _registerIfUnknown(0, 1, 1, scanCode, 0, 1, 1, keyCode); // Shift+Alt+ScanCode => Shift+Alt+KeyCode
615 > _registerIfUnknown(1, 1, 0, scanCode, 1, 0, 0, keyCode); // Ctrl+Shift+ScanCode => Ctrl+KeyCode
616 > _registerIfUnknown(1, 1, 0, scanCode, 1, 1, 0, keyCode); // Ctrl+Shift+ScanCode => Ctrl+Shift+KeyCode
617 > _registerIfUnknown(1, 1, 1, scanCode, 1, 0, 1, keyCode); // Ctrl+Shift+Alt+ScanCode => Ctrl+Alt+KeyCode
618 > _registerIfUnknown(1, 1, 1, scanCode, 1, 1, 1, keyCode); // Ctrl+Shift+Alt+ScanCode => Ctrl+Shift+Alt+KeyCode
619 > }
621 > // Handle all `value` entries macLinuxKeyboardMapper.ts ×43
622 > for (let i = mappings.length - 1; i >= 0; i--) {
623 > const mapping = mappings[i]; macLinuxKeyboardMapper.ts ×26
624 > const scanCode = mapping.scanCode;
625 > const kb = MacLinuxKeyboardMapper._charCodeToKb(mapping.value);
626 > if (!kb) {
628 > }
629 > const kbShiftKey = kb.shiftKey; macLinuxKeyboardMapper.ts ×26
630 > const keyCode = kb.keyCode;
631 >
632 > if (kbShiftKey) {
633 > // ScanCode => Shift+KeyCode macLinuxKeyboardMapper.ts ×1
634 > _registerIfUnknown(0, 0, 0, scanCode, 0, 1, 0, keyCode); // ScanCode => Shift+KeyCode
635 > _registerIfUnknown(0, 0, 1, scanCode, 0, 1, 1, keyCode); // Alt+ScanCode => Shift+Alt+KeyCode
636 > _registerIfUnknown(1, 0, 0, scanCode, 1, 1, 0, keyCode); // Ctrl+ScanCode => Ctrl+Shift+KeyCode
637 > _registerIfUnknown(1, 0, 1, scanCode, 1, 1, 1, keyCode); // Ctrl+Alt+ScanCode => Ctrl+Shift+Alt+KeyCode
639 > // ScanCode => KeyCode
640 > _registerIfUnknown(0, 0, 0, scanCode, 0, 0, 0, keyCode); // ScanCode => KeyCode
641 > _registerIfUnknown(0, 0, 1, scanCode, 0, 0, 1, keyCode); // Alt+ScanCode => Alt+KeyCode
642 > _registerIfUnknown(0, 1, 0, scanCode, 0, 1, 0, keyCode); // Shift+ScanCode => Shift+KeyCode
643 > _registerIfUnknown(0, 1, 1, scanCode, 0, 1, 1, keyCode); // Shift+Alt+ScanCode => Shift+Alt+KeyCode
644 > _registerIfUnknown(1, 0, 0, scanCode, 1, 0, 0, keyCode); // Ctrl+ScanCode => Ctrl+KeyCode
645 > _registerIfUnknown(1, 0, 1, scanCode, 1, 0, 1, keyCode); // Ctrl+Alt+ScanCode => Ctrl+Alt+KeyCode
646 > _registerIfUnknown(1, 1, 0, scanCode, 1, 1, 0, keyCode); // Ctrl+Shift+ScanCode => Ctrl+Shift+KeyCode
647 > _registerIfUnknown(1, 1, 1, scanCode, 1, 1, 1, keyCode); // Ctrl+Shift+Alt+ScanCode => Ctrl+Shift+Alt+KeyCode
648 > }
649 > }
650 > // Handle all left-over available digits macLinuxKeyboardMapper.ts ×43
651 > _registerAllCombos(0, 0, 0, ScanCode.Digit1, KeyCode.Digit1);
652 > _registerAllCombos(0, 0, 0, ScanCode.Digit2, KeyCode.Digit2);
653 > _registerAllCombos(0, 0, 0, ScanCode.Digit3, KeyCode.Digit3);
654 > _registerAllCombos(0, 0, 0, ScanCode.Digit4, KeyCode.Digit4);
655 > _registerAllCombos(0, 0, 0, ScanCode.Digit5, KeyCode.Digit5);
656 > _registerAllCombos(0, 0, 0, ScanCode.Digit6, KeyCode.Digit6);
657 > _registerAllCombos(0, 0, 0, ScanCode.Digit7, KeyCode.Digit7);
658 > _registerAllCombos(0, 0, 0, ScanCode.Digit8, KeyCode.Digit8);
659 > _registerAllCombos(0, 0, 0, ScanCode.Digit9, KeyCode.Digit9);
660 > _registerAllCombos(0, 0, 0, ScanCode.Digit0, KeyCode.Digit0);
661 >
662 > this._scanCodeKeyCodeMapper.registrationComplete();
663 > }
664 >
665 > public dumpDebugInfo(): string {
666 > const result: string[] = []; macLinuxKeyboardMapper.ts ×11
667 >
668 > const immutableSamples = [
669 > ScanCode.ArrowUp,
670 > ScanCode.Numpad0
671 > ];
672 >
673 > let cnt = 0;
674 > result.push(`isUSStandard: ${this._isUSStandard}`);
675 > result.push(`----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------`);
676 > for (let scanCode = ScanCode.None; scanCode < ScanCode.MAX_VALUE; scanCode++) {
677 > if (IMMUTABLE_CODE_TO_KEY_CODE[scanCode] !== KeyCode.DependsOnKbLayout) {
678 > if (immutableSamples.indexOf(scanCode) === -1) {
679 > continue;
680 > }
681 > }
682 >
683 > if (cnt % 4 === 0) {
684 > result.push(`| HW Code combination | Key | KeyCode combination | Pri | UI label | User settings | Electron accelerator | Dispatching string | WYSIWYG |`);
685 > result.push(`----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------`);
686 > }
687 > cnt++;
688 >
689 > const mapping = this._codeInfo[scanCode];
690 >
691 > for (let mod = 0; mod < 8; mod++) {
692 > const hwCtrlKey = (mod & 0b001) ? true : false;
693 > const hwShiftKey = (mod & 0b010) ? true : false;
694 > const hwAltKey = (mod & 0b100) ? true : false;
695 > const scanCodeCombo = new ScanCodeCombo(hwCtrlKey, hwShiftKey, hwAltKey, scanCode);
696 > const resolvedKb = this.resolveKeyboardEvent({
697 > _standardKeyboardEventBrand: true,
698 > ctrlKey: scanCodeCombo.ctrlKey,
699 > shiftKey: scanCodeCombo.shiftKey,
700 > altKey: scanCodeCombo.altKey,
701 > metaKey: false,
702 > altGraphKey: false,
703 > keyCode: KeyCode.DependsOnKbLayout,
704 > code: ScanCodeUtils.toString(scanCode)
705 > });
706 >
707 > const outScanCodeCombo = scanCodeCombo.toString();
708 > const outKey = scanCodeCombo.getProducedChar(mapping);
709 > const ariaLabel = resolvedKb.getAriaLabel();
710 > const outUILabel = (ariaLabel ? ariaLabel.replace(/Control\+/, 'Ctrl+') : null);
711 > const outUserSettings = resolvedKb.getUserSettingsLabel();
712 > const outElectronAccelerator = resolvedKb.getElectronAccelerator();
713 > const outDispatchStr = resolvedKb.getDispatchChords()[0];
714 >
715 > const isWYSIWYG = (resolvedKb ? resolvedKb.isWYSIWYG() : false);
716 > const outWYSIWYG = (isWYSIWYG ? ' ' : ' NO ');
717 >
718 > const kbCombos = this._scanCodeKeyCodeMapper.lookupScanCodeCombo(scanCodeCombo);
719 > if (kbCombos.length === 0) {
720 > result.push(`| ${this._leftPad(outScanCodeCombo, 30)} | ${outKey} | ${this._leftPad('', 25)} | ${this._leftPad('', 3)} | ${this._leftPad(outUILabel, 25)} | ${this._leftPad(outUserSettings, 30)} | ${this._leftPad(outElectronAccelerator, 25)} | ${this._leftPad(outDispatchStr, 30)} | ${outWYSIWYG} |`);
721 > } else {
722 > for (let i = 0, len = kbCombos.length; i < len; i++) {
723 > const kbCombo = kbCombos[i];
724 > // find out the priority of this scan code for this key code
725 > let colPriority: string;
726 >
727 > const scanCodeCombos = this._scanCodeKeyCodeMapper.lookupKeyCodeCombo(kbCombo);
728 > if (scanCodeCombos.length === 1) {
729 > // no need for priority, this key code combo maps to precisely this scan code combo
730 > colPriority = '';
731 > } else {
732 > let priority = -1; macLinuxKeyboardMapper.ts ×2
733 > for (let j = 0; j < scanCodeCombos.length; j++) {
734 > if (scanCodeCombos[j].equals(scanCodeCombo)) {
735 > priority = j + 1;
736 > break;
737 > }
738 > }
739 > colPriority = String(priority);
740 > }
742 > const outKeybinding = kbCombo.toString();
743 > if (i === 0) {
744 > result.push(`| ${this._leftPad(outScanCodeCombo, 30)} | ${outKey} | ${this._leftPad(outKeybinding, 25)} | ${this._leftPad(colPriority, 3)} | ${this._leftPad(outUILabel, 25)} | ${this._leftPad(outUserSettings, 30)} | ${this._leftPad(outElectronAccelerator, 25)} | ${this._leftPad(outDispatchStr, 30)} | ${outWYSIWYG} |`);
745 > } else {
746 > // secondary keybindings macLinuxKeyboardMapper.ts ×1
747 > result.push(`| ${this._leftPad('', 30)} | | ${this._leftPad(outKeybinding, 25)} | ${this._leftPad(colPriority, 3)} | ${this._leftPad('', 25)} | ${this._leftPad('', 30)} | ${this._leftPad('', 25)} | ${this._leftPad('', 30)} | |`);
748 > }
750 > }
751 >
752 > }
753 > result.push(`----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------`);
754 > }
755 >
756 > return result.join('\n');
757 > }
759 > private _leftPad(str: string | null, cnt: number): string {
760 > if (str === null) { macLinuxKeyboardMapper.ts ×11
761 > str = 'null';
762 > }
763 > while (str.length < cnt) {
764 > str = ' ' + str;
765 > }
766 > return str;
767 > }
769 > public keyCodeChordToScanCodeChord(chord: KeyCodeChord): ScanCodeChord[] {
770 > // Avoid double Enter bindings (both ScanCode.NumpadEnter and ScanCode.Enter point to KeyCode.Enter) macLinuxKeyboardMapper.ts ×2
771 > if (chord.keyCode === KeyCode.Enter) {
772 > return [new ScanCodeChord(chord.ctrlKey, chord.shiftKey, chord.altKey, chord.metaKey, ScanCode.Enter)]; macLinuxKeyboardMapper.ts ×1
773 > }
775 > const scanCodeCombos = this._scanCodeKeyCodeMapper.lookupKeyCodeCombo(
776 > new KeyCodeCombo(chord.ctrlKey, chord.shiftKey, chord.altKey, chord.keyCode)
777 > );
778 >
779 > const result: ScanCodeChord[] = [];
780 > for (let i = 0, len = scanCodeCombos.length; i < len; i++) {
781 > const scanCodeCombo = scanCodeCombos[i]; macLinuxKeyboardMapper.ts ×2
782 > result[i] = new ScanCodeChord(scanCodeCombo.ctrlKey, scanCodeCombo.shiftKey, scanCodeCombo.altKey, chord.metaKey, scanCodeCombo.scanCode);
783 > }
784 > return result; macLinuxKeyboardMapper.ts ×4
787 > public getUILabelForScanCodeChord(chord: ScanCodeChord | null): string | null {
788 > if (!chord) { macLinuxKeyboardMapper.ts ×9
789 return null;
790 }
791 > if (chord.isDuplicateModifierCase()) { macLinuxKeyboardMapper.ts ×9
793 > }
794 > if (this._OS === OperatingSystem.Macintosh) { macLinuxKeyboardMapper.ts ×1
795 > switch (chord.scanCode) { macLinuxKeyboardMapper.ts ×5
796 > case ScanCode.ArrowLeft:
797 return '←';
798 > case ScanCode.ArrowUp: macLinuxKeyboardMapper.ts ×5
799 return '↑';
800 > case ScanCode.ArrowRight: macLinuxKeyboardMapper.ts ×5
801 return '→';
802 > case ScanCode.ArrowDown: macLinuxKeyboardMapper.ts ×5
803 > return '↓'; macLinuxKeyboardMapper.ts ×1
805 > }
806 > return this._scanCodeToLabel[chord.scanCode]; macLinuxKeyboardMapper.ts ×1
809 > public getAriaLabelForScanCodeChord(chord: ScanCodeChord | null): string | null {
810 > if (!chord) { macLinuxKeyboardMapper.ts ×17
811 return null;
812 }
813 > if (chord.isDuplicateModifierCase()) { macLinuxKeyboardMapper.ts ×17
815 > }
816 > return this._scanCodeToLabel[chord.scanCode]; macLinuxKeyboardMapper.ts ×7
819 > public getDispatchStrForScanCodeChord(chord: ScanCodeChord): string | null {
820 > const codeDispatch = this._scanCodeToDispatch[chord.scanCode]; macLinuxKeyboardMapper.ts ×17
821 > if (!codeDispatch) {
822 > return null; macLinuxKeyboardMapper.ts ×1
823 > }
824 > let result = ''; macLinuxKeyboardMapper.ts ×7
825 >
826 > if (chord.ctrlKey) {
827 > result += 'ctrl+'; macLinuxKeyboardMapper.ts ×1
828 > }
829 > if (chord.shiftKey) { macLinuxKeyboardMapper.ts ×7
830 > result += 'shift+'; macLinuxKeyboardMapper.ts ×1
831 > }
832 > if (chord.altKey) { macLinuxKeyboardMapper.ts ×7
833 > result += 'alt+'; macLinuxKeyboardMapper.ts ×1
834 > }
835 > if (chord.metaKey) { macLinuxKeyboardMapper.ts ×7
836 > result += 'meta+'; macLinuxKeyboardMapper.ts ×1
837 > }
838 > result += codeDispatch; macLinuxKeyboardMapper.ts ×7
839 >
840 > return result;
843 > public getUserSettingsLabelForScanCodeChord(chord: ScanCodeChord | null): string | null {
844 > if (!chord) { macLinuxKeyboardMapper.ts ×17
845 return null;
846 }
847 > if (chord.isDuplicateModifierCase()) { macLinuxKeyboardMapper.ts ×17
849 > }
851 > const immutableKeyCode = IMMUTABLE_CODE_TO_KEY_CODE[chord.scanCode];
852 > if (immutableKeyCode !== KeyCode.DependsOnKbLayout) {
853 > return KeyCodeUtils.toUserSettingsUS(immutableKeyCode).toLowerCase(); macLinuxKeyboardMapper.ts ×2
854 > }
856 > // Check if this scanCode always maps to the same keyCode and back
857 > const constantKeyCode: KeyCode = this._scanCodeKeyCodeMapper.guessStableKeyCode(chord.scanCode);
858 > if (constantKeyCode !== KeyCode.DependsOnKbLayout) {
859 > // Verify that this is a good key code that can be mapped back to the same scan code macLinuxKeyboardMapper.ts ×1
860 > const reverseChords = this.keyCodeChordToScanCodeChord(new KeyCodeChord(chord.ctrlKey, chord.shiftKey, chord.altKey, chord.metaKey, constantKeyCode));
861 > for (let i = 0, len = reverseChords.length; i < len; i++) {
862 > const reverseChord = reverseChords[i]; macLinuxKeyboardMapper.ts ×1
863 > if (reverseChord.scanCode === chord.scanCode) {
864 > return KeyCodeUtils.toUserSettingsUS(constantKeyCode).toLowerCase();
865 > }
866 > }
869 > return this._scanCodeToDispatch[chord.scanCode];
872 > public getElectronAcceleratorLabelForScanCodeChord(chord: ScanCodeChord | null): string | null {
873 > if (!chord) { macLinuxKeyboardMapper.ts ×5
874 return null;
875 }
877 > const immutableKeyCode = IMMUTABLE_CODE_TO_KEY_CODE[chord.scanCode];
878 > if (immutableKeyCode !== KeyCode.DependsOnKbLayout) {
879 > return KeyCodeUtils.toElectronAccelerator(immutableKeyCode); macLinuxKeyboardMapper.ts ×2
880 > }
882 > // Check if this scanCode always maps to the same keyCode and back
883 > const constantKeyCode: KeyCode = this._scanCodeKeyCodeMapper.guessStableKeyCode(chord.scanCode);
884 >
885 > if (this._OS === OperatingSystem.Linux && !this._isUSStandard) { macLinuxKeyboardMapper.ts ×5
886 > // [Electron Accelerators] On Linux, Electron does not handle correctly OEM keys. macLinuxKeyboardMapper.ts ×3
887 > // when using a different keyboard layout than US Standard.
888 > // See https://github.com/microsoft/vscode/issues/23706
889 > // See https://github.com/microsoft/vscode/pull/134890#issuecomment-941671791
890 > const isOEMKey = (
891 > constantKeyCode === KeyCode.Semicolon
892 > || constantKeyCode === KeyCode.Equal
893 > || constantKeyCode === KeyCode.Comma
894 > || constantKeyCode === KeyCode.Minus
895 > || constantKeyCode === KeyCode.Period macLinuxKeyboardMapper.ts ×1
896 > || constantKeyCode === KeyCode.Slash
897 > || constantKeyCode === KeyCode.Backquote
898 > || constantKeyCode === KeyCode.BracketLeft macLinuxKeyboardMapper.ts ×1
899 > || constantKeyCode === KeyCode.Backslash
900 > || constantKeyCode === KeyCode.BracketRight
902 >
903 > if (isOEMKey) {
904 > return null; macLinuxKeyboardMapper.ts ×1
905 > }
908 > if (constantKeyCode !== KeyCode.DependsOnKbLayout) {
909 > return KeyCodeUtils.toElectronAccelerator(constantKeyCode); macLinuxKeyboardMapper.ts ×1
910 > }
912 > return null;
915 > private _toResolvedKeybinding(chordParts: ScanCodeChord[][]): NativeResolvedKeybinding[] {
916 > if (chordParts.length === 0) { macLinuxKeyboardMapper.ts ×8
917 return [];
918 }
919 > const result: NativeResolvedKeybinding[] = []; macLinuxKeyboardMapper.ts ×8
920 > this._generateResolvedKeybindings(chordParts, 0, [], result);
921 > return result;
922 > }
924 > private _generateResolvedKeybindings(chordParts: ScanCodeChord[][], currentIndex: number, previousParts: ScanCodeChord[], result: NativeResolvedKeybinding[]) {
925 > const chordPart = chordParts[currentIndex]; macLinuxKeyboardMapper.ts ×8
926 > const isFinalIndex = currentIndex === chordParts.length - 1;
927 > for (let i = 0, len = chordPart.length; i < len; i++) {
928 > const chords = [...previousParts, chordPart[i]]; macLinuxKeyboardMapper.ts ×3
929 > if (isFinalIndex) {
930 > result.push(new NativeResolvedKeybinding(this, this._OS, chords)); macLinuxKeyboardMapper.ts ×1
932 > this._generateResolvedKeybindings(chordParts, currentIndex + 1, chords, result); macLinuxKeyboardMapper.ts ×1
933 > }
937 > public resolveKeyboardEvent(keyboardEvent: IKeyboardEvent): NativeResolvedKeybinding {
938 > let code = ScanCodeUtils.toEnum(keyboardEvent.code); macLinuxKeyboardMapper.ts ×5
939 >
940 > // Treat NumpadEnter as Enter
941 > if (code === ScanCode.NumpadEnter) {
942 > code = ScanCode.Enter; macLinuxKeyboardMapper.ts ×1
943 > }
945 > const keyCode = keyboardEvent.keyCode;
946 >
947 > if (
948 > (keyCode === KeyCode.LeftArrow)
949 > || (keyCode === KeyCode.UpArrow)
950 > || (keyCode === KeyCode.RightArrow)
951 > || (keyCode === KeyCode.DownArrow)
952 > || (keyCode === KeyCode.Delete)
953 > || (keyCode === KeyCode.Insert)
954 > || (keyCode === KeyCode.Home)
955 > || (keyCode === KeyCode.End)
956 > || (keyCode === KeyCode.PageDown)
957 > || (keyCode === KeyCode.PageUp)
958 > || (keyCode === KeyCode.Backspace) macLinuxKeyboardMapper.ts ×4
960 > // "Dispatch" on keyCode for these key codes to workaround issues with remote desktoping software keyCodes.ts ×1
961 > // where the scan codes appear to be incorrect (see https://github.com/microsoft/vscode/issues/24107)
962 > const immutableScanCode = IMMUTABLE_KEY_CODE_TO_CODE[keyCode];
963 > if (immutableScanCode !== ScanCode.DependsOnKbLayout) {
964 > code = immutableScanCode;
965 > }
966 >
969 > if (
970 > (code === ScanCode.Numpad1)
971 > || (code === ScanCode.Numpad2)
972 > || (code === ScanCode.Numpad3)
973 > || (code === ScanCode.Numpad4)
974 > || (code === ScanCode.Numpad5)
975 > || (code === ScanCode.Numpad6) macLinuxKeyboardMapper.ts ×1
976 > || (code === ScanCode.Numpad7)
977 > || (code === ScanCode.Numpad8)
978 > || (code === ScanCode.Numpad9)
979 > || (code === ScanCode.Numpad0)
980 > || (code === ScanCode.NumpadDecimal)
982 > // "Dispatch" on keyCode for all numpad keys in order for NumLock to work correctly macLinuxKeyboardMapper.ts ×2
983 > if (keyCode >= 0) {
984 > const immutableScanCode = IMMUTABLE_KEY_CODE_TO_CODE[keyCode]; macLinuxKeyboardMapper.ts ×2
985 > if (immutableScanCode !== ScanCode.DependsOnKbLayout) {
986 code = immutableScanCode;
987 }
992 > const ctrlKey = keyboardEvent.ctrlKey || (this._mapAltGrToCtrlAlt && keyboardEvent.altGraphKey);
993 > const altKey = keyboardEvent.altKey || (this._mapAltGrToCtrlAlt && keyboardEvent.altGraphKey);
994 > const chord = new ScanCodeChord(ctrlKey, keyboardEvent.shiftKey, altKey, keyboardEvent.metaKey, code);
995 > return new NativeResolvedKeybinding(this, this._OS, [chord]);
996 > }
998 > private _resolveChord(chord: Chord | null): ScanCodeChord[] {
999 > if (!chord) { macLinuxKeyboardMapper.ts ×8
1000 return [];
1001 }
1002 > if (chord instanceof ScanCodeChord) { macLinuxKeyboardMapper.ts ×8
1003 > return [chord]; macLinuxKeyboardMapper.ts ×1
1004 > }
1005 > return this.keyCodeChordToScanCodeChord(chord); macLinuxKeyboardMapper.ts ×1
1008 > public resolveKeybinding(keybinding: Keybinding): ResolvedKeybinding[] {
1009 > const chords: ScanCodeChord[][] = keybinding.chords.map(chord => this._resolveChord(chord)); macLinuxKeyboardMapper.ts ×8
1010 > return this._toResolvedKeybinding(chords);
1011 > }
1013 > private static _redirectCharCode(charCode: number): number {
1014 > switch (charCode) { macLinuxKeyboardMapper.ts ×26
1015 > // allow-any-unicode-next-line
1016 > // CJK: 。 「 」 【 】 ; ,
1017 > // map: . [ ] [ ] ; ,
1018 > case CharCode.U_IDEOGRAPHIC_FULL_STOP: return CharCode.Period;
1019 > case CharCode.U_LEFT_CORNER_BRACKET: return CharCode.OpenSquareBracket;
1020 > case CharCode.U_RIGHT_CORNER_BRACKET: return CharCode.CloseSquareBracket;
1021 > case CharCode.U_LEFT_BLACK_LENTICULAR_BRACKET: return CharCode.OpenSquareBracket;
1022 > case CharCode.U_RIGHT_BLACK_LENTICULAR_BRACKET: return CharCode.CloseSquareBracket;
1023 > case CharCode.U_FULLWIDTH_SEMICOLON: return CharCode.Semicolon;
1024 > case CharCode.U_FULLWIDTH_COMMA: return CharCode.Comma;
1025 > }
1026 > return charCode;
1027 > }
1029 > private static _charCodeToKb(charCode: number): { keyCode: KeyCode; shiftKey: boolean } | null {
1030 > charCode = this._redirectCharCode(charCode); macLinuxKeyboardMapper.ts ×26
1031 > if (charCode < CHAR_CODE_TO_KEY_CODE.length) {
1032 > return CHAR_CODE_TO_KEY_CODE[charCode];
1033 > }
1034 > return null;
1035 > }
1037 > /**
1038 > * Attempt to map a combining character to a regular one that renders the same way.
1039 > *
1040 > * https://www.compart.com/en/unicode/bidiclass/NSM
1041 > */
1042 > public static getCharCode(char: string): number {
1043 > if (char.length === 0) { macLinuxKeyboardMapper.ts ×26
1045 > }
1046 > const charCode = char.charCodeAt(0); macLinuxKeyboardMapper.ts ×26
1047 > switch (charCode) {
1048 > case CharCode.U_Combining_Grave_Accent: return CharCode.U_GRAVE_ACCENT;
1049 > case CharCode.U_Combining_Acute_Accent: return CharCode.U_ACUTE_ACCENT;
1050 > case CharCode.U_Combining_Circumflex_Accent: return CharCode.U_CIRCUMFLEX;
1051 > case CharCode.U_Combining_Tilde: return CharCode.U_SMALL_TILDE;
1052 > case CharCode.U_Combining_Macron: return CharCode.U_MACRON;
1053 > case CharCode.U_Combining_Overline: return CharCode.U_OVERLINE;
1054 > case CharCode.U_Combining_Breve: return CharCode.U_BREVE;
1055 > case CharCode.U_Combining_Dot_Above: return CharCode.U_DOT_ABOVE;
1056 > case CharCode.U_Combining_Diaeresis: return CharCode.U_DIAERESIS;
1057 > case CharCode.U_Combining_Ring_Above: return CharCode.U_RING_ABOVE;
1058 > case CharCode.U_Combining_Double_Acute_Accent: return CharCode.U_DOUBLE_ACUTE_ACCENT;
1059 > }
1060 > return charCode;
1061 > }
1063 >
1064 > (function () {
1065 > function define(charCode: number, keyCode: KeyCode, shiftKey: boolean): void {
1066 > for (let i = CHAR_CODE_TO_KEY_CODE.length; i < charCode; i++) {
1067 > CHAR_CODE_TO_KEY_CODE[i] = null;
1068 > }
1069 > CHAR_CODE_TO_KEY_CODE[charCode] = { keyCode: keyCode, shiftKey: shiftKey };
1070 > }
1071 >
1072 > for (let chCode = CharCode.A; chCode <= CharCode.Z; chCode++) {
1073 > define(chCode, KeyCode.KeyA + (chCode - CharCode.A), true);
1074 > }
1075 >
1076 > for (let chCode = CharCode.a; chCode <= CharCode.z; chCode++) {
1077 > define(chCode, KeyCode.KeyA + (chCode - CharCode.a), false);
1078 > }
1079 >
1080 > define(CharCode.Semicolon, KeyCode.Semicolon, false);
1081 > define(CharCode.Colon, KeyCode.Semicolon, true);
1082 >
1083 > define(CharCode.Equals, KeyCode.Equal, false);
1084 > define(CharCode.Plus, KeyCode.Equal, true);
1085 >
1086 > define(CharCode.Comma, KeyCode.Comma, false);
1087 > define(CharCode.LessThan, KeyCode.Comma, true);
1088 >
1089 > define(CharCode.Dash, KeyCode.Minus, false);
1090 > define(CharCode.Underline, KeyCode.Minus, true);
1091 >
1092 > define(CharCode.Period, KeyCode.Period, false);
1093 > define(CharCode.GreaterThan, KeyCode.Period, true);
1094 >
1095 > define(CharCode.Slash, KeyCode.Slash, false);
1096 > define(CharCode.QuestionMark, KeyCode.Slash, true);
1097 >
1098 > define(CharCode.BackTick, KeyCode.Backquote, false);
1099 > define(CharCode.Tilde, KeyCode.Backquote, true);
1100 >
1101 > define(CharCode.OpenSquareBracket, KeyCode.BracketLeft, false);
1102 > define(CharCode.OpenCurlyBrace, KeyCode.BracketLeft, true);
1103 >
1104 > define(CharCode.Backslash, KeyCode.Backslash, false);
1105 > define(CharCode.Pipe, KeyCode.Backslash, true);
1106 >
1107 > define(CharCode.CloseSquareBracket, KeyCode.BracketRight, false);
1108 > define(CharCode.CloseCurlyBrace, KeyCode.BracketRight, true);
1109 >
1110 > define(CharCode.SingleQuote, KeyCode.Quote, false);
1111 > define(CharCode.DoubleQuote, KeyCode.Quote, true);
1112 > })();