@flighthq/shortcut 0.3.0-next.906.07cea63 → 0.3.1-next.209.43ef1bc

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.
@@ -1,2 +1,4 @@
1
+ export * from './enableShortcutGuards';
2
+ export * from './explainGlobalShortcutRegistration';
1
3
  export * from './shortcut';
2
4
  //# sourceMappingURL=contract.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,qCAAqC,CAAC;AACpD,cAAc,YAAY,CAAC"}
package/dist/contract.js CHANGED
@@ -1,2 +1,4 @@
1
+ export * from './enableShortcutGuards';
2
+ export * from './explainGlobalShortcutRegistration';
1
3
  export * from './shortcut';
2
4
  //# sourceMappingURL=contract.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,qCAAqC,CAAC;AACpD,cAAc,YAAY,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare function disableShortcutGuards(): void;
2
+ export declare function enableShortcutGuards(): void;
3
+ //# sourceMappingURL=enableShortcutGuards.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enableShortcutGuards.d.ts","sourceRoot":"","sources":["../src/enableShortcutGuards.ts"],"names":[],"mappings":"AAOA,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C;AAQD,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C"}
@@ -0,0 +1,32 @@
1
+ import { logOnce } from '@flighthq/log/contract';
2
+ import { LogLevel } from '@flighthq/types/contract';
3
+ import { setShortcutDropGuard } from './shortcut';
4
+ // Uninstalls the guard installed by enableShortcutGuards.
5
+ export function disableShortcutGuards() {
6
+ setShortcutDropGuard(null);
7
+ }
8
+ // Installs the caller-facing shortcut guard (opt-in, dev-only). Every global-shortcut command answers
9
+ // a bad call with the same `false` a legitimate miss returns, so the two footguns this package has are
10
+ // both silent: an accelerator string the parser rejects, and a whole application wired up against the
11
+ // default web backend, which has no OS registry to act on. The guard warns once per cause through
12
+ // @flighthq/log. Not importing this module costs production nothing — the message text and the
13
+ // @flighthq/log dependency live only here, and the command path sees a null slot. Idempotent.
14
+ export function enableShortcutGuards() {
15
+ setShortcutDropGuard(warnOnShortcutDrop);
16
+ }
17
+ function warnOnShortcutDrop(drop) {
18
+ if (drop.reason === 'no-native-backend') {
19
+ logOnce('shortcut:no-native-backend', LogLevel.Warn, {
20
+ message: `${drop.operation}: no native shortcut backend is installed, so the default web backend handled this call — a browser cannot register OS-level global hotkeys. Call setShortcutBackend(...) from a native host (Electron/Tauri), and gate the feature on hasNativeShortcutBackend().`,
21
+ }, 'shortcut');
22
+ return;
23
+ }
24
+ const parseError = drop.parseError;
25
+ const detail = parseError === null
26
+ ? 'it did not parse'
27
+ : `${parseError.reason}${parseError.token === '' ? '' : ` at '${parseError.token}'`}`;
28
+ logOnce('shortcut:unparseable-accelerator', LogLevel.Warn, {
29
+ message: `${drop.operation}('${drop.accelerator}'): the accelerator was dropped because ${detail}. Check the spelling against parseAcceleratorDetailed, or explainGlobalShortcutRegistration for the whole picture.`,
30
+ }, 'shortcut');
31
+ }
32
+ //# sourceMappingURL=enableShortcutGuards.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enableShortcutGuards.js","sourceRoot":"","sources":["../src/enableShortcutGuards.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAEjD,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAEpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAElD,0DAA0D;AAC1D,MAAM,UAAU,qBAAqB;IACnC,oBAAoB,CAAC,IAAI,CAAC,CAAC;AAC7B,CAAC;AAED,sGAAsG;AACtG,uGAAuG;AACvG,sGAAsG;AACtG,kGAAkG;AAClG,+FAA+F;AAC/F,8FAA8F;AAC9F,MAAM,UAAU,oBAAoB;IAClC,oBAAoB,CAAC,kBAAkB,CAAC,CAAC;AAC3C,CAAC;AAED,SAAS,kBAAkB,CAAC,IAA4B;IACtD,IAAI,IAAI,CAAC,MAAM,KAAK,mBAAmB,EAAE,CAAC;QACxC,OAAO,CACL,4BAA4B,EAC5B,QAAQ,CAAC,IAAI,EACb;YACE,OAAO,EAAE,GAAG,IAAI,CAAC,SAAS,oQAAoQ;SAC/R,EACD,UAAU,CACX,CAAC;QACF,OAAO;IACT,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;IACnC,MAAM,MAAM,GACV,UAAU,KAAK,IAAI;QACjB,CAAC,CAAC,kBAAkB;QACpB,CAAC,CAAC,GAAG,UAAU,CAAC,MAAM,GAAG,UAAU,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,UAAU,CAAC,KAAK,GAAG,EAAE,CAAC;IAC1F,OAAO,CACL,kCAAkC,EAClC,QAAQ,CAAC,IAAI,EACb;QACE,OAAO,EAAE,GAAG,IAAI,CAAC,SAAS,KAAK,IAAI,CAAC,WAAW,2CAA2C,MAAM,oHAAoH;KACrN,EACD,UAAU,CACX,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { GlobalShortcutExplanation } from '@flighthq/types/contract';
2
+ export declare function explainGlobalShortcutRegistration(accelerator: string): GlobalShortcutExplanation;
3
+ //# sourceMappingURL=explainGlobalShortcutRegistration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"explainGlobalShortcutRegistration.d.ts","sourceRoot":"","sources":["../src/explainGlobalShortcutRegistration.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAA6B,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AAiBrG,wBAAgB,iCAAiC,CAAC,WAAW,EAAE,MAAM,GAAG,yBAAyB,CAgBhG"}
@@ -0,0 +1,35 @@
1
+ import { createParsedAccelerator, hasNativeShortcutBackend, isGlobalShortcutRegistered, parseAcceleratorDetailed, } from './shortcut';
2
+ // Recomputes why registerGlobalShortcut(`accelerator`, …) would or would not take, and returns it as
3
+ // plain data. Pure: it re-runs the parser and reads the active backend's registry, mutates nothing,
4
+ // registers nothing, never throws on malformed input, and retains no reference to the backend. Import
5
+ // it to debug a hotkey that silently never fires; it sheds from production when unimported.
6
+ //
7
+ // This is the pull half of the diagnostics convention, and it duplicates the register path's drop
8
+ // conditions by design — the maintenance seam is that a new gate on registerGlobalShortcut must gain
9
+ // a matching check here or this query silently goes stale.
10
+ export function explainGlobalShortcutRegistration(accelerator) {
11
+ const parsed = parseAcceleratorDetailed(accelerator, createParsedAccelerator());
12
+ const failed = 'reason' in parsed;
13
+ const parseError = failed ? parsed : null;
14
+ const normalized = failed ? null : _joinNormalized(parsed.modifiers, parsed.key);
15
+ const hasBackend = hasNativeShortcutBackend();
16
+ const registered = normalized !== null && isGlobalShortcutRegistered(normalized);
17
+ let reason;
18
+ if (failed)
19
+ reason = 'unparseable';
20
+ else if (!hasBackend)
21
+ reason = 'no-native-backend';
22
+ else if (registered)
23
+ reason = 'already-registered';
24
+ else
25
+ reason = 'ok';
26
+ return { accelerator, hasNativeBackend: hasBackend, normalized, parseError, registered, reason };
27
+ }
28
+ // Rebuilds the canonical string from an already-parsed chord. Local rather than a call back into
29
+ // normalizeAccelerator so the explanation costs one parse, not two.
30
+ function _joinNormalized(modifiers, key) {
31
+ if (modifiers.length === 0)
32
+ return key;
33
+ return [...modifiers, key].join('+');
34
+ }
35
+ //# sourceMappingURL=explainGlobalShortcutRegistration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"explainGlobalShortcutRegistration.js","sourceRoot":"","sources":["../src/explainGlobalShortcutRegistration.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,uBAAuB,EACvB,wBAAwB,EACxB,0BAA0B,EAC1B,wBAAwB,GACzB,MAAM,YAAY,CAAC;AAEpB,qGAAqG;AACrG,oGAAoG;AACpG,sGAAsG;AACtG,4FAA4F;AAC5F,EAAE;AACF,kGAAkG;AAClG,qGAAqG;AACrG,2DAA2D;AAC3D,MAAM,UAAU,iCAAiC,CAAC,WAAmB;IACnE,MAAM,MAAM,GAAG,wBAAwB,CAAC,WAAW,EAAE,uBAAuB,EAAE,CAAC,CAAC;IAChF,MAAM,MAAM,GAAG,QAAQ,IAAI,MAAM,CAAC;IAClC,MAAM,UAAU,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;IAC1C,MAAM,UAAU,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;IAEjF,MAAM,UAAU,GAAG,wBAAwB,EAAE,CAAC;IAC9C,MAAM,UAAU,GAAG,UAAU,KAAK,IAAI,IAAI,0BAA0B,CAAC,UAAU,CAAC,CAAC;IAEjF,IAAI,MAAiC,CAAC;IACtC,IAAI,MAAM;QAAE,MAAM,GAAG,aAAa,CAAC;SAC9B,IAAI,CAAC,UAAU;QAAE,MAAM,GAAG,mBAAmB,CAAC;SAC9C,IAAI,UAAU;QAAE,MAAM,GAAG,oBAAoB,CAAC;;QAC9C,MAAM,GAAG,IAAI,CAAC;IAEnB,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC;AACnG,CAAC;AAED,iGAAiG;AACjG,oEAAoE;AACpE,SAAS,eAAe,CAAC,SAA4B,EAAE,GAAW;IAChE,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,GAAG,CAAC;IACvC,OAAO,CAAC,GAAG,SAAS,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACvC,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export { createParsedAccelerator, disableGlobalShortcut, enableGlobalShortcut, enableGlobalShortcutSignals, equalsAccelerator, formatAcceleratorForDisplay, getAcceleratorKey, getAcceleratorKeyLabel, getAcceleratorModifierLabel, getAcceleratorModifiers, getRegisteredGlobalShortcuts, hasGlobalShortcutConflict, isAcceleratorValid, isGlobalShortcutRegistered, normalizeAccelerator, parseAccelerator, parseAcceleratorDetailed, registerGlobalShortcut, resolveCommandOrControlModifier, resumeAllGlobalShortcuts, suspendAllGlobalShortcuts, unregisterAllGlobalShortcuts, unregisterGlobalShortcut, } from './contract';
1
+ export { createParsedAccelerator, disableGlobalShortcut, disableShortcutGuards, disposeGlobalShortcutSignals, enableGlobalShortcut, enableGlobalShortcutSignals, enableShortcutGuards, equalsAccelerator, explainGlobalShortcutRegistration, findAcceleratorConflict, formatAcceleratorForDisplay, getAcceleratorKey, getAcceleratorKeyLabel, getAcceleratorModifierLabel, getAcceleratorModifiers, getRegisteredGlobalShortcuts, hasGlobalShortcutConflict, hasNativeShortcutBackend, isAcceleratorValid, isGlobalShortcutRegistered, normalizeAccelerator, parseAccelerator, parseAcceleratorDetailed, registerGlobalShortcut, resolveCommandOrControlModifier, resumeAllGlobalShortcuts, suspendAllGlobalShortcuts, unregisterAllGlobalShortcuts, unregisterGlobalShortcut, } from './contract';
2
2
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACrB,oBAAoB,EACpB,2BAA2B,EAC3B,iBAAiB,EACjB,2BAA2B,EAC3B,iBAAiB,EACjB,sBAAsB,EACtB,2BAA2B,EAC3B,uBAAuB,EACvB,4BAA4B,EAC5B,yBAAyB,EACzB,kBAAkB,EAClB,0BAA0B,EAC1B,oBAAoB,EACpB,gBAAgB,EAChB,wBAAwB,EACxB,sBAAsB,EACtB,+BAA+B,EAC/B,wBAAwB,EACxB,yBAAyB,EACzB,4BAA4B,EAC5B,wBAAwB,GACzB,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACrB,qBAAqB,EACrB,4BAA4B,EAC5B,oBAAoB,EACpB,2BAA2B,EAC3B,oBAAoB,EACpB,iBAAiB,EACjB,iCAAiC,EACjC,uBAAuB,EACvB,2BAA2B,EAC3B,iBAAiB,EACjB,sBAAsB,EACtB,2BAA2B,EAC3B,uBAAuB,EACvB,4BAA4B,EAC5B,yBAAyB,EACzB,wBAAwB,EACxB,kBAAkB,EAClB,0BAA0B,EAC1B,oBAAoB,EACpB,gBAAgB,EAChB,wBAAwB,EACxB,sBAAsB,EACtB,+BAA+B,EAC/B,wBAAwB,EACxB,yBAAyB,EACzB,4BAA4B,EAC5B,wBAAwB,GACzB,MAAM,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- export { createParsedAccelerator, disableGlobalShortcut, enableGlobalShortcut, enableGlobalShortcutSignals, equalsAccelerator, formatAcceleratorForDisplay, getAcceleratorKey, getAcceleratorKeyLabel, getAcceleratorModifierLabel, getAcceleratorModifiers, getRegisteredGlobalShortcuts, hasGlobalShortcutConflict, isAcceleratorValid, isGlobalShortcutRegistered, normalizeAccelerator, parseAccelerator, parseAcceleratorDetailed, registerGlobalShortcut, resolveCommandOrControlModifier, resumeAllGlobalShortcuts, suspendAllGlobalShortcuts, unregisterAllGlobalShortcuts, unregisterGlobalShortcut, } from './contract';
1
+ export { createParsedAccelerator, disableGlobalShortcut, disableShortcutGuards, disposeGlobalShortcutSignals, enableGlobalShortcut, enableGlobalShortcutSignals, enableShortcutGuards, equalsAccelerator, explainGlobalShortcutRegistration, findAcceleratorConflict, formatAcceleratorForDisplay, getAcceleratorKey, getAcceleratorKeyLabel, getAcceleratorModifierLabel, getAcceleratorModifiers, getRegisteredGlobalShortcuts, hasGlobalShortcutConflict, hasNativeShortcutBackend, isAcceleratorValid, isGlobalShortcutRegistered, normalizeAccelerator, parseAccelerator, parseAcceleratorDetailed, registerGlobalShortcut, resolveCommandOrControlModifier, resumeAllGlobalShortcuts, suspendAllGlobalShortcuts, unregisterAllGlobalShortcuts, unregisterGlobalShortcut, } from './contract';
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACrB,oBAAoB,EACpB,2BAA2B,EAC3B,iBAAiB,EACjB,2BAA2B,EAC3B,iBAAiB,EACjB,sBAAsB,EACtB,2BAA2B,EAC3B,uBAAuB,EACvB,4BAA4B,EAC5B,yBAAyB,EACzB,kBAAkB,EAClB,0BAA0B,EAC1B,oBAAoB,EACpB,gBAAgB,EAChB,wBAAwB,EACxB,sBAAsB,EACtB,+BAA+B,EAC/B,wBAAwB,EACxB,yBAAyB,EACzB,4BAA4B,EAC5B,wBAAwB,GACzB,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACrB,qBAAqB,EACrB,4BAA4B,EAC5B,oBAAoB,EACpB,2BAA2B,EAC3B,oBAAoB,EACpB,iBAAiB,EACjB,iCAAiC,EACjC,uBAAuB,EACvB,2BAA2B,EAC3B,iBAAiB,EACjB,sBAAsB,EACtB,2BAA2B,EAC3B,uBAAuB,EACvB,4BAA4B,EAC5B,yBAAyB,EACzB,wBAAwB,EACxB,kBAAkB,EAClB,0BAA0B,EAC1B,oBAAoB,EACpB,gBAAgB,EAChB,wBAAwB,EACxB,sBAAsB,EACtB,+BAA+B,EAC/B,wBAAwB,EACxB,yBAAyB,EACzB,4BAA4B,EAC5B,wBAAwB,GACzB,MAAM,YAAY,CAAC"}
@@ -1,18 +1,21 @@
1
- import type { Accelerator, AcceleratorParseError, ParsedAccelerator, ShortcutBackend, ShortcutEvent, ShortcutModifier, ShortcutSignals } from '@flighthq/types/contract';
1
+ import type { Accelerator, AcceleratorParseError, ParsedAccelerator, ShortcutBackend, ShortcutDropGuard, ShortcutEvent, ShortcutKeyName, ShortcutModifier, ShortcutSignals } from '@flighthq/types/contract';
2
2
  export declare function createParsedAccelerator(): ParsedAccelerator;
3
3
  export declare function createWebShortcutBackend(): ShortcutBackend;
4
4
  export declare function disableGlobalShortcut(accelerator: string): boolean;
5
+ export declare function disposeGlobalShortcutSignals(): void;
5
6
  export declare function enableGlobalShortcut(accelerator: string): boolean;
6
7
  export declare function enableGlobalShortcutSignals(): ShortcutSignals;
7
8
  export declare function equalsAccelerator(a: string, b: string): boolean;
9
+ export declare function findAcceleratorConflict(accelerator: string, candidates: readonly string[]): string | null;
8
10
  export declare function formatAcceleratorForDisplay(accelerator: string, platform?: string): string;
9
- export declare function getAcceleratorKey(accelerator: string): string | null;
10
- export declare function getAcceleratorKeyLabel(key: string): string;
11
+ export declare function getAcceleratorKey(accelerator: string): ShortcutKeyName | null;
12
+ export declare function getAcceleratorKeyLabel(key: ShortcutKeyName): string;
11
13
  export declare function getAcceleratorModifierLabel(modifier: ShortcutModifier, platform?: string): string;
12
14
  export declare function getAcceleratorModifiers(accelerator: string, out: ShortcutModifier[]): readonly ShortcutModifier[] | null;
13
15
  export declare function getRegisteredGlobalShortcuts(): readonly Accelerator[];
14
16
  export declare function getShortcutBackend(): ShortcutBackend;
15
17
  export declare function hasGlobalShortcutConflict(accelerator: string): boolean;
18
+ export declare function hasNativeShortcutBackend(): boolean;
16
19
  export declare function isAcceleratorValid(input: string): boolean;
17
20
  export declare function isGlobalShortcutRegistered(accelerator: string): boolean;
18
21
  export declare function normalizeAccelerator(input: string): Accelerator | null;
@@ -22,6 +25,7 @@ export declare function registerGlobalShortcut(accelerator: string, handler: (ev
22
25
  export declare function resolveCommandOrControlModifier(platform?: string): Exclude<ShortcutModifier, 'CommandOrControl'>;
23
26
  export declare function resumeAllGlobalShortcuts(): void;
24
27
  export declare function setShortcutBackend(backend: ShortcutBackend | null): void;
28
+ export declare function setShortcutDropGuard(guard: ShortcutDropGuard | null): void;
25
29
  export declare function suspendAllGlobalShortcuts(): void;
26
30
  export declare function unregisterAllGlobalShortcuts(): void;
27
31
  export declare function unregisterGlobalShortcut(accelerator: string): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"shortcut.d.ts","sourceRoot":"","sources":["../src/shortcut.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,WAAW,EACX,qBAAqB,EACrB,iBAAiB,EACjB,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,eAAe,EAChB,MAAM,0BAA0B,CAAC;AAGlC,wBAAgB,uBAAuB,IAAI,iBAAiB,CAE3D;AAKD,wBAAgB,wBAAwB,IAAI,eAAe,CAwB1D;AAID,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAIlE;AAGD,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAIjE;AAMD,wBAAgB,2BAA2B,IAAI,eAAe,CAI7D;AAID,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAK/D;AAOD,wBAAgB,2BAA2B,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAW1F;AAGD,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGpE;AAID,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE1D;AAKD,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,gBAAgB,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAGjG;AAID,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,gBAAgB,EAAE,GACtB,SAAS,gBAAgB,EAAE,GAAG,IAAI,CAMpC;AAMD,wBAAgB,4BAA4B,IAAI,SAAS,WAAW,EAAE,CAQrE;AAGD,wBAAgB,kBAAkB,IAAI,eAAe,CAGpD;AAID,wBAAgB,yBAAyB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAItE;AAKD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEzD;AAID,wBAAgB,0BAA0B,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAIvE;AAKD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAItE;AAKD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,iBAAiB,GAAG,iBAAiB,GAAG,IAAI,CAMhG;AAKD,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,iBAAiB,GACrB,iBAAiB,GAAG,qBAAqB,CAM3C;AAKD,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,CAAC,KAAK,EAAE,QAAQ,CAAC,aAAa,CAAC,KAAK,IAAI,GAChD,OAAO,CAQT;AAKD,wBAAgB,+BAA+B,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,EAAE,kBAAkB,CAAC,CAEhH;AAGD,wBAAgB,wBAAwB,IAAI,IAAI,CAE/C;AAGD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI,GAAG,IAAI,CAExE;AAID,wBAAgB,yBAAyB,IAAI,IAAI,CAEhD;AAGD,wBAAgB,4BAA4B,IAAI,IAAI,CAEnD;AAID,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAIrE"}
1
+ {"version":3,"file":"shortcut.d.ts","sourceRoot":"","sources":["../src/shortcut.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,WAAW,EACX,qBAAqB,EACrB,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,gBAAgB,EAEhB,eAAe,EAChB,MAAM,0BAA0B,CAAC;AAGlC,wBAAgB,uBAAuB,IAAI,iBAAiB,CAE3D;AAKD,wBAAgB,wBAAwB,IAAI,eAAe,CAwB1D;AAID,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAIlE;AAMD,wBAAgB,4BAA4B,IAAI,IAAI,CAInD;AAGD,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAIjE;AAMD,wBAAgB,2BAA2B,IAAI,eAAe,CAI7D;AAID,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAK/D;AASD,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI,CAOzG;AAOD,wBAAgB,2BAA2B,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAW1F;AAGD,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAG7E;AAID,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,eAAe,GAAG,MAAM,CAEnE;AAKD,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,gBAAgB,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAGjG;AAID,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,gBAAgB,EAAE,GACtB,SAAS,gBAAgB,EAAE,GAAG,IAAI,CAMpC;AAMD,wBAAgB,4BAA4B,IAAI,SAAS,WAAW,EAAE,CAQrE;AAMD,wBAAgB,kBAAkB,IAAI,eAAe,CAIpD;AAID,wBAAgB,yBAAyB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAItE;AAKD,wBAAgB,wBAAwB,IAAI,OAAO,CAElD;AAKD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEzD;AAID,wBAAgB,0BAA0B,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAIvE;AAKD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAItE;AAKD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,iBAAiB,GAAG,iBAAiB,GAAG,IAAI,CAIhG;AAKD,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,iBAAiB,GACrB,iBAAiB,GAAG,qBAAqB,CAI3C;AAKD,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,CAAC,KAAK,EAAE,QAAQ,CAAC,aAAa,CAAC,KAAK,IAAI,GAChD,OAAO,CAQT;AAKD,wBAAgB,+BAA+B,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,EAAE,kBAAkB,CAAC,CAEhH;AAGD,wBAAgB,wBAAwB,IAAI,IAAI,CAG/C;AAGD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI,GAAG,IAAI,CAExE;AAKD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI,GAAG,IAAI,CAE1E;AAID,wBAAgB,yBAAyB,IAAI,IAAI,CAGhD;AAGD,wBAAgB,4BAA4B,IAAI,IAAI,CAGnD;AAID,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAIrE"}
package/dist/shortcut.js CHANGED
@@ -1,4 +1,4 @@
1
- import { createSignal, emitSignal } from '@flighthq/signals/contract';
1
+ import { clearSignal, createSignal, emitSignal } from '@flighthq/signals/contract';
2
2
  // Allocates a zeroed ParsedAccelerator for use as an `out` argument to parseAccelerator.
3
3
  export function createParsedAccelerator() {
4
4
  return { key: '', modifiers: [] };
@@ -34,14 +34,24 @@ export function createWebShortcutBackend() {
34
34
  // Disables a registered global shortcut without unregistering it; the handler is preserved and
35
35
  // can be re-enabled later. Returns false when not registered or unsupported.
36
36
  export function disableGlobalShortcut(accelerator) {
37
- const normalized = normalizeAccelerator(accelerator);
37
+ const normalized = _normalizeForCommand(accelerator, 'disableGlobalShortcut');
38
38
  if (normalized === null)
39
39
  return false;
40
40
  return getShortcutBackend().setEnabled(normalized, false);
41
41
  }
42
+ // Releases the global shortcut signal group armed by enableGlobalShortcutSignals: disconnects every
43
+ // onTrigger listener and drops the group so it becomes eligible for collection. A later
44
+ // enableGlobalShortcutSignals arms a fresh group — the identity is not preserved across a dispose.
45
+ // Registered shortcuts are untouched; their directly-registered handlers keep firing.
46
+ export function disposeGlobalShortcutSignals() {
47
+ if (_signals === null)
48
+ return;
49
+ clearSignal(_signals.onTrigger);
50
+ _signals = null;
51
+ }
42
52
  // Re-enables a previously disabled global shortcut. Returns false when not registered or unsupported.
43
53
  export function enableGlobalShortcut(accelerator) {
44
- const normalized = normalizeAccelerator(accelerator);
54
+ const normalized = _normalizeForCommand(accelerator, 'enableGlobalShortcut');
45
55
  if (normalized === null)
46
56
  return false;
47
57
  return getShortcutBackend().setEnabled(normalized, true);
@@ -65,6 +75,23 @@ export function equalsAccelerator(a, b) {
65
75
  return false;
66
76
  return na === nb;
67
77
  }
78
+ // Returns the first accelerator in `candidates` that names the same chord as `accelerator`, or null
79
+ // when none does. The conflict probe for a key-binding UI: it answers "is this chord already spoken
80
+ // for in *my* binding list", which is the question a settings screen asks before it lets a user
81
+ // commit a rebind — hasGlobalShortcutConflict only sees chords already registered with the OS, so it
82
+ // cannot see a pending list, another profile's bindings, or a chord the app reserves for itself.
83
+ // Comparison is by normalized form, so any accepted spelling on either side matches. Unparseable
84
+ // candidates never match, and an unparseable `accelerator` returns null.
85
+ export function findAcceleratorConflict(accelerator, candidates) {
86
+ const normalized = normalizeAccelerator(accelerator);
87
+ if (normalized === null)
88
+ return null;
89
+ for (const candidate of candidates) {
90
+ if (normalizeAccelerator(candidate) === normalized)
91
+ return candidate;
92
+ }
93
+ return null;
94
+ }
68
95
  // Formats an accelerator string for human-readable display per the current OS:
69
96
  // macOS: ⌘⇧K (symbols, no separator)
70
97
  // Windows/Linux: Ctrl+Shift+K (text labels, '+' separator)
@@ -126,10 +153,15 @@ export function getRegisteredGlobalShortcuts() {
126
153
  return result;
127
154
  }
128
155
  // The active shortcut backend, or a lazily-created web default. There is always a backend.
156
+ // The default is cached in its own slot rather than assigned into the installed-backend slot, so
157
+ // "a host installed a backend" stays distinguishable from "we fell back" for the whole process —
158
+ // folding the two together would make hasNativeShortcutBackend read true after the first command.
129
159
  export function getShortcutBackend() {
130
- if (_backend === null)
131
- _backend = createWebShortcutBackend();
132
- return _backend;
160
+ if (_backend !== null)
161
+ return _backend;
162
+ if (_webBackend === null)
163
+ _webBackend = createWebShortcutBackend();
164
+ return _webBackend;
133
165
  }
134
166
  // True when the (normalized) chord is already registered. A conflict probe over isGlobalShortcutRegistered.
135
167
  // Returns false when `accelerator` is unparseable.
@@ -139,6 +171,12 @@ export function hasGlobalShortcutConflict(accelerator) {
139
171
  return false;
140
172
  return isGlobalShortcutRegistered(normalized);
141
173
  }
174
+ // True when a native host backend is installed. False means the default web backend is active, whose
175
+ // registry is a sentinel — no chord can register, and every command is a no-op. The capability probe
176
+ // an application uses to decide whether to offer a global-hotkey settings screen at all.
177
+ export function hasNativeShortcutBackend() {
178
+ return _backend !== null;
179
+ }
142
180
  // True when `input` is a parseable accelerator (valid modifiers + recognized key).
143
181
  // Callers can use this to distinguish a malformed accelerator from an unsupported one before
144
182
  // attempting to register.
@@ -169,9 +207,7 @@ export function parseAccelerator(input, out) {
169
207
  const result = _parse(input);
170
208
  if (result === null)
171
209
  return null;
172
- out.key = result.key;
173
- out.modifiers = result.modifiers.slice();
174
- return out;
210
+ return _copyParsed(result, out);
175
211
  }
176
212
  // Like parseAccelerator but returns an AcceleratorParseError describing why parsing failed instead
177
213
  // of null. The common path (parse + ignore error) should use parseAccelerator; this is for
@@ -180,15 +216,13 @@ export function parseAcceleratorDetailed(input, out) {
180
216
  const result = _parseDetailed(input);
181
217
  if ('reason' in result)
182
218
  return result;
183
- out.key = result.key;
184
- out.modifiers = result.modifiers.slice();
185
- return out;
219
+ return _copyParsed(result, out);
186
220
  }
187
221
  // Registers a global hotkey. Returns false when the host lacks global-hotkey support (e.g. web).
188
222
  // Input is normalized before registration so any accepted spelling maps to the same registry slot.
189
223
  // When enableGlobalShortcutSignals() has been called, the onTrigger signal fires after the handler.
190
224
  export function registerGlobalShortcut(accelerator, handler) {
191
- const normalized = normalizeAccelerator(accelerator);
225
+ const normalized = _normalizeForCommand(accelerator, 'registerGlobalShortcut');
192
226
  if (normalized === null)
193
227
  return false;
194
228
  const wrappedHandler = (event) => {
@@ -206,31 +240,47 @@ export function resolveCommandOrControlModifier(platform) {
206
240
  }
207
241
  // Resumes all global shortcuts after suspendAllGlobalShortcuts(). No-op on unsupported hosts.
208
242
  export function resumeAllGlobalShortcuts() {
243
+ _reportNoNativeBackend('resumeAllGlobalShortcuts', '');
209
244
  getShortcutBackend().setAllEnabled(true);
210
245
  }
211
246
  // Installs a native host shortcut backend; pass null to fall back to the web default.
212
247
  export function setShortcutBackend(backend) {
213
248
  _backend = backend;
214
249
  }
250
+ // Installs the drop guard consulted whenever a global-shortcut command returns its sentinel for a
251
+ // knowable caller error; null uninstalls it. This is the diagnostics seam, not the caller-facing
252
+ // entry point — use enableShortcutGuards, which installs the @flighthq/log reporter through here.
253
+ export function setShortcutDropGuard(guard) {
254
+ _dropGuard = guard;
255
+ }
215
256
  // Temporarily silences all registered global shortcuts without unregistering them — useful when a
216
257
  // modal or text field has focus. Resume with resumeAllGlobalShortcuts(). No-op on unsupported hosts.
217
258
  export function suspendAllGlobalShortcuts() {
259
+ _reportNoNativeBackend('suspendAllGlobalShortcuts', '');
218
260
  getShortcutBackend().setAllEnabled(false);
219
261
  }
220
262
  // Unregisters every global hotkey. No-op when the host lacks global-hotkey support.
221
263
  export function unregisterAllGlobalShortcuts() {
264
+ _reportNoNativeBackend('unregisterAllGlobalShortcuts', '');
222
265
  getShortcutBackend().unregisterAll();
223
266
  }
224
267
  // Unregisters a global hotkey. Returns false when not registered or unsupported (e.g. web).
225
268
  // Input is normalized before the lookup.
226
269
  export function unregisterGlobalShortcut(accelerator) {
227
- const normalized = normalizeAccelerator(accelerator);
270
+ const normalized = _normalizeForCommand(accelerator, 'unregisterGlobalShortcut');
228
271
  if (normalized === null)
229
272
  return false;
230
273
  return getShortcutBackend().unregister(normalized);
231
274
  }
275
+ // The backend a native host installed, and separately the web default getShortcutBackend falls back
276
+ // to. Keeping them apart is what lets hasNativeShortcutBackend answer honestly.
232
277
  let _backend = null;
278
+ let _webBackend = null;
233
279
  let _signals = null;
280
+ // Diagnostics seam: enableShortcutGuards (separately imported, so its message text and its
281
+ // @flighthq/log dependency shake out of a production bundle) fills this, and the command functions
282
+ // reach it through the null check. Not enabling guards costs one comparison per command.
283
+ let _dropGuard = null;
234
284
  const _emptyList = [];
235
285
  // Canonical modifier order used in normalized form: Control < Alt < Shift < Meta < Super < CommandOrControl.
236
286
  // CommandOrControl carries its own ordinal (last) so any chord — including one mixing Control and
@@ -250,7 +300,9 @@ const _modifierAliases = new Map([
250
300
  ['super', 'Super'],
251
301
  ['win', 'Super'],
252
302
  ]);
253
- // Alias map: lowercase alias → canonical ShortcutKeyName (and other accepted key names).
303
+ // Alias map: lowercase alias → canonical ShortcutKeyName. Typing the values as ShortcutKeyName makes
304
+ // the header the checker: a misspelled canonical name here is a compile error rather than an
305
+ // accelerator that normalizes to a chord no backend recognizes.
254
306
  const _keyAliases = new Map([
255
307
  // Letters (uppercase canonical form)
256
308
  ['a', 'A'],
@@ -345,7 +397,13 @@ const _keyAliases = new Map([
345
397
  ['spacebar', 'Space'],
346
398
  [' ', 'Space'],
347
399
  ['tab', 'Tab'],
348
- // Numpad
400
+ // Numpad. The num*/num-operator short forms are the spellings Electron's accelerator syntax
401
+ // documents, so a chord copied from an Electron app parses unchanged.
402
+ ['numadd', 'NumpadAdd'],
403
+ ['numdec', 'NumpadDecimal'],
404
+ ['numdiv', 'NumpadDivide'],
405
+ ['nummult', 'NumpadMultiply'],
406
+ ['numsub', 'NumpadSubtract'],
349
407
  ['num0', 'Numpad0'],
350
408
  ['num1', 'Numpad1'],
351
409
  ['num2', 'Numpad2'],
@@ -372,8 +430,12 @@ const _keyAliases = new Map([
372
430
  ['numpadenter', 'NumpadEnter'],
373
431
  ['numpadmultiply', 'NumpadMultiply'],
374
432
  ['numpadsubtract', 'NumpadSubtract'],
375
- // Punctuation / symbols
433
+ // Punctuation / symbols. Both symbol characters that double as chord separators are here: the
434
+ // tokenizer hands a trailing '+' or '-' through as a key token rather than eating it, so
435
+ // 'CommandOrControl++' and 'CommandOrControl+-' — the conventional zoom pair — resolve like any
436
+ // other key.
376
437
  ["'", 'Quote'],
438
+ ['+', 'Plus'],
377
439
  [',', 'Comma'],
378
440
  ['-', 'Minus'],
379
441
  ['.', 'Period'],
@@ -396,7 +458,6 @@ const _keyAliases = new Map([
396
458
  ['quote', 'Quote'],
397
459
  ['semicolon', 'Semicolon'],
398
460
  ['slash', 'Slash'],
399
- // Note: '+' as a key name is mapped via 'plus'; bare '+' is the separator so it is filtered out.
400
461
  // Media
401
462
  ['medianexttrack', 'MediaNextTrack'],
402
463
  ['mediaplaypause', 'MediaPlayPause'],
@@ -470,6 +531,37 @@ function _isMacOS(platform) {
470
531
  const p = navigator.platform ?? '';
471
532
  return /mac/i.test(p);
472
533
  }
534
+ // Copies a successful parse into a caller-owned ParsedAccelerator. `out.modifiers` is cleared and
535
+ // refilled rather than reassigned, so the array the caller allocated with createParsedAccelerator
536
+ // stays the array they hold — an out parameter that swapped the array underneath would leave any
537
+ // retained reference silently stale.
538
+ function _copyParsed(source, out) {
539
+ out.key = source.key;
540
+ out.modifiers.length = 0;
541
+ for (const modifier of source.modifiers)
542
+ out.modifiers.push(modifier);
543
+ return out;
544
+ }
545
+ // Builds the normalized Accelerator string from a _Parsed result.
546
+ function _formatNormalized(parsed) {
547
+ if (parsed.modifiers.length === 0)
548
+ return parsed.key;
549
+ return [...parsed.modifiers, parsed.key].join('+');
550
+ }
551
+ // Normalizes on behalf of a command function, reporting an unparseable input and a missing native
552
+ // backend to the drop guard on the way through. When no guard is installed — the production default
553
+ // — this is exactly normalizeAccelerator plus one null comparison.
554
+ function _normalizeForCommand(accelerator, operation) {
555
+ if (_dropGuard === null)
556
+ return normalizeAccelerator(accelerator);
557
+ const result = _parseDetailed(accelerator);
558
+ if ('reason' in result) {
559
+ _dropGuard({ accelerator, operation, parseError: result, reason: 'unparseable' });
560
+ return null;
561
+ }
562
+ _reportNoNativeBackend(operation, accelerator);
563
+ return _formatNormalized(result);
564
+ }
473
565
  // Core parser. Returns a _Parsed on success or null on failure.
474
566
  function _parse(input) {
475
567
  const result = _parseDetailed(input);
@@ -479,15 +571,11 @@ function _parse(input) {
479
571
  }
480
572
  // Core parser with error diagnostics.
481
573
  function _parseDetailed(input) {
482
- if (!input || input.trim().length === 0) {
483
- return { reason: 'empty', token: '' };
484
- }
485
- const tokens = _splitTokens(input.trim());
574
+ const tokens = _splitTokens(input.trim(), _tokenScratch);
486
575
  if (tokens.length === 0) {
487
576
  return { reason: 'empty', token: '' };
488
577
  }
489
578
  const modifiers = [];
490
- const seenModifiers = new Set();
491
579
  let key = null;
492
580
  // Process all tokens: if a token is a known modifier alias, treat it as a modifier.
493
581
  // The last non-modifier token is the key; if all tokens are modifiers, it is missing-key.
@@ -495,10 +583,10 @@ function _parseDetailed(input) {
495
583
  const lower = token.toLowerCase();
496
584
  const mod = _modifierAliases.get(lower);
497
585
  if (mod !== undefined) {
498
- if (seenModifiers.has(mod)) {
586
+ // A chord carries at most six modifiers, so a linear scan beats allocating a Set per parse.
587
+ if (modifiers.indexOf(mod) !== -1) {
499
588
  return { reason: 'duplicate-modifier', token };
500
589
  }
501
- seenModifiers.add(mod);
502
590
  modifiers.push(mod);
503
591
  }
504
592
  else {
@@ -522,14 +610,38 @@ function _parseDetailed(input) {
522
610
  modifiers.sort((a, b) => _modifierOrder.indexOf(a) - _modifierOrder.indexOf(b));
523
611
  return { key: canonicalKey, modifiers };
524
612
  }
525
- // Splits input into tokens using '+' or '-' as separator. Filters out empty tokens from split.
526
- function _splitTokens(input) {
527
- return input.split(/[+-]/).filter((t) => t.length > 0);
528
- }
529
- // Builds the normalized Accelerator string from a _Parsed result.
530
- function _formatNormalized(parsed) {
531
- if (parsed.modifiers.length === 0)
532
- return parsed.key;
533
- return [...parsed.modifiers, parsed.key].join('+');
613
+ // Reports to the drop guard that a command reached the default web backend, whose registry is a
614
+ // sentinel, so the command could not have taken effect on any input. Silent once a native backend is
615
+ // installed: a native backend answering false is a real answer, not a drop.
616
+ function _reportNoNativeBackend(operation, accelerator) {
617
+ if (_dropGuard === null || _backend !== null)
618
+ return;
619
+ _dropGuard({ accelerator, operation, parseError: null, reason: 'no-native-backend' });
620
+ }
621
+ // Splits input into tokens on '+' and '-', writing into `out` and returning it.
622
+ //
623
+ // A separator character only separates when it *terminates* a token, which is what keeps a literal
624
+ // '+' or '-' key reachable: in 'Control+-' the '-' opens a token rather than closing the empty one,
625
+ // so it survives as the key. A naive split on /[+-]/ drops it, and with it the two most common
626
+ // accelerators an application registers — 'CommandOrControl+-' and 'CommandOrControl++' for zoom.
627
+ // The same rule makes a lone '+' or '-' a valid one-key accelerator, and leaves 'Ctrl-Shift-K'
628
+ // (dash as separator) tokenizing exactly as before.
629
+ function _splitTokens(input, out) {
630
+ out.length = 0;
631
+ let start = 0;
632
+ for (let i = 0; i < input.length; i++) {
633
+ const ch = input.charAt(i);
634
+ if ((ch === '+' || ch === '-') && i > start) {
635
+ out.push(input.slice(start, i));
636
+ start = i + 1;
637
+ }
638
+ }
639
+ if (start < input.length)
640
+ out.push(input.slice(start));
641
+ return out;
534
642
  }
643
+ // Scratch for _splitTokens. Contained entirely within _parseDetailed — the token strings are read
644
+ // into modifiers/key before the next parse can run, and the array itself never escapes — so reusing
645
+ // it costs no aliasing hazard.
646
+ const _tokenScratch = [];
535
647
  //# sourceMappingURL=shortcut.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"shortcut.js","sourceRoot":"","sources":["../src/shortcut.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"shortcut.js","sourceRoot":"","sources":["../src/shortcut.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,8 @@
1
1
  {
2
2
  "name": "@flighthq/shortcut",
3
- "version": "0.3.0-next.906.07cea63",
3
+ "version": "0.3.1-next.209.43ef1bc",
4
+ "author": "Joshua Granick and other contributors",
5
+ "license": "MIT",
4
6
  "repository": {
5
7
  "type": "git",
6
8
  "url": "https://github.com/flighthq/flight.git",
@@ -36,8 +38,9 @@
36
38
  "clean:dist": "tsx ../../scripts/clean-package-dist.ts"
37
39
  },
38
40
  "dependencies": {
39
- "@flighthq/signals": "0.3.0-next.906.07cea63",
40
- "@flighthq/types": "0.3.0-next.906.07cea63"
41
+ "@flighthq/log": "0.3.1-next.209.43ef1bc",
42
+ "@flighthq/signals": "0.3.1-next.209.43ef1bc",
43
+ "@flighthq/types": "0.3.1-next.209.43ef1bc"
41
44
  },
42
45
  "devDependencies": {
43
46
  "typescript": "^5.3.0"
@@ -0,0 +1,122 @@
1
+ import { addLogSink, createMemoryLogSink, getMemoryLogSinkEntries, removeLogSink } from '@flighthq/log/contract';
2
+ import type { LogEntry, ShortcutBackend, ShortcutDrop } from '@flighthq/types/contract';
3
+
4
+ import { disableShortcutGuards, enableShortcutGuards } from './enableShortcutGuards';
5
+ import { registerGlobalShortcut, setShortcutBackend, setShortcutDropGuard, unregisterGlobalShortcut } from './shortcut';
6
+
7
+ // A native-looking backend, so the no-native-backend drop does not fire and the parse drop can be
8
+ // observed alone.
9
+ function nativeBackend(): ShortcutBackend {
10
+ return {
11
+ getRegistered() {
12
+ return [];
13
+ },
14
+ isRegistered() {
15
+ return false;
16
+ },
17
+ register() {
18
+ return true;
19
+ },
20
+ setAllEnabled() {},
21
+ setEnabled() {
22
+ return false;
23
+ },
24
+ unregister() {
25
+ return true;
26
+ },
27
+ unregisterAll() {},
28
+ };
29
+ }
30
+
31
+ function captureLog(run: () => void): readonly LogEntry[] {
32
+ const sink = createMemoryLogSink(8);
33
+ addLogSink(sink.sink);
34
+ try {
35
+ run();
36
+ return getMemoryLogSinkEntries(sink);
37
+ } finally {
38
+ removeLogSink(sink.sink);
39
+ }
40
+ }
41
+
42
+ function messageOf(entry: Readonly<LogEntry>): string {
43
+ return String((entry.data as Record<string, unknown>).message);
44
+ }
45
+
46
+ afterEach(() => {
47
+ disableShortcutGuards();
48
+ setShortcutBackend(null);
49
+ });
50
+
51
+ describe('disableShortcutGuards', () => {
52
+ it('uninstalls the guard so a later drop reports nothing', () => {
53
+ setShortcutBackend(nativeBackend());
54
+ enableShortcutGuards();
55
+ disableShortcutGuards();
56
+ const entries = captureLog(() => {
57
+ registerGlobalShortcut('Control+NotAKey', () => {});
58
+ });
59
+ expect(entries.length).toBe(0);
60
+ });
61
+
62
+ it('is safe to call without a prior enable', () => {
63
+ expect(() => disableShortcutGuards()).not.toThrow();
64
+ });
65
+ });
66
+
67
+ describe('enableShortcutGuards', () => {
68
+ // logOnce dedupes by key for the lifetime of the process, so each reason is asserted in exactly one
69
+ // test in this file and later tests observe the suppressed (zero-entry) behavior instead.
70
+ it('warns once, naming the call and the parse reason, when an accelerator does not parse', () => {
71
+ setShortcutBackend(nativeBackend());
72
+ enableShortcutGuards();
73
+ const entries = captureLog(() => {
74
+ registerGlobalShortcut('Control+NotAKey', () => {});
75
+ });
76
+ expect(entries.length).toBe(1);
77
+ const message = messageOf(entries[0]);
78
+ expect(message).toContain('registerGlobalShortcut');
79
+ expect(message).toContain('Control+NotAKey');
80
+ expect(message).toContain('unknown-key');
81
+ expect(message).toContain("at 'NotAKey'");
82
+ });
83
+
84
+ it('suppresses a repeat of the same reason', () => {
85
+ setShortcutBackend(nativeBackend());
86
+ enableShortcutGuards();
87
+ const entries = captureLog(() => {
88
+ unregisterGlobalShortcut('Control+AlsoNotAKey');
89
+ });
90
+ expect(entries.length).toBe(0);
91
+ });
92
+
93
+ it('warns once when a command reaches the default web backend, naming the missing native backend', () => {
94
+ enableShortcutGuards();
95
+ const entries = captureLog(() => {
96
+ registerGlobalShortcut('Control+K', () => {});
97
+ });
98
+ expect(entries.length).toBe(1);
99
+ const message = messageOf(entries[0]);
100
+ expect(message).toContain('registerGlobalShortcut');
101
+ expect(message).toContain('no native shortcut backend');
102
+ expect(message).toContain('setShortcutBackend');
103
+ });
104
+
105
+ it('stays silent once a native backend is installed — a native false is an answer, not a drop', () => {
106
+ setShortcutBackend(nativeBackend());
107
+ enableShortcutGuards();
108
+ const entries = captureLog(() => {
109
+ registerGlobalShortcut('Control+K', () => {});
110
+ });
111
+ expect(entries.length).toBe(0);
112
+ });
113
+
114
+ it('is idempotent — a second enable leaves exactly one guard installed', () => {
115
+ enableShortcutGuards();
116
+ enableShortcutGuards();
117
+ const drops: ShortcutDrop[] = [];
118
+ setShortcutDropGuard((drop) => drops.push({ ...drop }));
119
+ registerGlobalShortcut('Control+K', () => {});
120
+ expect(drops.length).toBe(1);
121
+ });
122
+ });
@@ -0,0 +1,93 @@
1
+ import type { ShortcutBackend } from '@flighthq/types/contract';
2
+
3
+ import { explainGlobalShortcutRegistration } from './explainGlobalShortcutRegistration';
4
+ import { setShortcutBackend } from './shortcut';
5
+
6
+ function nativeBackend(registered: readonly string[] = []): ShortcutBackend {
7
+ const entries = new Set(registered);
8
+ return {
9
+ getRegistered() {
10
+ return [...entries];
11
+ },
12
+ isRegistered(accelerator) {
13
+ return entries.has(accelerator);
14
+ },
15
+ register(accelerator) {
16
+ entries.add(accelerator);
17
+ return true;
18
+ },
19
+ setAllEnabled() {},
20
+ setEnabled() {
21
+ return true;
22
+ },
23
+ unregister(accelerator) {
24
+ return entries.delete(accelerator);
25
+ },
26
+ unregisterAll() {
27
+ entries.clear();
28
+ },
29
+ };
30
+ }
31
+
32
+ afterEach(() => {
33
+ setShortcutBackend(null);
34
+ });
35
+
36
+ describe('explainGlobalShortcutRegistration', () => {
37
+ it('reports ok for a free chord on a native backend', () => {
38
+ setShortcutBackend(nativeBackend());
39
+ expect(explainGlobalShortcutRegistration('Ctrl+Shift+K')).toEqual({
40
+ accelerator: 'Ctrl+Shift+K',
41
+ hasNativeBackend: true,
42
+ normalized: 'Control+Shift+K',
43
+ parseError: null,
44
+ registered: false,
45
+ reason: 'ok',
46
+ });
47
+ });
48
+
49
+ it('reports already-registered through an alias spelling, since the register path normalizes first', () => {
50
+ setShortcutBackend(nativeBackend(['Control+Shift+K']));
51
+ const explanation = explainGlobalShortcutRegistration('ctrl+shift+k');
52
+ expect(explanation.reason).toBe('already-registered');
53
+ expect(explanation.normalized).toBe('Control+Shift+K');
54
+ expect(explanation.registered).toBe(true);
55
+ expect(explanation.parseError).toBeNull();
56
+ });
57
+
58
+ it('reports no-native-backend on the web default, and never claims a registration there', () => {
59
+ const explanation = explainGlobalShortcutRegistration('Control+K');
60
+ expect(explanation.reason).toBe('no-native-backend');
61
+ expect(explanation.hasNativeBackend).toBe(false);
62
+ expect(explanation.registered).toBe(false);
63
+ expect(explanation.normalized).toBe('Control+K');
64
+ });
65
+
66
+ it('reports unparseable with the parse error, outranking a missing backend', () => {
67
+ const explanation = explainGlobalShortcutRegistration('Control+NotAKey');
68
+ expect(explanation.reason).toBe('unparseable');
69
+ expect(explanation.normalized).toBeNull();
70
+ expect(explanation.parseError).toEqual({ reason: 'unknown-key', token: 'NotAKey' });
71
+ // The backend is also missing here, but the input error is the root cause and wins.
72
+ expect(explanation.hasNativeBackend).toBe(false);
73
+ });
74
+
75
+ it('echoes the caller spelling rather than the normalized form', () => {
76
+ setShortcutBackend(nativeBackend());
77
+ expect(explainGlobalShortcutRegistration('cmd-shift-p').accelerator).toBe('cmd-shift-p');
78
+ });
79
+
80
+ it('registers nothing and mutates no state', () => {
81
+ const backend = nativeBackend();
82
+ setShortcutBackend(backend);
83
+ explainGlobalShortcutRegistration('Control+K');
84
+ explainGlobalShortcutRegistration('Control+K');
85
+ expect(backend.getRegistered()).toEqual([]);
86
+ });
87
+
88
+ it('does not throw on empty or garbage input', () => {
89
+ expect(explainGlobalShortcutRegistration('').reason).toBe('unparseable');
90
+ expect(explainGlobalShortcutRegistration('').parseError).toEqual({ reason: 'empty', token: '' });
91
+ expect(explainGlobalShortcutRegistration('Control+').parseError).toEqual({ reason: 'missing-key', token: '' });
92
+ });
93
+ });
@@ -3,6 +3,7 @@ import type {
3
3
  AcceleratorParseError,
4
4
  ParsedAccelerator,
5
5
  ShortcutBackend,
6
+ ShortcutDrop,
6
7
  ShortcutEvent,
7
8
  ShortcutModifier,
8
9
  } from '@flighthq/types/contract';
@@ -12,8 +13,10 @@ import {
12
13
  createParsedAccelerator,
13
14
  createWebShortcutBackend,
14
15
  disableGlobalShortcut,
16
+ disposeGlobalShortcutSignals,
15
17
  enableGlobalShortcut,
16
18
  enableGlobalShortcutSignals,
19
+ findAcceleratorConflict,
17
20
  formatAcceleratorForDisplay,
18
21
  getAcceleratorKey,
19
22
  getAcceleratorKeyLabel,
@@ -22,6 +25,7 @@ import {
22
25
  getRegisteredGlobalShortcuts,
23
26
  getShortcutBackend,
24
27
  hasGlobalShortcutConflict,
28
+ hasNativeShortcutBackend,
25
29
  isAcceleratorValid,
26
30
  isGlobalShortcutRegistered,
27
31
  normalizeAccelerator,
@@ -31,6 +35,7 @@ import {
31
35
  resolveCommandOrControlModifier,
32
36
  resumeAllGlobalShortcuts,
33
37
  setShortcutBackend,
38
+ setShortcutDropGuard,
34
39
  suspendAllGlobalShortcuts,
35
40
  unregisterAllGlobalShortcuts,
36
41
  unregisterGlobalShortcut,
@@ -78,6 +83,7 @@ function fakeBackend(): FakeBackend {
78
83
 
79
84
  afterEach(() => {
80
85
  setShortcutBackend(null);
86
+ setShortcutDropGuard(null);
81
87
  // Disconnect any signal listeners registered in this test to avoid cross-test bleed.
82
88
  const signals = enableGlobalShortcutSignals();
83
89
  clearSignal(signals.onTrigger);
@@ -132,6 +138,49 @@ describe('disableGlobalShortcut', () => {
132
138
  });
133
139
  });
134
140
 
141
+ describe('disposeGlobalShortcutSignals', () => {
142
+ it('disconnects onTrigger listeners so a later trigger does not reach them', () => {
143
+ const backend = fakeBackend();
144
+ setShortcutBackend(backend);
145
+ const signals = enableGlobalShortcutSignals();
146
+ let fired = 0;
147
+ connectSignal(signals.onTrigger, () => {
148
+ fired++;
149
+ });
150
+ registerGlobalShortcut('Control+K', () => {});
151
+ backend.entries.get('Control+K')!.handler({ accelerator: 'Control+K' });
152
+ expect(fired).toBe(1);
153
+
154
+ disposeGlobalShortcutSignals();
155
+ backend.entries.get('Control+K')!.handler({ accelerator: 'Control+K' });
156
+ expect(fired).toBe(1);
157
+ });
158
+
159
+ it('arms a fresh group on the next enable — identity is not preserved across a dispose', () => {
160
+ const before = enableGlobalShortcutSignals();
161
+ disposeGlobalShortcutSignals();
162
+ expect(enableGlobalShortcutSignals()).not.toBe(before);
163
+ });
164
+
165
+ it('leaves directly-registered handlers firing', () => {
166
+ const backend = fakeBackend();
167
+ setShortcutBackend(backend);
168
+ enableGlobalShortcutSignals();
169
+ let handled = 0;
170
+ registerGlobalShortcut('Control+K', () => {
171
+ handled++;
172
+ });
173
+ disposeGlobalShortcutSignals();
174
+ backend.entries.get('Control+K')!.handler({ accelerator: 'Control+K' });
175
+ expect(handled).toBe(1);
176
+ });
177
+
178
+ it('is a no-op when no group was armed', () => {
179
+ disposeGlobalShortcutSignals();
180
+ expect(() => disposeGlobalShortcutSignals()).not.toThrow();
181
+ });
182
+ });
183
+
135
184
  describe('enableGlobalShortcut', () => {
136
185
  it('re-enables a disabled shortcut', () => {
137
186
  const backend = fakeBackend();
@@ -235,6 +284,40 @@ describe('equalsAccelerator', () => {
235
284
  });
236
285
  });
237
286
 
287
+ describe('findAcceleratorConflict', () => {
288
+ it('returns the conflicting candidate, in the caller spelling it was given in', () => {
289
+ expect(findAcceleratorConflict('Control+K', ['Alt+J', 'ctrl-k', 'Meta+P'])).toBe('ctrl-k');
290
+ });
291
+
292
+ it('returns null when nothing in the list names the same chord', () => {
293
+ expect(findAcceleratorConflict('Control+K', ['Alt+J', 'Meta+P'])).toBeNull();
294
+ });
295
+
296
+ it('returns the first conflict when several candidates name the chord', () => {
297
+ expect(findAcceleratorConflict('Control+K', ['ctrl+k', 'Control-K'])).toBe('ctrl+k');
298
+ });
299
+
300
+ it('returns null for an unparseable accelerator, even against an identical unparseable candidate', () => {
301
+ expect(findAcceleratorConflict('NotAKey', ['NotAKey'])).toBeNull();
302
+ });
303
+
304
+ it('skips unparseable candidates rather than matching them', () => {
305
+ expect(findAcceleratorConflict('Control+K', ['NotAKey', '', 'Ctrl+K'])).toBe('Ctrl+K');
306
+ });
307
+
308
+ it('returns null for an empty candidate list', () => {
309
+ expect(findAcceleratorConflict('Control+K', [])).toBeNull();
310
+ });
311
+
312
+ it('sees a pending binding list that hasGlobalShortcutConflict cannot — nothing is registered', () => {
313
+ const backend = fakeBackend();
314
+ setShortcutBackend(backend);
315
+ const pending = ['Control+Shift+P'];
316
+ expect(hasGlobalShortcutConflict('Control+Shift+P')).toBe(false);
317
+ expect(findAcceleratorConflict('Control+Shift+P', pending)).toBe('Control+Shift+P');
318
+ });
319
+ });
320
+
238
321
  describe('formatAcceleratorForDisplay', () => {
239
322
  // Tests are environment-neutral: we just check the output is non-empty and contains
240
323
  // both the expected modifier component and key. Platform-specific symbol vs text is tested
@@ -451,6 +534,21 @@ describe('hasGlobalShortcutConflict', () => {
451
534
  });
452
535
  });
453
536
 
537
+ describe('hasNativeShortcutBackend', () => {
538
+ it('is false on the web default and true once a backend is installed', () => {
539
+ expect(hasNativeShortcutBackend()).toBe(false);
540
+ setShortcutBackend(fakeBackend());
541
+ expect(hasNativeShortcutBackend()).toBe(true);
542
+ setShortcutBackend(null);
543
+ expect(hasNativeShortcutBackend()).toBe(false);
544
+ });
545
+
546
+ it('stays false when getShortcutBackend has lazily built the web default', () => {
547
+ getShortcutBackend();
548
+ expect(hasNativeShortcutBackend()).toBe(false);
549
+ });
550
+ });
551
+
454
552
  describe('isAcceleratorValid', () => {
455
553
  it('returns true for well-formed accelerators', () => {
456
554
  expect(isAcceleratorValid('Control+K')).toBe(true);
@@ -581,6 +679,46 @@ describe('normalizeAccelerator', () => {
581
679
  expect(normalizeAccelerator('Ctrl-Shift-K')).toBe('Control+Shift+K');
582
680
  });
583
681
 
682
+ it('reaches a literal +/- key, so the conventional zoom pair parses', () => {
683
+ expect(normalizeAccelerator('CommandOrControl+-')).toBe('CommandOrControl+Minus');
684
+ expect(normalizeAccelerator('CommandOrControl++')).toBe('CommandOrControl+Plus');
685
+ expect(normalizeAccelerator('Ctrl+-')).toBe('Control+Minus');
686
+ expect(normalizeAccelerator('Ctrl++')).toBe('Control+Plus');
687
+ });
688
+
689
+ it('accepts a bare +/- as a one-key accelerator', () => {
690
+ expect(normalizeAccelerator('-')).toBe('Minus');
691
+ expect(normalizeAccelerator('+')).toBe('Plus');
692
+ });
693
+
694
+ it('reaches a literal +/- through the dash separator too', () => {
695
+ expect(normalizeAccelerator('Ctrl-+')).toBe('Control+Plus');
696
+ expect(normalizeAccelerator('Ctrl--')).toBe('Control+Minus');
697
+ });
698
+
699
+ it('round-trips a literal +/- chord through its own normalized form', () => {
700
+ const once = normalizeAccelerator('Ctrl+-');
701
+ expect(normalizeAccelerator(once!)).toBe(once);
702
+ });
703
+
704
+ it('normalizes the named spellings of +/- to the same chord as the literals', () => {
705
+ expect(normalizeAccelerator('Ctrl+Minus')).toBe(normalizeAccelerator('Ctrl+-'));
706
+ expect(normalizeAccelerator('Ctrl+Plus')).toBe(normalizeAccelerator('Ctrl++'));
707
+ });
708
+
709
+ it('normalizes the Electron numpad short spellings', () => {
710
+ expect(normalizeAccelerator('Ctrl+numadd')).toBe('Control+NumpadAdd');
711
+ expect(normalizeAccelerator('Ctrl+numsub')).toBe('Control+NumpadSubtract');
712
+ expect(normalizeAccelerator('Ctrl+nummult')).toBe('Control+NumpadMultiply');
713
+ expect(normalizeAccelerator('Ctrl+numdiv')).toBe('Control+NumpadDivide');
714
+ expect(normalizeAccelerator('Ctrl+numdec')).toBe('Control+NumpadDecimal');
715
+ });
716
+
717
+ it('rejects a separator glued to a key name rather than silently dropping it', () => {
718
+ // 'Ctrl+-K' is malformed: the '-' opens the key token, so the key reads as '-K' and fails.
719
+ expect(normalizeAccelerator('Ctrl+-K')).toBeNull();
720
+ });
721
+
584
722
  it('produces stable output (idempotent)', () => {
585
723
  const once = normalizeAccelerator('ctrl+shift+k');
586
724
  const twice = normalizeAccelerator(once!);
@@ -626,6 +764,24 @@ describe('parseAccelerator', () => {
626
764
  expect(out.modifiers).toEqual([]);
627
765
  });
628
766
 
767
+ it('fills the modifiers array in place, keeping a retained reference live', () => {
768
+ const out = createParsedAccelerator();
769
+ const modifiers = out.modifiers;
770
+ parseAccelerator('Control+Shift+K', out);
771
+ expect(out.modifiers).toBe(modifiers);
772
+ expect(modifiers).toEqual(['Control', 'Shift']);
773
+ parseAccelerator('Alt+F', out);
774
+ expect(out.modifiers).toBe(modifiers);
775
+ expect(modifiers).toEqual(['Alt']);
776
+ });
777
+
778
+ it('clears stale modifiers when the new chord has fewer', () => {
779
+ const out = createParsedAccelerator();
780
+ parseAccelerator('Control+Alt+Shift+K', out);
781
+ parseAccelerator('K', out);
782
+ expect(out.modifiers).toEqual([]);
783
+ });
784
+
629
785
  it('aliased out — same object as a previously-filled value', () => {
630
786
  const out = createParsedAccelerator();
631
787
  parseAccelerator('Ctrl+K', out);
@@ -769,6 +925,97 @@ describe('setShortcutBackend', () => {
769
925
  });
770
926
  });
771
927
 
928
+ describe('setShortcutDropGuard', () => {
929
+ it('reports an unparseable accelerator with the operation, the raw input, and the parse error', () => {
930
+ setShortcutBackend(fakeBackend());
931
+ const drops: ShortcutDrop[] = [];
932
+ setShortcutDropGuard((drop) => drops.push({ ...drop }));
933
+ expect(registerGlobalShortcut('Control+NotAKey', () => {})).toBe(false);
934
+ expect(drops).toEqual([
935
+ {
936
+ accelerator: 'Control+NotAKey',
937
+ operation: 'registerGlobalShortcut',
938
+ parseError: { reason: 'unknown-key', token: 'NotAKey' },
939
+ reason: 'unparseable',
940
+ },
941
+ ]);
942
+ });
943
+
944
+ it('names the operation each command dropped from', () => {
945
+ const seen: string[] = [];
946
+ setShortcutBackend(fakeBackend());
947
+ setShortcutDropGuard((drop) => seen.push(drop.operation));
948
+ disableGlobalShortcut('');
949
+ enableGlobalShortcut('');
950
+ registerGlobalShortcut('', () => {});
951
+ unregisterGlobalShortcut('');
952
+ expect(seen).toEqual([
953
+ 'disableGlobalShortcut',
954
+ 'enableGlobalShortcut',
955
+ 'registerGlobalShortcut',
956
+ 'unregisterGlobalShortcut',
957
+ ]);
958
+ });
959
+
960
+ it('reports no-native-backend for a parseable chord on the web default, with no parse error', () => {
961
+ const drops: ShortcutDrop[] = [];
962
+ setShortcutDropGuard((drop) => drops.push({ ...drop }));
963
+ registerGlobalShortcut('Control+K', () => {});
964
+ expect(drops).toEqual([
965
+ {
966
+ accelerator: 'Control+K',
967
+ operation: 'registerGlobalShortcut',
968
+ parseError: null,
969
+ reason: 'no-native-backend',
970
+ },
971
+ ]);
972
+ });
973
+
974
+ it('reports no-native-backend from the accelerator-free bulk commands too', () => {
975
+ const seen: string[] = [];
976
+ setShortcutDropGuard((drop) => seen.push(drop.operation));
977
+ suspendAllGlobalShortcuts();
978
+ resumeAllGlobalShortcuts();
979
+ unregisterAllGlobalShortcuts();
980
+ expect(seen).toEqual(['suspendAllGlobalShortcuts', 'resumeAllGlobalShortcuts', 'unregisterAllGlobalShortcuts']);
981
+ });
982
+
983
+ it('stays silent once a native backend is installed', () => {
984
+ setShortcutBackend(fakeBackend());
985
+ const drops: ShortcutDrop[] = [];
986
+ setShortcutDropGuard((drop) => drops.push({ ...drop }));
987
+ registerGlobalShortcut('Control+K', () => {});
988
+ unregisterGlobalShortcut('Control+K');
989
+ suspendAllGlobalShortcuts();
990
+ expect(drops).toEqual([]);
991
+ });
992
+
993
+ it('reports the parse failure rather than the missing backend when both apply', () => {
994
+ const drops: ShortcutDrop[] = [];
995
+ setShortcutDropGuard((drop) => drops.push({ ...drop }));
996
+ registerGlobalShortcut('Control+NotAKey', () => {});
997
+ expect(drops.length).toBe(1);
998
+ expect(drops[0].reason).toBe('unparseable');
999
+ });
1000
+
1001
+ it('null uninstalls it', () => {
1002
+ const drops: ShortcutDrop[] = [];
1003
+ setShortcutDropGuard((drop) => drops.push({ ...drop }));
1004
+ setShortcutDropGuard(null);
1005
+ registerGlobalShortcut('Control+NotAKey', () => {});
1006
+ expect(drops).toEqual([]);
1007
+ });
1008
+
1009
+ it('does not change what a command returns', () => {
1010
+ const backend = fakeBackend();
1011
+ setShortcutBackend(backend);
1012
+ setShortcutDropGuard(() => {});
1013
+ expect(registerGlobalShortcut('ctrl+k', () => {})).toBe(true);
1014
+ expect(backend.entries.has('Control+K')).toBe(true);
1015
+ expect(registerGlobalShortcut('Control+NotAKey', () => {})).toBe(false);
1016
+ });
1017
+ });
1018
+
772
1019
  describe('suspendAllGlobalShortcuts', () => {
773
1020
  it('disables all registered shortcuts', () => {
774
1021
  const backend = fakeBackend();