Skip to content

Commit 411d8d0

Browse files
committed
Prepare KeybindingService for dispatching based on code
1 parent 0f927b7 commit 411d8d0

18 files changed

Lines changed: 166 additions & 85 deletions

File tree

src/vs/base/browser/keyboardEvent.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,11 +174,12 @@ export interface IKeyboardEvent {
174174
readonly altKey: boolean;
175175
readonly metaKey: boolean;
176176
readonly keyCode: KeyCode;
177+
readonly code: string;
177178

178179
/**
179180
* @internal
180181
*/
181-
toRuntimeKeybinding(): SimpleKeybinding;
182+
toKeybinding(): SimpleKeybinding;
182183
equals(keybinding: number): boolean;
183184

184185
preventDefault(): void;
@@ -200,6 +201,7 @@ export class StandardKeyboardEvent implements IKeyboardEvent {
200201
public readonly altKey: boolean;
201202
public readonly metaKey: boolean;
202203
public readonly keyCode: KeyCode;
204+
public readonly code: string;
203205

204206
private _asKeybinding: number;
205207
private _asRuntimeKeybinding: SimpleKeybinding;
@@ -215,6 +217,7 @@ export class StandardKeyboardEvent implements IKeyboardEvent {
215217
this.altKey = e.altKey;
216218
this.metaKey = e.metaKey;
217219
this.keyCode = extractKeyCode(e);
220+
this.code = e.code;
218221

219222
// console.info(e.type + ": keyCode: " + e.keyCode + ", which: " + e.which + ", charCode: " + e.charCode + ", detail: " + e.detail + " ====> " + this.keyCode + ' -- ' + KeyCode[this.keyCode]);
220223

@@ -241,7 +244,7 @@ export class StandardKeyboardEvent implements IKeyboardEvent {
241244
}
242245
}
243246

244-
public toRuntimeKeybinding(): SimpleKeybinding {
247+
public toKeybinding(): SimpleKeybinding {
245248
return this._asRuntimeKeybinding;
246249
}
247250

src/vs/base/parts/tree/browser/treeDefaults.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ export class DefaultController implements _.IController {
264264
}
265265

266266
private onKey(bindings: KeybindingDispatcher, tree: _.ITree, event: IKeyboardEvent): boolean {
267-
var handler = bindings.dispatch(event.toRuntimeKeybinding());
267+
var handler = bindings.dispatch(event.toKeybinding());
268268
if (handler) {
269269
if (handler(tree, event)) {
270270
event.preventDefault();

src/vs/editor/browser/standalone/simpleServices.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { ICommandService, ICommand, ICommandEvent, ICommandHandler, CommandsRegi
1414
import { AbstractKeybindingService } from 'vs/platform/keybinding/common/abstractKeybindingService';
1515
import { USLayoutResolvedKeybinding } from 'vs/platform/keybinding/common/usLayoutResolvedKeybinding';
1616
import { KeybindingResolver } from 'vs/platform/keybinding/common/keybindingResolver';
17-
import { IKeybindingEvent, KeybindingSource } from 'vs/platform/keybinding/common/keybinding';
17+
import { IKeybindingEvent, KeybindingSource, IKeyboardEvent } from 'vs/platform/keybinding/common/keybinding';
1818
import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
1919
import { IConfirmation, IMessageService } from 'vs/platform/message/common/message';
2020
import * as editorCommon from 'vs/editor/common/editorCommon';
@@ -32,7 +32,7 @@ import { KeybindingsRegistry, IKeybindingItem } from 'vs/platform/keybinding/com
3232
import { MenuId, IMenu, IMenuService } from 'vs/platform/actions/common/actions';
3333
import { Menu } from 'vs/platform/actions/common/menu';
3434
import { ITelemetryService, ITelemetryExperiments, ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry';
35-
import { ResolvedKeybinding, Keybinding, createKeybinding } from 'vs/base/common/keyCodes';
35+
import { ResolvedKeybinding, Keybinding, createKeybinding, SimpleKeybinding } from 'vs/base/common/keyCodes';
3636
import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem';
3737
import { OS } from 'vs/base/common/platform';
3838

@@ -323,7 +323,7 @@ export class StandaloneKeybindingService extends AbstractKeybindingService {
323323

324324
this.toDispose.push(dom.addDisposableListener(domNode, dom.EventType.KEY_DOWN, (e: KeyboardEvent) => {
325325
let keyEvent = new StandardKeyboardEvent(e);
326-
let shouldPreventDefault = this._dispatch(keyEvent.toRuntimeKeybinding(), keyEvent.target);
326+
let shouldPreventDefault = this._dispatch(keyEvent, keyEvent.target);
327327
if (shouldPreventDefault) {
328328
keyEvent.preventDefault();
329329
}
@@ -387,18 +387,28 @@ export class StandaloneKeybindingService extends AbstractKeybindingService {
387387
const item = items[i];
388388
const when = (item.when ? item.when.normalize() : null);
389389
const keybinding = item.keybinding;
390-
const resolvedKeybinding = (keybinding ? this._createResolvedKeybinding(keybinding) : null);
390+
const resolvedKeybinding = (keybinding ? this.resolveKeybinding(keybinding) : null);
391391

392392
result[resultLen++] = new ResolvedKeybindingItem(resolvedKeybinding, item.command, item.commandArgs, when, isDefault);
393393
}
394394

395395
return result;
396396
}
397397

398-
protected _createResolvedKeybinding(kb: Keybinding): ResolvedKeybinding {
398+
public resolveKeybinding(kb: Keybinding): ResolvedKeybinding {
399399
return new USLayoutResolvedKeybinding(kb, OS);
400400
}
401401

402+
public resolveKeyboardEvent(keyboardEvent: IKeyboardEvent): ResolvedKeybinding {
403+
let keybinding = new SimpleKeybinding(
404+
keyboardEvent.ctrlKey,
405+
keyboardEvent.shiftKey,
406+
keyboardEvent.altKey,
407+
keyboardEvent.metaKey,
408+
keyboardEvent.keyCode
409+
);
410+
return this.resolveKeybinding(keybinding);
411+
}
402412
}
403413

404414
export class SimpleConfigurationService implements IConfigurationService {

src/vs/editor/contrib/suggest/test/common/suggestModel.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@ import { MockCodeEditor, MockScopeLocation } from 'vs/editor/test/common/mocks/m
1717
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
1818
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
1919
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
20-
import { MockKeybindingService } from 'vs/platform/keybinding/test/common/mockKeybindingService';
20+
import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService';
2121
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
2222
import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils';
2323

2424
function createMockEditor(model: Model): MockCodeEditor {
25-
const contextKeyService = new MockKeybindingService();
25+
const contextKeyService = new MockContextKeyService();
2626
const telemetryService = NullTelemetryService;
2727
const instantiationService = new InstantiationService(new ServiceCollection(
2828
[IContextKeyService, contextKeyService],

src/vs/editor/test/browser/standalone/simpleServices.test.ts

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,14 @@ import { ContextKeyService } from 'vs/platform/contextkey/browser/contextKeyServ
99
import { SimpleConfigurationService, SimpleMessageService, StandaloneKeybindingService, StandaloneCommandService } from 'vs/editor/browser/standalone/simpleServices';
1010
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
1111
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
12-
import { KeyCode, SimpleKeybinding } from 'vs/base/common/keyCodes';
13-
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
12+
import { KeyCode } from 'vs/base/common/keyCodes';
13+
import { IKeyboardEvent } from "vs/platform/keybinding/common/keybinding";
1414

1515
suite('StandaloneKeybindingService', () => {
1616

1717
class TestStandaloneKeybindingService extends StandaloneKeybindingService {
18-
public dispatch(e: IKeyboardEvent): void {
19-
let shouldPreventDefault = super._dispatch(e.toRuntimeKeybinding(), e.target);
20-
if (shouldPreventDefault) {
21-
e.preventDefault();
22-
}
18+
public testDispatch(e: IKeyboardEvent): void {
19+
super._dispatch(e, null);
2320
}
2421
}
2522

@@ -45,9 +42,13 @@ suite('StandaloneKeybindingService', () => {
4542
commandInvoked = true;
4643
}, null);
4744

48-
keybindingService.dispatch(<any>{
49-
toRuntimeKeybinding: () => new SimpleKeybinding(false, false, false, false, KeyCode.F9),
50-
preventDefault: () => { }
45+
keybindingService.testDispatch({
46+
ctrlKey: false,
47+
shiftKey: false,
48+
altKey: false,
49+
metaKey: false,
50+
keyCode: KeyCode.F9,
51+
code: null
5152
});
5253

5354
assert.ok(commandInvoked, 'command invoked');

src/vs/editor/test/common/mocks/mockCodeEditor.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { EventEmitter, IEventEmitter } from 'vs/base/common/eventEmitter';
88
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
99
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
1010
import { IContextKeyService, IContextKeyServiceTarget } from 'vs/platform/contextkey/common/contextkey';
11-
import { MockKeybindingService } from 'vs/platform/keybinding/test/common/mockKeybindingService';
11+
import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService';
1212
import { CommonCodeEditor } from 'vs/editor/common/commonCodeEditor';
1313
import { CommonEditorConfiguration } from 'vs/editor/common/config/commonEditorConfig';
1414
import { Cursor } from 'vs/editor/common/controller/cursor';
@@ -87,7 +87,7 @@ export function withMockCodeEditor(text: string[], options: editorCommon.ICodeEd
8787

8888
export function mockCodeEditor(text: string[], options: editorCommon.ICodeEditorWidgetCreationOptions): CommonCodeEditor {
8989

90-
let contextKeyService = new MockKeybindingService();
90+
let contextKeyService = new MockContextKeyService();
9191

9292
let services = new ServiceCollection();
9393
services.set(IContextKeyService, contextKeyService);

src/vs/monaco.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,7 @@ declare module monaco {
380380
readonly altKey: boolean;
381381
readonly metaKey: boolean;
382382
readonly keyCode: KeyCode;
383+
readonly code: string;
383384
equals(keybinding: number): boolean;
384385
preventDefault(): void;
385386
stopPropagation(): void;

src/vs/platform/actions/test/common/menuService.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
99
import { MenuService } from 'vs/platform/actions/common/menuService';
1010
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
1111
import { NullCommandService } from 'vs/platform/commands/common/commands';
12-
import { MockKeybindingService } from 'vs/platform/keybinding/test/common/mockKeybindingService';
12+
import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService';
1313
import { AbstractExtensionService, ActivatedExtension } from 'vs/platform/extensions/common/abstractExtensionService';
1414

1515
// --- service instances
@@ -26,7 +26,7 @@ const extensionService = new class extends AbstractExtensionService<ActivatedExt
2626
}
2727
}(true);
2828

29-
const contextKeyService = new class extends MockKeybindingService {
29+
const contextKeyService = new class extends MockContextKeyService {
3030
contextMatchesRules() {
3131
return true;
3232
}

src/vs/platform/keybinding/common/abstractKeybindingService.ts

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@
55
'use strict';
66

77
import * as nls from 'vs/nls';
8-
import { ResolvedKeybinding, Keybinding, SimpleKeybinding } from 'vs/base/common/keyCodes';
8+
import { ResolvedKeybinding, Keybinding } from 'vs/base/common/keyCodes';
99
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
1010
import Severity from 'vs/base/common/severity';
1111
import { ICommandService } from 'vs/platform/commands/common/commands';
1212
import { KeybindingResolver, IResolveResult } from 'vs/platform/keybinding/common/keybindingResolver';
13-
import { IKeybindingEvent, IKeybindingService, IKeybindingItem2, KeybindingSource } from 'vs/platform/keybinding/common/keybinding';
13+
import { IKeybindingEvent, IKeybindingService, IKeybindingItem2, KeybindingSource, IKeyboardEvent } from 'vs/platform/keybinding/common/keybinding';
1414
import { IContextKeyService, IContextKeyServiceTarget } from 'vs/platform/contextkey/common/contextkey';
1515
import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar';
1616
import { IMessageService } from 'vs/platform/message/common/message';
@@ -56,16 +56,13 @@ export abstract class AbstractKeybindingService implements IKeybindingService {
5656
this.toDispose = dispose(this.toDispose);
5757
}
5858

59-
protected abstract _getResolver(): KeybindingResolver;
60-
protected abstract _createResolvedKeybinding(kb: Keybinding): ResolvedKeybinding;
61-
6259
get onDidUpdateKeybindings(): Event<IKeybindingEvent> {
6360
return this._onDidUpdateKeybindings ? this._onDidUpdateKeybindings.event : Event.None; // Sinon stubbing walks properties on prototype
6461
}
6562

66-
public resolveKeybinding(keybinding: Keybinding): ResolvedKeybinding {
67-
return this._createResolvedKeybinding(keybinding);
68-
}
63+
protected abstract _getResolver(): KeybindingResolver;
64+
public abstract resolveKeybinding(keybinding: Keybinding): ResolvedKeybinding;
65+
public abstract resolveKeyboardEvent(keyboardEvent: IKeyboardEvent): ResolvedKeybinding;
6966

7067
public getDefaultKeybindings(): string {
7168
return '';
@@ -96,32 +93,40 @@ export abstract class AbstractKeybindingService implements IKeybindingService {
9693
return result.resolvedKeybinding;
9794
}
9895

99-
public resolve(keybinding: SimpleKeybinding, target: IContextKeyServiceTarget): IResolveResult {
100-
if (keybinding.isModifierKey()) {
96+
public softDispatch(e: IKeyboardEvent, target: IContextKeyServiceTarget): IResolveResult {
97+
const keybinding = this.resolveKeyboardEvent(e);
98+
if (keybinding.isChord()) {
99+
console.warn('Unexpected keyboard event mapped to a chord');
100+
return null;
101+
}
102+
const [firstPart,] = keybinding.getDispatchParts();
103+
if (firstPart === null) {
104+
// cannot be dispatched, probably only modifier keys
101105
return null;
102106
}
103107

104108
const contextValue = this._contextKeyService.getContextValue(target);
105109
const currentChord = this._currentChord ? this._currentChord.keypress : null;
106-
const resolvedKeybinding = this._createResolvedKeybinding(keybinding);
107-
const [firstPart,] = resolvedKeybinding.getDispatchParts();
108-
// We know for a fact the chordPart is null since we're using a single keypress
109110
return this._getResolver().resolve(contextValue, currentChord, firstPart);
110111
}
111112

112-
protected _dispatch(keybinding: SimpleKeybinding, target: IContextKeyServiceTarget): boolean {
113-
// Check modifier key here and cancel early, it's also checked in resolve as the function
114-
// is used externally.
113+
protected _dispatch(e: IKeyboardEvent, target: IContextKeyServiceTarget): boolean {
115114
let shouldPreventDefault = false;
116-
if (keybinding.isModifierKey()) {
115+
116+
const keybinding = this.resolveKeyboardEvent(e);
117+
if (keybinding.isChord()) {
118+
console.warn('Unexpected keyboard event mapped to a chord');
119+
return null;
120+
}
121+
const [firstPart,] = keybinding.getDispatchParts();
122+
if (firstPart === null) {
123+
// cannot be dispatched, probably only modifier keys
117124
return shouldPreventDefault;
118125
}
119126

120127
const contextValue = this._contextKeyService.getContextValue(target);
121128
const currentChord = this._currentChord ? this._currentChord.keypress : null;
122-
const resolvedKeybinding = this._createResolvedKeybinding(keybinding);
123-
const [firstPart,] = resolvedKeybinding.getDispatchParts();
124-
const keypressLabel = resolvedKeybinding.getLabel();
129+
const keypressLabel = keybinding.getLabel();
125130
const resolveResult = this._getResolver().resolve(contextValue, currentChord, firstPart);
126131

127132
if (resolveResult && resolveResult.enterChord) {

src/vs/platform/keybinding/common/keybinding.ts

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*--------------------------------------------------------------------------------------------*/
55
'use strict';
66

7-
import { ResolvedKeybinding, Keybinding, SimpleKeybinding } from 'vs/base/common/keyCodes';
7+
import { ResolvedKeybinding, Keybinding, KeyCode } from 'vs/base/common/keyCodes';
88
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
99
import { ContextKeyExpr, IContextKeyServiceTarget } from 'vs/platform/contextkey/common/contextkey';
1010
import { IResolveResult } from 'vs/platform/keybinding/common/keybindingResolver';
@@ -34,6 +34,15 @@ export interface IKeybindingEvent {
3434
keybindings?: IUserFriendlyKeybinding[];
3535
}
3636

37+
export interface IKeyboardEvent {
38+
readonly ctrlKey: boolean;
39+
readonly shiftKey: boolean;
40+
readonly altKey: boolean;
41+
readonly metaKey: boolean;
42+
readonly keyCode: KeyCode;
43+
readonly code: string;
44+
}
45+
3746
export let IKeybindingService = createDecorator<IKeybindingService>('keybindingService');
3847

3948
export interface IKeybindingService {
@@ -43,9 +52,12 @@ export interface IKeybindingService {
4352

4453
resolveKeybinding(keybinding: Keybinding): ResolvedKeybinding;
4554

46-
getDefaultKeybindings(): string;
55+
resolveKeyboardEvent(keyboardEvent: IKeyboardEvent): ResolvedKeybinding;
4756

48-
getKeybindings(): IKeybindingItem2[];
57+
/**
58+
* Resolve and dispatch `keyboardEvent`, but do not invoke the command or change inner state.
59+
*/
60+
softDispatch(keyboardEvent: IKeyboardEvent, target: IContextKeyServiceTarget): IResolveResult;
4961

5062
/**
5163
* Look up keybindings for a command.
@@ -59,8 +71,10 @@ export interface IKeybindingService {
5971
*/
6072
lookupKeybinding(commandId: string): ResolvedKeybinding;
6173

62-
customKeybindingsCount(): number;
74+
getDefaultKeybindings(): string;
6375

64-
resolve(keybinding: SimpleKeybinding, target: IContextKeyServiceTarget): IResolveResult;
76+
getKeybindings(): IKeybindingItem2[];
77+
78+
customKeybindingsCount(): number;
6579
}
6680

0 commit comments

Comments
 (0)