Skip to content

Commit

Permalink
Fixes #24153: ISO Keyboards: Backslash and IntlBackslash "swapped"
Browse files Browse the repository at this point in the history
  • Loading branch information
alexdima committed Apr 28, 2017
1 parent 830b94b commit 2865949
Show file tree
Hide file tree
Showing 8 changed files with 150 additions and 22 deletions.
6 changes: 3 additions & 3 deletions npm-shrinkwrap.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"iconv-lite": "0.4.15",
"jschardet": "^1.4.2",
"minimist": "1.2.0",
"native-keymap": "1.2.2",
"native-keymap": "1.2.3",
"node-pty": "0.6.4",
"semver": "4.3.6",
"v8-profiler": "jrieken/v8-profiler#vscode",
Expand Down
2 changes: 2 additions & 0 deletions src/typings/native-keymap.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,6 @@ declare module 'native-keymap' {
export function getCurrentKeyboardLayout(): IKeyboardLayoutInfo;

export function onDidChangeKeyboardLayout(callback: () => void);

export function isISOKeyboard(): boolean;
}
43 changes: 37 additions & 6 deletions src/vs/code/electron-main/windows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -253,9 +253,9 @@ export class WindowsManager implements IWindowsMainService {
this.lifecycleService.onBeforeWindowClose(win => this.onBeforeWindowClose(win));
this.lifecycleService.onBeforeQuit(() => this.onBeforeQuit());

KeyboardLayoutMonitor.INSTANCE.onDidChangeKeyboardLayout(() => {
KeyboardLayoutMonitor.INSTANCE.onDidChangeKeyboardLayout((isISOKeyboard: boolean) => {
WindowsManager.WINDOWS.forEach((window) => {
window.sendWhenReady('vscode:keyboardLayoutChanged');
window.sendWhenReady('vscode:keyboardLayoutChanged', isISOKeyboard);
});
});
}
Expand Down Expand Up @@ -1329,21 +1329,52 @@ class KeyboardLayoutMonitor {

public static INSTANCE = new KeyboardLayoutMonitor();

private _emitter: Emitter<void>;
private _emitter: Emitter<boolean>;
private _registered: boolean;

private constructor() {
this._emitter = new Emitter<void>();
this._emitter = new Emitter<boolean>();
this._registered = false;
}

public onDidChangeKeyboardLayout(callback: () => void): IDisposable {
public onDidChangeKeyboardLayout(callback: (isISOKeyboard: boolean) => void): IDisposable {
if (!this._registered) {
this._registered = true;

nativeKeymap.onDidChangeKeyboardLayout(() => {
this._emitter.fire();
this._emitter.fire(this._isISOKeyboard());
});

if (platform.isMacintosh) {
// See https://github.com/Microsoft/vscode/issues/24153
// On OSX, on ISO keyboards, Chromium swaps the scan codes
// of IntlBackslash and Backquote.
//
// The C++ methods can give the current keyboard type (ISO or not)
// only after a NSEvent was handled.
//
// We therefore poll.
let prevValue: boolean = null;
setInterval(() => {
let newValue = this._isISOKeyboard();
if (prevValue === newValue) {
// no change
return;
}

prevValue = newValue;
this._emitter.fire(this._isISOKeyboard());

}, 3000);
}
}
return this._emitter.event(callback);
}

private _isISOKeyboard(): boolean {
if (platform.isMacintosh) {
return nativeKeymap.isISOKeyboard();
}
return false;
}
}
4 changes: 2 additions & 2 deletions src/vs/workbench/electron-browser/window.ts
Original file line number Diff line number Diff line change
Expand Up @@ -297,8 +297,8 @@ export class ElectronWindow extends Themable {
});

// keyboard layout changed event
ipc.on('vscode:keyboardLayoutChanged', () => {
KeyboardMapperFactory.INSTANCE._onKeyboardLayoutChanged();
ipc.on('vscode:keyboardLayoutChanged', (event, isISOKeyboard: boolean) => {
KeyboardMapperFactory.INSTANCE._onKeyboardLayoutChanged(isISOKeyboard);
});

// Configuration changes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,11 @@ class ScanCodeKeyCodeMapper {
export class MacLinuxKeyboardMapper implements IKeyboardMapper {

/**
* OS (can be Linux or Macintosh)
* Is the keyboard type ISO (on Mac)
*/
private readonly _isISOKeyboard: boolean;
/**
* Is this the standard US keyboard layout?
*/
private readonly _isUSStandard: boolean;
/**
Expand All @@ -534,7 +538,8 @@ export class MacLinuxKeyboardMapper implements IKeyboardMapper {
*/
private readonly _scanCodeToDispatch: string[] = [];

constructor(isUSStandard: boolean, rawMappings: IMacLinuxKeyboardMapping, OS: OperatingSystem) {
constructor(isISOKeyboard: boolean, isUSStandard: boolean, rawMappings: IMacLinuxKeyboardMapping, OS: OperatingSystem) {
this._isISOKeyboard = isISOKeyboard;
this._isUSStandard = isUSStandard;
this._OS = OS;
this._codeInfo = [];
Expand Down Expand Up @@ -1051,11 +1056,27 @@ export class MacLinuxKeyboardMapper implements IKeyboardMapper {

public resolveKeyboardEvent(keyboardEvent: IKeyboardEvent): NativeResolvedKeybinding {
let code = ScanCodeUtils.toEnum(keyboardEvent.code);

// Treat NumpadEnter as Enter
if (code === ScanCode.NumpadEnter) {
code = ScanCode.Enter;
}

if (this._OS === OperatingSystem.Macintosh && this._isISOKeyboard) {
// See https://github.com/Microsoft/vscode/issues/24153
// On OSX, on ISO keyboards, Chromium swaps the scan codes
// of IntlBackslash and Backquote.

switch (code) {
case ScanCode.IntlBackslash:
code = ScanCode.Backquote;
break;
case ScanCode.Backquote:
code = ScanCode.IntlBackslash;
break;
}
}

const keyCode = keyboardEvent.keyCode;

if (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
export class KeyboardMapperFactory {
public static INSTANCE = new KeyboardMapperFactory();

private _isISOKeyboard: boolean;
private _layoutInfo: nativeKeymap.IKeyboardLayoutInfo;
private _rawMapping: nativeKeymap.IKeyboardMapping;
private _keyboardMapper: IKeyboardMapper;
Expand All @@ -53,13 +54,15 @@ export class KeyboardMapperFactory {
public onDidChangeKeyboardMapper: Event<void> = this._onDidChangeKeyboardMapper.event;

private constructor() {
this._isISOKeyboard = false;
this._layoutInfo = null;
this._rawMapping = null;
this._keyboardMapper = null;
this._initialized = false;
}

public _onKeyboardLayoutChanged(): void {
public _onKeyboardLayoutChanged(isISOKeyboard: boolean): void {
this._isISOKeyboard = isISOKeyboard;
if (this._initialized) {
this._setKeyboardData(nativeKeymap.getCurrentKeyboardLayout(), nativeKeymap.getKeyMap());
}
Expand Down Expand Up @@ -124,11 +127,11 @@ export class KeyboardMapperFactory {
this._initialized = true;

this._rawMapping = rawMapping;
this._keyboardMapper = KeyboardMapperFactory._createKeyboardMapper(KeyboardMapperFactory._isUSStandard(this._layoutInfo), this._rawMapping);
this._keyboardMapper = KeyboardMapperFactory._createKeyboardMapper(this._isISOKeyboard, KeyboardMapperFactory._isUSStandard(this._layoutInfo), this._rawMapping);
this._onDidChangeKeyboardMapper.fire();
}

private static _createKeyboardMapper(isUSStandard: boolean, rawMapping: nativeKeymap.IKeyboardMapping): IKeyboardMapper {
private static _createKeyboardMapper(isISOKeyboard: boolean, isUSStandard: boolean, rawMapping: nativeKeymap.IKeyboardMapping): IKeyboardMapper {
if (OS === OperatingSystem.Windows) {
return new WindowsKeyboardMapper(<IWindowsKeyboardMapping>rawMapping);
}
Expand All @@ -138,7 +141,7 @@ export class KeyboardMapperFactory {
return new MacLinuxFallbackKeyboardMapper(OS);
}

return new MacLinuxKeyboardMapper(isUSStandard, <IMacLinuxKeyboardMapping>rawMapping, OS);
return new MacLinuxKeyboardMapper(isISOKeyboard, isUSStandard, <IMacLinuxKeyboardMapping>rawMapping, OS);
}

private static _equals(a: nativeKeymap.IKeyboardMapping, b: nativeKeymap.IKeyboardMapping): boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const WRITE_FILE_IF_DIFFERENT = false;

function createKeyboardMapper(isUSStandard: boolean, file: string, OS: OperatingSystem): TPromise<MacLinuxKeyboardMapper> {
return readRawMapping<IMacLinuxKeyboardMapping>(file).then((rawMappings) => {
return new MacLinuxKeyboardMapper(isUSStandard, rawMappings, OS);
return new MacLinuxKeyboardMapper(false, isUSStandard, rawMappings, OS);
});
}

Expand Down Expand Up @@ -1562,7 +1562,7 @@ suite('keyboardMapper - LINUX en_us', () => {
suite('keyboardMapper', () => {

test('issue #23706: Linux UK layout: Ctrl + Apostrophe also toggles terminal', () => {
let mapper = new MacLinuxKeyboardMapper(false, {
let mapper = new MacLinuxKeyboardMapper(false, false, {
'Backquote': {
'value': '`',
'withShift': '¬',
Expand Down Expand Up @@ -1600,7 +1600,7 @@ suite('keyboardMapper', () => {
});

test('issue #24064: NumLock/NumPad keys stopped working in 1.11 on Linux', () => {
let mapper = new MacLinuxKeyboardMapper(false, {}, OperatingSystem.Linux);
let mapper = new MacLinuxKeyboardMapper(false, false, {}, OperatingSystem.Linux);

function assertNumpadKeyboardEvent(keyCode: KeyCode, code: string, label: string, electronAccelerator: string, userSettingsLabel: string, dispatch: string): void {
assertResolveKeyboardEvent(
Expand Down Expand Up @@ -1645,7 +1645,7 @@ suite('keyboardMapper', () => {
});

test('issue #24107: Delete, Insert, Home, End, PgUp, PgDn, and arrow keys no longer work editor in 1.11', () => {
let mapper = new MacLinuxKeyboardMapper(false, {}, OperatingSystem.Linux);
let mapper = new MacLinuxKeyboardMapper(false, false, {}, OperatingSystem.Linux);

function assertKeyboardEvent(keyCode: KeyCode, code: string, label: string, electronAccelerator: string, userSettingsLabel: string, dispatch: string): void {
assertResolveKeyboardEvent(
Expand Down Expand Up @@ -1701,6 +1701,77 @@ suite('keyboardMapper', () => {
assertKeyboardEvent(KeyCode.UpArrow, 'Lang3', 'UpArrow', 'Up', 'up', '[ArrowUp]');
});

test('issue #24153: ISO Keyboards: Backslash and IntlBackslash "swapped"', () => {
let mapper = new MacLinuxKeyboardMapper(true, false, {
'Backquote': {
'value': '`',
'withShift': '~',
'withAltGr': '`',
'withShiftAltGr': '`'
},
'IntlBackslash': {
'value': '§',
'withShift': '°',
'withAltGr': '§',
'withShiftAltGr': '°'
}
}, OperatingSystem.Macintosh);

assertResolveKeyboardEvent(
mapper,
{
ctrlKey: true,
shiftKey: false,
altKey: false,
metaKey: false,
keyCode: -1,
code: 'Backquote'
},
{
label: '⌃§',
ariaLabel: 'Control+§',
labelWithoutModifiers: '§',
ariaLabelWithoutModifiers: '§',
electronAccelerator: null,
userSettingsLabel: 'ctrl+[IntlBackslash]',
isWYSIWYG: false,
isChord: false,
hasCtrlModifier: true,
hasShiftModifier: false,
hasAltModifier: false,
hasMetaModifier: false,
dispatchParts: ['ctrl+[IntlBackslash]', null],
}
);

assertResolveKeyboardEvent(
mapper,
{
ctrlKey: true,
shiftKey: false,
altKey: false,
metaKey: false,
keyCode: -1,
code: 'IntlBackslash'
},
{
label: '⌃`',
ariaLabel: 'Control+`',
labelWithoutModifiers: '`',
ariaLabelWithoutModifiers: '`',
electronAccelerator: null,
userSettingsLabel: 'ctrl+`',
isWYSIWYG: true,
isChord: false,
hasCtrlModifier: true,
hasShiftModifier: false,
hasAltModifier: false,
hasMetaModifier: false,
dispatchParts: ['ctrl+[Backquote]', null],
}
);
});

});

suite('keyboardMapper - LINUX ru', () => {
Expand Down

0 comments on commit 2865949

Please sign in to comment.