Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { CharCode } from '../../../../base/common/charCode.js';
import { KeyCode, KeyCodeUtils, IMMUTABLE_CODE_TO_KEY_CODE, IMMUTABLE_KEY_CODE_TO_CODE, ScanCode, ScanCodeUtils, isModifierKey } from '../../../../base/common/keyCodes.js';
import { ResolvedKeybinding, KeyCodeChord, SingleModifierChord, ScanCodeChord, Keybinding, Chord } from '../../../../base/common/keybindings.js';
import { OperatingSystem } from '../../../../base/common/platform.js';
import { hasKey } from '../../../../base/common/types.js';
import { IKeyboardEvent } from '../../../../platform/keybinding/common/keybinding.js';
import { IKeyboardMapper } from '../../../../platform/keyboardLayout/common/keyboardMapper.js';
import { BaseResolvedKeybinding } from '../../../../platform/keybinding/common/baseResolvedKeybinding.js';
Expand All @@ -19,6 +20,11 @@ import { IMacLinuxKeyboardMapping, IMacLinuxKeyMapping } from '../../../../platf
* - '?' => { keyCode: KeyCode.US_SLASH, shiftKey: true }
*/
const CHAR_CODE_TO_KEY_CODE: ({ keyCode: KeyCode; shiftKey: boolean } | null)[] = [];
const ELECTRON_SHIFTED_ACCELERATOR_CHARACTERS = '!"#$%&()*+:<>?@^_{|}~';
const ELECTRON_NAMED_ACCELERATOR_CHARACTERS = new Map<number, string>([
[CharCode.Space, 'Space'],
[CharCode.Plus, 'Plus'],
]);

export class NativeResolvedKeybinding extends BaseResolvedKeybinding<ScanCodeChord> {

Expand Down Expand Up @@ -909,9 +915,34 @@ export class MacLinuxKeyboardMapper implements IKeyboardMapper {
return KeyCodeUtils.toElectronAccelerator(constantKeyCode);
}

if (this._OS === OperatingSystem.Macintosh) {
return this._getElectronAcceleratorLabelForUnstableScanCode(chord);
}

return null;
}

private _getElectronAcceleratorLabelForUnstableScanCode(chord: ScanCodeChord): string | null {
const mapping = this._codeInfo[chord.scanCode];
if (!mapping) {
return null;
}

if (hasKey(mapping, { valueIsDeadKey: true }) && mapping.valueIsDeadKey) {
return null;
}

const charCode = MacLinuxKeyboardMapper._redirectCharCode(MacLinuxKeyboardMapper.getCharCode(mapping.value));
const character = String.fromCharCode(charCode);
const isPrintableAscii = charCode >= CharCode.Space && charCode <= CharCode.Tilde;
const isUppercaseLetter = charCode >= CharCode.A && charCode <= CharCode.Z;
if (!isPrintableAscii || isUppercaseLetter || (chord.shiftKey && ELECTRON_SHIFTED_ACCELERATOR_CHARACTERS.includes(character))) {
return null;
}

return ELECTRON_NAMED_ACCELERATOR_CHARACTERS.get(charCode) ?? character;
}

private _toResolvedKeybinding(chordParts: ScanCodeChord[][]): NativeResolvedKeybinding[] {
if (chordParts.length === 0) {
return [];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ suite('keyboardMapper - MAC de_ch', () => {
[{
label: '⇧⌘\'',
ariaLabel: 'Shift+Command+\'',
electronAccelerator: null,
electronAccelerator: 'Shift+Cmd+\'',
userSettingsLabel: 'shift+cmd+[Minus]',
isWYSIWYG: false,
isMultiChord: false,
Expand Down Expand Up @@ -1805,6 +1805,65 @@ suite('keyboardMapper - MAC zh_hant2', () => {
});
});

suite('keyboardMapper - MAC layout-dependent accelerators', () => {

ensureNoDisposablesAreLeakedInTestSuite();

function resolveElectronAccelerator(value: string, withShift: string, shiftKey = false, valueIsDeadKey = false): string | null {
const mapper = new MacLinuxKeyboardMapper(false, {
Equal: {
value,
valueIsDeadKey,
withShift,
withShiftIsDeadKey: false,
withAltGr: '',
withAltGrIsDeadKey: false,
withShiftAltGr: '',
withShiftAltGrIsDeadKey: false,
}
}, false, OperatingSystem.Macintosh);

const keybinding = mapper.resolveKeyboardEvent({
_standardKeyboardEventBrand: true,
ctrlKey: false,
shiftKey,
altKey: false,
metaKey: true,
altGraphKey: false,
keyCode: KeyCode.DependsOnKbLayout,
code: 'Equal'
});

return keybinding.getElectronAccelerator();
}

test('uses the produced character when the scan code has no stable key code', () => {
assert.deepStrictEqual({
plus: resolveElectronAccelerator('+', ':'),
space: resolveElectronAccelerator(' ', ':'),
digit: resolveElectronAccelerator('1', ':'),
questionMark: resolveElectronAccelerator('?', 'é'),
shiftedApostrophe: resolveElectronAccelerator('\'', '?', true),
shiftedPlus: resolveElectronAccelerator('+', ':', true),
shiftedExclamationMark: resolveElectronAccelerator('!', ':', true),
deadKey: resolveElectronAccelerator('`', ':', false, true),
uppercase: resolveElectronAccelerator('A', ':'),
unsupported: resolveElectronAccelerator('é', 'É'),
}, {
plus: 'Cmd+Plus',
space: 'Cmd+Space',
digit: 'Cmd+1',
questionMark: 'Cmd+?',
shiftedApostrophe: 'Shift+Cmd+\'',
shiftedPlus: null,
shiftedExclamationMark: null,
deadKey: null,
uppercase: null,
unsupported: null,
});
});
});

function _assertKeybindingTranslation(mapper: MacLinuxKeyboardMapper, OS: OperatingSystem, kb: number, _expected: string | string[]): void {
let expected: string[];
if (typeof _expected === 'string') {
Expand Down
Loading
Loading