constructor()

in src/vs/workbench/services/keybinding/common/macLinuxKeyboardMapper.ts [378:667]


	constructor(isUSStandard: boolean, rawMappings: IMacLinuxKeyboardMapping, OS: OperatingSystem) {
		this._isUSStandard = isUSStandard;
		this._OS = OS;
		this._codeInfo = [];
		this._scanCodeKeyCodeMapper = new ScanCodeKeyCodeMapper();
		this._scanCodeToLabel = [];
		this._scanCodeToDispatch = [];

		const _registerIfUnknown = (
			hwCtrlKey: 0 | 1, hwShiftKey: 0 | 1, hwAltKey: 0 | 1, scanCode: ScanCode,
			kbCtrlKey: 0 | 1, kbShiftKey: 0 | 1, kbAltKey: 0 | 1, keyCode: KeyCode,
		): void => {
			this._scanCodeKeyCodeMapper.registerIfUnknown(
				new ScanCodeCombo(hwCtrlKey ? true : false, hwShiftKey ? true : false, hwAltKey ? true : false, scanCode),
				new KeyCodeCombo(kbCtrlKey ? true : false, kbShiftKey ? true : false, kbAltKey ? true : false, keyCode)
			);
		};

		const _registerAllCombos = (_ctrlKey: 0 | 1, _shiftKey: 0 | 1, _altKey: 0 | 1, scanCode: ScanCode, keyCode: KeyCode): void => {
			for (let ctrlKey = _ctrlKey; ctrlKey <= 1; ctrlKey++) {
				for (let shiftKey = _shiftKey; shiftKey <= 1; shiftKey++) {
					for (let altKey = _altKey; altKey <= 1; altKey++) {
						_registerIfUnknown(
							ctrlKey, shiftKey, altKey, scanCode,
							ctrlKey, shiftKey, altKey, keyCode
						);
					}
				}
			}
		};

		// Initialize `_scanCodeToLabel`
		for (let scanCode = ScanCode.None; scanCode < ScanCode.MAX_VALUE; scanCode++) {
			this._scanCodeToLabel[scanCode] = null;
		}

		// Initialize `_scanCodeToDispatch`
		for (let scanCode = ScanCode.None; scanCode < ScanCode.MAX_VALUE; scanCode++) {
			this._scanCodeToDispatch[scanCode] = null;
		}

		// Handle immutable mappings
		for (let scanCode = ScanCode.None; scanCode < ScanCode.MAX_VALUE; scanCode++) {
			const keyCode = IMMUTABLE_CODE_TO_KEY_CODE[scanCode];
			if (keyCode !== KeyCode.DependsOnKbLayout) {
				_registerAllCombos(0, 0, 0, scanCode, keyCode);
				this._scanCodeToLabel[scanCode] = KeyCodeUtils.toString(keyCode);

				if (keyCode === KeyCode.Unknown || keyCode === KeyCode.Ctrl || keyCode === KeyCode.Meta || keyCode === KeyCode.Alt || keyCode === KeyCode.Shift) {
					this._scanCodeToDispatch[scanCode] = null; // cannot dispatch on this ScanCode
				} else {
					this._scanCodeToDispatch[scanCode] = `[${ScanCodeUtils.toString(scanCode)}]`;
				}
			}
		}

		// Try to identify keyboard layouts where characters A-Z are missing
		// and forcibly map them to their corresponding scan codes if that is the case
		const missingLatinLettersOverride: { [scanCode: string]: IMacLinuxKeyMapping; } = {};

		{
			let producesLatinLetter: boolean[] = [];
			for (let strScanCode in rawMappings) {
				if (rawMappings.hasOwnProperty(strScanCode)) {
					const scanCode = ScanCodeUtils.toEnum(strScanCode);
					if (scanCode === ScanCode.None) {
						continue;
					}
					if (IMMUTABLE_CODE_TO_KEY_CODE[scanCode] !== KeyCode.DependsOnKbLayout) {
						continue;
					}

					const rawMapping = rawMappings[strScanCode];
					const value = MacLinuxKeyboardMapper.getCharCode(rawMapping.value);

					if (value >= CharCode.a && value <= CharCode.z) {
						const upperCaseValue = CharCode.A + (value - CharCode.a);
						producesLatinLetter[upperCaseValue] = true;
					}
				}
			}

			const _registerLetterIfMissing = (charCode: CharCode, scanCode: ScanCode, value: string, withShift: string): void => {
				if (!producesLatinLetter[charCode]) {
					missingLatinLettersOverride[ScanCodeUtils.toString(scanCode)] = {
						value: value,
						withShift: withShift,
						withAltGr: '',
						withShiftAltGr: ''
					};
				}
			};

			// Ensure letters are mapped
			_registerLetterIfMissing(CharCode.A, ScanCode.KeyA, 'a', 'A');
			_registerLetterIfMissing(CharCode.B, ScanCode.KeyB, 'b', 'B');
			_registerLetterIfMissing(CharCode.C, ScanCode.KeyC, 'c', 'C');
			_registerLetterIfMissing(CharCode.D, ScanCode.KeyD, 'd', 'D');
			_registerLetterIfMissing(CharCode.E, ScanCode.KeyE, 'e', 'E');
			_registerLetterIfMissing(CharCode.F, ScanCode.KeyF, 'f', 'F');
			_registerLetterIfMissing(CharCode.G, ScanCode.KeyG, 'g', 'G');
			_registerLetterIfMissing(CharCode.H, ScanCode.KeyH, 'h', 'H');
			_registerLetterIfMissing(CharCode.I, ScanCode.KeyI, 'i', 'I');
			_registerLetterIfMissing(CharCode.J, ScanCode.KeyJ, 'j', 'J');
			_registerLetterIfMissing(CharCode.K, ScanCode.KeyK, 'k', 'K');
			_registerLetterIfMissing(CharCode.L, ScanCode.KeyL, 'l', 'L');
			_registerLetterIfMissing(CharCode.M, ScanCode.KeyM, 'm', 'M');
			_registerLetterIfMissing(CharCode.N, ScanCode.KeyN, 'n', 'N');
			_registerLetterIfMissing(CharCode.O, ScanCode.KeyO, 'o', 'O');
			_registerLetterIfMissing(CharCode.P, ScanCode.KeyP, 'p', 'P');
			_registerLetterIfMissing(CharCode.Q, ScanCode.KeyQ, 'q', 'Q');
			_registerLetterIfMissing(CharCode.R, ScanCode.KeyR, 'r', 'R');
			_registerLetterIfMissing(CharCode.S, ScanCode.KeyS, 's', 'S');
			_registerLetterIfMissing(CharCode.T, ScanCode.KeyT, 't', 'T');
			_registerLetterIfMissing(CharCode.U, ScanCode.KeyU, 'u', 'U');
			_registerLetterIfMissing(CharCode.V, ScanCode.KeyV, 'v', 'V');
			_registerLetterIfMissing(CharCode.W, ScanCode.KeyW, 'w', 'W');
			_registerLetterIfMissing(CharCode.X, ScanCode.KeyX, 'x', 'X');
			_registerLetterIfMissing(CharCode.Y, ScanCode.KeyY, 'y', 'Y');
			_registerLetterIfMissing(CharCode.Z, ScanCode.KeyZ, 'z', 'Z');
		}

		let mappings: IScanCodeMapping[] = [], mappingsLen = 0;
		for (let strScanCode in rawMappings) {
			if (rawMappings.hasOwnProperty(strScanCode)) {
				const scanCode = ScanCodeUtils.toEnum(strScanCode);
				if (scanCode === ScanCode.None) {
					continue;
				}
				if (IMMUTABLE_CODE_TO_KEY_CODE[scanCode] !== KeyCode.DependsOnKbLayout) {
					continue;
				}

				this._codeInfo[scanCode] = rawMappings[strScanCode];

				const rawMapping = missingLatinLettersOverride[strScanCode] || rawMappings[strScanCode];
				const value = MacLinuxKeyboardMapper.getCharCode(rawMapping.value);
				const withShift = MacLinuxKeyboardMapper.getCharCode(rawMapping.withShift);
				const withAltGr = MacLinuxKeyboardMapper.getCharCode(rawMapping.withAltGr);
				const withShiftAltGr = MacLinuxKeyboardMapper.getCharCode(rawMapping.withShiftAltGr);

				const mapping: IScanCodeMapping = {
					scanCode: scanCode,
					value: value,
					withShift: withShift,
					withAltGr: withAltGr,
					withShiftAltGr: withShiftAltGr,
				};
				mappings[mappingsLen++] = mapping;

				this._scanCodeToDispatch[scanCode] = `[${ScanCodeUtils.toString(scanCode)}]`;

				if (value >= CharCode.a && value <= CharCode.z) {
					const upperCaseValue = CharCode.A + (value - CharCode.a);
					this._scanCodeToLabel[scanCode] = String.fromCharCode(upperCaseValue);
				} else if (value >= CharCode.A && value <= CharCode.Z) {
					this._scanCodeToLabel[scanCode] = String.fromCharCode(value);
				} else if (value) {
					this._scanCodeToLabel[scanCode] = String.fromCharCode(value);
				} else {
					this._scanCodeToLabel[scanCode] = null;
				}
			}
		}

		// Handle all `withShiftAltGr` entries
		for (let i = mappings.length - 1; i >= 0; i--) {
			const mapping = mappings[i];
			const scanCode = mapping.scanCode;
			const withShiftAltGr = mapping.withShiftAltGr;
			if (withShiftAltGr === mapping.withAltGr || withShiftAltGr === mapping.withShift || withShiftAltGr === mapping.value) {
				// handled below
				continue;
			}
			const kb = MacLinuxKeyboardMapper._charCodeToKb(withShiftAltGr);
			if (!kb) {
				continue;
			}
			const kbShiftKey = kb.shiftKey;
			const keyCode = kb.keyCode;

			if (kbShiftKey) {
				// Ctrl+Shift+Alt+ScanCode => Shift+KeyCode
				_registerIfUnknown(1, 1, 1, scanCode, 0, 1, 0, keyCode); //       Ctrl+Alt+ScanCode =>          Shift+KeyCode
			} else {
				// Ctrl+Shift+Alt+ScanCode => KeyCode
				_registerIfUnknown(1, 1, 1, scanCode, 0, 0, 0, keyCode); //       Ctrl+Alt+ScanCode =>                KeyCode
			}
		}
		// Handle all `withAltGr` entries
		for (let i = mappings.length - 1; i >= 0; i--) {
			const mapping = mappings[i];
			const scanCode = mapping.scanCode;
			const withAltGr = mapping.withAltGr;
			if (withAltGr === mapping.withShift || withAltGr === mapping.value) {
				// handled below
				continue;
			}
			const kb = MacLinuxKeyboardMapper._charCodeToKb(withAltGr);
			if (!kb) {
				continue;
			}
			const kbShiftKey = kb.shiftKey;
			const keyCode = kb.keyCode;

			if (kbShiftKey) {
				// Ctrl+Alt+ScanCode => Shift+KeyCode
				_registerIfUnknown(1, 0, 1, scanCode, 0, 1, 0, keyCode); //       Ctrl+Alt+ScanCode =>          Shift+KeyCode
			} else {
				// Ctrl+Alt+ScanCode => KeyCode
				_registerIfUnknown(1, 0, 1, scanCode, 0, 0, 0, keyCode); //       Ctrl+Alt+ScanCode =>                KeyCode
			}
		}
		// Handle all `withShift` entries
		for (let i = mappings.length - 1; i >= 0; i--) {
			const mapping = mappings[i];
			const scanCode = mapping.scanCode;
			const withShift = mapping.withShift;
			if (withShift === mapping.value) {
				// handled below
				continue;
			}
			const kb = MacLinuxKeyboardMapper._charCodeToKb(withShift);
			if (!kb) {
				continue;
			}
			const kbShiftKey = kb.shiftKey;
			const keyCode = kb.keyCode;

			if (kbShiftKey) {
				// Shift+ScanCode => Shift+KeyCode
				_registerIfUnknown(0, 1, 0, scanCode, 0, 1, 0, keyCode); //          Shift+ScanCode =>          Shift+KeyCode
				_registerIfUnknown(0, 1, 1, scanCode, 0, 1, 1, keyCode); //      Shift+Alt+ScanCode =>      Shift+Alt+KeyCode
				_registerIfUnknown(1, 1, 0, scanCode, 1, 1, 0, keyCode); //     Ctrl+Shift+ScanCode =>     Ctrl+Shift+KeyCode
				_registerIfUnknown(1, 1, 1, scanCode, 1, 1, 1, keyCode); // Ctrl+Shift+Alt+ScanCode => Ctrl+Shift+Alt+KeyCode
			} else {
				// Shift+ScanCode => KeyCode
				_registerIfUnknown(0, 1, 0, scanCode, 0, 0, 0, keyCode); //          Shift+ScanCode =>                KeyCode
				_registerIfUnknown(0, 1, 0, scanCode, 0, 1, 0, keyCode); //          Shift+ScanCode =>          Shift+KeyCode
				_registerIfUnknown(0, 1, 1, scanCode, 0, 0, 1, keyCode); //      Shift+Alt+ScanCode =>            Alt+KeyCode
				_registerIfUnknown(0, 1, 1, scanCode, 0, 1, 1, keyCode); //      Shift+Alt+ScanCode =>      Shift+Alt+KeyCode
				_registerIfUnknown(1, 1, 0, scanCode, 1, 0, 0, keyCode); //     Ctrl+Shift+ScanCode =>           Ctrl+KeyCode
				_registerIfUnknown(1, 1, 0, scanCode, 1, 1, 0, keyCode); //     Ctrl+Shift+ScanCode =>     Ctrl+Shift+KeyCode
				_registerIfUnknown(1, 1, 1, scanCode, 1, 0, 1, keyCode); // Ctrl+Shift+Alt+ScanCode =>       Ctrl+Alt+KeyCode
				_registerIfUnknown(1, 1, 1, scanCode, 1, 1, 1, keyCode); // Ctrl+Shift+Alt+ScanCode => Ctrl+Shift+Alt+KeyCode
			}
		}
		// Handle all `value` entries
		for (let i = mappings.length - 1; i >= 0; i--) {
			const mapping = mappings[i];
			const scanCode = mapping.scanCode;
			const kb = MacLinuxKeyboardMapper._charCodeToKb(mapping.value);
			if (!kb) {
				continue;
			}
			const kbShiftKey = kb.shiftKey;
			const keyCode = kb.keyCode;

			if (kbShiftKey) {
				// ScanCode => Shift+KeyCode
				_registerIfUnknown(0, 0, 0, scanCode, 0, 1, 0, keyCode); //                ScanCode =>          Shift+KeyCode
				_registerIfUnknown(0, 0, 1, scanCode, 0, 1, 1, keyCode); //            Alt+ScanCode =>      Shift+Alt+KeyCode
				_registerIfUnknown(1, 0, 0, scanCode, 1, 1, 0, keyCode); //           Ctrl+ScanCode =>     Ctrl+Shift+KeyCode
				_registerIfUnknown(1, 0, 1, scanCode, 1, 1, 1, keyCode); //       Ctrl+Alt+ScanCode => Ctrl+Shift+Alt+KeyCode
			} else {
				// ScanCode => KeyCode
				_registerIfUnknown(0, 0, 0, scanCode, 0, 0, 0, keyCode); //                ScanCode =>                KeyCode
				_registerIfUnknown(0, 0, 1, scanCode, 0, 0, 1, keyCode); //            Alt+ScanCode =>            Alt+KeyCode
				_registerIfUnknown(0, 1, 0, scanCode, 0, 1, 0, keyCode); //          Shift+ScanCode =>          Shift+KeyCode
				_registerIfUnknown(0, 1, 1, scanCode, 0, 1, 1, keyCode); //      Shift+Alt+ScanCode =>      Shift+Alt+KeyCode
				_registerIfUnknown(1, 0, 0, scanCode, 1, 0, 0, keyCode); //           Ctrl+ScanCode =>           Ctrl+KeyCode
				_registerIfUnknown(1, 0, 1, scanCode, 1, 0, 1, keyCode); //       Ctrl+Alt+ScanCode =>       Ctrl+Alt+KeyCode
				_registerIfUnknown(1, 1, 0, scanCode, 1, 1, 0, keyCode); //     Ctrl+Shift+ScanCode =>     Ctrl+Shift+KeyCode
				_registerIfUnknown(1, 1, 1, scanCode, 1, 1, 1, keyCode); // Ctrl+Shift+Alt+ScanCode => Ctrl+Shift+Alt+KeyCode
			}
		}
		// Handle all left-over available digits
		_registerAllCombos(0, 0, 0, ScanCode.Digit1, KeyCode.Digit1);
		_registerAllCombos(0, 0, 0, ScanCode.Digit2, KeyCode.Digit2);
		_registerAllCombos(0, 0, 0, ScanCode.Digit3, KeyCode.Digit3);
		_registerAllCombos(0, 0, 0, ScanCode.Digit4, KeyCode.Digit4);
		_registerAllCombos(0, 0, 0, ScanCode.Digit5, KeyCode.Digit5);
		_registerAllCombos(0, 0, 0, ScanCode.Digit6, KeyCode.Digit6);
		_registerAllCombos(0, 0, 0, ScanCode.Digit7, KeyCode.Digit7);
		_registerAllCombos(0, 0, 0, ScanCode.Digit8, KeyCode.Digit8);
		_registerAllCombos(0, 0, 0, ScanCode.Digit9, KeyCode.Digit9);
		_registerAllCombos(0, 0, 0, ScanCode.Digit0, KeyCode.Digit0);

		this._scanCodeKeyCodeMapper.registrationComplete();
	}