in src/vs/workbench/services/keybinding/common/macLinuxKeyboardMapper.ts [405:694]
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 !== -1) {
_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 forcefully 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] !== -1) {
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] !== -1) {
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.KEY_1);
_registerAllCombos(0, 0, 0, ScanCode.Digit2, KeyCode.KEY_2);
_registerAllCombos(0, 0, 0, ScanCode.Digit3, KeyCode.KEY_3);
_registerAllCombos(0, 0, 0, ScanCode.Digit4, KeyCode.KEY_4);
_registerAllCombos(0, 0, 0, ScanCode.Digit5, KeyCode.KEY_5);
_registerAllCombos(0, 0, 0, ScanCode.Digit6, KeyCode.KEY_6);
_registerAllCombos(0, 0, 0, ScanCode.Digit7, KeyCode.KEY_7);
_registerAllCombos(0, 0, 0, ScanCode.Digit8, KeyCode.KEY_8);
_registerAllCombos(0, 0, 0, ScanCode.Digit9, KeyCode.KEY_9);
_registerAllCombos(0, 0, 0, ScanCode.Digit0, KeyCode.KEY_0);
this._scanCodeKeyCodeMapper.registrationComplete();
}