diff --git a/src/vs/base/common/keyCodes.ts b/src/vs/base/common/keyCodes.ts index 7b327aee4bfa8c0a146df385544e29d55370b326..8343795bb9c819e20e94c3050e33f8d4fefe445b 100644 --- a/src/vs/base/common/keyCodes.ts +++ b/src/vs/base/common/keyCodes.ts @@ -416,13 +416,11 @@ export function createKeybinding(keybinding: number, OS: OperatingSystem): Keybi } const firstPart = (keybinding & 0x0000FFFF) >>> 0; const chordPart = (keybinding & 0xFFFF0000) >>> 16; + let parts = [createSimpleKeybinding(firstPart, OS)]; if (chordPart !== 0) { - return new ChordKeybinding([ - createSimpleKeybinding(firstPart, OS), - createSimpleKeybinding(chordPart, OS), - ]); + parts.push(createSimpleKeybinding(chordPart, OS)); } - return createSimpleKeybinding(firstPart, OS); + return new ChordKeybinding(parts); } export function createSimpleKeybinding(keybinding: number, OS: OperatingSystem): SimpleKeybinding { @@ -461,10 +459,7 @@ export class SimpleKeybinding { this.keyCode = keyCode; } - public equals(other: Keybinding): boolean { - if (other.type !== KeybindingType.Simple) { - return false; - } + public equals(other: SimpleKeybinding): boolean { return ( this.ctrlKey === other.ctrlKey && this.shiftKey === other.shiftKey @@ -492,6 +487,10 @@ export class SimpleKeybinding { ); } + public toChord(): ChordKeybinding { + return new ChordKeybinding([this]); + } + /** * Does this keybinding refer to the key code of a modifier and it also has the modifier flag? */ @@ -517,9 +516,21 @@ export class ChordKeybinding { let hashCodes = this.parts.map((p) => p.getHashCode().toString()); return hashCodes.join(';'); } + + public equals(other: ChordKeybinding): boolean { + if (this.parts.length !== other.parts.length) { + return false; + } + for (let i = 0; i < this.parts.length; i++) { + if (!this.parts[i].equals(other.parts[i])) { + return false; + } + } + return true; + } } -export type Keybinding = SimpleKeybinding | ChordKeybinding; +export type Keybinding = ChordKeybinding; export class ResolvedKeybindingPart { readonly ctrlKey: boolean; @@ -574,10 +585,10 @@ export abstract class ResolvedKeybinding { /** * Returns the firstPart, chordPart that should be used for dispatching. */ - public abstract getDispatchParts(): [string | null, string | null]; + public abstract getDispatchParts(): string[]; /** * Returns the firstPart, chordPart of the keybinding. * For simple keybindings, the second element will be null. */ - public abstract getParts(): [ResolvedKeybindingPart, ResolvedKeybindingPart | null]; + public abstract getParts(): ResolvedKeybindingPart[]; } diff --git a/src/vs/base/common/keybindingParser.ts b/src/vs/base/common/keybindingParser.ts index de5522dc0cb35af10eec1b7b6e5dd486cf3df51f..2a69e99fda07cdfc9b693884e8e1f8e657e0a3b6 100644 --- a/src/vs/base/common/keybindingParser.ts +++ b/src/vs/base/common/keybindingParser.ts @@ -92,11 +92,6 @@ export class KeybindingParser { [part, input] = this.parseSimpleKeybinding(input); parts.push(part); } while (input.length > 0); - - if (parts.length === 1) { - // This is a simple keybinding - return parts[0]; - } return new ChordKeybinding(parts); } diff --git a/src/vs/base/parts/tree/browser/treeDefaults.ts b/src/vs/base/parts/tree/browser/treeDefaults.ts index 01e55bc45cd645985d5633fc152a49b60e3f8d31..d35643dab22c44aacb6e19bcdc48be893ad52721 100644 --- a/src/vs/base/parts/tree/browser/treeDefaults.ts +++ b/src/vs/base/parts/tree/browser/treeDefaults.ts @@ -12,7 +12,7 @@ import * as dom from 'vs/base/browser/dom'; import * as mouse from 'vs/base/browser/mouseEvent'; import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import * as _ from 'vs/base/parts/tree/browser/tree'; -import { KeyCode, KeyMod, Keybinding, SimpleKeybinding, createSimpleKeybinding } from 'vs/base/common/keyCodes'; +import { KeyCode, KeyMod, Keybinding, SimpleKeybinding, createKeybinding } from 'vs/base/common/keyCodes'; export interface IKeyBindingCallback { (tree: _.ITree, event: IKeyboardEvent): void; @@ -61,7 +61,7 @@ export class KeybindingDispatcher { } public has(keybinding: KeyCode): boolean { - let target = createSimpleKeybinding(keybinding, platform.OS); + let target = createKeybinding(keybinding, platform.OS); for (const a of this._arr) { if (target.equals(a.keybinding)) { return true; @@ -72,7 +72,7 @@ export class KeybindingDispatcher { public set(keybinding: number, callback: IKeyBindingCallback) { this._arr.push({ - keybinding: createSimpleKeybinding(keybinding, platform.OS), + keybinding: createKeybinding(keybinding, platform.OS), callback: callback }); } @@ -81,7 +81,7 @@ export class KeybindingDispatcher { // Loop from the last to the first to handle overwrites for (let i = this._arr.length - 1; i >= 0; i--) { let item = this._arr[i]; - if (keybinding.equals(item.keybinding)) { + if (keybinding.toChord().equals(item.keybinding)) { return item.callback; } } diff --git a/src/vs/base/test/common/keyCodes.test.ts b/src/vs/base/test/common/keyCodes.test.ts index 1af47ac57a417cdbcc5ca8ae8d918a2b3444ef66..f8b2b55a452e33d78412a260551d09133116dd96 100644 --- a/src/vs/base/test/common/keyCodes.test.ts +++ b/src/vs/base/test/common/keyCodes.test.ts @@ -20,22 +20,22 @@ suite('keyCodes', () => { } test(null, 0); - test(new SimpleKeybinding(false, false, false, false, KeyCode.Enter), KeyCode.Enter); - test(new SimpleKeybinding(true, false, false, false, KeyCode.Enter), KeyMod.WinCtrl | KeyCode.Enter); - test(new SimpleKeybinding(false, false, true, false, KeyCode.Enter), KeyMod.Alt | KeyCode.Enter); - test(new SimpleKeybinding(true, false, true, false, KeyCode.Enter), KeyMod.Alt | KeyMod.WinCtrl | KeyCode.Enter); - test(new SimpleKeybinding(false, true, false, false, KeyCode.Enter), KeyMod.Shift | KeyCode.Enter); - test(new SimpleKeybinding(true, true, false, false, KeyCode.Enter), KeyMod.Shift | KeyMod.WinCtrl | KeyCode.Enter); - test(new SimpleKeybinding(false, true, true, false, KeyCode.Enter), KeyMod.Shift | KeyMod.Alt | KeyCode.Enter); - test(new SimpleKeybinding(true, true, true, false, KeyCode.Enter), KeyMod.Shift | KeyMod.Alt | KeyMod.WinCtrl | KeyCode.Enter); - test(new SimpleKeybinding(false, false, false, true, KeyCode.Enter), KeyMod.CtrlCmd | KeyCode.Enter); - test(new SimpleKeybinding(true, false, false, true, KeyCode.Enter), KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.Enter); - test(new SimpleKeybinding(false, false, true, true, KeyCode.Enter), KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.Enter); - test(new SimpleKeybinding(true, false, true, true, KeyCode.Enter), KeyMod.CtrlCmd | KeyMod.Alt | KeyMod.WinCtrl | KeyCode.Enter); - test(new SimpleKeybinding(false, true, false, true, KeyCode.Enter), KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Enter); - test(new SimpleKeybinding(true, true, false, true, KeyCode.Enter), KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.WinCtrl | KeyCode.Enter); - test(new SimpleKeybinding(false, true, true, true, KeyCode.Enter), KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyCode.Enter); - test(new SimpleKeybinding(true, true, true, true, KeyCode.Enter), KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyMod.WinCtrl | KeyCode.Enter); + test(new SimpleKeybinding(false, false, false, false, KeyCode.Enter).toChord(), KeyCode.Enter); + test(new SimpleKeybinding(true, false, false, false, KeyCode.Enter).toChord(), KeyMod.WinCtrl | KeyCode.Enter); + test(new SimpleKeybinding(false, false, true, false, KeyCode.Enter).toChord(), KeyMod.Alt | KeyCode.Enter); + test(new SimpleKeybinding(true, false, true, false, KeyCode.Enter).toChord(), KeyMod.Alt | KeyMod.WinCtrl | KeyCode.Enter); + test(new SimpleKeybinding(false, true, false, false, KeyCode.Enter).toChord(), KeyMod.Shift | KeyCode.Enter); + test(new SimpleKeybinding(true, true, false, false, KeyCode.Enter).toChord(), KeyMod.Shift | KeyMod.WinCtrl | KeyCode.Enter); + test(new SimpleKeybinding(false, true, true, false, KeyCode.Enter).toChord(), KeyMod.Shift | KeyMod.Alt | KeyCode.Enter); + test(new SimpleKeybinding(true, true, true, false, KeyCode.Enter).toChord(), KeyMod.Shift | KeyMod.Alt | KeyMod.WinCtrl | KeyCode.Enter); + test(new SimpleKeybinding(false, false, false, true, KeyCode.Enter).toChord(), KeyMod.CtrlCmd | KeyCode.Enter); + test(new SimpleKeybinding(true, false, false, true, KeyCode.Enter).toChord(), KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.Enter); + test(new SimpleKeybinding(false, false, true, true, KeyCode.Enter).toChord(), KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.Enter); + test(new SimpleKeybinding(true, false, true, true, KeyCode.Enter).toChord(), KeyMod.CtrlCmd | KeyMod.Alt | KeyMod.WinCtrl | KeyCode.Enter); + test(new SimpleKeybinding(false, true, false, true, KeyCode.Enter).toChord(), KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Enter); + test(new SimpleKeybinding(true, true, false, true, KeyCode.Enter).toChord(), KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.WinCtrl | KeyCode.Enter); + test(new SimpleKeybinding(false, true, true, true, KeyCode.Enter).toChord(), KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyCode.Enter); + test(new SimpleKeybinding(true, true, true, true, KeyCode.Enter).toChord(), KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyMod.WinCtrl | KeyCode.Enter); test( new ChordKeybinding([ @@ -62,22 +62,22 @@ suite('keyCodes', () => { } test(null, 0); - test(new SimpleKeybinding(false, false, false, false, KeyCode.Enter), KeyCode.Enter); - test(new SimpleKeybinding(false, false, false, true, KeyCode.Enter), KeyMod.WinCtrl | KeyCode.Enter); - test(new SimpleKeybinding(false, false, true, false, KeyCode.Enter), KeyMod.Alt | KeyCode.Enter); - test(new SimpleKeybinding(false, false, true, true, KeyCode.Enter), KeyMod.Alt | KeyMod.WinCtrl | KeyCode.Enter); - test(new SimpleKeybinding(false, true, false, false, KeyCode.Enter), KeyMod.Shift | KeyCode.Enter); - test(new SimpleKeybinding(false, true, false, true, KeyCode.Enter), KeyMod.Shift | KeyMod.WinCtrl | KeyCode.Enter); - test(new SimpleKeybinding(false, true, true, false, KeyCode.Enter), KeyMod.Shift | KeyMod.Alt | KeyCode.Enter); - test(new SimpleKeybinding(false, true, true, true, KeyCode.Enter), KeyMod.Shift | KeyMod.Alt | KeyMod.WinCtrl | KeyCode.Enter); - test(new SimpleKeybinding(true, false, false, false, KeyCode.Enter), KeyMod.CtrlCmd | KeyCode.Enter); - test(new SimpleKeybinding(true, false, false, true, KeyCode.Enter), KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.Enter); - test(new SimpleKeybinding(true, false, true, false, KeyCode.Enter), KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.Enter); - test(new SimpleKeybinding(true, false, true, true, KeyCode.Enter), KeyMod.CtrlCmd | KeyMod.Alt | KeyMod.WinCtrl | KeyCode.Enter); - test(new SimpleKeybinding(true, true, false, false, KeyCode.Enter), KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Enter); - test(new SimpleKeybinding(true, true, false, true, KeyCode.Enter), KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.WinCtrl | KeyCode.Enter); - test(new SimpleKeybinding(true, true, true, false, KeyCode.Enter), KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyCode.Enter); - test(new SimpleKeybinding(true, true, true, true, KeyCode.Enter), KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyMod.WinCtrl | KeyCode.Enter); + test(new SimpleKeybinding(false, false, false, false, KeyCode.Enter).toChord(), KeyCode.Enter); + test(new SimpleKeybinding(false, false, false, true, KeyCode.Enter).toChord(), KeyMod.WinCtrl | KeyCode.Enter); + test(new SimpleKeybinding(false, false, true, false, KeyCode.Enter).toChord(), KeyMod.Alt | KeyCode.Enter); + test(new SimpleKeybinding(false, false, true, true, KeyCode.Enter).toChord(), KeyMod.Alt | KeyMod.WinCtrl | KeyCode.Enter); + test(new SimpleKeybinding(false, true, false, false, KeyCode.Enter).toChord(), KeyMod.Shift | KeyCode.Enter); + test(new SimpleKeybinding(false, true, false, true, KeyCode.Enter).toChord(), KeyMod.Shift | KeyMod.WinCtrl | KeyCode.Enter); + test(new SimpleKeybinding(false, true, true, false, KeyCode.Enter).toChord(), KeyMod.Shift | KeyMod.Alt | KeyCode.Enter); + test(new SimpleKeybinding(false, true, true, true, KeyCode.Enter).toChord(), KeyMod.Shift | KeyMod.Alt | KeyMod.WinCtrl | KeyCode.Enter); + test(new SimpleKeybinding(true, false, false, false, KeyCode.Enter).toChord(), KeyMod.CtrlCmd | KeyCode.Enter); + test(new SimpleKeybinding(true, false, false, true, KeyCode.Enter).toChord(), KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.Enter); + test(new SimpleKeybinding(true, false, true, false, KeyCode.Enter).toChord(), KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.Enter); + test(new SimpleKeybinding(true, false, true, true, KeyCode.Enter).toChord(), KeyMod.CtrlCmd | KeyMod.Alt | KeyMod.WinCtrl | KeyCode.Enter); + test(new SimpleKeybinding(true, true, false, false, KeyCode.Enter).toChord(), KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Enter); + test(new SimpleKeybinding(true, true, false, true, KeyCode.Enter).toChord(), KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.WinCtrl | KeyCode.Enter); + test(new SimpleKeybinding(true, true, true, false, KeyCode.Enter).toChord(), KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyCode.Enter); + test(new SimpleKeybinding(true, true, true, true, KeyCode.Enter).toChord(), KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyMod.WinCtrl | KeyCode.Enter); test( new ChordKeybinding([ diff --git a/src/vs/editor/standalone/browser/simpleServices.ts b/src/vs/editor/standalone/browser/simpleServices.ts index 42fa70cee9bccbb8186f2b99ce33e8d01bba0f06..ed2b4aea20b9bea3abbaf2cff7e00f2338fc084c 100644 --- a/src/vs/editor/standalone/browser/simpleServices.ts +++ b/src/vs/editor/standalone/browser/simpleServices.ts @@ -370,7 +370,7 @@ export class StandaloneKeybindingService extends AbstractKeybindingService { keyboardEvent.altKey, keyboardEvent.metaKey, keyboardEvent.keyCode - ); + ).toChord(); return new USLayoutResolvedKeybinding(keybinding, OS); } diff --git a/src/vs/platform/driver/electron-main/driver.ts b/src/vs/platform/driver/electron-main/driver.ts index cc6eecc1819f3b48328f1e00ac9a3a56ebc75269..3371f0ccdc26ba10dc5a269077da4a1c008d1555 100644 --- a/src/vs/platform/driver/electron-main/driver.ts +++ b/src/vs/platform/driver/electron-main/driver.ts @@ -99,7 +99,7 @@ export class Driver implements IDriver, IWindowDriverRegistry { const window = this.windowsService.getWindowById(windowId); const webContents = window.win.webContents; const noModifiedKeybinding = new SimpleKeybinding(false, false, false, false, keybinding.keyCode); - const resolvedKeybinding = new USLayoutResolvedKeybinding(noModifiedKeybinding, OS); + const resolvedKeybinding = new USLayoutResolvedKeybinding(noModifiedKeybinding.toChord(), OS); const keyCode = resolvedKeybinding.getElectronAccelerator(); const modifiers: string[] = []; diff --git a/src/vs/platform/keybinding/common/keybindingsRegistry.ts b/src/vs/platform/keybinding/common/keybindingsRegistry.ts index 02dbe001ed45f22064df7107c150258da1a0f477..c40da019374c97ad6127eb898c9bc685d542f998 100644 --- a/src/vs/platform/keybinding/common/keybindingsRegistry.ts +++ b/src/vs/platform/keybinding/common/keybindingsRegistry.ts @@ -2,8 +2,7 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ - -import { KeyCode, Keybinding, KeybindingType, SimpleKeybinding, createKeybinding } from 'vs/base/common/keyCodes'; +import { KeyCode, Keybinding, SimpleKeybinding, createKeybinding } from 'vs/base/common/keyCodes'; import { OS, OperatingSystem } from 'vs/base/common/platform'; import { CommandsRegistry, ICommandHandler, ICommandHandlerDescription } from 'vs/platform/commands/common/commands'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; @@ -199,11 +198,7 @@ class KeybindingsRegistryImpl implements IKeybindingsRegistry { private _registerDefaultKeybinding(keybinding: Keybinding, commandId: string, commandArgs: any, weight1: number, weight2: number, when: ContextKeyExpr | null | undefined, source: KeybindingRuleSource): void { if (source === KeybindingRuleSource.Core && OS === OperatingSystem.Windows) { - if (keybinding.type === KeybindingType.Chord) { - this._assertNoCtrlAlt(keybinding.parts[0], commandId); - } else { - this._assertNoCtrlAlt(keybinding, commandId); - } + this._assertNoCtrlAlt(keybinding.parts[0], commandId); } this._keybindings.push({ keybinding: keybinding, diff --git a/src/vs/platform/keybinding/common/usLayoutResolvedKeybinding.ts b/src/vs/platform/keybinding/common/usLayoutResolvedKeybinding.ts index 587e5c17fe81a3b0f2987a6ff0fe204c101e4681..338f31a295513eada0f5a7b854fa6de9fcd27f8a 100644 --- a/src/vs/platform/keybinding/common/usLayoutResolvedKeybinding.ts +++ b/src/vs/platform/keybinding/common/usLayoutResolvedKeybinding.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { KeyCode, KeyCodeUtils, Keybinding, KeybindingType, ResolvedKeybinding, ResolvedKeybindingPart, SimpleKeybinding } from 'vs/base/common/keyCodes'; +import { KeyCode, KeyCodeUtils, Keybinding, ResolvedKeybinding, ResolvedKeybindingPart, SimpleKeybinding } from 'vs/base/common/keyCodes'; import { AriaLabelProvider, ElectronAcceleratorLabelProvider, UILabelProvider, UserSettingsLabelProvider } from 'vs/base/common/keybindingLabels'; import { OperatingSystem } from 'vs/base/common/platform'; @@ -13,21 +13,15 @@ import { OperatingSystem } from 'vs/base/common/platform'; export class USLayoutResolvedKeybinding extends ResolvedKeybinding { private readonly _os: OperatingSystem; - private readonly _firstPart: SimpleKeybinding; - private readonly _chordPart: SimpleKeybinding | null; + private readonly _chords: SimpleKeybinding[]; constructor(actual: Keybinding, OS: OperatingSystem) { super(); this._os = OS; if (!actual) { throw new Error(`Invalid USLayoutResolvedKeybinding`); - } else if (actual.type === KeybindingType.Chord) { - // TODO@chords - this._firstPart = actual.parts[0]; - this._chordPart = actual.parts[1]; } else { - this._firstPart = actual; - this._chordPart = null; + this._chords = actual.parts; } } @@ -58,9 +52,9 @@ export class USLayoutResolvedKeybinding extends ResolvedKeybinding { } public getLabel(): string | null { - let firstPart = this._getUILabelForKeybinding(this._firstPart); - let chordPart = this._getUILabelForKeybinding(this._chordPart); - return UILabelProvider.toLabel(this._firstPart, firstPart, this._chordPart, chordPart, this._os); + let firstPart = this._getUILabelForKeybinding(this._chords[0]); + let chordPart = this._getUILabelForKeybinding(this._chords[1]); + return UILabelProvider.toLabel(this._chords[0], firstPart, this._chords[1], chordPart, this._os); } private _getAriaLabelForKeybinding(keybinding: SimpleKeybinding | null): string | null { @@ -74,9 +68,9 @@ export class USLayoutResolvedKeybinding extends ResolvedKeybinding { } public getAriaLabel(): string | null { - let firstPart = this._getAriaLabelForKeybinding(this._firstPart); - let chordPart = this._getAriaLabelForKeybinding(this._chordPart); - return AriaLabelProvider.toLabel(this._firstPart, firstPart, this._chordPart, chordPart, this._os); + let firstPart = this._getAriaLabelForKeybinding(this._chords[0]); + let chordPart = this._getAriaLabelForKeybinding(this._chords[1]); + return AriaLabelProvider.toLabel(this._chords[0], firstPart, this._chords[1], chordPart, this._os); } private _keyCodeToElectronAccelerator(keyCode: KeyCode): string | null { @@ -110,13 +104,13 @@ export class USLayoutResolvedKeybinding extends ResolvedKeybinding { } public getElectronAccelerator(): string | null { - if (this._chordPart !== null) { + if (this._chords.length > 1) { // Electron cannot handle chords return null; } - let firstPart = this._getElectronAcceleratorLabelForKeybinding(this._firstPart); - return ElectronAcceleratorLabelProvider.toLabel(this._firstPart, firstPart, null, null, this._os); + let firstPart = this._getElectronAcceleratorLabelForKeybinding(this._chords[0]); + return ElectronAcceleratorLabelProvider.toLabel(this._chords[0], firstPart, null, null, this._os); } private _getUserSettingsLabelForKeybinding(keybinding: SimpleKeybinding | null): string | null { @@ -130,9 +124,9 @@ export class USLayoutResolvedKeybinding extends ResolvedKeybinding { } public getUserSettingsLabel(): string | null { - let firstPart = this._getUserSettingsLabelForKeybinding(this._firstPart); - let chordPart = this._getUserSettingsLabelForKeybinding(this._chordPart); - let result = UserSettingsLabelProvider.toLabel(this._firstPart, firstPart, this._chordPart, chordPart, this._os); + let firstPart = this._getUserSettingsLabelForKeybinding(this._chords[0]); + let chordPart = this._getUserSettingsLabelForKeybinding(this._chords[1]); + let result = UserSettingsLabelProvider.toLabel(this._chords[0], firstPart, this._chords[1], chordPart, this._os); return (result ? result.toLowerCase() : result); } @@ -141,14 +135,11 @@ export class USLayoutResolvedKeybinding extends ResolvedKeybinding { } public isChord(): boolean { - return (this._chordPart ? true : false); + return this._chords.length > 1; } - public getParts(): [ResolvedKeybindingPart, ResolvedKeybindingPart | null] { - return [ - this._toResolvedKeybindingPart(this._firstPart), - this._chordPart ? this._toResolvedKeybindingPart(this._chordPart) : null - ]; + public getParts(): ResolvedKeybindingPart[] { + return this._chords.map(this._toResolvedKeybindingPart); } private _toResolvedKeybindingPart(keybinding: SimpleKeybinding): ResolvedKeybindingPart { @@ -162,10 +153,8 @@ export class USLayoutResolvedKeybinding extends ResolvedKeybinding { ); } - public getDispatchParts(): [string | null, string | null] { - let firstPart = this._firstPart ? USLayoutResolvedKeybinding.getDispatchStr(this._firstPart) : null; - let chordPart = this._chordPart ? USLayoutResolvedKeybinding.getDispatchStr(this._chordPart) : null; - return [firstPart, chordPart]; + public getDispatchParts(): string[] { + return this._chords.map((chord) => USLayoutResolvedKeybinding.getDispatchStr(chord)); } public static getDispatchStr(keybinding: SimpleKeybinding): string | null { diff --git a/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts b/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts index accb7f54d4cf07b842a158a64361a80b00750147..b79fd79c7f1517a153e1f9f3a5976368adf49ad9 100644 --- a/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts +++ b/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts @@ -61,7 +61,7 @@ suite('AbstractKeybindingService', () => { keyboardEvent.altKey, keyboardEvent.metaKey, keyboardEvent.keyCode - ); + ).toChord(); return this.resolveKeybinding(keybinding)[0]; } diff --git a/src/vs/platform/keybinding/test/common/keybindingResolver.test.ts b/src/vs/platform/keybinding/test/common/keybindingResolver.test.ts index c931a82a4238b0ff77ef447fbfe7d421d0f40115..647ee143de57979bea36588dd92eb728721f1096 100644 --- a/src/vs/platform/keybinding/test/common/keybindingResolver.test.ts +++ b/src/vs/platform/keybinding/test/common/keybindingResolver.test.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { KeyChord, KeyCode, KeyMod, KeybindingType, SimpleKeybinding, createKeybinding } from 'vs/base/common/keyCodes'; +import { KeyChord, KeyCode, KeyMod, SimpleKeybinding, createKeybinding, createSimpleKeybinding } from 'vs/base/common/keyCodes'; import { OS } from 'vs/base/common/platform'; import { ContextKeyAndExpr, ContextKeyExpr, IContext } from 'vs/platform/contextkey/common/contextkey'; import { KeybindingResolver } from 'vs/platform/keybinding/common/keybindingResolver'; @@ -37,7 +37,7 @@ suite('KeybindingResolver', () => { test('resolve key', function () { let keybinding = KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_Z; - let runtimeKeybinding = createKeybinding(keybinding, OS); + let runtimeKeybinding = createSimpleKeybinding(keybinding, OS); let contextRules = ContextKeyExpr.equals('bar', 'baz'); let keybindingItem = kbItem(keybinding, 'yes', null, contextRules, true); @@ -45,19 +45,19 @@ suite('KeybindingResolver', () => { assert.equal(KeybindingResolver.contextMatchesRules(createContext({ bar: 'bz' }), contextRules), false); let resolver = new KeybindingResolver([keybindingItem], []); - assert.equal(resolver.resolve(createContext({ bar: 'baz' }), null, getDispatchStr(runtimeKeybinding))!.commandId, 'yes'); - assert.equal(resolver.resolve(createContext({ bar: 'bz' }), null, getDispatchStr(runtimeKeybinding)), null); + assert.equal(resolver.resolve(createContext({ bar: 'baz' }), null, getDispatchStr(runtimeKeybinding))!.commandId, 'yes'); + assert.equal(resolver.resolve(createContext({ bar: 'bz' }), null, getDispatchStr(runtimeKeybinding)), null); }); test('resolve key with arguments', function () { let commandArgs = { text: 'no' }; let keybinding = KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_Z; - let runtimeKeybinding = createKeybinding(keybinding, OS); + let runtimeKeybinding = createSimpleKeybinding(keybinding, OS); let contextRules = ContextKeyExpr.equals('bar', 'baz'); let keybindingItem = kbItem(keybinding, 'yes', commandArgs, contextRules, true); let resolver = new KeybindingResolver([keybindingItem], []); - assert.equal(resolver.resolve(createContext({ bar: 'baz' }), null, getDispatchStr(runtimeKeybinding))!.commandArgs, commandArgs); + assert.equal(resolver.resolve(createContext({ bar: 'baz' }), null, getDispatchStr(runtimeKeybinding))!.commandArgs, commandArgs); }); test('KeybindingResolver.combine simple 1', function () { @@ -346,25 +346,12 @@ suite('KeybindingResolver', () => { let testResolve = (ctx: IContext, _expectedKey: number, commandId: string) => { const expectedKey = createKeybinding(_expectedKey, OS)!; - if (expectedKey.type === KeybindingType.Chord) { - // TODO@chords - let firstPart = getDispatchStr(expectedKey.parts[0]); - let chordPart = getDispatchStr(expectedKey.parts[1]); - - let result = resolver.resolve(ctx, null, firstPart)!; - assert.ok(result !== null, 'Enters chord for ' + commandId); - assert.equal(result.commandId, null, 'Enters chord for ' + commandId); - assert.equal(result.enterChord, true, 'Enters chord for ' + commandId); - - result = resolver.resolve(ctx, firstPart, chordPart)!; - assert.ok(result !== null, 'Enters chord for ' + commandId); - assert.equal(result.commandId, commandId, 'Finds chorded command ' + commandId); - assert.equal(result.enterChord, false, 'Finds chorded command ' + commandId); - } else { - let result = resolver.resolve(ctx, null, getDispatchStr(expectedKey))!; - assert.ok(result !== null, 'Finds command ' + commandId); - assert.equal(result.commandId, commandId, 'Finds command ' + commandId); - assert.equal(result.enterChord, false, 'Finds command ' + commandId); + for (let i = 0; i < expectedKey.parts.length; i++) { + let part = getDispatchStr(expectedKey.parts[i]); + let result = resolver.resolve(ctx, null, part); + assert.ok(result !== null, `Enters chord for {commandId} at index {i}`); + assert.equal(result.commandId, null, `Enters chord for {commandId} at index {i}`); + assert.equal(result.enterChord, true, `Enters chord for {commandId} at index {i}`); } }; diff --git a/src/vs/platform/keybinding/test/common/mockKeybindingService.ts b/src/vs/platform/keybinding/test/common/mockKeybindingService.ts index a4056ae0d71f33eb109b6ba14416bb85aece85fa..af0f436ca7d0703320aa0ec6ea312c6833e2d971 100644 --- a/src/vs/platform/keybinding/test/common/mockKeybindingService.ts +++ b/src/vs/platform/keybinding/test/common/mockKeybindingService.ts @@ -97,7 +97,7 @@ export class MockKeybindingService implements IKeybindingService { keyboardEvent.metaKey, keyboardEvent.keyCode ); - return this.resolveKeybinding(keybinding)[0]; + return this.resolveKeybinding(keybinding.toChord())[0]; } public resolveUserBinding(userBinding: string): ResolvedKeybinding[] { diff --git a/src/vs/workbench/services/keybinding/common/macLinuxFallbackKeyboardMapper.ts b/src/vs/workbench/services/keybinding/common/macLinuxFallbackKeyboardMapper.ts index 28f86ef5eb1dc511b4d31b9e6c0d9f39bd480d35..d30d2cfc963417b9ffbb1d766c9061a77b5a890f 100644 --- a/src/vs/workbench/services/keybinding/common/macLinuxFallbackKeyboardMapper.ts +++ b/src/vs/workbench/services/keybinding/common/macLinuxFallbackKeyboardMapper.ts @@ -40,7 +40,7 @@ export class MacLinuxFallbackKeyboardMapper implements IKeyboardMapper { keyboardEvent.metaKey, keyboardEvent.keyCode ); - return new USLayoutResolvedKeybinding(keybinding, this._OS); + return new USLayoutResolvedKeybinding(keybinding.toChord(), this._OS); } private _scanCodeToKeyCode(scanCode: ScanCode): KeyCode { @@ -120,11 +120,14 @@ export class MacLinuxFallbackKeyboardMapper implements IKeyboardMapper { public resolveUserBinding(firstPart: SimpleKeybinding | ScanCodeBinding | null, chordPart: SimpleKeybinding | ScanCodeBinding | null): ResolvedKeybinding[] { const _firstPart = this._resolveSimpleUserBinding(firstPart); const _chordPart = this._resolveSimpleUserBinding(chordPart); - if (_firstPart && _chordPart) { - return [new USLayoutResolvedKeybinding(new ChordKeybinding([_firstPart, _chordPart]), this._OS)]; - } if (_firstPart) { - return [new USLayoutResolvedKeybinding(_firstPart, this._OS)]; + let parts = [_firstPart]; + if (_chordPart) { + parts.push(_chordPart); + } + return [new USLayoutResolvedKeybinding( + new ChordKeybinding(parts), this._OS + )]; } return []; } diff --git a/src/vs/workbench/services/keybinding/common/macLinuxKeyboardMapper.ts b/src/vs/workbench/services/keybinding/common/macLinuxKeyboardMapper.ts index 743aa451f2f8a1294bb83319c52912ce69699d3d..d4efca2649545e4be88faeb56bbc9f8017d253c1 100644 --- a/src/vs/workbench/services/keybinding/common/macLinuxKeyboardMapper.ts +++ b/src/vs/workbench/services/keybinding/common/macLinuxKeyboardMapper.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { CharCode } from 'vs/base/common/charCode'; -import { KeyCode, KeyCodeUtils, Keybinding, KeybindingType, ResolvedKeybinding, ResolvedKeybindingPart, SimpleKeybinding } from 'vs/base/common/keyCodes'; +import { KeyCode, KeyCodeUtils, Keybinding, ResolvedKeybinding, ResolvedKeybindingPart, SimpleKeybinding } from 'vs/base/common/keyCodes'; import { AriaLabelProvider, ElectronAcceleratorLabelProvider, UILabelProvider, UserSettingsLabelProvider } from 'vs/base/common/keybindingLabels'; import { OperatingSystem } from 'vs/base/common/platform'; import { IMMUTABLE_CODE_TO_KEY_CODE, IMMUTABLE_KEY_CODE_TO_CODE, ScanCode, ScanCodeBinding, ScanCodeUtils } from 'vs/base/common/scanCode'; @@ -67,46 +67,44 @@ export class NativeResolvedKeybinding extends ResolvedKeybinding { private readonly _mapper: MacLinuxKeyboardMapper; private readonly _OS: OperatingSystem; - private readonly _firstPart: ScanCodeBinding; - private readonly _chordPart: ScanCodeBinding | null; + private readonly _chords: ScanCodeBinding[]; - constructor(mapper: MacLinuxKeyboardMapper, OS: OperatingSystem, firstPart: ScanCodeBinding, chordPart: ScanCodeBinding | null) { + constructor(mapper: MacLinuxKeyboardMapper, OS: OperatingSystem, chords: ScanCodeBinding[]) { super(); - if (!firstPart) { + if (chords.length === 0) { throw new Error(`Invalid USLayoutResolvedKeybinding`); } this._mapper = mapper; this._OS = OS; - this._firstPart = firstPart; - this._chordPart = chordPart; + this._chords = chords; } public getLabel(): string | null { - let firstPart = this._mapper.getUILabelForScanCodeBinding(this._firstPart); - let chordPart = this._mapper.getUILabelForScanCodeBinding(this._chordPart); - return UILabelProvider.toLabel(this._firstPart, firstPart, this._chordPart, chordPart, this._OS); + let firstPart = this._mapper.getUILabelForScanCodeBinding(this._chords[0]); + let chordPart = this._mapper.getUILabelForScanCodeBinding(this._chords[1]); + return UILabelProvider.toLabel(this._chords[0], firstPart, this._chords[1], chordPart, this._OS); } public getAriaLabel(): string | null { - let firstPart = this._mapper.getAriaLabelForScanCodeBinding(this._firstPart); - let chordPart = this._mapper.getAriaLabelForScanCodeBinding(this._chordPart); - return AriaLabelProvider.toLabel(this._firstPart, firstPart, this._chordPart, chordPart, this._OS); + let firstPart = this._mapper.getAriaLabelForScanCodeBinding(this._chords[0]); + let chordPart = this._mapper.getAriaLabelForScanCodeBinding(this._chords[1]); + return AriaLabelProvider.toLabel(this._chords[0], firstPart, this._chords[1], chordPart, this._OS); } public getElectronAccelerator(): string | null { - if (this._chordPart !== null) { + if (this._chords.length > 1) { // Electron cannot handle chords return null; } - let firstPart = this._mapper.getElectronAcceleratorLabelForScanCodeBinding(this._firstPart); - return ElectronAcceleratorLabelProvider.toLabel(this._firstPart, firstPart, null, null, this._OS); + let firstPart = this._mapper.getElectronAcceleratorLabelForScanCodeBinding(this._chords[0]); + return ElectronAcceleratorLabelProvider.toLabel(this._chords[0], firstPart, null, null, this._OS); } public getUserSettingsLabel(): string | null { - let firstPart = this._mapper.getUserSettingsLabelForScanCodeBinding(this._firstPart); - let chordPart = this._mapper.getUserSettingsLabelForScanCodeBinding(this._chordPart); - return UserSettingsLabelProvider.toLabel(this._firstPart, firstPart, this._chordPart, chordPart, this._OS); + let firstPart = this._mapper.getUserSettingsLabelForScanCodeBinding(this._chords[0]); + let chordPart = this._mapper.getUserSettingsLabelForScanCodeBinding(this._chords[1]); + return UserSettingsLabelProvider.toLabel(this._chords[0], firstPart, this._chords[1], chordPart, this._OS); } private _isWYSIWYG(binding: ScanCodeBinding | null): boolean { @@ -129,18 +127,15 @@ export class NativeResolvedKeybinding extends ResolvedKeybinding { } public isWYSIWYG(): boolean { - return (this._isWYSIWYG(this._firstPart) && this._isWYSIWYG(this._chordPart)); + return this._chords.every(this._isWYSIWYG); } public isChord(): boolean { - return (this._chordPart ? true : false); + return this._chords.length > 1; } - public getParts(): [ResolvedKeybindingPart, ResolvedKeybindingPart | null] { - return [ - this._toResolvedKeybindingPart(this._firstPart), - this._chordPart ? this._toResolvedKeybindingPart(this._chordPart) : null - ]; + public getParts(): ResolvedKeybindingPart[] { + return this._chords.map(this._toResolvedKeybindingPart); } private _toResolvedKeybindingPart(binding: ScanCodeBinding): ResolvedKeybindingPart { @@ -154,10 +149,8 @@ export class NativeResolvedKeybinding extends ResolvedKeybinding { ); } - public getDispatchParts(): [string | null, string | null] { - let firstPart = this._firstPart ? this._mapper.getDispatchStrForScanCodeBinding(this._firstPart) : null; - let chordPart = this._chordPart ? this._mapper.getDispatchStrForScanCodeBinding(this._chordPart) : null; - return [firstPart, chordPart]; + public getDispatchParts(): string[] { + return this._chords.map(this._mapper.getDispatchStrForScanCodeBinding); } } @@ -1012,32 +1005,23 @@ export class MacLinuxKeyboardMapper implements IKeyboardMapper { } public resolveKeybinding(keybinding: Keybinding): NativeResolvedKeybinding[] { - let result: NativeResolvedKeybinding[] = [], resultLen = 0; - - if (keybinding.type === KeybindingType.Chord) { - // TODO@chords - const firstParts = this.simpleKeybindingToScanCodeBinding(keybinding.parts[0]); - const chordParts = this.simpleKeybindingToScanCodeBinding(keybinding.parts[1]); - - for (let i = 0, len = firstParts.length; i < len; i++) { - const firstPart = firstParts[i]; - for (let j = 0, lenJ = chordParts.length; j < lenJ; j++) { - const chordPart = chordParts[j]; - - result[resultLen++] = new NativeResolvedKeybinding(this, this._OS, firstPart, chordPart); - } - } - } else { - const firstParts = this.simpleKeybindingToScanCodeBinding(keybinding); - - for (let i = 0, len = firstParts.length; i < len; i++) { - const firstPart = firstParts[i]; + let chordParts = keybinding.parts.map(this.simpleKeybindingToScanCodeBinding); + let result: NativeResolvedKeybinding[] = []; + this._resolveKeybindingPart(chordParts, 0, [], result); + return result; + } - result[resultLen++] = new NativeResolvedKeybinding(this, this._OS, firstPart, null); + private _resolveKeybindingPart(chordParts: ScanCodeBinding[][], currentIndex: number, previousParts: ScanCodeBinding[], result: NativeResolvedKeybinding[]) { + const chordPart = chordParts[currentIndex]; + const isFinalIndex = currentIndex === chordParts.length - 1; + for (let i = 0, len = chordPart.length; i < len; i++) { + let chords = [...previousParts, chordPart[i]]; + if (isFinalIndex) { + result.push(new NativeResolvedKeybinding(this, this._OS, chords)); + } else { + this._resolveKeybindingPart(chordParts, currentIndex + 1, chords, result); } } - - return result; } public resolveKeyboardEvent(keyboardEvent: IKeyboardEvent): NativeResolvedKeybinding { @@ -1095,7 +1079,7 @@ export class MacLinuxKeyboardMapper implements IKeyboardMapper { } const keypress = new ScanCodeBinding(keyboardEvent.ctrlKey, keyboardEvent.shiftKey, keyboardEvent.altKey, keyboardEvent.metaKey, code); - return new NativeResolvedKeybinding(this, this._OS, keypress, null); + return new NativeResolvedKeybinding(this, this._OS, [keypress]); } private _resolveSimpleUserBinding(binding: SimpleKeybinding | ScanCodeBinding | null): ScanCodeBinding[] { @@ -1109,22 +1093,15 @@ export class MacLinuxKeyboardMapper implements IKeyboardMapper { } public resolveUserBinding(_firstPart: SimpleKeybinding | ScanCodeBinding | null, _chordPart: SimpleKeybinding | ScanCodeBinding | null): ResolvedKeybinding[] { - const firstParts = this._resolveSimpleUserBinding(_firstPart); - const chordParts = this._resolveSimpleUserBinding(_chordPart); - - let result: NativeResolvedKeybinding[] = [], resultLen = 0; - for (let i = 0, len = firstParts.length; i < len; i++) { - const firstPart = firstParts[i]; - if (_chordPart) { - for (let j = 0, lenJ = chordParts.length; j < lenJ; j++) { - const chordPart = chordParts[j]; - - result[resultLen++] = new NativeResolvedKeybinding(this, this._OS, firstPart, chordPart); - } - } else { - result[resultLen++] = new NativeResolvedKeybinding(this, this._OS, firstPart, null); - } + let chordParts = []; + if (_firstPart) { + chordParts.push(this._resolveSimpleUserBinding(_firstPart)); + } + if (_chordPart) { + chordParts.push(this._resolveSimpleUserBinding(_chordPart)); } + let result: NativeResolvedKeybinding[] = []; + this._resolveKeybindingPart(chordParts, 0, [], result); return result; } diff --git a/src/vs/workbench/services/keybinding/common/windowsKeyboardMapper.ts b/src/vs/workbench/services/keybinding/common/windowsKeyboardMapper.ts index e7a4e2ab86037cd1e7f60ddf60931c62109422e7..54db9453d9767c46529343d9b79d8b72b1f7194f 100644 --- a/src/vs/workbench/services/keybinding/common/windowsKeyboardMapper.ts +++ b/src/vs/workbench/services/keybinding/common/windowsKeyboardMapper.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { CharCode } from 'vs/base/common/charCode'; -import { KeyCode, KeyCodeUtils, Keybinding, KeybindingType, ResolvedKeybinding, ResolvedKeybindingPart, SimpleKeybinding } from 'vs/base/common/keyCodes'; +import { KeyCode, KeyCodeUtils, Keybinding, ResolvedKeybinding, ResolvedKeybindingPart, SimpleKeybinding } from 'vs/base/common/keyCodes'; import { AriaLabelProvider, ElectronAcceleratorLabelProvider, UILabelProvider, UserSettingsLabelProvider } from 'vs/base/common/keybindingLabels'; import { OperatingSystem } from 'vs/base/common/platform'; import { IMMUTABLE_CODE_TO_KEY_CODE, ScanCode, ScanCodeBinding, ScanCodeUtils } from 'vs/base/common/scanCode'; @@ -79,17 +79,15 @@ export interface IScanCodeMapping { export class WindowsNativeResolvedKeybinding extends ResolvedKeybinding { private readonly _mapper: WindowsKeyboardMapper; - private readonly _firstPart: SimpleKeybinding; - private readonly _chordPart: SimpleKeybinding | null; + private readonly _parts: SimpleKeybinding[]; - constructor(mapper: WindowsKeyboardMapper, firstPart: SimpleKeybinding, chordPart: SimpleKeybinding | null) { + constructor(mapper: WindowsKeyboardMapper, parts: SimpleKeybinding[]) { super(); - if (!firstPart) { + if (parts.length === 0) { throw new Error(`Invalid WindowsNativeResolvedKeybinding firstPart`); } this._mapper = mapper; - this._firstPart = firstPart; - this._chordPart = chordPart; + this._parts = parts; } private _getUILabelForKeybinding(keybinding: SimpleKeybinding | null): string | null { @@ -103,9 +101,9 @@ export class WindowsNativeResolvedKeybinding extends ResolvedKeybinding { } public getLabel(): string | null { - let firstPart = this._getUILabelForKeybinding(this._firstPart); - let chordPart = this._getUILabelForKeybinding(this._chordPart); - return UILabelProvider.toLabel(this._firstPart, firstPart, this._chordPart, chordPart, OperatingSystem.Windows); + let firstPart = this._getUILabelForKeybinding(this._parts[0]); + let chordPart = this._getUILabelForKeybinding(this._parts[1]); + return UILabelProvider.toLabel(this._parts[0], firstPart, this._parts[1], chordPart, OperatingSystem.Windows); } private _getUSLabelForKeybinding(keybinding: SimpleKeybinding | null): string | null { @@ -119,9 +117,9 @@ export class WindowsNativeResolvedKeybinding extends ResolvedKeybinding { } public getUSLabel(): string | null { - let firstPart = this._getUSLabelForKeybinding(this._firstPart); - let chordPart = this._getUSLabelForKeybinding(this._chordPart); - return UILabelProvider.toLabel(this._firstPart, firstPart, this._chordPart, chordPart, OperatingSystem.Windows); + let firstPart = this._getUSLabelForKeybinding(this._parts[0]); + let chordPart = this._getUSLabelForKeybinding(this._parts[1]); + return UILabelProvider.toLabel(this._parts[0], firstPart, this._parts[1], chordPart, OperatingSystem.Windows); } private _getAriaLabelForKeybinding(keybinding: SimpleKeybinding | null): string | null { @@ -135,9 +133,9 @@ export class WindowsNativeResolvedKeybinding extends ResolvedKeybinding { } public getAriaLabel(): string | null { - let firstPart = this._getAriaLabelForKeybinding(this._firstPart); - let chordPart = this._getAriaLabelForKeybinding(this._chordPart); - return AriaLabelProvider.toLabel(this._firstPart, firstPart, this._chordPart, chordPart, OperatingSystem.Windows); + let firstPart = this._getAriaLabelForKeybinding(this._parts[0]); + let chordPart = this._getAriaLabelForKeybinding(this._parts[1]); + return AriaLabelProvider.toLabel(this._parts[0], firstPart, this._parts[1], chordPart, OperatingSystem.Windows); } private _keyCodeToElectronAccelerator(keyCode: KeyCode): string | null { @@ -172,13 +170,13 @@ export class WindowsNativeResolvedKeybinding extends ResolvedKeybinding { } public getElectronAccelerator(): string | null { - if (this._chordPart !== null) { + if (this._parts.length > 1) { // Electron cannot handle chords return null; } - let firstPart = this._getElectronAcceleratorLabelForKeybinding(this._firstPart); - return ElectronAcceleratorLabelProvider.toLabel(this._firstPart, firstPart, null, null, OperatingSystem.Windows); + let firstPart = this._getElectronAcceleratorLabelForKeybinding(this._parts[0]); + return ElectronAcceleratorLabelProvider.toLabel(this._parts[0], firstPart, null, null, OperatingSystem.Windows); } private _getUserSettingsLabelForKeybinding(keybinding: SimpleKeybinding | null): string | null { @@ -192,17 +190,17 @@ export class WindowsNativeResolvedKeybinding extends ResolvedKeybinding { } public getUserSettingsLabel(): string | null { - let firstPart = this._getUserSettingsLabelForKeybinding(this._firstPart); - let chordPart = this._getUserSettingsLabelForKeybinding(this._chordPart); - let result = UserSettingsLabelProvider.toLabel(this._firstPart, firstPart, this._chordPart, chordPart, OperatingSystem.Windows); + let firstPart = this._getUserSettingsLabelForKeybinding(this._parts[0]); + let chordPart = this._getUserSettingsLabelForKeybinding(this._parts[1]); + let result = UserSettingsLabelProvider.toLabel(this._parts[0], firstPart, this._parts[1], chordPart, OperatingSystem.Windows); return (result ? result.toLowerCase() : result); } public isWYSIWYG(): boolean { - if (this._firstPart && !this._isWYSIWYG(this._firstPart.keyCode)) { + if (this._parts[0] && !this._isWYSIWYG(this._parts[0].keyCode)) { return false; } - if (this._chordPart && !this._isWYSIWYG(this._chordPart.keyCode)) { + if (this._parts[1] && !this._isWYSIWYG(this._parts[1].keyCode)) { return false; } return true; @@ -223,13 +221,13 @@ export class WindowsNativeResolvedKeybinding extends ResolvedKeybinding { } public isChord(): boolean { - return (this._chordPart ? true : false); + return this._parts.length > 1; } public getParts(): [ResolvedKeybindingPart, ResolvedKeybindingPart | null] { return [ - this._toResolvedKeybindingPart(this._firstPart), - this._chordPart ? this._toResolvedKeybindingPart(this._chordPart) : null + this._toResolvedKeybindingPart(this._parts[0]), + this._parts[1] ? this._toResolvedKeybindingPart(this._parts[1]) : null ]; } @@ -244,10 +242,8 @@ export class WindowsNativeResolvedKeybinding extends ResolvedKeybinding { ); } - public getDispatchParts(): [string | null, string | null] { - let firstPart = this._firstPart ? this._getDispatchStr(this._firstPart) : null; - let chordPart = this._chordPart ? this._getDispatchStr(this._chordPart) : null; - return [firstPart, chordPart]; + public getDispatchParts(): string[] { + return this._parts.map(this._getDispatchStr); } private _getDispatchStr(keybinding: SimpleKeybinding): string | null { @@ -468,7 +464,7 @@ export class WindowsKeyboardMapper implements IKeyboardMapper { const scanCodeBinding = new ScanCodeBinding(ctrlKey, shiftKey, altKey, false, scanCode); const kb = this._resolveSimpleUserBinding(scanCodeBinding); const strKeyCode = (kb ? KeyCodeUtils.toString(kb.keyCode) : null); - const resolvedKb = (kb ? new WindowsNativeResolvedKeybinding(this, kb, null) : null); + const resolvedKb = (kb ? new WindowsNativeResolvedKeybinding(this, [kb]) : null); const outScanCode = `${ctrlKey ? 'Ctrl+' : ''}${shiftKey ? 'Shift+' : ''}${altKey ? 'Alt+' : ''}${strCode}`; const ariaLabel = (resolvedKb ? resolvedKb.getAriaLabel() : null); @@ -517,25 +513,17 @@ export class WindowsKeyboardMapper implements IKeyboardMapper { } public resolveKeybinding(keybinding: Keybinding): WindowsNativeResolvedKeybinding[] { - if (keybinding.type === KeybindingType.Chord) { - // TODO@chords - const firstPartKeyCode = keybinding.parts[0].keyCode; - const chordPartKeyCode = keybinding.parts[1].keyCode; - if (!this._keyCodeExists[firstPartKeyCode] || !this._keyCodeExists[chordPartKeyCode]) { + for (let part of keybinding.parts) { + if (!this._keyCodeExists[part.keyCode]) { return []; } - return [new WindowsNativeResolvedKeybinding(this, keybinding.parts[0], keybinding.parts[1])]; - } else { - if (!this._keyCodeExists[keybinding.keyCode]) { - return []; - } - return [new WindowsNativeResolvedKeybinding(this, keybinding, null)]; } + return [new WindowsNativeResolvedKeybinding(this, keybinding.parts)]; } public resolveKeyboardEvent(keyboardEvent: IKeyboardEvent): WindowsNativeResolvedKeybinding { const keybinding = new SimpleKeybinding(keyboardEvent.ctrlKey, keyboardEvent.shiftKey, keyboardEvent.altKey, keyboardEvent.metaKey, keyboardEvent.keyCode); - return new WindowsNativeResolvedKeybinding(this, keybinding, null); + return new WindowsNativeResolvedKeybinding(this, [keybinding]); } private _resolveSimpleUserBinding(binding: SimpleKeybinding | ScanCodeBinding | null): SimpleKeybinding | null { @@ -558,11 +546,15 @@ export class WindowsKeyboardMapper implements IKeyboardMapper { public resolveUserBinding(firstPart: SimpleKeybinding | ScanCodeBinding | null, chordPart: SimpleKeybinding | ScanCodeBinding | null): ResolvedKeybinding[] { const _firstPart = this._resolveSimpleUserBinding(firstPart); const _chordPart = this._resolveSimpleUserBinding(chordPart); - if (_firstPart && _chordPart) { - return [new WindowsNativeResolvedKeybinding(this, _firstPart, _chordPart)]; - } + let parts = []; if (_firstPart) { - return [new WindowsNativeResolvedKeybinding(this, _firstPart, null)]; + parts.push(_firstPart); + } + if (_chordPart) { + parts.push(_chordPart); + } + if (parts.length > 0) { + return [new WindowsNativeResolvedKeybinding(this, parts)]; } return []; } diff --git a/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts b/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts index 5b92b0af69ef2d8993bd45d100f64dbb1db7b88e..3dc1838bdf5c8906c55f8f034611df175086cca7 100644 --- a/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts +++ b/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts @@ -249,8 +249,15 @@ suite('KeybindingsEditing', () => { const { ctrlKey, shiftKey, altKey, metaKey } = part.modifiers || { ctrlKey: false, shiftKey: false, altKey: false, metaKey: false }; return new SimpleKeybinding(ctrlKey!, shiftKey!, altKey!, metaKey!, part.keyCode); }; - const keybinding = firstPart ? chordPart ? new ChordKeybinding([aSimpleKeybinding(firstPart), aSimpleKeybinding(chordPart)]) : aSimpleKeybinding(firstPart) : null; - return new ResolvedKeybindingItem(keybinding ? new USLayoutResolvedKeybinding(keybinding, OS) : null, command || 'some command', null, when ? ContextKeyExpr.deserialize(when) : null, isDefault === undefined ? true : isDefault); + let parts = []; + if (firstPart) { + parts.push(aSimpleKeybinding(firstPart)); + if (chordPart) { + parts.push(aSimpleKeybinding(chordPart)); + } + } + let keybinding = parts.length > 0 ? new USLayoutResolvedKeybinding(new ChordKeybinding(parts), OS) : null; + return new ResolvedKeybindingItem(keybinding, command || 'some command', null, when ? ContextKeyExpr.deserialize(when) : null, isDefault === undefined ? true : isDefault); } }); diff --git a/src/vs/workbench/services/keybinding/test/keyboardMapperTestUtils.ts b/src/vs/workbench/services/keybinding/test/keyboardMapperTestUtils.ts index 37241813bae14b03e87816fbe934f5ff394edb58..de5cf9fa26952a7ca0d4baacb21e93a37ce923b6 100644 --- a/src/vs/workbench/services/keybinding/test/keyboardMapperTestUtils.ts +++ b/src/vs/workbench/services/keybinding/test/keyboardMapperTestUtils.ts @@ -19,7 +19,7 @@ export interface IResolvedKeybinding { userSettingsLabel: string | null; isWYSIWYG: boolean; isChord: boolean; - dispatchParts: [string | null, string | null]; + dispatchParts: string[]; } function toIResolvedKeybinding(kb: ResolvedKeybinding): IResolvedKeybinding { diff --git a/src/vs/workbench/services/keybinding/test/macLinuxKeyboardMapper.test.ts b/src/vs/workbench/services/keybinding/test/macLinuxKeyboardMapper.test.ts index 544b8ae03efa297d6ab86b256186e1193beac510..b6e9c6d43a9691cfcb5553a6ef724976548650ee 100644 --- a/src/vs/workbench/services/keybinding/test/macLinuxKeyboardMapper.test.ts +++ b/src/vs/workbench/services/keybinding/test/macLinuxKeyboardMapper.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { KeyChord, KeyCode, KeyMod, SimpleKeybinding, createKeybinding } from 'vs/base/common/keyCodes'; +import { KeyChord, KeyCode, KeyMod, SimpleKeybinding, createKeybinding, createSimpleKeybinding } from 'vs/base/common/keyCodes'; import { UserSettingsLabelProvider } from 'vs/base/common/keybindingLabels'; import { OperatingSystem } from 'vs/base/common/platform'; import { ScanCode, ScanCodeBinding, ScanCodeUtils } from 'vs/base/common/scanCode'; @@ -1425,11 +1425,11 @@ function _assertKeybindingTranslation(mapper: MacLinuxKeyboardMapper, OS: Operat expected = []; } - const runtimeKeybinding = createKeybinding(kb, OS); + const runtimeKeybinding = createSimpleKeybinding(kb, OS); - const keybindingLabel = new USLayoutResolvedKeybinding(runtimeKeybinding!, OS).getUserSettingsLabel(); + const keybindingLabel = new USLayoutResolvedKeybinding(runtimeKeybinding.toChord()!, OS).getUserSettingsLabel(); - const actualHardwareKeypresses = mapper.simpleKeybindingToScanCodeBinding(runtimeKeybinding); + const actualHardwareKeypresses = mapper.simpleKeybindingToScanCodeBinding(runtimeKeybinding); if (actualHardwareKeypresses.length === 0) { assert.deepEqual([], expected, `simpleKeybindingToHardwareKeypress -- "${keybindingLabel}" -- actual: "[]" -- expected: "${expected}"`); return; diff --git a/src/vs/workbench/services/preferences/test/common/keybindingsEditorModel.test.ts b/src/vs/workbench/services/preferences/test/common/keybindingsEditorModel.test.ts index b6ab30b2d85da573e01d438d76b96d4d4c557cc6..1a500c6cb3499cf7cbdcb459aaa695d0f2dc5918 100644 --- a/src/vs/workbench/services/preferences/test/common/keybindingsEditorModel.test.ts +++ b/src/vs/workbench/services/preferences/test/common/keybindingsEditorModel.test.ts @@ -610,8 +610,21 @@ suite('KeybindingsEditorModel test', () => { const { ctrlKey, shiftKey, altKey, metaKey } = part.modifiers || { ctrlKey: false, shiftKey: false, altKey: false, metaKey: false }; return new SimpleKeybinding(ctrlKey!, shiftKey!, altKey!, metaKey!, part.keyCode); }; - const keybinding = firstPart ? chordPart ? new ChordKeybinding([aSimpleKeybinding(firstPart), aSimpleKeybinding(chordPart)]) : aSimpleKeybinding(firstPart) : null; - return new ResolvedKeybindingItem(keybinding ? new USLayoutResolvedKeybinding(keybinding, OS) : null, command || 'some command', null, when ? ContextKeyExpr.deserialize(when) : null, isDefault === undefined ? true : isDefault); + let parts = []; + if (firstPart) { + parts.push(aSimpleKeybinding(firstPart)); + } + if (chordPart) { + parts.push(aSimpleKeybinding(chordPart)); + } + let keybinding = parts.length > 0 ? new USLayoutResolvedKeybinding(new ChordKeybinding(parts), OS) : null; + return new ResolvedKeybindingItem( + keybinding, + command || 'some command', + null, + when ? ContextKeyExpr.deserialize(when) : null, + isDefault === undefined ? true : isDefault + ); } function asResolvedKeybindingItems(keybindingEntries: IKeybindingItemEntry[], keepUnassigned: boolean = false): ResolvedKeybindingItem[] {