@tanstack/hotkeys 0.15.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/_keyboard-event.js +19 -3
- package/dist/_manager-ref.js +10 -0
- package/dist/_match.js +9 -1
- package/dist/_recorder-chord.js +10 -6
- package/dist/_registration.js +8 -5
- package/dist/adapter.d.ts +53 -6
- package/dist/adapter.js +45 -3
- package/dist/app-hotkeys.d.ts +11 -8
- package/dist/app-hotkeys.js +13 -7
- package/dist/conflicts.js +9 -8
- package/dist/constants.d.ts +1 -24
- package/dist/constants.js +21 -83
- package/dist/format.d.ts +13 -9
- package/dist/format.js +12 -28
- package/dist/hint.js +2 -2
- package/dist/hotkey-manager.d.ts +94 -11
- package/dist/hotkey-manager.js +231 -78
- package/dist/hotkey-recorder.d.ts +44 -4
- package/dist/hotkey-recorder.js +9 -5
- package/dist/hotkey.types.d.ts +72 -46
- package/dist/index.d.ts +6 -7
- package/dist/index.js +3 -3
- package/dist/key-state-tracker.js +36 -31
- package/dist/match.d.ts +19 -18
- package/dist/match.js +26 -40
- package/dist/parse.d.ts +36 -73
- package/dist/parse.js +58 -151
- package/dist/validate.js +8 -24
- package/package.json +1 -1
- package/dist/recorder-options.d.ts +0 -34
package/dist/hotkey.types.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ import { CanonicalModifier, Key, LogicalKey } from "./key.types.js";
|
|
|
11
11
|
* This enables cross-platform hotkey definitions that automatically adapt to the platform.
|
|
12
12
|
* For example, `Mod+S` becomes `Command+S` on Mac and `Ctrl+S` on Windows/Linux.
|
|
13
13
|
*/
|
|
14
|
-
export type
|
|
14
|
+
export type SingleModifierHotkeyChord = `Control+${Key}` | `Alt+${Key}` | `Shift+${Key}` | `Meta+${Key}` | `Mod+${Key}`;
|
|
15
15
|
/**
|
|
16
16
|
* Two modifier + key combinations.
|
|
17
17
|
*
|
|
@@ -21,7 +21,7 @@ export type SingleModifierHotkey = `Control+${Key}` | `Alt+${Key}` | `Shift+${Ke
|
|
|
21
21
|
* - `Mod+Control` duplicates `Control` on Windows/Linux (Mod = Control)
|
|
22
22
|
* - `Mod+Meta` duplicates `Meta` on macOS (Mod = Meta)
|
|
23
23
|
*/
|
|
24
|
-
export type
|
|
24
|
+
export type TwoModifierHotkeyChord = `Control+Alt+${Key}` | `Control+Shift+${Key}` | `Control+Meta+${Key}` | `Alt+Shift+${Key}` | `Alt+Meta+${Key}` | `Shift+Meta+${Key}` | `Mod+Alt+${Key}` | `Mod+Shift+${Key}`;
|
|
25
25
|
/**
|
|
26
26
|
* Three modifier + key combinations.
|
|
27
27
|
*
|
|
@@ -31,7 +31,7 @@ export type TwoModifierHotkey = `Control+Alt+${Key}` | `Control+Shift+${Key}` |
|
|
|
31
31
|
* - `Mod+Control+Shift` duplicates `Control` on Windows/Linux (Mod = Control)
|
|
32
32
|
* - `Mod+Shift+Meta` duplicates `Meta` on macOS (Mod = Meta)
|
|
33
33
|
*/
|
|
34
|
-
export type
|
|
34
|
+
export type ThreeModifierHotkeyChord = `Control+Alt+Shift+${Key}` | `Control+Alt+Meta+${Key}` | `Control+Shift+Meta+${Key}` | `Alt+Shift+Meta+${Key}` | `Mod+Alt+Shift+${Key}`;
|
|
35
35
|
/**
|
|
36
36
|
* Four modifier + key combinations.
|
|
37
37
|
*
|
|
@@ -44,7 +44,7 @@ export type ThreeModifierHotkey = `Control+Alt+Shift+${Key}` | `Control+Alt+Meta
|
|
|
44
44
|
* - `Mod+Control+Alt+Shift` → duplicates `Control` on Windows/Linux
|
|
45
45
|
* - `Mod+Alt+Shift+Meta` → duplicates `Meta` on macOS
|
|
46
46
|
*/
|
|
47
|
-
export type
|
|
47
|
+
export type FourModifierHotkeyChord = `Control+Alt+Shift+Meta+${Key}`;
|
|
48
48
|
/**
|
|
49
49
|
* A type-safe hotkey string.
|
|
50
50
|
*
|
|
@@ -97,7 +97,7 @@ export type FourModifierHotkey = `Control+Alt+Shift+Meta+${Key}`;
|
|
|
97
97
|
* const windowsOnly: HotkeyChord = 'Control+S' // Ctrl+S on Windows/Linux only
|
|
98
98
|
* ```
|
|
99
99
|
*/
|
|
100
|
-
export type HotkeyChord = Key |
|
|
100
|
+
export type HotkeyChord = Key | SingleModifierHotkeyChord | TwoModifierHotkeyChord | ThreeModifierHotkeyChord | FourModifierHotkeyChord;
|
|
101
101
|
/** Resolved modifier flags shared by both parsed binding variants. */
|
|
102
102
|
export interface ParsedModifiers {
|
|
103
103
|
/** Whether Control is required. */
|
|
@@ -112,31 +112,41 @@ export interface ParsedModifiers {
|
|
|
112
112
|
modifiers: Array<CanonicalModifier>;
|
|
113
113
|
}
|
|
114
114
|
/**
|
|
115
|
-
* A parsed
|
|
115
|
+
* A parsed chord matches either a logical key or a physical code, never both.
|
|
116
116
|
* Check `code !== undefined` to narrow to a physical binding. Its logical
|
|
117
117
|
* character is unknown without a keyboard event and is not stored in `key`.
|
|
118
118
|
*
|
|
119
119
|
* @example
|
|
120
120
|
* parseHotkey('Alt+S') // { key: 'S', alt: true, ... }
|
|
121
|
-
* parseHotkey('Alt+[KeyS]') // { code: 'KeyS', alt: true, ... }
|
|
121
|
+
* parseHotkey('Alt+[KeyS]') // { code: 'KeyS', alt: true, ... } with no key property
|
|
122
122
|
*/
|
|
123
|
-
export type
|
|
123
|
+
export type ParsedHotkeyChord = ParsedModifiers & ({
|
|
124
124
|
key: LogicalKey | (string & {});
|
|
125
125
|
code?: never;
|
|
126
126
|
} | {
|
|
127
127
|
code: string;
|
|
128
128
|
key?: never;
|
|
129
129
|
});
|
|
130
|
+
/** Modifier flags shared by logical-key and physical-code registrations. */
|
|
131
|
+
export interface RawModifiers {
|
|
132
|
+
/** Platform-adaptive modifier: Command on macOS, Control on Windows/Linux. Defaults to false. */
|
|
133
|
+
mod?: boolean;
|
|
134
|
+
/** Whether the Control key is required. Defaults to false. */
|
|
135
|
+
ctrl?: boolean;
|
|
136
|
+
/** Whether the Shift key is required. Defaults to false. */
|
|
137
|
+
shift?: boolean;
|
|
138
|
+
/** Whether the Alt key is required. Defaults to false. */
|
|
139
|
+
alt?: boolean;
|
|
140
|
+
/** Whether the Meta (Command) key is required. Defaults to false. */
|
|
141
|
+
meta?: boolean;
|
|
142
|
+
}
|
|
130
143
|
/**
|
|
131
|
-
* A
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
* and with optional modifier booleans (default to `false` when omitted).
|
|
135
|
-
* Use with `HotkeyManager.register()` and `useHotkey()` when you prefer
|
|
136
|
-
* object form over a string.
|
|
144
|
+
* A chord written as an object instead of a string, for building chords from
|
|
145
|
+
* data. Set `key` for a logical key or `code` for a physical one, and set a
|
|
146
|
+
* boolean for each modifier. Omitted modifiers default to `false`.
|
|
137
147
|
*
|
|
138
148
|
* The `mod` modifier is platform-adaptive: Command on macOS, Control on Windows/Linux.
|
|
139
|
-
*
|
|
149
|
+
* Sequence steps can be objects too: `[{ key: 'K', mod: true }, 'C']`.
|
|
140
150
|
*
|
|
141
151
|
* @example
|
|
142
152
|
* ```ts
|
|
@@ -149,21 +159,7 @@ export type ParsedHotkey = ParsedModifiers & ({
|
|
|
149
159
|
* useHotkey({ code: 'NumpadAdd', mod: true }, handler) // Physical numpad plus
|
|
150
160
|
* ```
|
|
151
161
|
*/
|
|
152
|
-
|
|
153
|
-
export interface RawModifiers {
|
|
154
|
-
/** The non-modifier key (e.g., 'S', 'Escape', 'F1'). */
|
|
155
|
-
/** Platform-adaptive modifier: Command on macOS, Control on Windows/Linux. Defaults to false. */
|
|
156
|
-
mod?: boolean;
|
|
157
|
-
/** Whether the Control key is required. Defaults to false. */
|
|
158
|
-
ctrl?: boolean;
|
|
159
|
-
/** Whether the Shift key is required. Defaults to false. */
|
|
160
|
-
shift?: boolean;
|
|
161
|
-
/** Whether the Alt key is required. Defaults to false. */
|
|
162
|
-
alt?: boolean;
|
|
163
|
-
/** Whether the Meta (Command) key is required. Defaults to false. */
|
|
164
|
-
meta?: boolean;
|
|
165
|
-
}
|
|
166
|
-
export type RawHotkey = ({
|
|
162
|
+
export type RawHotkeyChord = ({
|
|
167
163
|
key: LogicalKey | (string & {});
|
|
168
164
|
code?: never;
|
|
169
165
|
} & RawModifiers) | ({
|
|
@@ -171,7 +167,9 @@ export type RawHotkey = ({
|
|
|
171
167
|
key?: never;
|
|
172
168
|
} & RawModifiers);
|
|
173
169
|
/**
|
|
174
|
-
* A sequence of
|
|
170
|
+
* A sequence of chord strings pressed one after another (Vim-style), such as
|
|
171
|
+
* `['G', 'G']`. Registered sequences are stored in this form. To register
|
|
172
|
+
* steps written as objects, see {@link RegisterableHotkeySequence}.
|
|
175
173
|
*
|
|
176
174
|
* Steps may include modifiers; the same modifier can appear on consecutive
|
|
177
175
|
* steps (e.g. `['Shift+R', 'Shift+T']`). Modifier-only key events do not
|
|
@@ -183,36 +181,64 @@ export type HotkeySequence = ReadonlyArray<HotkeyChord>;
|
|
|
183
181
|
* A hotkey: one chord (`'Mod+S'`) or a sequence of chords (`['G', 'G']`).
|
|
184
182
|
*/
|
|
185
183
|
export type Hotkey = HotkeyChord | HotkeySequence;
|
|
186
|
-
/** A single chord as a type-safe string (`HotkeyChord`) or
|
|
187
|
-
export type RegisterableHotkeyChord = HotkeyChord |
|
|
184
|
+
/** A single chord as a type-safe string (`HotkeyChord`) or an object (`RawHotkeyChord`). */
|
|
185
|
+
export type RegisterableHotkeyChord = HotkeyChord | RawHotkeyChord;
|
|
188
186
|
/**
|
|
189
|
-
*
|
|
187
|
+
* A sequence whose steps are chord strings or chord objects, such as
|
|
188
|
+
* `['G', { key: 'H', shift: true }]`.
|
|
190
189
|
*/
|
|
191
|
-
export type
|
|
190
|
+
export type RegisterableHotkeySequence = ReadonlyArray<RegisterableHotkeyChord>;
|
|
192
191
|
/**
|
|
193
|
-
*
|
|
192
|
+
* Anything that can be registered: a chord or a sequence, with each chord
|
|
193
|
+
* written as a string or an object.
|
|
194
194
|
*/
|
|
195
|
-
export
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
195
|
+
export type RegisterableHotkey = RegisterableHotkeyChord | RegisterableHotkeySequence;
|
|
196
|
+
/** Context passed to a chord's callback. */
|
|
197
|
+
export interface HotkeyChordCallbackContext {
|
|
198
|
+
kind: 'chord';
|
|
199
|
+
/** The registered chord */
|
|
200
|
+
hotkey: HotkeyChord;
|
|
201
|
+
/** The chord with `Mod` resolved for the registration's platform */
|
|
202
|
+
parsedChord: ParsedHotkeyChord;
|
|
203
|
+
}
|
|
204
|
+
/** Context passed to a sequence's callback. */
|
|
205
|
+
export interface HotkeySequenceCallbackContext {
|
|
206
|
+
kind: 'sequence';
|
|
207
|
+
/** The registered sequence */
|
|
208
|
+
hotkey: HotkeySequence;
|
|
209
|
+
/** Each step with `Mod` resolved for the registration's platform */
|
|
210
|
+
parsedSequence: Array<ParsedHotkeyChord>;
|
|
200
211
|
}
|
|
212
|
+
/**
|
|
213
|
+
* Context passed to hotkey callbacks along with the keyboard event.
|
|
214
|
+
* Narrow with `kind` to read `parsedChord` or `parsedSequence`.
|
|
215
|
+
*/
|
|
216
|
+
export type HotkeyCallbackContext = HotkeyChordCallbackContext | HotkeySequenceCallbackContext;
|
|
217
|
+
/**
|
|
218
|
+
* The callback context for a hotkey: chord context for chords (including
|
|
219
|
+
* one-step tuples), sequence context for sequences, and either when the kind
|
|
220
|
+
* is not known statically.
|
|
221
|
+
*/
|
|
222
|
+
export type HotkeyCallbackContextFor<T extends RegisterableHotkey> = [T] extends [never] ? HotkeyCallbackContext : T extends readonly [RegisterableHotkeyChord] ? HotkeyChordCallbackContext : T extends RegisterableHotkeySequence ? HotkeySequenceCallbackContext : HotkeyChordCallbackContext;
|
|
201
223
|
/**
|
|
202
224
|
* Callback function type for hotkey handlers.
|
|
203
225
|
*
|
|
204
226
|
* @param event - The keyboard event that triggered the hotkey
|
|
205
|
-
* @param context -
|
|
227
|
+
* @param context - The registered hotkey and its parsed form. APIs that take
|
|
228
|
+
* one hotkey narrow it to chord or sequence context from the hotkey you pass.
|
|
206
229
|
*
|
|
207
230
|
* @example
|
|
208
231
|
* ```ts
|
|
209
|
-
* const handler: HotkeyCallback = (event,
|
|
210
|
-
*
|
|
211
|
-
*
|
|
232
|
+
* const handler: HotkeyCallback = (event, context) => {
|
|
233
|
+
* if (context.kind === 'chord') {
|
|
234
|
+
* console.log(context.hotkey, context.parsedChord.modifiers)
|
|
235
|
+
* } else {
|
|
236
|
+
* console.log(context.hotkey.join(' '), context.parsedSequence.length)
|
|
237
|
+
* }
|
|
212
238
|
* }
|
|
213
239
|
* ```
|
|
214
240
|
*/
|
|
215
|
-
export type HotkeyCallback = (event: KeyboardEvent, context:
|
|
241
|
+
export type HotkeyCallback<TContext extends HotkeyCallbackContext = HotkeyCallbackContext> = (event: KeyboardEvent, context: TContext) => void;
|
|
216
242
|
/**
|
|
217
243
|
* Metadata for hotkey registrations, chords and sequences alike.
|
|
218
244
|
* Includes `name`, `description`, and `group` by default. Extend via declaration merging:
|
package/dist/index.d.ts
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import { CanonicalModifier, EditingKey, FunctionKey, IndividualKey, Key, LetterKey, LogicalKey, Modifier, NamedKey, NavigationKey, NonPunctuationKey, NormalizedKeyboardEvent, NumberKey, PhysicalKey, PhysicalKeyCode, PunctuationKey } from "./key.types.js";
|
|
2
|
-
import { ConflictBehavior,
|
|
3
|
-
import { HotkeyChordOptions, HotkeyChordRegistration, HotkeyChordRegistrationView, HotkeyManager, HotkeyOptions, HotkeyOptionsFor, HotkeyRegistration, HotkeyRegistrationHandle, HotkeyRegistrationView, HotkeySequenceOptions, HotkeySequenceRegistration, HotkeySequenceRegistrationView, Target, getHotkeyManager, toHotkeyRegistrationView } from "./hotkey-manager.js";
|
|
2
|
+
import { ConflictBehavior, FourModifierHotkeyChord, Hotkey, HotkeyCallback, HotkeyCallbackContext, HotkeyCallbackContextFor, HotkeyChord, HotkeyChordCallbackContext, HotkeyMeta, HotkeySequence, HotkeySequenceCallbackContext, ParsedHotkeyChord, ParsedModifiers, RawHotkeyChord, RawModifiers, RegisterableHotkey, RegisterableHotkeyChord, RegisterableHotkeySequence, SingleModifierHotkeyChord, ThreeModifierHotkeyChord, TwoModifierHotkeyChord } from "./hotkey.types.js";
|
|
3
|
+
import { ActivateHotkeyScopeOptions, HotkeyChordOptions, HotkeyChordRegistration, HotkeyChordRegistrationView, HotkeyManager, HotkeyOptions, HotkeyOptionsFor, HotkeyRegistration, HotkeyRegistrationHandle, HotkeyRegistrationView, HotkeyScopesState, HotkeySequenceOptions, HotkeySequenceRegistration, HotkeySequenceRegistrationView, Target, getHotkeyManager, toHotkeyRegistrationView } from "./hotkey-manager.js";
|
|
4
4
|
import { AppHotkey, AppHotkeyChordOptions, AppHotkeyDefaultKind, AppHotkeyId, AppHotkeyInput, AppHotkeyListItem, AppHotkeyOptions, AppHotkeySequenceOptions, AppHotkeyStatus, AppHotkeys, AppHotkeysState, AppHotkeysStore, AppHotkeysStoreOptions, CustomHotkeys, DefinedAppHotkeys, Register, RegisteredAppHotkeys, defineAppHotkeys, getAppHotkeyRegistrationOptions, isAppHotkey, isCustomHotkey, provideAppHotkeys, publishAppHotkeysStore, resolveAppHotkey } from "./app-hotkeys.js";
|
|
5
5
|
import { ALL_KEYS, EDITING_KEYS, FUNCTION_KEYS, LETTER_KEYS, MODIFIER_ALIASES, MODIFIER_KEYS, MODIFIER_ORDER, NAVIGATION_KEYS, NUMBER_KEYS, PUNCTUATION_CODE_MAP, PUNCTUATION_KEYS, isSingleLetterKey, normalizeKeyName } from "./constants.js";
|
|
6
6
|
import { KEY_DISPLAY_SYMBOLS, LINUX_MODIFIER_LABELS, MAC_MODIFIER_LABELS, MAC_MODIFIER_SYMBOLS, PUNCTUATION_KEY_DISPLAY_LABELS, WINDOWS_MODIFIER_LABELS } from "./display-labels.js";
|
|
7
7
|
import { detectPlatform, resolveModifier } from "./platform.js";
|
|
8
8
|
import { DisplayHotkey, DisplayHotkeyChord, FormatDisplayOptions, formatForDisplay, formatHotkey } from "./format.js";
|
|
9
|
-
import { hasNonModifierKey, isHotkeySequence, isModifierKey, normalizeHotkey,
|
|
9
|
+
import { hasNonModifierKey, isHotkeySequence, isModifierKey, normalizeHotkey, parseHotkey, parseKeyboardEvent, simplifyHotkey } from "./parse.js";
|
|
10
10
|
import { ValidatableHotkey, ValidationResult, assertValidHotkey, checkHotkey, validateHotkey } from "./validate.js";
|
|
11
|
-
import {
|
|
11
|
+
import { CreateHotkeyChordHandlerOptions, DEFAULT_SEQUENCE_TIMEOUT, KeyboardEventMatch, MultiHotkeyChordHandler, areHotkeysEqual, createHotkeyChordHandler, createMultiHotkeyChordHandler, createSequenceMatcher, matchesKeyboardEvent } from "./match.js";
|
|
12
12
|
import { HeldModifierOptions, matchesHeldModifiers } from "./hint.js";
|
|
13
13
|
import { HotkeyConflict, HotkeyConflictOptions, findHotkeyConflicts } from "./conflicts.js";
|
|
14
14
|
import { KeyStateTracker, KeyStateTrackerState, getKeyStateTracker } from "./key-state-tracker.js";
|
|
15
|
-
import { HotkeyRecorderValidationContext, RecorderKeyMode, RecorderOptions, RecorderRejection } from "./recorder
|
|
16
|
-
|
|
17
|
-
export { ALL_KEYS, AppHotkey, AppHotkeyChordOptions, AppHotkeyDefaultKind, AppHotkeyId, AppHotkeyInput, AppHotkeyListItem, AppHotkeyOptions, AppHotkeySequenceOptions, AppHotkeyStatus, AppHotkeys, AppHotkeysState, AppHotkeysStore, AppHotkeysStoreOptions, CanonicalModifier, ConflictBehavior, CreateHotkeyHandlerOptions, CustomHotkeys, DEFAULT_SEQUENCE_TIMEOUT, DefinedAppHotkeys, DisplayHotkey, DisplayHotkeyChord, EDITING_KEYS, EditingKey, FUNCTION_KEYS, FormatDisplayOptions, FourModifierHotkey, FunctionKey, HeldModifierOptions, Hotkey, HotkeyCallback, HotkeyCallbackContext, HotkeyChord, HotkeyChordOptions, HotkeyChordRecorderOptions, HotkeyChordRegistration, HotkeyChordRegistrationView, HotkeyConflict, HotkeyConflictOptions, HotkeyManager, HotkeyMeta, HotkeyOptions, HotkeyOptionsFor, HotkeyRecorder, HotkeyRecorderCommitKeys, HotkeyRecorderOptions, HotkeyRecorderState, HotkeyRecorderValidationContext, HotkeyRegistration, HotkeyRegistrationHandle, HotkeyRegistrationView, HotkeySequence, HotkeySequenceOptions, HotkeySequenceRecorderOptions, HotkeySequenceRegistration, HotkeySequenceRegistrationView, IndividualKey, KEY_DISPLAY_SYMBOLS, Key, KeyStateTracker, KeyStateTrackerState, KeyboardEventMatch, LETTER_KEYS, LINUX_MODIFIER_LABELS, LetterKey, LogicalKey, MAC_MODIFIER_LABELS, MAC_MODIFIER_SYMBOLS, MODIFIER_ALIASES, MODIFIER_KEYS, MODIFIER_ORDER, Modifier, MultiHotkeyHandler, NAVIGATION_KEYS, NUMBER_KEYS, NamedKey, NavigationKey, NonPunctuationKey, NormalizedKeyboardEvent, NumberKey, PUNCTUATION_CODE_MAP, PUNCTUATION_KEYS, PUNCTUATION_KEY_DISPLAY_LABELS, ParsedHotkey, ParsedModifiers, PhysicalKey, PhysicalKeyCode, PunctuationKey, RawHotkey, RawModifiers, RecorderKeyMode, RecorderOptions, RecorderRejection, Register, RegisterableHotkey, RegisterableHotkeyChord, RegisteredAppHotkeys, SingleModifierHotkey, Target, ThreeModifierHotkey, TwoModifierHotkey, ValidatableHotkey, ValidationResult, WINDOWS_MODIFIER_LABELS, areHotkeysEqual, assertValidHotkey, checkHotkey, createHotkeyHandler, createMultiHotkeyHandler, createSequenceMatcher, defineAppHotkeys, detectPlatform, findHotkeyConflicts, formatForDisplay, formatHotkey, getAppHotkeyRegistrationOptions, getHotkeyManager, getKeyStateTracker, hasNonModifierKey, isAppHotkey, isCustomHotkey, isHotkeySequence, isModifierKey, isSingleLetterKey, matchesHeldModifiers, matchesKeyboardEvent, normalizeHotkey, normalizeHotkeyFromEvent, normalizeHotkeyFromParsed, normalizeKeyName, normalizeRegisterableHotkey, parseHotkey, parseKeyboardEvent, parseRegisterableHotkey, provideAppHotkeys, publishAppHotkeysStore, rawHotkeyToParsedHotkey, resolveAppHotkey, resolveModifier, simplifyHotkey, toHotkeyRegistrationView, validateHotkey };
|
|
15
|
+
import { HotkeyChordRecorderOptions, HotkeyChordRecorderValidationContext, HotkeyRecorder, HotkeyRecorderCommitKeys, HotkeyRecorderOptions, HotkeyRecorderState, HotkeyRecorderValidationContext, HotkeySequenceRecorderOptions, HotkeySequenceRecorderValidationContext, RecorderKeyMode, RecorderOptions, RecorderRejection } from "./hotkey-recorder.js";
|
|
16
|
+
export { ALL_KEYS, ActivateHotkeyScopeOptions, AppHotkey, AppHotkeyChordOptions, AppHotkeyDefaultKind, AppHotkeyId, AppHotkeyInput, AppHotkeyListItem, AppHotkeyOptions, AppHotkeySequenceOptions, AppHotkeyStatus, AppHotkeys, AppHotkeysState, AppHotkeysStore, AppHotkeysStoreOptions, CanonicalModifier, ConflictBehavior, CreateHotkeyChordHandlerOptions, CustomHotkeys, DEFAULT_SEQUENCE_TIMEOUT, DefinedAppHotkeys, DisplayHotkey, DisplayHotkeyChord, EDITING_KEYS, EditingKey, FUNCTION_KEYS, FormatDisplayOptions, FourModifierHotkeyChord, FunctionKey, HeldModifierOptions, Hotkey, HotkeyCallback, HotkeyCallbackContext, HotkeyCallbackContextFor, HotkeyChord, HotkeyChordCallbackContext, HotkeyChordOptions, HotkeyChordRecorderOptions, HotkeyChordRecorderValidationContext, HotkeyChordRegistration, HotkeyChordRegistrationView, HotkeyConflict, HotkeyConflictOptions, HotkeyManager, HotkeyMeta, HotkeyOptions, HotkeyOptionsFor, HotkeyRecorder, HotkeyRecorderCommitKeys, HotkeyRecorderOptions, HotkeyRecorderState, HotkeyRecorderValidationContext, HotkeyRegistration, HotkeyRegistrationHandle, HotkeyRegistrationView, HotkeyScopesState, HotkeySequence, HotkeySequenceCallbackContext, HotkeySequenceOptions, HotkeySequenceRecorderOptions, HotkeySequenceRecorderValidationContext, HotkeySequenceRegistration, HotkeySequenceRegistrationView, IndividualKey, KEY_DISPLAY_SYMBOLS, Key, KeyStateTracker, KeyStateTrackerState, KeyboardEventMatch, LETTER_KEYS, LINUX_MODIFIER_LABELS, LetterKey, LogicalKey, MAC_MODIFIER_LABELS, MAC_MODIFIER_SYMBOLS, MODIFIER_ALIASES, MODIFIER_KEYS, MODIFIER_ORDER, Modifier, MultiHotkeyChordHandler, NAVIGATION_KEYS, NUMBER_KEYS, NamedKey, NavigationKey, NonPunctuationKey, NormalizedKeyboardEvent, NumberKey, PUNCTUATION_CODE_MAP, PUNCTUATION_KEYS, PUNCTUATION_KEY_DISPLAY_LABELS, ParsedHotkeyChord, ParsedModifiers, PhysicalKey, PhysicalKeyCode, PunctuationKey, RawHotkeyChord, RawModifiers, RecorderKeyMode, RecorderOptions, RecorderRejection, Register, RegisterableHotkey, RegisterableHotkeyChord, RegisterableHotkeySequence, RegisteredAppHotkeys, SingleModifierHotkeyChord, Target, ThreeModifierHotkeyChord, TwoModifierHotkeyChord, ValidatableHotkey, ValidationResult, WINDOWS_MODIFIER_LABELS, areHotkeysEqual, assertValidHotkey, checkHotkey, createHotkeyChordHandler, createMultiHotkeyChordHandler, createSequenceMatcher, defineAppHotkeys, detectPlatform, findHotkeyConflicts, formatForDisplay, formatHotkey, getAppHotkeyRegistrationOptions, getHotkeyManager, getKeyStateTracker, hasNonModifierKey, isAppHotkey, isCustomHotkey, isHotkeySequence, isModifierKey, isSingleLetterKey, matchesHeldModifiers, matchesKeyboardEvent, normalizeHotkey, normalizeKeyName, parseHotkey, parseKeyboardEvent, provideAppHotkeys, publishAppHotkeysStore, resolveAppHotkey, resolveModifier, simplifyHotkey, toHotkeyRegistrationView, validateHotkey };
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { ALL_KEYS, EDITING_KEYS, FUNCTION_KEYS, LETTER_KEYS, MODIFIER_ALIASES, MODIFIER_KEYS, MODIFIER_ORDER, NAVIGATION_KEYS, NUMBER_KEYS, PUNCTUATION_CODE_MAP, PUNCTUATION_KEYS, isSingleLetterKey, normalizeKeyName } from "./constants.js";
|
|
2
2
|
import { KEY_DISPLAY_SYMBOLS, LINUX_MODIFIER_LABELS, MAC_MODIFIER_LABELS, MAC_MODIFIER_SYMBOLS, PUNCTUATION_KEY_DISPLAY_LABELS, WINDOWS_MODIFIER_LABELS } from "./display-labels.js";
|
|
3
3
|
import { detectPlatform, resolveModifier } from "./platform.js";
|
|
4
|
-
import { hasNonModifierKey, isHotkeySequence, isModifierKey, normalizeHotkey,
|
|
4
|
+
import { hasNonModifierKey, isHotkeySequence, isModifierKey, normalizeHotkey, parseHotkey, parseKeyboardEvent, simplifyHotkey } from "./parse.js";
|
|
5
5
|
import { formatForDisplay, formatHotkey } from "./format.js";
|
|
6
6
|
import { assertValidHotkey, checkHotkey, validateHotkey } from "./validate.js";
|
|
7
|
-
import { DEFAULT_SEQUENCE_TIMEOUT, areHotkeysEqual,
|
|
7
|
+
import { DEFAULT_SEQUENCE_TIMEOUT, areHotkeysEqual, createHotkeyChordHandler, createMultiHotkeyChordHandler, createSequenceMatcher, matchesKeyboardEvent } from "./match.js";
|
|
8
8
|
import { matchesHeldModifiers } from "./hint.js";
|
|
9
9
|
import { HotkeyManager, getHotkeyManager, toHotkeyRegistrationView } from "./hotkey-manager.js";
|
|
10
10
|
import { findHotkeyConflicts } from "./conflicts.js";
|
|
@@ -12,4 +12,4 @@ import { AppHotkeysStore, defineAppHotkeys, getAppHotkeyRegistrationOptions, isA
|
|
|
12
12
|
import { KeyStateTracker, getKeyStateTracker } from "./key-state-tracker.js";
|
|
13
13
|
import { HotkeyRecorder } from "./hotkey-recorder.js";
|
|
14
14
|
|
|
15
|
-
export { ALL_KEYS, AppHotkeysStore, DEFAULT_SEQUENCE_TIMEOUT, EDITING_KEYS, FUNCTION_KEYS, HotkeyManager, HotkeyRecorder, KEY_DISPLAY_SYMBOLS, KeyStateTracker, LETTER_KEYS, LINUX_MODIFIER_LABELS, MAC_MODIFIER_LABELS, MAC_MODIFIER_SYMBOLS, MODIFIER_ALIASES, MODIFIER_KEYS, MODIFIER_ORDER, NAVIGATION_KEYS, NUMBER_KEYS, PUNCTUATION_CODE_MAP, PUNCTUATION_KEYS, PUNCTUATION_KEY_DISPLAY_LABELS, WINDOWS_MODIFIER_LABELS, areHotkeysEqual, assertValidHotkey, checkHotkey,
|
|
15
|
+
export { ALL_KEYS, AppHotkeysStore, DEFAULT_SEQUENCE_TIMEOUT, EDITING_KEYS, FUNCTION_KEYS, HotkeyManager, HotkeyRecorder, KEY_DISPLAY_SYMBOLS, KeyStateTracker, LETTER_KEYS, LINUX_MODIFIER_LABELS, MAC_MODIFIER_LABELS, MAC_MODIFIER_SYMBOLS, MODIFIER_ALIASES, MODIFIER_KEYS, MODIFIER_ORDER, NAVIGATION_KEYS, NUMBER_KEYS, PUNCTUATION_CODE_MAP, PUNCTUATION_KEYS, PUNCTUATION_KEY_DISPLAY_LABELS, WINDOWS_MODIFIER_LABELS, areHotkeysEqual, assertValidHotkey, checkHotkey, createHotkeyChordHandler, createMultiHotkeyChordHandler, createSequenceMatcher, defineAppHotkeys, detectPlatform, findHotkeyConflicts, formatForDisplay, formatHotkey, getAppHotkeyRegistrationOptions, getHotkeyManager, getKeyStateTracker, hasNonModifierKey, isAppHotkey, isCustomHotkey, isHotkeySequence, isModifierKey, isSingleLetterKey, matchesHeldModifiers, matchesKeyboardEvent, normalizeHotkey, normalizeKeyName, parseHotkey, parseKeyboardEvent, provideAppHotkeys, publishAppHotkeysStore, resolveAppHotkey, resolveModifier, simplifyHotkey, toHotkeyRegistrationView, validateHotkey };
|
|
@@ -53,10 +53,8 @@ var KeyStateTracker = class KeyStateTracker {
|
|
|
53
53
|
*/
|
|
54
54
|
store = new Store(getDefaultKeyStateTrackerState());
|
|
55
55
|
#heldEntries = /* @__PURE__ */ new Map();
|
|
56
|
-
|
|
57
|
-
#
|
|
58
|
-
#mouseListener = null;
|
|
59
|
-
#blurListener = null;
|
|
56
|
+
/** Window listeners as `[type, listener, capture]`, removed together on destroy. */
|
|
57
|
+
#listeners = [];
|
|
60
58
|
constructor() {
|
|
61
59
|
this.#setupListeners();
|
|
62
60
|
}
|
|
@@ -81,7 +79,7 @@ var KeyStateTracker = class KeyStateTracker {
|
|
|
81
79
|
*/
|
|
82
80
|
#setupListeners() {
|
|
83
81
|
if (typeof document === "undefined") return;
|
|
84
|
-
|
|
82
|
+
const onKeydown = (event) => {
|
|
85
83
|
let changed = this.#reconcileModifiers(event);
|
|
86
84
|
const key = normalizeKeyName(event.key);
|
|
87
85
|
const identity = event.code || `key:${key}`;
|
|
@@ -94,7 +92,7 @@ var KeyStateTracker = class KeyStateTracker {
|
|
|
94
92
|
}
|
|
95
93
|
if (changed) this.#syncState();
|
|
96
94
|
};
|
|
97
|
-
|
|
95
|
+
const onKeyup = (event) => {
|
|
98
96
|
const key = normalizeKeyName(event.key);
|
|
99
97
|
const identity = event.code || `key:${key}`;
|
|
100
98
|
this.#heldEntries.delete(identity);
|
|
@@ -107,20 +105,43 @@ var KeyStateTracker = class KeyStateTracker {
|
|
|
107
105
|
}
|
|
108
106
|
this.#syncState();
|
|
109
107
|
};
|
|
110
|
-
|
|
108
|
+
const onMouse = (event) => {
|
|
111
109
|
if (this.#reconcileModifiers(event)) this.#syncState();
|
|
112
110
|
};
|
|
113
|
-
|
|
111
|
+
const onBlur = () => {
|
|
114
112
|
if (this.#heldEntries.size > 0) {
|
|
115
113
|
this.#heldEntries.clear();
|
|
116
114
|
this.#syncState();
|
|
117
115
|
}
|
|
118
116
|
};
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
117
|
+
this.#listeners = [
|
|
118
|
+
[
|
|
119
|
+
"keydown",
|
|
120
|
+
onKeydown,
|
|
121
|
+
true
|
|
122
|
+
],
|
|
123
|
+
[
|
|
124
|
+
"keyup",
|
|
125
|
+
onKeyup,
|
|
126
|
+
true
|
|
127
|
+
],
|
|
128
|
+
[
|
|
129
|
+
"mousemove",
|
|
130
|
+
onMouse,
|
|
131
|
+
true
|
|
132
|
+
],
|
|
133
|
+
[
|
|
134
|
+
"mousedown",
|
|
135
|
+
onMouse,
|
|
136
|
+
true
|
|
137
|
+
],
|
|
138
|
+
[
|
|
139
|
+
"blur",
|
|
140
|
+
onBlur,
|
|
141
|
+
false
|
|
142
|
+
]
|
|
143
|
+
];
|
|
144
|
+
for (const [type, listener, capture] of this.#listeners) window.addEventListener(type, listener, capture);
|
|
124
145
|
}
|
|
125
146
|
/**
|
|
126
147
|
* Removes modifiers whose release was missed without a window blur.
|
|
@@ -153,24 +174,8 @@ var KeyStateTracker = class KeyStateTracker {
|
|
|
153
174
|
* Removes the keyboard event listeners.
|
|
154
175
|
*/
|
|
155
176
|
#removeListeners() {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
window.removeEventListener("keydown", this.#keydownListener, true);
|
|
159
|
-
this.#keydownListener = null;
|
|
160
|
-
}
|
|
161
|
-
if (this.#keyupListener) {
|
|
162
|
-
window.removeEventListener("keyup", this.#keyupListener, true);
|
|
163
|
-
this.#keyupListener = null;
|
|
164
|
-
}
|
|
165
|
-
if (this.#mouseListener) {
|
|
166
|
-
window.removeEventListener("mousemove", this.#mouseListener, true);
|
|
167
|
-
window.removeEventListener("mousedown", this.#mouseListener, true);
|
|
168
|
-
this.#mouseListener = null;
|
|
169
|
-
}
|
|
170
|
-
if (this.#blurListener) {
|
|
171
|
-
window.removeEventListener("blur", this.#blurListener);
|
|
172
|
-
this.#blurListener = null;
|
|
173
|
-
}
|
|
177
|
+
for (const [type, listener, capture] of this.#listeners) window.removeEventListener(type, listener, capture);
|
|
178
|
+
this.#listeners = [];
|
|
174
179
|
}
|
|
175
180
|
/**
|
|
176
181
|
* Gets an array of currently held key names.
|
package/dist/match.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { HotkeyCallback, HotkeyChord,
|
|
1
|
+
import { HotkeyCallback, HotkeyChord, HotkeyChordCallbackContext, ParsedHotkeyChord, RegisterableHotkey, RegisterableHotkeySequence } from "./hotkey.types.js";
|
|
2
2
|
//#region src/match.d.ts
|
|
3
3
|
export interface KeyboardEventMatch {
|
|
4
4
|
matched: boolean;
|
|
@@ -24,9 +24,9 @@ export interface KeyboardEventMatch {
|
|
|
24
24
|
* In these cases, `event.code` is used to determine the physical key.
|
|
25
25
|
*
|
|
26
26
|
* @param event - The KeyboardEvent to check
|
|
27
|
-
* @param
|
|
27
|
+
* @param chord - The chord string or parsed chord to match against
|
|
28
28
|
* @param platform - The target platform for resolving 'Mod' (defaults to auto-detection)
|
|
29
|
-
* @returns True if the event matches the
|
|
29
|
+
* @returns True if the event matches the chord
|
|
30
30
|
*
|
|
31
31
|
* @example
|
|
32
32
|
* ```ts
|
|
@@ -38,29 +38,30 @@ export interface KeyboardEventMatch {
|
|
|
38
38
|
* })
|
|
39
39
|
* ```
|
|
40
40
|
*/
|
|
41
|
-
export declare function matchesKeyboardEvent(event: KeyboardEvent,
|
|
41
|
+
export declare function matchesKeyboardEvent(event: KeyboardEvent, chord: HotkeyChord | ParsedHotkeyChord, platform?: 'mac' | 'windows' | 'linux'): boolean;
|
|
42
42
|
/**
|
|
43
|
-
* Options for creating a
|
|
43
|
+
* Options for creating a chord handler.
|
|
44
44
|
*/
|
|
45
|
-
export interface
|
|
46
|
-
/** Prevent the default browser action when the
|
|
45
|
+
export interface CreateHotkeyChordHandlerOptions {
|
|
46
|
+
/** Prevent the default browser action when the chord matches. Defaults to true */
|
|
47
47
|
preventDefault?: boolean;
|
|
48
|
-
/** Stop event propagation when the
|
|
48
|
+
/** Stop event propagation when the chord matches. Defaults to true */
|
|
49
49
|
stopPropagation?: boolean;
|
|
50
50
|
/** The target platform for resolving 'Mod' */
|
|
51
51
|
platform?: 'mac' | 'windows' | 'linux';
|
|
52
52
|
}
|
|
53
53
|
/**
|
|
54
|
-
* Creates a keyboard event handler that calls the callback when the
|
|
54
|
+
* Creates a keyboard event handler that calls the callback when the chord
|
|
55
|
+
* matches. For sequences, use `createSequenceMatcher`.
|
|
55
56
|
*
|
|
56
|
-
* @param
|
|
57
|
+
* @param chord - The chord string or parsed chord to match
|
|
57
58
|
* @param callback - The function to call when the hotkey matches
|
|
58
59
|
* @param options - Options for matching and handling
|
|
59
60
|
* @returns A function that can be used as an event handler
|
|
60
61
|
*
|
|
61
62
|
* @example
|
|
62
63
|
* ```ts
|
|
63
|
-
* const handler =
|
|
64
|
+
* const handler = createHotkeyChordHandler('Mod+S', (event, { hotkey, parsedChord }) => {
|
|
64
65
|
* console.log(`${hotkey} was pressed`)
|
|
65
66
|
* handleSave()
|
|
66
67
|
* })
|
|
@@ -68,18 +69,18 @@ export interface CreateHotkeyHandlerOptions {
|
|
|
68
69
|
* document.addEventListener('keydown', handler)
|
|
69
70
|
* ```
|
|
70
71
|
*/
|
|
71
|
-
export declare function
|
|
72
|
-
export type
|
|
72
|
+
export declare function createHotkeyChordHandler(chord: HotkeyChord | ParsedHotkeyChord, callback: HotkeyCallback<HotkeyChordCallbackContext>, options?: CreateHotkeyChordHandlerOptions): (event: KeyboardEvent) => void;
|
|
73
|
+
export type MultiHotkeyChordHandler = { [K in HotkeyChord]?: HotkeyCallback<HotkeyChordCallbackContext>; };
|
|
73
74
|
/**
|
|
74
|
-
* Creates a handler that matches
|
|
75
|
+
* Creates a handler that matches several chords.
|
|
75
76
|
*
|
|
76
|
-
* @param handlers - A map of
|
|
77
|
+
* @param handlers - A map of chord strings to their handlers
|
|
77
78
|
* @param options - Options for matching and handling
|
|
78
79
|
* @returns A function that can be used as an event handler
|
|
79
80
|
*
|
|
80
81
|
* @example
|
|
81
82
|
* ```ts
|
|
82
|
-
* const handler =
|
|
83
|
+
* const handler = createMultiHotkeyChordHandler({
|
|
83
84
|
* 'Mod+S': (event, { hotkey }) => handleSave(),
|
|
84
85
|
* 'Mod+Z': (event, { hotkey }) => handleUndo(),
|
|
85
86
|
* 'Mod+Shift+Z': (event, { hotkey }) => handleRedo(),
|
|
@@ -88,7 +89,7 @@ export type MultiHotkeyHandler = { [K in HotkeyChord]?: HotkeyCallback; };
|
|
|
88
89
|
* document.addEventListener('keydown', handler)
|
|
89
90
|
* ```
|
|
90
91
|
*/
|
|
91
|
-
export declare function
|
|
92
|
+
export declare function createMultiHotkeyChordHandler(handlers: MultiHotkeyChordHandler, options?: CreateHotkeyChordHandlerOptions): (event: KeyboardEvent) => void;
|
|
92
93
|
/**
|
|
93
94
|
* Compares normalized hotkey identity, including all four modifiers.
|
|
94
95
|
* Sequences are equal when every step is equal; a one-step sequence equals its chord.
|
|
@@ -120,7 +121,7 @@ export declare const DEFAULT_SEQUENCE_TIMEOUT = 1000;
|
|
|
120
121
|
* })
|
|
121
122
|
* ```
|
|
122
123
|
*/
|
|
123
|
-
export declare function createSequenceMatcher(sequence:
|
|
124
|
+
export declare function createSequenceMatcher(sequence: RegisterableHotkeySequence, options?: {
|
|
124
125
|
timeout?: number;
|
|
125
126
|
platform?: 'mac' | 'windows' | 'linux';
|
|
126
127
|
}): {
|
package/dist/match.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { normalizeKeyName } from "./constants.js";
|
|
2
2
|
import { detectPlatform } from "./platform.js";
|
|
3
|
-
import {
|
|
4
|
-
import { isHotkeySequence, isModifierKey, parseHotkey
|
|
5
|
-
import {
|
|
3
|
+
import { normalizeKeyboardEvent } from "./_keyboard-event.js";
|
|
4
|
+
import { isHotkeySequence, isModifierKey, parseHotkey } from "./parse.js";
|
|
5
|
+
import { formatHotkey } from "./format.js";
|
|
6
|
+
import { matchKeyboardEvent, parsedChordsEqual } from "./_match.js";
|
|
6
7
|
|
|
7
8
|
//#region src/match.ts
|
|
8
9
|
/**
|
|
@@ -20,9 +21,9 @@ import { matchKeyboardEvent } from "./_match.js";
|
|
|
20
21
|
* In these cases, `event.code` is used to determine the physical key.
|
|
21
22
|
*
|
|
22
23
|
* @param event - The KeyboardEvent to check
|
|
23
|
-
* @param
|
|
24
|
+
* @param chord - The chord string or parsed chord to match against
|
|
24
25
|
* @param platform - The target platform for resolving 'Mod' (defaults to auto-detection)
|
|
25
|
-
* @returns True if the event matches the
|
|
26
|
+
* @returns True if the event matches the chord
|
|
26
27
|
*
|
|
27
28
|
* @example
|
|
28
29
|
* ```ts
|
|
@@ -34,20 +35,21 @@ import { matchKeyboardEvent } from "./_match.js";
|
|
|
34
35
|
* })
|
|
35
36
|
* ```
|
|
36
37
|
*/
|
|
37
|
-
function matchesKeyboardEvent(event,
|
|
38
|
-
return matchKeyboardEvent(event,
|
|
38
|
+
function matchesKeyboardEvent(event, chord, platform = detectPlatform()) {
|
|
39
|
+
return matchKeyboardEvent(event, chord, platform).matched;
|
|
39
40
|
}
|
|
40
41
|
/**
|
|
41
|
-
* Creates a keyboard event handler that calls the callback when the
|
|
42
|
+
* Creates a keyboard event handler that calls the callback when the chord
|
|
43
|
+
* matches. For sequences, use `createSequenceMatcher`.
|
|
42
44
|
*
|
|
43
|
-
* @param
|
|
45
|
+
* @param chord - The chord string or parsed chord to match
|
|
44
46
|
* @param callback - The function to call when the hotkey matches
|
|
45
47
|
* @param options - Options for matching and handling
|
|
46
48
|
* @returns A function that can be used as an event handler
|
|
47
49
|
*
|
|
48
50
|
* @example
|
|
49
51
|
* ```ts
|
|
50
|
-
* const handler =
|
|
52
|
+
* const handler = createHotkeyChordHandler('Mod+S', (event, { hotkey, parsedChord }) => {
|
|
51
53
|
* console.log(`${hotkey} was pressed`)
|
|
52
54
|
* handleSave()
|
|
53
55
|
* })
|
|
@@ -55,14 +57,15 @@ function matchesKeyboardEvent(event, hotkey, platform = detectPlatform()) {
|
|
|
55
57
|
* document.addEventListener('keydown', handler)
|
|
56
58
|
* ```
|
|
57
59
|
*/
|
|
58
|
-
function
|
|
60
|
+
function createHotkeyChordHandler(chord, callback, options = {}) {
|
|
59
61
|
const { preventDefault = true, stopPropagation = true, platform } = options;
|
|
60
62
|
const resolvedPlatform = platform ?? detectPlatform();
|
|
61
|
-
const hotkeyString = typeof
|
|
62
|
-
const parsed = typeof
|
|
63
|
+
const hotkeyString = typeof chord === "string" ? chord : formatHotkey(chord);
|
|
64
|
+
const parsed = typeof chord === "string" ? parseHotkey(chord, resolvedPlatform) : chord;
|
|
63
65
|
const context = {
|
|
66
|
+
kind: "chord",
|
|
64
67
|
hotkey: hotkeyString,
|
|
65
|
-
|
|
68
|
+
parsedChord: parsed
|
|
66
69
|
};
|
|
67
70
|
return (event) => {
|
|
68
71
|
if (matchesKeyboardEvent(event, parsed, resolvedPlatform)) {
|
|
@@ -73,15 +76,15 @@ function createHotkeyHandler(hotkey, callback, options = {}) {
|
|
|
73
76
|
};
|
|
74
77
|
}
|
|
75
78
|
/**
|
|
76
|
-
* Creates a handler that matches
|
|
79
|
+
* Creates a handler that matches several chords.
|
|
77
80
|
*
|
|
78
|
-
* @param handlers - A map of
|
|
81
|
+
* @param handlers - A map of chord strings to their handlers
|
|
79
82
|
* @param options - Options for matching and handling
|
|
80
83
|
* @returns A function that can be used as an event handler
|
|
81
84
|
*
|
|
82
85
|
* @example
|
|
83
86
|
* ```ts
|
|
84
|
-
* const handler =
|
|
87
|
+
* const handler = createMultiHotkeyChordHandler({
|
|
85
88
|
* 'Mod+S': (event, { hotkey }) => handleSave(),
|
|
86
89
|
* 'Mod+Z': (event, { hotkey }) => handleUndo(),
|
|
87
90
|
* 'Mod+Shift+Z': (event, { hotkey }) => handleRedo(),
|
|
@@ -90,7 +93,7 @@ function createHotkeyHandler(hotkey, callback, options = {}) {
|
|
|
90
93
|
* document.addEventListener('keydown', handler)
|
|
91
94
|
* ```
|
|
92
95
|
*/
|
|
93
|
-
function
|
|
96
|
+
function createMultiHotkeyChordHandler(handlers, options = {}) {
|
|
94
97
|
const { preventDefault = true, stopPropagation = true, platform } = options;
|
|
95
98
|
const resolvedPlatform = platform ?? detectPlatform();
|
|
96
99
|
const parsedHandlers = Object.entries(handlers).filter((entry) => Boolean(entry[1])).map(([hotkey, handler]) => {
|
|
@@ -99,8 +102,9 @@ function createMultiHotkeyHandler(handlers, options = {}) {
|
|
|
99
102
|
parsed,
|
|
100
103
|
handler,
|
|
101
104
|
context: {
|
|
105
|
+
kind: "chord",
|
|
102
106
|
hotkey,
|
|
103
|
-
|
|
107
|
+
parsedChord: parsed
|
|
104
108
|
}
|
|
105
109
|
};
|
|
106
110
|
});
|
|
@@ -114,19 +118,6 @@ function createMultiHotkeyHandler(handlers, options = {}) {
|
|
|
114
118
|
};
|
|
115
119
|
}
|
|
116
120
|
/**
|
|
117
|
-
* Formats a ParsedHotkey back to a hotkey string.
|
|
118
|
-
* Used internally to provide the hotkey string in callback context.
|
|
119
|
-
*/
|
|
120
|
-
function formatParsedHotkey(parsed) {
|
|
121
|
-
const parts = [];
|
|
122
|
-
if (parsed.ctrl) parts.push("Control");
|
|
123
|
-
if (parsed.alt) parts.push("Alt");
|
|
124
|
-
if (parsed.shift) parts.push("Shift");
|
|
125
|
-
if (parsed.meta) parts.push("Meta");
|
|
126
|
-
parts.push(parsed.code !== void 0 ? `[${parsed.code}]` : parsed.key);
|
|
127
|
-
return parts.join("+");
|
|
128
|
-
}
|
|
129
|
-
/**
|
|
130
121
|
* Compares normalized hotkey identity, including all four modifiers.
|
|
131
122
|
* Sequences are equal when every step is equal; a one-step sequence equals its chord.
|
|
132
123
|
* Aliases resolve on the supplied platform. A physical code and a logical key
|
|
@@ -135,12 +126,7 @@ function formatParsedHotkey(parsed) {
|
|
|
135
126
|
function areHotkeysEqual(left, right, platform = detectPlatform()) {
|
|
136
127
|
const a = isHotkeySequence(left) ? left : [left];
|
|
137
128
|
const b = isHotkeySequence(right) ? right : [right];
|
|
138
|
-
return a.length === b.length && a.every((step, index) =>
|
|
139
|
-
}
|
|
140
|
-
function areChordsEqual(left, right, platform) {
|
|
141
|
-
const a = parseRegisterableHotkey(left, platform);
|
|
142
|
-
const b = parseRegisterableHotkey(right, platform);
|
|
143
|
-
return a.ctrl === b.ctrl && a.alt === b.alt && a.shift === b.shift && a.meta === b.meta && (a.code !== void 0 || b.code !== void 0 ? a.code === b.code : keysEqual(a.key, b.key));
|
|
129
|
+
return a.length === b.length && a.every((step, index) => parsedChordsEqual(parseHotkey(step, platform), parseHotkey(b[index], platform)));
|
|
144
130
|
}
|
|
145
131
|
/** Default timeout between sequence steps (in milliseconds). */
|
|
146
132
|
const DEFAULT_SEQUENCE_TIMEOUT = 1e3;
|
|
@@ -169,7 +155,7 @@ const DEFAULT_SEQUENCE_TIMEOUT = 1e3;
|
|
|
169
155
|
function createSequenceMatcher(sequence, options = {}) {
|
|
170
156
|
const platform = options.platform ?? detectPlatform();
|
|
171
157
|
const timeout = options.timeout ?? 1e3;
|
|
172
|
-
const parsedSequence =
|
|
158
|
+
const parsedSequence = parseHotkey(sequence, platform);
|
|
173
159
|
let currentIndex = 0;
|
|
174
160
|
let lastKeyTime = 0;
|
|
175
161
|
return {
|
|
@@ -205,4 +191,4 @@ function createSequenceMatcher(sequence, options = {}) {
|
|
|
205
191
|
}
|
|
206
192
|
|
|
207
193
|
//#endregion
|
|
208
|
-
export { DEFAULT_SEQUENCE_TIMEOUT, areHotkeysEqual,
|
|
194
|
+
export { DEFAULT_SEQUENCE_TIMEOUT, areHotkeysEqual, createHotkeyChordHandler, createMultiHotkeyChordHandler, createSequenceMatcher, matchesKeyboardEvent };
|