or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

command-management.mdcommand-metadata.mdindex.mdkey-binding-system.md

key-binding-system.mddocs/

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

```