abstractKeybindingService.ts ×22

Frontier kind: Code frontier

unlabeled · c_c3687082495c

20 tests · 11661 LOC · 57 files · introduces 0 tests · 179 LOC · 2 files

Introduces — evidence that enters the hierarchy at this concept

Code
26 ranges179 lines · 2 files
Tests
0 tests

Contains — complete concept membership

All code (extent)
1643 ranges11661 lines · 57 files · Browse complete extent
All tests (intent)
20 testsBrowse complete intent

Neighbourhood graph

The orange circle is the focus. Violet and green circles are every ancestor and descendant, broader and narrower, at any distance; blue squares and pink diamonds are the introduced files and exact introduced tests of every visible concept, not only the focus's. Arrows point from broader to narrower concepts and bridge only concepts omitted from this view. Undirected links show source or test introduction. Concept and file size follows LOC; exact test nodes use test-count units.

Introduced files, introduced tests, and structurally relevant concept specialization

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the native relationship evidence on this page.

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the native relationship evidence on this page while the interactive map is unavailable.

Native relationship evidence

Every exact file and test below is linked only from the concept that introduces it.

Introduced tests

Every collected test enters the hierarchy at exactly one concept.

No tests are introduced at this concept. Its intent tests are introduced by other concepts.

Introduced code

Every collected source range enters the hierarchy at exactly one concept.

2 files ranked by introduced lines: 179 introduced LOC across 26 ranges. Expand a file to inspect source; the > gutter marks introduced lines.

src/vs/platform/keybinding/common/abstractKeybindingService.ts 151 introduced LOC · 22 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- abstractKeybindingService.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { WorkbenchActionExecutedClassification, WorkbenchActionExecutedEvent } from '../../../base/common/actions.js';
7 > import * as arrays from '../../../base/common/arrays.js';
8 > import { IntervalTimer, TimeoutTimer } from '../../../base/common/async.js';
9 > import { illegalState } from '../../../base/common/errors.js';
10 > import { Emitter, Event } from '../../../base/common/event.js';
11 > import { IME } from '../../../base/common/ime.js';
12 > import { KeyCode } from '../../../base/common/keyCodes.js';
13 > import { Keybinding, ResolvedChord, ResolvedKeybinding, SingleModifierChord } from '../../../base/common/keybindings.js';
14 > import { Disposable, IDisposable } from '../../../base/common/lifecycle.js';
15 > import * as nls from '../../../nls.js';
16 >
17 > import { ICommandService } from '../../commands/common/commands.js';
18 > import { IContextKeyService, IContextKeyServiceTarget } from '../../contextkey/common/contextkey.js';
19 > import { IKeybindingService, IKeyboardEvent, KeybindingsSchemaContribution } from './keybinding.js';
20 > import { ResolutionResult, KeybindingResolver, ResultKind, NoMatchingKb } from './keybindingResolver.js';
21 > import { ResolvedKeybindingItem } from './resolvedKeybindingItem.js';
22 > import { ILogService } from '../../log/common/log.js';
23 > import { INotificationService, IStatusHandle } from '../../notification/common/notification.js';
24 > import { ITelemetryService } from '../../telemetry/common/telemetry.js';
25 >
26 > interface CurrentChord {
27 > keypress: string;
28 > label: string | null;
29 > }
30 >
31 > const HIGH_FREQ_COMMANDS = /^(cursor|delete|undo|redo|tab|editor\.action\.clipboard)/;
32 >
33 > export abstract class AbstractKeybindingService extends Disposable implements IKeybindingService {
34 >
35 > public _serviceBrand: undefined;
36 >
37 > protected readonly _onDidUpdateKeybindings: Emitter<void> = this._register(new Emitter<void>());
38 > get onDidUpdateKeybindings(): Event<void> {
39 > return this._onDidUpdateKeybindings ? this._onDidUpdateKeybindings.event : Event.None; // Sinon stubbing walks properties on prototype
40 > }
41 >
42 > /** recently recorded keypresses that can trigger a keybinding;
43 > *
44 > * example: say, there's "cmd+k cmd+i" keybinding;
45 > * the user pressed "cmd+k" (before they press "cmd+i")
46 > * "cmd+k" would be stored in this array, when on pressing "cmd+i", the service
47 > * would invoke the command bound by the keybinding
48 > */
49 > private _currentChords: CurrentChord[];
50 >
51 > private _currentChordChecker: IntervalTimer;
52 > private _currentChordStatusMessage: IStatusHandle | null;
53 > private _ignoreSingleModifiers: KeybindingModifierSet;
54 > private _currentSingleModifier: SingleModifierChord | null;
55 > private _currentSingleModifierClearTimeout: TimeoutTimer;
56 > protected _currentlyDispatchingCommandId: string | null;
57 >
58 > protected _logging: boolean;
59 >
60 > public get inChordMode(): boolean {
61 return this._currentChords.length > 0;
62 }
64 > constructor(
65 > private _contextKeyService: IContextKeyService,
66 > protected _commandService: ICommandService,
67 > protected _telemetryService: ITelemetryService,
68 > private _notificationService: INotificationService,
69 > protected _logService: ILogService,
70 > ) {
71 > super();
72 >
73 > this._currentChords = [];
74 > this._currentChordChecker = new IntervalTimer();
75 > this._currentChordStatusMessage = null;
76 > this._ignoreSingleModifiers = KeybindingModifierSet.EMPTY;
77 > this._currentSingleModifier = null;
78 > this._currentSingleModifierClearTimeout = new TimeoutTimer();
79 > this._currentlyDispatchingCommandId = null;
80 > this._logging = false;
81 > }
82 >
83 >
84 > protected abstract _getResolver(): KeybindingResolver;
85 > protected abstract _documentHasFocus(): boolean;
86 > public abstract resolveKeybinding(keybinding: Keybinding): ResolvedKeybinding[];
87 > public abstract resolveKeyboardEvent(keyboardEvent: IKeyboardEvent): ResolvedKeybinding;
88 > public abstract resolveUserBinding(userBinding: string): ResolvedKeybinding[];
89 > public abstract registerSchemaContribution(contribution: KeybindingsSchemaContribution): IDisposable;
90 > public abstract _dumpDebugInfo(): string;
91 > public abstract _dumpDebugInfoJSON(): string;
92 >
93 > public getDefaultKeybindingsContent(): string {
94 return '';
95 }
97 > public toggleLogging(): boolean {
98 this._logging = !this._logging;
99 return this._logging;
100 }
102 > protected _log(str: string): void {
103 if (this._logging) {
104 this._logService.info(`[KeybindingService]: ${str}`);
105 }
106 }
108 > public getDefaultKeybindings(): readonly ResolvedKeybindingItem[] {
109 return this._getResolver().getDefaultKeybindings();
110 }
112 > public getKeybindings(): readonly ResolvedKeybindingItem[] {
113 return this._getResolver().getKeybindings();
114 }
116 > public customKeybindingsCount(): number {
117 return 0;
118 }
120 > public lookupKeybindings(commandId: string): ResolvedKeybinding[] {
121 return arrays.coalesce(
122 this._getResolver().lookupKeybindings(commandId).map(item => item.resolvedKeybinding)
123 );
124 }
126 > public lookupKeybinding(commandId: string, context?: IContextKeyService, enforceContextCheck = false): ResolvedKeybinding | undefined {
127 const result = this._getResolver().lookupPrimaryKeybinding(commandId, context || this._contextKeyService, enforceContextCheck);
128 if (!result) {
131 return result.resolvedKeybinding;
132 }
134 > public dispatchEvent(e: IKeyboardEvent, target: IContextKeyServiceTarget): boolean {
135 return this._dispatch(e, target);
136 }
138 > // TODO@ulugbekna: update namings to align with `_doDispatch`
139 > // TODO@ulugbekna: this fn doesn't seem to take into account single-modifier keybindings, eg `shift shift`
140 > public softDispatch(e: IKeyboardEvent, target: IContextKeyServiceTarget): ResolutionResult {
141 this._log(`/ Soft dispatching keyboard event`);
142 const keybinding = this.resolveKeyboardEvent(e);
156 return this._getResolver().resolve(contextValue, currentChords, firstChord);
157 }
159 > private _scheduleLeaveChordMode(): void {
160 const chordLastInteractedTime = Date.now();
161 this._currentChordChecker.cancelAndSet(() => {
174 }, 500);
175 }
177 > private _expectAnotherChord(firstChord: string, keypressLabel: string | null): void {
178
179 this._currentChords.push({ keypress: firstChord, label: keypressLabel });
198 }
199 }
201 > private _leaveChordMode(): void {
202 if (this._currentChordStatusMessage) {
203 this._currentChordStatusMessage.close();
208 IME.enable();
209 }
211 > public dispatchByUserSettingsLabel(userSettingsLabel: string, target: IContextKeyServiceTarget): void {
212 this._log(`/ Dispatching keybinding triggered via menu entry accelerator - ${userSettingsLabel}`);
213 const keybindings = this.resolveUserBinding(userSettingsLabel);
218 }
219 }
221 > protected _dispatch(e: IKeyboardEvent, target: IContextKeyServiceTarget): boolean {
222 return this._doDispatch(this.resolveKeyboardEvent(e), target, /*isSingleModiferChord*/false);
223 }
225 > protected _singleModifierDispatch(e: IKeyboardEvent, target: IContextKeyServiceTarget): boolean {
226 const keybinding = this.resolveKeyboardEvent(e);
227 const [singleModifier,] = keybinding.getSingleModifierDispatchChords();
276 return false;
277 }
279 > private _doDispatch(userKeypress: ResolvedKeybinding, target: IContextKeyServiceTarget, isSingleModiferChord = false): boolean {
280 let shouldPreventDefault = false;
281
382 }
383 }
385 > abstract enableKeybindingHoldMode(commandId: string): Promise<void> | undefined;
386 >
387 > mightProducePrintableCharacter(event: IKeyboardEvent): boolean {
388 if (event.ctrlKey || event.metaKey) {
389 // ignore ctrl/cmd-combination but not shift/alt-combinatios
398 return false;
399 }
401 > public appendKeybinding(label: string, commandId: string | undefined | null, context?: IContextKeyService, enforceContextCheck?: boolean): string {
402 if (commandId) {
403 const keybindingLabel = this.lookupKeybinding(commandId, context, enforceContextCheck)?.getLabel();
412 return label;
413 }
415 >
416 > class KeybindingModifierSet {
417 >
418 > public static EMPTY = new KeybindingModifierSet(null);
419 >
420 > private readonly _ctrlKey: boolean;
421 > private readonly _shiftKey: boolean;
422 > private readonly _altKey: boolean;
423 > private readonly _metaKey: boolean;
424 >
425 > constructor(source: ResolvedChord | null) {
426 > this._ctrlKey = source ? source.ctrlKey : false;
427 > this._shiftKey = source ? source.shiftKey : false;
428 > this._altKey = source ? source.altKey : false;
429 > this._metaKey = source ? source.metaKey : false;
430 > }
431 >
432 > has(modifier: SingleModifierChord) {
433 switch (modifier) {
434 case 'ctrl': return this._ctrlKey;
src/vs/base/common/ime.ts 28 introduced LOC · 4 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- ime.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { Emitter } from './event.js';
7 >
8 > export class IMEImpl {
9 >
10 > private readonly _onDidChange = new Emitter<void>();
11 > public readonly onDidChange = this._onDidChange.event;
12 >
13 > private _enabled = true;
14 >
15 > public get enabled() {
16 return this._enabled;
17 }
18 > ime.ts
19 > /**
20 > * Enable IME
21 > */
22 > public enable(): void {
23 this._enabled = true;
24 this._onDidChange.fire();
25 }
26 > ime.ts
27 > /**
28 > * Disable IME
29 > */
30 > public disable(): void {
31 this._enabled = false;
32 this._onDidChange.fire();
33 }
34 > } ime.ts
35 >
36 > export const IME = new IMEImpl();