0
# Key Binding System
1
2
Advanced keyboard shortcut system with context-aware matching, chord sequences, and platform-specific key mappings. Key bindings connect keyboard events to command execution with fine-grained control over when and where shortcuts are active.
3
4
## Capabilities
5
6
### Key Binding Registration
7
8
Add keyboard shortcuts that trigger commands in specific contexts.
9
10
```typescript { .api }
11
/**
12
* Add a key binding to the registry.
13
* @param options - The options for creating the key binding
14
* @returns A disposable which removes the added key binding
15
*/
16
addKeyBinding(options: CommandRegistry.IKeyBindingOptions): IDisposable;
17
18
/**
19
* A read-only array of the key bindings in the registry.
20
*/
21
get keyBindings(): ReadonlyArray<CommandRegistry.IKeyBinding>;
22
```
23
24
### Key Binding Options
25
26
Configuration for creating key bindings with platform-specific overrides and context matching.
27
28
```typescript { .api }
29
interface IKeyBindingOptions {
30
/** The default key sequence for the key binding (required) */
31
keys: string[];
32
33
/** The CSS selector for the key binding (required) */
34
selector: string;
35
36
/** The id of the command to execute when the binding is matched (required) */
37
command: string;
38
39
/** The arguments for the command, if necessary */
40
args?: ReadonlyPartialJSONObject;
41
42
/** The key sequence to use when running on Windows */
43
winKeys?: string[];
44
45
/** The key sequence to use when running on Mac */
46
macKeys?: string[];
47
48
/** The key sequence to use when running on Linux */
49
linuxKeys?: string[];
50
51
/** Whether to prevent default action of the keyboard events during sequence matching */
52
preventDefault?: boolean;
53
}
54
```
55
56
### Key Binding Interface
57
58
Immutable key binding object created by the registry.
59
60
```typescript { .api }
61
interface IKeyBinding {
62
/** The key sequence for the binding */
63
readonly keys: ReadonlyArray<string>;
64
65
/** The CSS selector for the binding */
66
readonly selector: string;
67
68
/** The command executed when the binding is matched */
69
readonly command: string;
70
71
/** The arguments for the command */
72
readonly args: ReadonlyPartialJSONObject;
73
74
/** Whether to prevent default action of the keyboard events during sequence matching */
75
readonly preventDefault?: boolean;
76
}
77
```
78
79
### Event Processing
80
81
Process keyboard events to match and execute key bindings.
82
83
```typescript { .api }
84
/**
85
* Process a 'keydown' event and invoke a matching key binding.
86
* @param event - The event object for a 'keydown' event
87
*/
88
processKeydownEvent(event: KeyboardEvent): void;
89
90
/**
91
* Process a 'keyup' event to clear the timer on the modifier, if it exists.
92
* @param event - The event object for a 'keyup' event
93
*/
94
processKeyupEvent(event: KeyboardEvent): void;
95
96
/**
97
* Delay the execution of any command matched against the given 'keydown' event
98
* until the permission to execute is granted.
99
* @param event - The event object for a 'keydown' event
100
* @param permission - The promise with value indicating whether to proceed with the execution
101
*/
102
holdKeyBindingExecution(event: KeyboardEvent, permission: Promise<boolean>): void;
103
```
104
105
### Keystroke Parsing and Formatting
106
107
Utilities for working with keystroke strings and keyboard events.
108
109
```typescript { .api }
110
interface IKeystrokeParts {
111
/** Whether 'Cmd' appears in the keystroke */
112
cmd: boolean;
113
114
/** Whether 'Ctrl' appears in the keystroke */
115
ctrl: boolean;
116
117
/** Whether 'Alt' appears in the keystroke */
118
alt: boolean;
119
120
/** Whether 'Shift' appears in the keystroke */
121
shift: boolean;
122
123
/** The primary key for the keystroke */
124
key: string;
125
}
126
127
/**
128
* Parse a keystroke into its constituent components.
129
* @param keystroke - The keystroke of interest
130
* @returns The parsed components of the keystroke
131
*/
132
function parseKeystroke(keystroke: string): IKeystrokeParts;
133
134
/**
135
* Normalize a keystroke into a canonical representation.
136
* @param keystroke - The keystroke of interest
137
* @returns The normalized representation of the keystroke
138
*/
139
function normalizeKeystroke(keystroke: string): string;
140
141
/**
142
* Get the platform-specific normalized keys for an options object.
143
* @param options - The options for the key binding
144
* @returns Array of combined, normalized keys
145
*/
146
function normalizeKeys(options: IKeyBindingOptions): string[];
147
148
/**
149
* Format keystrokes for display on the local system.
150
* @param keystroke - The keystrokes to format
151
* @returns The keystrokes representation
152
*/
153
function formatKeystroke(keystroke: string | readonly string[]): string;
154
155
/**
156
* Check if 'keydown' event is caused by pressing a modifier key that should be ignored.
157
* @param event - The event object for a 'keydown' event
158
* @returns true if modifier key was pressed, false otherwise
159
*/
160
function isModifierKeyPressed(event: KeyboardEvent): boolean;
161
162
/**
163
* Create a normalized keystroke for a 'keydown' event.
164
* @param event - The event object for a 'keydown' event
165
* @returns A normalized keystroke, or an empty string if the event does not represent a valid keystroke
166
*/
167
function keystrokeForKeydownEvent(event: KeyboardEvent): string;
168
```
169
170
## Usage Examples
171
172
### Basic Key Binding
173
174
```typescript
175
import { CommandRegistry } from "@lumino/commands";
176
177
const registry = new CommandRegistry();
178
179
// Add a command
180
registry.addCommand("save-file", {
181
execute: () => console.log("Saving file..."),
182
label: "Save File"
183
});
184
185
// Add a key binding
186
const binding = registry.addKeyBinding({
187
keys: ["Ctrl S"],
188
selector: "body",
189
command: "save-file"
190
});
191
192
// Set up event processing
193
document.addEventListener("keydown", (event) => {
194
registry.processKeydownEvent(event);
195
});
196
197
// Clean up
198
binding.dispose();
199
```
200
201
### Platform-Specific Key Bindings
202
203
```typescript
204
import { CommandRegistry } from "@lumino/commands";
205
206
const registry = new CommandRegistry();
207
208
registry.addCommand("copy", {
209
execute: () => console.log("Copying..."),
210
label: "Copy"
211
});
212
213
// Different key combinations for different platforms
214
registry.addKeyBinding({
215
keys: ["Ctrl C"], // Default
216
macKeys: ["Cmd C"], // Mac-specific
217
winKeys: ["Ctrl C"], // Windows-specific
218
linuxKeys: ["Ctrl C"], // Linux-specific
219
selector: ".editable",
220
command: "copy"
221
});
222
```
223
224
### Context-Sensitive Key Bindings
225
226
```typescript
227
import { CommandRegistry } from "@lumino/commands";
228
229
const registry = new CommandRegistry();
230
231
registry.addCommand("delete-item", {
232
execute: (args) => console.log("Deleting item:", args.itemId),
233
label: "Delete Item"
234
});
235
236
// Key binding only active within list containers
237
registry.addKeyBinding({
238
keys: ["Delete"],
239
selector: ".item-list .item",
240
command: "delete-item",
241
args: { context: "list" }
242
});
243
244
// Different behavior in tree views
245
registry.addKeyBinding({
246
keys: ["Delete"],
247
selector: ".tree-view .node",
248
command: "delete-item",
249
args: { context: "tree" }
250
});
251
```
252
253
### Chord Sequences
254
255
```typescript
256
import { CommandRegistry } from "@lumino/commands";
257
258
const registry = new CommandRegistry();
259
260
registry.addCommand("goto-line", {
261
execute: () => console.log("Opening goto line dialog..."),
262
label: "Go to Line"
263
});
264
265
// Multi-key chord sequence
266
registry.addKeyBinding({
267
keys: ["Ctrl G", "Ctrl L"], // Press Ctrl+G, then Ctrl+L
268
selector: ".editor",
269
command: "goto-line"
270
});
271
272
// Set up event processing with proper timing
273
document.addEventListener("keydown", (event) => {
274
registry.processKeydownEvent(event);
275
});
276
277
document.addEventListener("keyup", (event) => {
278
registry.processKeyupEvent(event);
279
});
280
```
281
282
### Keystroke Utilities
283
284
```typescript
285
import { CommandRegistry } from "@lumino/commands";
286
287
// Parse keystroke components
288
const parts = CommandRegistry.parseKeystroke("Ctrl Alt Shift F12");
289
console.log(parts); // { ctrl: true, alt: true, shift: true, cmd: false, key: "F12" }
290
291
// Normalize keystroke
292
const normalized = CommandRegistry.normalizeKeystroke("alt shift ctrl f12");
293
console.log(normalized); // "Ctrl Alt Shift F12"
294
295
// Format for display
296
const formatted = CommandRegistry.formatKeystroke(["Ctrl G", "Ctrl L"]);
297
console.log(formatted); // "Ctrl+G, Ctrl+L" (on Windows/Linux) or "⌃G, ⌃L" (on Mac)
298
299
// Handle keyboard events
300
document.addEventListener("keydown", (event) => {
301
const keystroke = CommandRegistry.keystrokeForKeydownEvent(event);
302
console.log("Keystroke:", keystroke);
303
304
if (!CommandRegistry.isModifierKeyPressed(event)) {
305
// Process non-modifier keys
306
registry.processKeydownEvent(event);
307
}
308
});
309
```
310
311
### Advanced Event Handling
312
313
```typescript
314
import { CommandRegistry } from "@lumino/commands";
315
316
const registry = new CommandRegistry();
317
318
registry.addCommand("dangerous-action", {
319
execute: () => console.log("Performing dangerous action..."),
320
label: "Dangerous Action"
321
});
322
323
registry.addKeyBinding({
324
keys: ["Ctrl Shift Delete"],
325
selector: "body",
326
command: "dangerous-action"
327
});
328
329
// Set up event processing with permission control
330
document.addEventListener("keydown", async (event) => {
331
// Hold execution pending user confirmation
332
const confirmPromise = new Promise<boolean>((resolve) => {
333
if (event.ctrlKey && event.shiftKey && event.key === "Delete") {
334
const confirmed = confirm("Are you sure you want to perform this dangerous action?");
335
resolve(confirmed);
336
} else {
337
resolve(true);
338
}
339
});
340
341
registry.holdKeyBindingExecution(event, confirmPromise);
342
registry.processKeydownEvent(event);
343
});
344
```
345
346
### Key Binding State Management
347
348
```typescript
349
import { CommandRegistry } from "@lumino/commands";
350
351
const registry = new CommandRegistry();
352
353
// Listen for key binding changes
354
registry.keyBindingChanged.connect((sender, args) => {
355
console.log(`Key binding ${args.type}:`, args.binding);
356
updateUI();
357
});
358
359
function updateUI() {
360
// Display current key bindings
361
const bindings = registry.keyBindings;
362
console.log("Current key bindings:", bindings.map(b => ({
363
keys: b.keys,
364
command: b.command,
365
selector: b.selector
366
})));
367
}
368
369
// Add key bindings
370
const binding1 = registry.addKeyBinding({
371
keys: ["F1"],
372
selector: "body",
373
command: "help"
374
});
375
376
const binding2 = registry.addKeyBinding({
377
keys: ["Escape"],
378
selector: ".modal",
379
command: "close-modal"
380
});
381
382
// Remove key bindings
383
binding1.dispose(); // Triggers keyBindingChanged signal
384
```