blob: 0e96a08c401e41280b0dec284e4980405beb2f0c [file] [log] [blame]
Blink Reformat4c46d092018-04-07 15:32:371// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
Paul Lewis9950e182019-12-16 16:06:074
Tim van der Lippeee97fa32020-04-23 15:20:565// @ts-nocheck
6// TODO(crbug.com/1011811): Enable TypeScript compiler checks
7
Paul Lewis0fd43712020-01-08 17:07:368import * as Host from '../host/host.js';
Tim van der Lippeee97fa32020-04-23 15:20:569import * as Platform from '../platform/platform.js';
Tim van der Lippeaa76aa22020-02-14 14:38:2410
Paul Lewis9950e182019-12-16 16:06:0711import {Action} from './Action.js'; // eslint-disable-line no-unused-vars
12import {ActionRegistry} from './ActionRegistry.js'; // eslint-disable-line no-unused-vars
13import {Context} from './Context.js';
14import {Dialog} from './Dialog.js';
Jack Lynch94a9b0c2020-03-11 21:45:1415import {Descriptor, KeyboardShortcut, Modifiers, Type} from './KeyboardShortcut.js'; // eslint-disable-line no-unused-vars
Paul Lewis9950e182019-12-16 16:06:0716import {isEditing} from './UIUtils.js';
17
Tim van der Lippe9c9fb122020-09-08 15:06:1718/** @type {!ShortcutRegistry} */
19let shortcutRegistryInstance;
Sigurd Schneider46da7db2020-05-20 13:45:1120
Paul Lewis9950e182019-12-16 16:06:0721export class ShortcutRegistry {
Blink Reformat4c46d092018-04-07 15:32:3722 /**
Paul Lewis9950e182019-12-16 16:06:0723 * @param {!ActionRegistry} actionRegistry
Blink Reformat4c46d092018-04-07 15:32:3724 */
Jack Lynch94a9b0c2020-03-11 21:45:1425 constructor(actionRegistry) {
Blink Reformat4c46d092018-04-07 15:32:3726 this._actionRegistry = actionRegistry;
Jack Lynch94a9b0c2020-03-11 21:45:1427 /** @type {!Platform.Multimap.<number, !KeyboardShortcut>} */
28 this._keyToShortcut = new Platform.Multimap();
29 /** @type {!Platform.Multimap.<string, !KeyboardShortcut>} */
30 this._actionToShortcut = new Platform.Multimap();
Jack Lynch966040b2020-04-23 20:11:4431 this._keyMap = new ShortcutTreeNode(0, 0);
32 /** @type {?ShortcutTreeNode} */
33 this._activePrefixKey = null;
34 /** @type {?number} */
35 this._activePrefixTimeout = null;
36 /** @type {?function():Promise<void>} */
37 this._consumePrefix = null;
Jack Lynch42297a72020-06-21 01:54:3038 /** @type {!Set.<string>} */
39 this._devToolsDefaultShortcutActions = new Set();
Jack Lynchf1f00fa2020-05-01 22:16:1240 const keybindSetSetting = self.Common.settings.moduleSetting('activeKeybindSet');
41 if (!Root.Runtime.experiments.isEnabled('customKeyboardShortcuts') &&
42 keybindSetSetting.get() !== DefaultShortcutSetting) {
43 keybindSetSetting.set(DefaultShortcutSetting);
44 }
Jack Lynch9de6dbb2020-06-04 18:22:1245 keybindSetSetting.addChangeListener(event => {
46 Host.userMetrics.keybindSetSettingChanged(event.data);
47 this._registerBindings();
48 });
Jack Lynchf1f00fa2020-05-01 22:16:1249
Jack Lynch94a9b0c2020-03-11 21:45:1450 this._registerBindings();
Blink Reformat4c46d092018-04-07 15:32:3751 }
52
53 /**
Tim van der Lippe9c9fb122020-09-08 15:06:1754 * @param {{forceNew: ?boolean, actionRegistry: ?ActionRegistry}} opts
55 */
56 static instance(opts = {forceNew: null, actionRegistry: null}) {
57 const {forceNew, actionRegistry} = opts;
58 if (!shortcutRegistryInstance || forceNew) {
59 if (!actionRegistry) {
60 throw new Error('Missing actionRegistry for shortcutRegistry');
61 }
62 shortcutRegistryInstance = new ShortcutRegistry(actionRegistry);
63 }
64
65 return shortcutRegistryInstance;
66 }
67
68 /**
Blink Reformat4c46d092018-04-07 15:32:3769 * @param {number} key
Jack Lynch966040b2020-04-23 20:11:4470 * @param {!Object.<string, function():Promise.<boolean>>=} handlers
Paul Lewis9950e182019-12-16 16:06:0771 * @return {!Array.<!Action>}
Blink Reformat4c46d092018-04-07 15:32:3772 */
Jack Lynch966040b2020-04-23 20:11:4473 _applicableActions(key, handlers = {}) {
74 let actions = [];
75 const keyMap = this._activePrefixKey || this._keyMap;
76 const keyNode = keyMap.getNode(key);
77 if (keyNode) {
78 actions = keyNode.actions();
79 }
Tim van der Lipped1a00aa2020-08-19 16:03:5680 const applicableActions = this._actionRegistry.applicableActions(actions, Context.instance());
Jack Lynch966040b2020-04-23 20:11:4481 if (keyNode) {
82 for (const actionId of Object.keys(handlers)) {
83 if (keyNode.actions().indexOf(actionId) >= 0) {
84 const action = this._actionRegistry.action(actionId);
85 if (action) {
86 applicableActions.push(action);
87 }
88 }
89 }
90 }
91 return applicableActions;
Blink Reformat4c46d092018-04-07 15:32:3792 }
93
94 /**
Jack Lynch575e9fb2020-03-26 22:20:5195 * @param {string} action
96 * @return {!Array.<!KeyboardShortcut>}
97 */
98 shortcutsForAction(action) {
99 return [...this._actionToShortcut.get(action)];
100 }
101
102 /**
Joel Einbinder67f28fb2018-08-02 00:33:47103 * @return {!Array<number>}
104 */
105 globalShortcutKeys() {
106 const keys = [];
Jack Lynch966040b2020-04-23 20:11:44107 for (const node of this._keyMap.chords().values()) {
108 const actions = node.actions();
Tim van der Lipped1a00aa2020-08-19 16:03:56109 const applicableActions = this._actionRegistry.applicableActions(actions, Context.instance());
Jack Lynch966040b2020-04-23 20:11:44110 if (applicableActions.length || node.hasChords()) {
111 keys.push(node.key());
Tim van der Lippe1d6e57a2019-09-30 11:55:34112 }
Joel Einbinder67f28fb2018-08-02 00:33:47113 }
114 return keys;
115 }
116
117 /**
Jack Lynchb8fb3c72020-04-21 05:36:16118 * @deprecated this function is obsolete and will be removed in the
119 * future along with the legacy shortcuts settings tab
120 * crbug.com/174309
121 *
Blink Reformat4c46d092018-04-07 15:32:37122 * @param {string} actionId
Tim van der Lippeaa76aa22020-02-14 14:38:24123 * @return {!Array.<!Descriptor>}
Blink Reformat4c46d092018-04-07 15:32:37124 */
125 shortcutDescriptorsForAction(actionId) {
Jack Lynchb8fb3c72020-04-21 05:36:16126 return [...this._actionToShortcut.get(actionId)].map(shortcut => shortcut.descriptors[0]);
Blink Reformat4c46d092018-04-07 15:32:37127 }
128
129 /**
130 * @param {!Array.<string>} actionIds
131 * @return {!Array.<number>}
132 */
133 keysForActions(actionIds) {
Jack Lynchb8fb3c72020-04-21 05:36:16134 const keys = actionIds.flatMap(
135 action => [...this._actionToShortcut.get(action)].flatMap(
136 shortcut => shortcut.descriptors.map(descriptor => descriptor.key)));
137 return [...(new Set(keys))];
Blink Reformat4c46d092018-04-07 15:32:37138 }
139
140 /**
141 * @param {string} actionId
142 * @return {string|undefined}
143 */
144 shortcutTitleForAction(actionId) {
Jack Lynchb8fb3c72020-04-21 05:36:16145 const shortcuts = this._actionToShortcut.get(actionId);
146 if (shortcuts.size) {
147 return shortcuts.firstValue().title();
Tim van der Lippe1d6e57a2019-09-30 11:55:34148 }
Blink Reformat4c46d092018-04-07 15:32:37149 }
150
151 /**
152 * @param {!KeyboardEvent} event
Jack Lynch966040b2020-04-23 20:11:44153 * @param {!Object.<string, function():Promise.<boolean>>=} handlers
Blink Reformat4c46d092018-04-07 15:32:37154 */
Jack Lynch966040b2020-04-23 20:11:44155 handleShortcut(event, handlers) {
156 this.handleKey(KeyboardShortcut.makeKeyFromEvent(event), event.key, event, handlers);
Blink Reformat4c46d092018-04-07 15:32:37157 }
158
159 /**
Jack Lynch42297a72020-06-21 01:54:30160 * @param {string} actionId
161 * return {boolean}
162 */
163 actionHasDefaultShortcut(actionId) {
164 return this._devToolsDefaultShortcutActions.has(actionId);
165 }
166
167 /**
Blink Reformat4c46d092018-04-07 15:32:37168 * @param {!Element} element
Jack Lynch966040b2020-04-23 20:11:44169 * @param {!Object.<string, function():Promise.<boolean>>} handlers
Blink Reformat4c46d092018-04-07 15:32:37170 */
Jack Lynch966040b2020-04-23 20:11:44171 addShortcutListener(element, handlers) {
172 // We only want keys for these specific actions to get handled this
Mathias Bynens5165a7a2020-06-10 05:51:43173 // way; all others should be allowed to bubble up.
174 const allowlistKeyMap = new ShortcutTreeNode(0, 0);
Jack Lynch966040b2020-04-23 20:11:44175 const shortcuts = Object.keys(handlers).flatMap(action => [...this._actionToShortcut.get(action)]);
176 shortcuts.forEach(shortcut => {
Mathias Bynens5165a7a2020-06-10 05:51:43177 allowlistKeyMap.addKeyMapping(shortcut.descriptors.map(descriptor => descriptor.key), shortcut.action);
Jack Lynch966040b2020-04-23 20:11:44178 });
179
Blink Reformat4c46d092018-04-07 15:32:37180 element.addEventListener('keydown', event => {
Jack Lynch966040b2020-04-23 20:11:44181 const key = KeyboardShortcut.makeKeyFromEvent(/** @type {!KeyboardEvent} */ (event));
Mathias Bynens5165a7a2020-06-10 05:51:43182 let keyMap = allowlistKeyMap;
Jack Lynch966040b2020-04-23 20:11:44183 if (this._activePrefixKey) {
184 keyMap = keyMap.getNode(this._activePrefixKey.key());
185 if (!keyMap) {
186 return;
187 }
Tim van der Lippe1d6e57a2019-09-30 11:55:34188 }
Jack Lynch966040b2020-04-23 20:11:44189 if (keyMap.getNode(key)) {
190 this.handleShortcut(/** @type {!KeyboardEvent} */ (event), handlers);
191 }
192 });
Blink Reformat4c46d092018-04-07 15:32:37193 }
194
195 /**
196 * @param {number} key
197 * @param {string} domKey
198 * @param {!KeyboardEvent=} event
Jack Lynch966040b2020-04-23 20:11:44199 * @param {!Object.<string, function():Promise.<boolean>>=} handlers
Blink Reformat4c46d092018-04-07 15:32:37200 */
Jack Lynch966040b2020-04-23 20:11:44201 async handleKey(key, domKey, event, handlers) {
Blink Reformat4c46d092018-04-07 15:32:37202 const keyModifiers = key >> 8;
Jack Lyncha0dd1f02020-05-04 23:33:35203 const hasHandlersOrPrefixKey = !!handlers || !!this._activePrefixKey;
Jack Lynch4a6f7532020-05-07 00:48:09204 const keyMapNode = this._keyMap.getNode(key);
205 const maybeHasActions = this._applicableActions(key, handlers).length > 0 || (keyMapNode && keyMapNode.hasChords());
Jack Lyncha0dd1f02020-05-04 23:33:35206 if ((!hasHandlersOrPrefixKey && isPossiblyInputKey()) || !maybeHasActions ||
Jack Lynch966040b2020-04-23 20:11:44207 KeyboardShortcut.isModifier(KeyboardShortcut.keyCodeAndModifiersFromKey(key).keyCode)) {
Blink Reformat4c46d092018-04-07 15:32:37208 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34209 }
Jack Lyncha0dd1f02020-05-04 23:33:35210 if (event) {
211 event.consume(true);
212 }
213 if (!hasHandlersOrPrefixKey && Dialog.hasInstance()) {
214 return;
215 }
Jack Lynch966040b2020-04-23 20:11:44216
217 if (this._activePrefixTimeout) {
218 clearTimeout(this._activePrefixTimeout);
219 const handled = await maybeExecuteActionForKey.call(this);
220 this._activePrefixKey = null;
221 this._activePrefixTimeout = null;
222 if (handled) {
223 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34224 }
Jack Lynch966040b2020-04-23 20:11:44225 if (this._consumePrefix) {
226 await this._consumePrefix();
227 }
228 }
Jack Lynch966040b2020-04-23 20:11:44229 if (keyMapNode && keyMapNode.hasChords()) {
Jack Lynch966040b2020-04-23 20:11:44230 this._activePrefixKey = keyMapNode;
231 this._consumePrefix = async () => {
232 this._activePrefixKey = null;
233 this._activePrefixTimeout = null;
234 await maybeExecuteActionForKey.call(this);
235 };
236 this._activePrefixTimeout = setTimeout(this._consumePrefix, KeyTimeout);
237 } else {
238 await maybeExecuteActionForKey.call(this);
Blink Reformat4c46d092018-04-07 15:32:37239 }
240
241 /**
242 * @return {boolean}
243 */
244 function isPossiblyInputKey() {
Paul Lewis9950e182019-12-16 16:06:07245 if (!event || !isEditing() || /^F\d+|Control|Shift|Alt|Meta|Escape|Win|U\+001B$/.test(domKey)) {
Blink Reformat4c46d092018-04-07 15:32:37246 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34247 }
Blink Reformat4c46d092018-04-07 15:32:37248
Tim van der Lippe1d6e57a2019-09-30 11:55:34249 if (!keyModifiers) {
Blink Reformat4c46d092018-04-07 15:32:37250 return true;
Tim van der Lippe1d6e57a2019-09-30 11:55:34251 }
Blink Reformat4c46d092018-04-07 15:32:37252
Paul Lewis9950e182019-12-16 16:06:07253 const modifiers = Modifiers;
Joel Einbindera66e5bf2018-05-31 01:26:37254 // Undo/Redo will also cause input, so textual undo should take precedence over DevTools undo when editing.
Paul Lewis0fd43712020-01-08 17:07:36255 if (Host.Platform.isMac()) {
Paul Lewis9950e182019-12-16 16:06:07256 if (KeyboardShortcut.makeKey('z', modifiers.Meta) === key) {
Joel Einbindera66e5bf2018-05-31 01:26:37257 return true;
Tim van der Lippe1d6e57a2019-09-30 11:55:34258 }
Paul Lewis9950e182019-12-16 16:06:07259 if (KeyboardShortcut.makeKey('z', modifiers.Meta | modifiers.Shift) === key) {
Joel Einbindera66e5bf2018-05-31 01:26:37260 return true;
Tim van der Lippe1d6e57a2019-09-30 11:55:34261 }
Joel Einbindera66e5bf2018-05-31 01:26:37262 } else {
Paul Lewis9950e182019-12-16 16:06:07263 if (KeyboardShortcut.makeKey('z', modifiers.Ctrl) === key) {
Joel Einbindera66e5bf2018-05-31 01:26:37264 return true;
Tim van der Lippe1d6e57a2019-09-30 11:55:34265 }
Paul Lewis9950e182019-12-16 16:06:07266 if (KeyboardShortcut.makeKey('y', modifiers.Ctrl) === key) {
Joel Einbindera66e5bf2018-05-31 01:26:37267 return true;
Tim van der Lippe1d6e57a2019-09-30 11:55:34268 }
Paul Lewis0fd43712020-01-08 17:07:36269 if (!Host.Platform.isWin() && KeyboardShortcut.makeKey('z', modifiers.Ctrl | modifiers.Shift) === key) {
Joel Einbindera66e5bf2018-05-31 01:26:37270 return true;
Tim van der Lippe1d6e57a2019-09-30 11:55:34271 }
Joel Einbindera66e5bf2018-05-31 01:26:37272 }
273
Tim van der Lippe1d6e57a2019-09-30 11:55:34274 if ((keyModifiers & (modifiers.Ctrl | modifiers.Alt)) === (modifiers.Ctrl | modifiers.Alt)) {
Paul Lewis0fd43712020-01-08 17:07:36275 return Host.Platform.isWin();
Tim van der Lippe1d6e57a2019-09-30 11:55:34276 }
Blink Reformat4c46d092018-04-07 15:32:37277
278 return !hasModifier(modifiers.Ctrl) && !hasModifier(modifiers.Alt) && !hasModifier(modifiers.Meta);
279 }
280
281 /**
282 * @param {number} mod
283 * @return {boolean}
284 */
285 function hasModifier(mod) {
286 return !!(keyModifiers & mod);
287 }
Jack Lynch966040b2020-04-23 20:11:44288
289 /**
290 * @return {!Promise.<boolean>};
291 * @this {!ShortcutRegistry}
292 */
293 async function maybeExecuteActionForKey() {
294 const actions = this._applicableActions(key, handlers);
295 if (!actions.length) {
296 return false;
297 }
Jack Lynch966040b2020-04-23 20:11:44298 for (const action of actions) {
299 let handled;
300 if (handlers && handlers[action.id()]) {
301 handled = await handlers[action.id()]();
302 }
303 if (!handlers) {
304 handled = await action.execute();
305 }
306 if (handled) {
307 Host.userMetrics.keyboardShortcutFired(action.id());
308 return true;
309 }
310 }
311 return false;
312 }
Blink Reformat4c46d092018-04-07 15:32:37313 }
314
315 /**
Jack Lynch94a9b0c2020-03-11 21:45:14316 * @param {!KeyboardShortcut} shortcut
Blink Reformat4c46d092018-04-07 15:32:37317 */
Jack Lynch94a9b0c2020-03-11 21:45:14318 _registerShortcut(shortcut) {
319 this._actionToShortcut.set(shortcut.action, shortcut);
Jack Lynch966040b2020-04-23 20:11:44320 this._keyMap.addKeyMapping(shortcut.descriptors.map(descriptor => descriptor.key), shortcut.action);
Blink Reformat4c46d092018-04-07 15:32:37321 }
322
Jack Lynch94a9b0c2020-03-11 21:45:14323 _registerBindings() {
Jack Lynchf1f00fa2020-05-01 22:16:12324 this._keyToShortcut.clear();
325 this._actionToShortcut.clear();
326 this._keyMap.clear();
327 const keybindSet = self.Common.settings.moduleSetting('activeKeybindSet').get();
Blink Reformat4c46d092018-04-07 15:32:37328 const extensions = self.runtime.extensions('action');
Jack Lynch10d70552020-06-10 20:30:36329 const forwardedKeys = [];
Blink Reformat4c46d092018-04-07 15:32:37330 extensions.forEach(registerExtension, this);
Jack Lynch10d70552020-06-10 20:30:36331 Host.InspectorFrontendHost.InspectorFrontendHostInstance.setWhitelistedShortcuts(JSON.stringify(forwardedKeys));
Blink Reformat4c46d092018-04-07 15:32:37332
333 /**
Tim van der Lippe99e59b82019-09-30 20:00:59334 * @param {!Root.Runtime.Extension} extension
Tim van der Lippe0830b3d2019-10-03 13:20:07335 * @this {ShortcutRegistry}
Blink Reformat4c46d092018-04-07 15:32:37336 */
337 function registerExtension(extension) {
338 const descriptor = extension.descriptor();
Jack Lynch94a9b0c2020-03-11 21:45:14339 const bindings = descriptor.bindings;
Blink Reformat4c46d092018-04-07 15:32:37340 for (let i = 0; bindings && i < bindings.length; ++i) {
Jack Lynchf1f00fa2020-05-01 22:16:12341 const keybindSets = bindings[i].keybindSets;
342 if (!platformMatches(bindings[i].platform) || !keybindSetsMatch(keybindSets)) {
Blink Reformat4c46d092018-04-07 15:32:37343 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:34344 }
Jack Lynch966040b2020-04-23 20:11:44345 const keys = bindings[i].shortcut.split(/\s+/);
346 const shortcutDescriptors = keys.map(KeyboardShortcut.makeDescriptorFromBindingShortcut);
347 if (shortcutDescriptors.length > 0) {
Jack Lynchf1f00fa2020-05-01 22:16:12348 const actionId = /** @type {string} */ (descriptor.actionId);
Jack Lynch10d70552020-06-10 20:30:36349 if (ForwardedActions.has(actionId)) {
350 forwardedKeys.push(
351 ...shortcutDescriptors.map(shortcut => KeyboardShortcut.keyCodeAndModifiersFromKey(shortcut.key)));
352 }
Jack Lynchf1f00fa2020-05-01 22:16:12353 if (!keybindSets) {
Jack Lynch42297a72020-06-21 01:54:30354 this._devToolsDefaultShortcutActions.add(actionId);
Jack Lynchf1f00fa2020-05-01 22:16:12355 this._registerShortcut(new KeyboardShortcut(shortcutDescriptors, actionId, Type.DefaultShortcut));
356 } else {
Jack Lynch42297a72020-06-21 01:54:30357 if (keybindSets.includes(DefaultShortcutSetting)) {
358 this._devToolsDefaultShortcutActions.add(actionId);
359 }
Jack Lynchf1f00fa2020-05-01 22:16:12360 this._registerShortcut(
Jack Lynch42297a72020-06-21 01:54:30361 new KeyboardShortcut(shortcutDescriptors, actionId, Type.KeybindSetShortcut, new Set(keybindSets)));
Jack Lynchf1f00fa2020-05-01 22:16:12362 }
Jack Lynchf0d14242020-04-07 22:42:04363 }
Blink Reformat4c46d092018-04-07 15:32:37364 }
365 }
366
367 /**
368 * @param {string=} platformsString
369 * @return {boolean}
370 */
371 function platformMatches(platformsString) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34372 if (!platformsString) {
Blink Reformat4c46d092018-04-07 15:32:37373 return true;
Tim van der Lippe1d6e57a2019-09-30 11:55:34374 }
Blink Reformat4c46d092018-04-07 15:32:37375 const platforms = platformsString.split(',');
376 let isMatch = false;
Paul Lewis0fd43712020-01-08 17:07:36377 const currentPlatform = Host.Platform.platform();
Tim van der Lippe1d6e57a2019-09-30 11:55:34378 for (let i = 0; !isMatch && i < platforms.length; ++i) {
Blink Reformat4c46d092018-04-07 15:32:37379 isMatch = platforms[i] === currentPlatform;
Tim van der Lippe1d6e57a2019-09-30 11:55:34380 }
Blink Reformat4c46d092018-04-07 15:32:37381 return isMatch;
382 }
Jack Lynchf1f00fa2020-05-01 22:16:12383
384 /**
385 * @param {!Array<string>=} keybindSets
386 */
387 function keybindSetsMatch(keybindSets) {
388 if (!keybindSets) {
389 return true;
390 }
391 return keybindSets.includes(keybindSet);
392 }
Blink Reformat4c46d092018-04-07 15:32:37393 }
Tim van der Lippe0830b3d2019-10-03 13:20:07394}
Blink Reformat4c46d092018-04-07 15:32:37395
Jack Lynch966040b2020-04-23 20:11:44396export class ShortcutTreeNode {
397 /**
398 * @param {number} key
399 * @param {number=} depth
400 */
401 constructor(key, depth = 0) {
402 this._key = key;
403 /** @type {!Array.<string>} */
404 this._actions = [];
405 this._chords = new Map();
406 this._depth = depth;
407 }
408
409 /**
410 * @param {string} action
411 */
412 addAction(action) {
413 this._actions.push(action);
414 }
415
416 /**
417 * @return {number}
418 */
419 key() {
420 return this._key;
421 }
422
423 /**
424 * @return {!Map.<number, !ShortcutTreeNode>}
425 */
426 chords() {
427 return this._chords;
428 }
429
430 /**
431 * @return {boolean}
432 */
433 hasChords() {
434 return this._chords.size > 0;
435 }
436
437 /**
438 * @param {!Array.<number>} keys
439 * @param {string} action
440 */
441 addKeyMapping(keys, action) {
442 if (keys.length < this._depth) {
443 return;
444 }
445
446 if (keys.length === this._depth) {
447 this.addAction(action);
448 } else {
449 const key = keys[this._depth];
450 if (!this._chords.has(key)) {
451 this._chords.set(key, new ShortcutTreeNode(key, this._depth + 1));
452 }
453 this._chords.get(key).addKeyMapping(keys, action);
454 }
455 }
456
457 /**
458 * @param {number} key
459 * @return {?ShortcutTreeNode}
460 */
461 getNode(key) {
462 return this._chords.get(key) || null;
463 }
464
465 /**
466 * @return {!Array.<string>}
467 */
468 actions() {
469 return this._actions;
470 }
Jack Lynchf1f00fa2020-05-01 22:16:12471
472 clear() {
473 this._actions = [];
474 this._chords = new Map();
475 }
Jack Lynch966040b2020-04-23 20:11:44476}
477
Sigurd Schneider46da7db2020-05-20 13:45:11478
Tim van der Lippe0830b3d2019-10-03 13:20:07479export class ForwardedShortcut {}
Blink Reformat4c46d092018-04-07 15:32:37480
Tim van der Lippe0830b3d2019-10-03 13:20:07481ForwardedShortcut.instance = new ForwardedShortcut();
Jack Lynch966040b2020-04-23 20:11:44482
Jack Lynch10d70552020-06-10 20:30:36483export const ForwardedActions = new Set([
484 'main.toggle-dock', 'debugger.toggle-breakpoints-active', 'debugger.toggle-pause', 'commandMenu.show', 'console.show'
485]);
Jack Lynch966040b2020-04-23 20:11:44486export const KeyTimeout = 1000;
Jack Lynchf1f00fa2020-05-01 22:16:12487export const DefaultShortcutSetting = 'devToolsDefault';