Skip to content

Commit

Permalink
Workaround for the broken keyboard event support on Linux. Dvorak key…
Browse files Browse the repository at this point in the history
…boards should work better now.
  • Loading branch information
sedwards2009 committed Aug 25, 2016
1 parent b132e9e commit 03779b8
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 32 deletions.
32 changes: 26 additions & 6 deletions src/keybindingmanager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export interface MinimalKeyboardEvent {
shiftKey: boolean;
key: string;
keyCode: number;
keyIdentifier: string;
}

// Internal data structure for pairing a key binding with a command.
Expand Down Expand Up @@ -85,7 +86,10 @@ export class KeyBindingMapping {

private _log = new Logger("KeyBindingMapping");

constructor(mappingName: string, allMappingsJson: Object) {
private _platform: string;

constructor(mappingName: string, allMappingsJson: Object, platform: string) {
this._platform = platform;
this._gatherPairs(mappingName, allMappingsJson).forEach( (pair) => {
const parsedKeyBinding = parseKeyBinding(pair.key, pair.value);
if (parsedKeyBinding !== null) {
Expand Down Expand Up @@ -136,7 +140,23 @@ export class KeyBindingMapping {
if (ev.key.charCodeAt(0) === 160) { // nbsp to space on the Mac
key = " ";
} else {
key = ev.key;

key = ev.key; // use ev.key until proven otherwise.
if (this._platform === "linux") {
// FIXME The key handling on Linux is broken a bit in Chrome 52. This code is a work around.
// It is mostly needed to make Dvorak work ok.
if (ev.keyIdentifier.startsWith("U+")) {
const keyValue = Number.parseInt(ev.keyIdentifier.slice(2), 16);
const keyStr = String.fromCodePoint(keyValue);
if ((keyStr >= 'a' && keyStr <= 'z') || (keyStr >= 'A' && keyStr <= 'Z')) {
if ( ! ev.shiftKey) {
key = keyStr.toLowerCase();
} else {
key = keyStr;
}
}
}
}
}
}

Expand Down Expand Up @@ -272,10 +292,10 @@ export class KeyBindingContexts {

public contextNames = [];

constructor(obj: Object) {
constructor(obj: Object, platform: string) {
for (let key in obj) {
if (key !== NAME) {
const mapper = new KeyBindingMapping(key, obj);
const mapper = new KeyBindingMapping(key, obj, platform);
this.contextNames.push(key);
this._contexts.set(key, mapper);
}
Expand All @@ -301,8 +321,8 @@ export class KeyBindingContexts {
* being objects mapping key binding strings to command strings
* @return the object which maps context names to `KeyBindingMapping` objects
*/
export function loadKeyBindingsFromObject(obj: Object): KeyBindingContexts {
return new KeyBindingContexts(obj);
export function loadKeyBindingsFromObject(obj: Object, platform: string): KeyBindingContexts {
return new KeyBindingContexts(obj, platform);
}

export interface KeyBindingManager {
Expand Down
46 changes: 23 additions & 23 deletions src/keybindingmanagertest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const keyBindingsMap = {
};

export function testContext(test: nodeunit.Test): void {
const cutsContexts = KeyBindingsManager.loadKeyBindingsFromObject(keyBindingsMap);
const cutsContexts = KeyBindingsManager.loadKeyBindingsFromObject(keyBindingsMap, "linux");
const editorKeyBindings = cutsContexts.context("editor");

test.notEqual(editorKeyBindings, null);
Expand All @@ -56,35 +56,35 @@ function keyIdentifier(key: string): string {
}

export function testMapEventToCommand(test: nodeunit.Test): void {
const cutsContexts = KeyBindingsManager.loadKeyBindingsFromObject(keyBindingsMap);
const cutsContexts = KeyBindingsManager.loadKeyBindingsFromObject(keyBindingsMap, "linux");
const editorKeyBindings = cutsContexts.context("editor");

test.equal(editorKeyBindings.mapEventToCommand({ altKey: false, ctrlKey: true, metaKey: false, shiftKey: false, key: "o", keyCode: keyCode("o") }), "open");
test.equal(editorKeyBindings.mapEventToCommand({ altKey: false, ctrlKey: true, metaKey: false, shiftKey: false, key: " ", keyCode: keyCode(" ") }), "togglemode");
test.equal(editorKeyBindings.mapEventToCommand({ altKey: false, ctrlKey: true, metaKey: false, shiftKey: false, key: "+", keyCode: keyCode("+") }), "zoom");
test.equal(editorKeyBindings.mapEventToCommand({ altKey: true, ctrlKey: false, metaKey: true, shiftKey: true, key: "A", keyCode: keyCode("A",false) }), "all");
test.equal(editorKeyBindings.mapEventToCommand({ altKey: false, ctrlKey: false, metaKey: false, shiftKey: false, key: " ", keyCode: keyCode(" ",false) }), "makespace");
test.equal(editorKeyBindings.mapEventToCommand({ altKey: true, ctrlKey: false, metaKey: false, shiftKey: true, key: "S", keyCode: keyCode("S",false) }), "smeg");
test.equal(editorKeyBindings.mapEventToCommand({ altKey: false, ctrlKey: true, metaKey: false, shiftKey: true, key: "W", keyCode: keyCode("W") }), "closewindow");
test.equal(editorKeyBindings.mapEventToCommand({ altKey: false, ctrlKey: false, metaKey: false, shiftKey: true, key: "Z", keyCode: keyCode("Z",false) }), "sleep");
test.equal(editorKeyBindings.mapEventToCommand({ altKey: false, ctrlKey: false, metaKey: false, shiftKey: false, key: "PageUp", keyCode: keyCode("PageUp",false) }), "pageup");
test.equal(editorKeyBindings.mapEventToCommand({ altKey: false, ctrlKey: false, metaKey: false, shiftKey: false, key: "Home", keyCode: keyCode("Home",false) }), "gohome");
test.equal(editorKeyBindings.mapEventToCommand({ altKey: false, ctrlKey: false, metaKey: false, shiftKey: false, key: "Home", keyCode: keyCode("Home",false) }), "gohome");
test.equal(editorKeyBindings.mapEventToCommand({ altKey: true, ctrlKey: false, metaKey: false, shiftKey: false, key: "Tab", keyCode: keyCode("Tab",false) }), "dedent");
test.equal(editorKeyBindings.mapEventToCommand({ altKey: false, ctrlKey: false, metaKey: false, shiftKey: false, key: "End", keyCode: keyCode("End",false) }), "finish");
test.equal(editorKeyBindings.mapEventToCommand({ altKey: false, ctrlKey: false, metaKey: false, shiftKey: false, key: "ArrowUp", keyCode: keyCode("ArrowUp",false) }), "up");
test.equal(editorKeyBindings.mapEventToCommand({ altKey: false, ctrlKey: false, metaKey: false, shiftKey: false, key: "ArrowDown", keyCode: keyCode("ArrowDown",false) }), "down");
test.equal(editorKeyBindings.mapEventToCommand({ altKey: false, ctrlKey: false, metaKey: false, shiftKey: false, key: "F2", keyCode: keyCode("F2",false) }), "rename");
test.equal(editorKeyBindings.mapEventToCommand({ altKey: true, ctrlKey: false, metaKey: false, shiftKey: false, key: "ArrowLeft", keyCode: keyCode("ArrowLeft",false) }), "select-left");
test.equal(editorKeyBindings.mapEventToCommand({ altKey: false, ctrlKey: true, metaKey: false, shiftKey: false, key: "Tab", keyCode: 9 }), "otherpane");
test.equal(editorKeyBindings.mapEventToCommand({ altKey: false, ctrlKey: true, metaKey: false, shiftKey: false, key: "c", keyCode: 67 }), "break");
test.equal(editorKeyBindings.mapEventToCommand({ altKey: false, ctrlKey: true, metaKey: false, shiftKey: true, key: "C", keyCode: 67 }), "bigbreak");
test.equal(editorKeyBindings.mapEventToCommand({ altKey: false, ctrlKey: true, metaKey: false, shiftKey: false, key: "o", keyIdentifier: "", keyCode: keyCode("o") }), "open");
test.equal(editorKeyBindings.mapEventToCommand({ altKey: false, ctrlKey: true, metaKey: false, shiftKey: false, key: " ", keyIdentifier: "", keyCode: keyCode(" ") }), "togglemode");
test.equal(editorKeyBindings.mapEventToCommand({ altKey: false, ctrlKey: true, metaKey: false, shiftKey: false, key: "+", keyIdentifier: "", keyCode: keyCode("+") }), "zoom");
test.equal(editorKeyBindings.mapEventToCommand({ altKey: true, ctrlKey: false, metaKey: true, shiftKey: true, key: "A", keyIdentifier: "", keyCode: keyCode("A",false) }), "all");
test.equal(editorKeyBindings.mapEventToCommand({ altKey: false, ctrlKey: false, metaKey: false, shiftKey: false, key: " ", keyIdentifier: "", keyCode: keyCode(" ",false) }), "makespace");
test.equal(editorKeyBindings.mapEventToCommand({ altKey: true, ctrlKey: false, metaKey: false, shiftKey: true, key: "S", keyIdentifier: "", keyCode: keyCode("S",false) }), "smeg");
test.equal(editorKeyBindings.mapEventToCommand({ altKey: false, ctrlKey: true, metaKey: false, shiftKey: true, key: "W", keyIdentifier: "", keyCode: keyCode("W") }), "closewindow");
test.equal(editorKeyBindings.mapEventToCommand({ altKey: false, ctrlKey: false, metaKey: false, shiftKey: true, key: "Z", keyIdentifier: "", keyCode: keyCode("Z",false) }), "sleep");
test.equal(editorKeyBindings.mapEventToCommand({ altKey: false, ctrlKey: false, metaKey: false, shiftKey: false, key: "PageUp", keyIdentifier: "", keyCode: keyCode("PageUp",false) }), "pageup");
test.equal(editorKeyBindings.mapEventToCommand({ altKey: false, ctrlKey: false, metaKey: false, shiftKey: false, key: "Home", keyIdentifier: "", keyCode: keyCode("Home",false) }), "gohome");
test.equal(editorKeyBindings.mapEventToCommand({ altKey: false, ctrlKey: false, metaKey: false, shiftKey: false, key: "Home", keyIdentifier: "", keyCode: keyCode("Home",false) }), "gohome");
test.equal(editorKeyBindings.mapEventToCommand({ altKey: true, ctrlKey: false, metaKey: false, shiftKey: false, key: "Tab", keyIdentifier: "", keyCode: keyCode("Tab",false) }), "dedent");
test.equal(editorKeyBindings.mapEventToCommand({ altKey: false, ctrlKey: false, metaKey: false, shiftKey: false, key: "End", keyIdentifier: "", keyCode: keyCode("End",false) }), "finish");
test.equal(editorKeyBindings.mapEventToCommand({ altKey: false, ctrlKey: false, metaKey: false, shiftKey: false, key: "ArrowUp", keyIdentifier: "", keyCode: keyCode("ArrowUp",false) }), "up");
test.equal(editorKeyBindings.mapEventToCommand({ altKey: false, ctrlKey: false, metaKey: false, shiftKey: false, key: "ArrowDown", keyIdentifier: "", keyCode: keyCode("ArrowDown",false) }), "down");
test.equal(editorKeyBindings.mapEventToCommand({ altKey: false, ctrlKey: false, metaKey: false, shiftKey: false, key: "F2", keyIdentifier: "", keyCode: keyCode("F2",false) }), "rename");
test.equal(editorKeyBindings.mapEventToCommand({ altKey: true, ctrlKey: false, metaKey: false, shiftKey: false, key: "ArrowLeft", keyIdentifier: "", keyCode: keyCode("ArrowLeft",false) }), "select-left");
test.equal(editorKeyBindings.mapEventToCommand({ altKey: false, ctrlKey: true, metaKey: false, shiftKey: false, key: "Tab", keyIdentifier: "", keyCode: 9 }), "otherpane");
test.equal(editorKeyBindings.mapEventToCommand({ altKey: false, ctrlKey: true, metaKey: false, shiftKey: false, key: "c", keyIdentifier: "", keyCode: 67 }), "break");
test.equal(editorKeyBindings.mapEventToCommand({ altKey: false, ctrlKey: true, metaKey: false, shiftKey: true, key: "C", keyIdentifier: "", keyCode: 67 }), "bigbreak");

test.done();
}

export function testMapCommandToKeyBindings(test: nodeunit.Test): void {
const cutsContexts = KeyBindingsManager.loadKeyBindingsFromObject(keyBindingsMap);
const cutsContexts = KeyBindingsManager.loadKeyBindingsFromObject(keyBindingsMap, "linux");
const editorKeyBindings = cutsContexts.context("editor");

test.equal(editorKeyBindings.mapCommandToKeyBinding("open"), "Ctrl+O");
Expand Down
3 changes: 2 additions & 1 deletion src/mainweb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,8 @@ function handleClipboardRead(msg: Messages.Message): void {
*
*/
function setupConfiguration(oldConfig: Config, newConfig: Config): Promise<void> {
const keyBindingContexts = keybindingmanager.loadKeyBindingsFromObject(newConfig.systemConfig.keyBindingsContexts);
const keyBindingContexts = keybindingmanager.loadKeyBindingsFromObject(newConfig.systemConfig.keyBindingsContexts,
process.platform);
keyBindingManager.setKeyBindingContexts(keyBindingContexts);

if (oldConfig === null || oldConfig.terminalFontSize !== newConfig.terminalFontSize ||
Expand Down
3 changes: 2 additions & 1 deletion src/viewers/terminalviewer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1052,7 +1052,8 @@ class EtTerminalViewer extends ViewerElement implements CommandPaletteRequestTyp
altKey: ev.altKey,
ctrlKey: ev.ctrlKey,
key: ev.key,
keyCode: ev.keyCode
keyCode: ev.keyCode,
keyIdentifier: ev.keyIdentifier
};
command = keyBindings.mapEventToCommand(evWithoutShift);
if (command !== null && command.startsWith("go")) {
Expand Down
3 changes: 2 additions & 1 deletion src/viewers/textviewer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -795,7 +795,8 @@ class EtTextViewer extends ViewerElement implements CommandPaletteRequestTypes.C
altKey: ev.altKey,
ctrlKey: ev.ctrlKey,
key: ev.key,
keyCode: ev.keyCode
keyCode: ev.keyCode,
keyIdentifier: ev.keyIdentifier
};
command = keyBindings.mapEventToCommand(evWithoutShift);
if (command !== null && command.startsWith("go")) {
Expand Down

0 comments on commit 03779b8

Please sign in to comment.