abstractKeybindingService.ts 6.7 KB
Newer Older
E
Erich Gamma 已提交
1 2 3 4 5 6
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
'use strict';

7
import * as nls from 'vs/nls';
8
import { ResolvedKeybinding, Keybinding } from 'vs/base/common/keyCodes';
J
Johannes Rieken 已提交
9
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
E
Erich Gamma 已提交
10
import Severity from 'vs/base/common/severity';
A
Alex Dima 已提交
11
import { ICommandService } from 'vs/platform/commands/common/commands';
12
import { KeybindingResolver, IResolveResult } from 'vs/platform/keybinding/common/keybindingResolver';
13
import { IKeybindingEvent, IKeybindingService, IKeyboardEvent } from 'vs/platform/keybinding/common/keybinding';
D
Daniel Imms 已提交
14
import { IContextKeyService, IContextKeyServiceTarget } from 'vs/platform/contextkey/common/contextkey';
J
Johannes Rieken 已提交
15 16 17
import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar';
import { IMessageService } from 'vs/platform/message/common/message';
import Event, { Emitter } from 'vs/base/common/event';
18
import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem';
19
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
A
Alex Dima 已提交
20

21 22 23 24 25
interface CurrentChord {
	keypress: string;
	label: string;
}

26
export abstract class AbstractKeybindingService implements IKeybindingService {
A
Alex Dima 已提交
27 28
	public _serviceBrand: any;

29
	protected toDispose: IDisposable[] = [];
B
Benjamin Pasero 已提交
30

31
	private _currentChord: CurrentChord;
32
	private _currentChordStatusMessage: IDisposable;
33
	protected _onDidUpdateKeybindings: Emitter<IKeybindingEvent>;
A
Alex Dima 已提交
34

35
	private _contextKeyService: IContextKeyService;
36
	private _statusService: IStatusbarService;
37
	private _messageService: IMessageService;
38 39
	protected _commandService: ICommandService;
	protected _telemetryService: ITelemetryService;
E
Erich Gamma 已提交
40

A
Alex Dima 已提交
41
	constructor(
42
		contextKeyService: IContextKeyService,
A
Alex Dima 已提交
43
		commandService: ICommandService,
44
		telemetryService: ITelemetryService,
A
Alex Dima 已提交
45 46 47
		messageService: IMessageService,
		statusService?: IStatusbarService
	) {
48
		this._contextKeyService = contextKeyService;
A
Alex Dima 已提交
49
		this._commandService = commandService;
J
Johannes Rieken 已提交
50
		this._telemetryService = telemetryService;
A
Alex Dima 已提交
51 52
		this._statusService = statusService;
		this._messageService = messageService;
53

A
Alex Dima 已提交
54
		this._currentChord = null;
55
		this._currentChordStatusMessage = null;
C
Christof Marti 已提交
56
		this._onDidUpdateKeybindings = new Emitter<IKeybindingEvent>();
57
		this.toDispose.push(this._onDidUpdateKeybindings);
A
Alex Dima 已提交
58
	}
59

A
Alex Dima 已提交
60
	public dispose(): void {
61
		this.toDispose = dispose(this.toDispose);
62
	}
63

C
Christof Marti 已提交
64
	get onDidUpdateKeybindings(): Event<IKeybindingEvent> {
65 66 67
		return this._onDidUpdateKeybindings ? this._onDidUpdateKeybindings.event : Event.None; // Sinon stubbing walks properties on prototype
	}

68
	protected abstract _getResolver(): KeybindingResolver;
69
	public abstract resolveKeybinding(keybinding: Keybinding): ResolvedKeybinding[];
70
	public abstract resolveKeyboardEvent(keyboardEvent: IKeyboardEvent): ResolvedKeybinding;
71
	public abstract resolveUserBinding(userBinding: string): ResolvedKeybinding[];
72

S
Sandeep Somavarapu 已提交
73
	public getDefaultKeybindingsContent(): string {
A
Alex Dima 已提交
74
		return '';
E
Erich Gamma 已提交
75 76
	}

S
Sandeep Somavarapu 已提交
77 78 79 80
	public getDefaultKeybindings(): ResolvedKeybindingItem[] {
		return this._getResolver().getDefaultKeybindings();
	}

81 82
	public getKeybindings(): ResolvedKeybindingItem[] {
		return this._getResolver().getKeybindings();
83 84
	}

85 86 87 88
	public customKeybindingsCount(): number {
		return 0;
	}

89
	public lookupKeybindings(commandId: string): ResolvedKeybinding[] {
90
		return this._getResolver().lookupKeybindings(commandId).map(item => item.resolvedKeybinding);
91 92 93 94 95 96 97
	}

	public lookupKeybinding(commandId: string): ResolvedKeybinding {
		let result = this._getResolver().lookupPrimaryKeybinding(commandId);
		if (!result) {
			return null;
		}
98
		return result.resolvedKeybinding;
99 100
	}

101 102 103 104 105 106 107 108 109
	public softDispatch(e: IKeyboardEvent, target: IContextKeyServiceTarget): IResolveResult {
		const keybinding = this.resolveKeyboardEvent(e);
		if (keybinding.isChord()) {
			console.warn('Unexpected keyboard event mapped to a chord');
			return null;
		}
		const [firstPart,] = keybinding.getDispatchParts();
		if (firstPart === null) {
			// cannot be dispatched, probably only modifier keys
110
			return null;
E
Erich Gamma 已提交
111 112
		}

J
Joao Moreno 已提交
113
		const contextValue = this._contextKeyService.getContext(target);
114
		const currentChord = this._currentChord ? this._currentChord.keypress : null;
115
		return this._getResolver().resolve(contextValue, currentChord, firstPart);
D
Daniel Imms 已提交
116 117
	}

118
	protected _dispatch(e: IKeyboardEvent, target: IContextKeyServiceTarget): boolean {
119
		let shouldPreventDefault = false;
120 121 122 123 124 125 126 127 128

		const keybinding = this.resolveKeyboardEvent(e);
		if (keybinding.isChord()) {
			console.warn('Unexpected keyboard event mapped to a chord');
			return null;
		}
		const [firstPart,] = keybinding.getDispatchParts();
		if (firstPart === null) {
			// cannot be dispatched, probably only modifier keys
129
			return shouldPreventDefault;
D
Daniel Imms 已提交
130
		}
E
Erich Gamma 已提交
131

J
Joao Moreno 已提交
132
		const contextValue = this._contextKeyService.getContext(target);
133
		const currentChord = this._currentChord ? this._currentChord.keypress : null;
134
		const keypressLabel = keybinding.getLabel();
135
		const resolveResult = this._getResolver().resolve(contextValue, currentChord, firstPart);
D
Daniel Imms 已提交
136 137

		if (resolveResult && resolveResult.enterChord) {
138
			shouldPreventDefault = true;
139
			this._currentChord = {
140
				keypress: firstPart,
141 142
				label: keypressLabel
			};
143
			if (this._statusService) {
144
				this._currentChordStatusMessage = this._statusService.setStatusMessage(nls.localize('first.chord', "({0}) was pressed. Waiting for second key of chord...", keypressLabel));
E
Erich Gamma 已提交
145
			}
146
			return shouldPreventDefault;
E
Erich Gamma 已提交
147 148
		}

149
		if (this._statusService && this._currentChord) {
E
Erich Gamma 已提交
150
			if (!resolveResult || !resolveResult.commandId) {
151
				this._statusService.setStatusMessage(nls.localize('missing.chord', "The key combination ({0}, {1}) is not a command.", this._currentChord.label, keypressLabel), 10 * 1000 /* 10s */);
152
				shouldPreventDefault = true;
E
Erich Gamma 已提交
153 154 155 156 157 158
			}
		}
		if (this._currentChordStatusMessage) {
			this._currentChordStatusMessage.dispose();
			this._currentChordStatusMessage = null;
		}
A
Alex Dima 已提交
159
		this._currentChord = null;
E
Erich Gamma 已提交
160 161

		if (resolveResult && resolveResult.commandId) {
162
			if (!resolveResult.bubble) {
163
				shouldPreventDefault = true;
E
Erich Gamma 已提交
164
			}
165
			this._commandService.executeCommand(resolveResult.commandId, resolveResult.commandArgs || {}).done(undefined, err => {
E
Erich Gamma 已提交
166 167
				this._messageService.show(Severity.Warning, err);
			});
168 169 170 171 172 173 174
			/* __GDPR__
				"workbenchActionExecuted" : {
					"id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
					"from": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
				}
			*/
			this._telemetryService.publicLog('workbenchActionExecuted', { id: resolveResult.commandId, from: 'keybinding' });
E
Erich Gamma 已提交
175
		}
176 177

		return shouldPreventDefault;
E
Erich Gamma 已提交
178
	}
179
}