Skip to content

Commit a0f9a42

Browse files
authored
fix(shortcuts): match single-letter hotkeys by layout-aware key (#3525)
1 parent e11448d commit a0f9a42

6 files changed

Lines changed: 89 additions & 6 deletions

File tree

packages/agent/src/adapters/codex-app-server/codex-app-server-agent.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,11 @@ import {
7474
APP_SERVER_NOTIFICATIONS,
7575
APP_SERVER_REQUESTS,
7676
} from "./protocol";
77-
import { type CodexSandboxPolicy, SessionConfigState } from "./session-config";
77+
import {
78+
type CodexSandboxPolicy,
79+
type RawModel,
80+
SessionConfigState,
81+
} from "./session-config";
7882
import {
7983
type CodexAppServerProcess,
8084
type CodexAppServerProcessOptions,
@@ -606,7 +610,7 @@ export class CodexAppServerAgent extends BaseAcpAgent {
606610

607611
private async loadModelConfig(): Promise<void> {
608612
try {
609-
const res = await this.rpc.request<{ data?: any[] }>(
613+
const res = await this.rpc.request<{ data?: RawModel[] }>(
610614
APP_SERVER_METHODS.MODEL_LIST,
611615
{},
612616
);

packages/agent/src/adapters/codex-app-server/session-config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ export function buildConfigOptions(s: ConfigSelectors): SessionConfigOption[] {
227227
}
228228

229229
/** A model entry from the app-server's `model/list` (loosely typed). */
230-
interface RawModel {
230+
export interface RawModel {
231231
id?: string;
232232
model?: string;
233233
displayName?: string;
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { renderHook } from "@testing-library/react";
2+
import { useHotkeys } from "react-hotkeys-hook";
3+
import { describe, expect, it, vi } from "vitest";
4+
5+
// Regression guard for patches/react-hotkeys-hook.patch. Single-letter shortcuts must match the
6+
// layout-aware event.key, not the physical event.code. On a Dvorak layout the key labelled "c"
7+
// sits at the physical QWERTY-"I" slot (event.code "KeyI"), which used to trigger the "mod+i"
8+
// Inbox shortcut and hijack Cmd+C.
9+
function press(init: KeyboardEventInit): void {
10+
document.dispatchEvent(
11+
new KeyboardEvent("keydown", { bubbles: true, ...init }),
12+
);
13+
}
14+
15+
describe("react-hotkeys-hook layout-aware matching", () => {
16+
it("fires mod+i when the logical key is i", () => {
17+
const onInbox = vi.fn();
18+
renderHook(() =>
19+
useHotkeys("mod+i", onInbox, { enableOnContentEditable: true }),
20+
);
21+
22+
press({ key: "i", code: "KeyI", metaKey: true });
23+
24+
expect(onInbox).toHaveBeenCalledTimes(1);
25+
});
26+
27+
it("does not fire mod+i on a Dvorak Cmd+C that lands on the physical KeyI slot", () => {
28+
const onInbox = vi.fn();
29+
renderHook(() =>
30+
useHotkeys("mod+i", onInbox, { enableOnContentEditable: true }),
31+
);
32+
33+
press({ key: "c", code: "KeyI", metaKey: true });
34+
35+
expect(onInbox).not.toHaveBeenCalled();
36+
});
37+
});

patches/react-hotkeys-hook.patch

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
--- a/dist/react-hotkeys-hook.esm.js
2+
+++ b/dist/react-hotkeys-hook.esm.js
3+
@@ -206,7 +206,12 @@
4+
metaKey = e.metaKey,
5+
shiftKey = e.shiftKey,
6+
altKey = e.altKey;
7+
- var keyCode = mapKey(code);
8+
+ var layoutKey = mapKey(pressedKeyUppercase);
9+
+ // PostHog patch: prefer the layout-aware key (event.key). Fall back to the physical
10+
+ // event.code only when a modifier such as macOS Option turns event.key into a
11+
+ // non-alphanumeric glyph, so single-letter shortcuts match the printed letter on
12+
+ // non-QWERTY layouts (Dvorak, AZERTY, ...) instead of the QWERTY key at that slot.
13+
+ var keyCode = /^[a-z0-9]$/.test(layoutKey) ? layoutKey : mapKey(code);
14+
var pressedKey = pressedKeyUppercase.toLowerCase();
15+
if (!(keys != null && keys.includes(keyCode)) && !(keys != null && keys.includes(pressedKey)) && !['ctrl', 'control', 'unknown', 'meta', 'alt', 'shift', 'os'].includes(keyCode)) {
16+
return false;
17+
--- a/dist/react-hotkeys-hook.cjs.development.js
18+
+++ b/dist/react-hotkeys-hook.cjs.development.js
19+
@@ -208,7 +208,12 @@
20+
metaKey = e.metaKey,
21+
shiftKey = e.shiftKey,
22+
altKey = e.altKey;
23+
- var keyCode = mapKey(code);
24+
+ var layoutKey = mapKey(pressedKeyUppercase);
25+
+ // PostHog patch: prefer the layout-aware key (event.key). Fall back to the physical
26+
+ // event.code only when a modifier such as macOS Option turns event.key into a
27+
+ // non-alphanumeric glyph, so single-letter shortcuts match the printed letter on
28+
+ // non-QWERTY layouts (Dvorak, AZERTY, ...) instead of the QWERTY key at that slot.
29+
+ var keyCode = /^[a-z0-9]$/.test(layoutKey) ? layoutKey : mapKey(code);
30+
var pressedKey = pressedKeyUppercase.toLowerCase();
31+
if (!(keys != null && keys.includes(keyCode)) && !(keys != null && keys.includes(pressedKey)) && !['ctrl', 'control', 'unknown', 'meta', 'alt', 'shift', 'os'].includes(keyCode)) {
32+
return false;
33+
--- a/dist/react-hotkeys-hook.cjs.production.min.js
34+
+++ b/dist/react-hotkeys-hook.cjs.production.min.js
35+
@@ -1,2 +1,2 @@
36+
-"use strict";var e=require("react"),t=require("react/jsx-runtime");function n(){return(n=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var o in n)({}).hasOwnProperty.call(n,o)&&(e[o]=n[o])}return e}).apply(null,arguments)}var o=["shift","alt","meta","mod","ctrl"],r={esc:"escape",return:"enter",".":"period",",":"comma","-":"slash"," ":"space","`":"backquote","#":"backslash","+":"bracketright",ShiftLeft:"shift",ShiftRight:"shift",AltLeft:"alt",AltRight:"alt",MetaLeft:"meta",MetaRight:"meta",OSLeft:"meta",OSRight:"meta",ControlLeft:"ctrl",ControlRight:"ctrl"};function i(e){return(e&&r[e]||e||"").trim().toLowerCase().replace(/key|digit|numpad|arrow/,"")}function u(e,t){return void 0===t&&(t=","),e.split(t)}function c(e,t,r){void 0===t&&(t="+");var u=e.toLocaleLowerCase().split(t).map((function(e){return i(e)}));return n({},{alt:u.includes("alt"),ctrl:u.includes("ctrl")||u.includes("control"),shift:u.includes("shift"),meta:u.includes("meta"),mod:u.includes("mod")},{keys:u.filter((function(e){return!o.includes(e)})),description:r,hotkey:e})}"undefined"!=typeof document&&(document.addEventListener("keydown",(function(e){void 0!==e.key&&d([i(e.key),i(e.code)])})),document.addEventListener("keyup",(function(e){void 0!==e.key&&f([i(e.key),i(e.code)])}))),"undefined"!=typeof window&&window.addEventListener("blur",(function(){a.clear()}));var a=new Set;function l(e){return Array.isArray(e)}function s(e,t){return void 0===t&&(t=","),(l(e)?e:e.split(t)).every((function(e){return a.has(e.trim().toLowerCase())}))}function d(e){var t=Array.isArray(e)?e:[e];a.has("meta")&&a.forEach((function(e){return!function(e){return o.includes(e)}(e)&&a.delete(e.toLowerCase())})),t.forEach((function(e){return a.add(e.toLowerCase())}))}function f(e){var t=Array.isArray(e)?e:[e];"meta"===e?a.clear():t.forEach((function(e){return a.delete(e.toLowerCase())}))}function v(e,t){void 0===t&&(t=!1);var n,o,r=e.target,i=e.composed;return o=(n=r).tagName&&!n.tagName.startsWith("-")&&n.tagName.includes("-")&&i?e.composedPath()[0]&&e.composedPath()[0].tagName:r&&r.tagName,l(t)?Boolean(o&&t&&t.some((function(e){var t;return e.toLowerCase()===(null==(t=o)?void 0:t.toLowerCase())}))):Boolean(o&&t&&t)}var y=e.createContext(void 0);function p(e){return t.jsx(y.Provider,{value:{addHotkey:e.addHotkey,removeHotkey:e.removeHotkey},children:e.children})}function m(e,t){return e&&t&&"object"==typeof e&&"object"==typeof t?Object.keys(e).length===Object.keys(t).length&&Object.keys(e).reduce((function(n,o){return n&&m(e[o],t[o])}),!0):e===t}var k=e.createContext({hotkeys:[],enabledScopes:[],toggleScope:function(){},enableScope:function(){},disableScope:function(){}}),h=function(){return e.useContext(k)},b=function(e){e.stopPropagation(),e.preventDefault(),e.stopImmediatePropagation()},g="undefined"!=typeof window?e.useLayoutEffect:e.useEffect;exports.HotkeysProvider=function(n){var o=n.initiallyActiveScopes,r=void 0===o?["*"]:o,i=n.children,u=e.useState((null==r?void 0:r.length)>0?r:["*"]),c=u[0],a=u[1],l=e.useState([]),s=l[0],d=l[1],f=e.useCallback((function(e){a((function(t){return t.includes("*")?[e]:Array.from(new Set([].concat(t,[e])))}))}),[]),v=e.useCallback((function(e){a((function(t){return 0===t.filter((function(t){return t!==e})).length?["*"]:t.filter((function(t){return t!==e}))}))}),[]),y=e.useCallback((function(e){a((function(t){return t.includes(e)?0===t.filter((function(t){return t!==e})).length?["*"]:t.filter((function(t){return t!==e})):t.includes("*")?[e]:Array.from(new Set([].concat(t,[e])))}))}),[]),h=e.useCallback((function(e){d((function(t){return[].concat(t,[e])}))}),[]),b=e.useCallback((function(e){d((function(t){return t.filter((function(t){return!m(t,e)}))}))}),[]);return t.jsx(k.Provider,{value:{enabledScopes:c,hotkeys:s,enableScope:f,disableScope:v,toggleScope:y},children:t.jsx(p,{addHotkey:h,removeHotkey:b,children:i})})},exports.isHotkeyPressed=s,exports.useHotkeys=function(t,n,o,r){var a=e.useState(null),p=a[0],k=a[1],w=e.useRef(!1),L=o instanceof Array?r instanceof Array?void 0:r:o,C=l(t)?t.join(null==L?void 0:L.splitKey):t,S=o instanceof Array?o:r instanceof Array?r:void 0,E=e.useCallback(n,null!=S?S:[]),A=e.useRef(E);A.current=S?E:n;var x=function(t){var n=e.useRef(void 0);return m(n.current,t)||(n.current=t),n.current}(L),H=h().enabledScopes,O=e.useContext(y);return g((function(){if(!1!==(null==x?void 0:x.enabled)&&(t=null==x?void 0:x.scopes,0===(e=H).length&&t?(console.warn('A hotkey has the "scopes" option set, however no active scopes were found. If you want to use the global scopes feature, you need to wrap your app in a <HotkeysProvider>'),1):!t||e.some((function(e){return t.includes(e)}))||e.includes("*"))){var e,t,n=function(e,t){var n;if(void 0===t&&(t=!1),!v(e,["input","textarea","select"])||v(e,null==x?void 0:x.enableOnFormTags)){if(null!==p){var o=p.getRootNode();if((o instanceof Document||o instanceof ShadowRoot)&&o.activeElement!==p&&!p.contains(o.activeElement))return void b(e)}(null==(n=e.target)||!n.isContentEditable||null!=x&&x.enableOnContentEditable)&&u(C,null==x?void 0:x.splitKey).forEach((function(n){var o,r=c(n,null==x?void 0:x.combinationKey);if(function(e,t,n){void 0===n&&(n=!1);var o=t.alt,r=t.meta,u=t.mod,c=t.shift,a=t.ctrl,l=t.keys,d=e.key,f=e.ctrlKey,v=e.metaKey,y=e.shiftKey,p=e.altKey,m=i(e.code),k=d.toLowerCase();if(!(null!=l&&l.includes(m)||null!=l&&l.includes(k)||["ctrl","control","unknown","meta","alt","shift","os"].includes(m)))return!1;if(!n){if(o===!p&&"alt"!==k)return!1;if(c===!y&&"shift"!==k)return!1;if(u){if(!v&&!f)return!1}else{if(r===!v&&"meta"!==k&&"os"!==k)return!1;if(a===!f&&"ctrl"!==k&&"control"!==k)return!1}}return!(!l||1!==l.length||!l.includes(k)&&!l.includes(m))||(l?s(l):!l)}(e,r,null==x?void 0:x.ignoreModifiers)||null!=(o=r.keys)&&o.includes("*")){if(null!=x&&null!=x.ignoreEventWhen&&x.ignoreEventWhen(e))return;if(t&&w.current)return;if(function(e,t,n){("function"==typeof n&&n(e,t)||!0===n)&&e.preventDefault()}(e,r,null==x?void 0:x.preventDefault),!function(e,t,n){return"function"==typeof n?n(e,t):!0===n||void 0===n}(e,r,null==x?void 0:x.enabled))return void b(e);A.current(e,r),t||(w.current=!0)}}))}},o=function(e){void 0!==e.key&&(d(i(e.code)),(void 0===(null==x?void 0:x.keydown)&&!0!==(null==x?void 0:x.keyup)||null!=x&&x.keydown)&&n(e))},r=function(e){void 0!==e.key&&(f(i(e.code)),w.current=!1,null!=x&&x.keyup&&n(e,!0))},a=p||(null==L?void 0:L.document)||document;return a.addEventListener("keyup",r,null==L?void 0:L.eventListenerOptions),a.addEventListener("keydown",o,null==L?void 0:L.eventListenerOptions),O&&u(C,null==x?void 0:x.splitKey).forEach((function(e){return O.addHotkey(c(e,null==x?void 0:x.combinationKey,null==x?void 0:x.description))})),function(){a.removeEventListener("keyup",r,null==L?void 0:L.eventListenerOptions),a.removeEventListener("keydown",o,null==L?void 0:L.eventListenerOptions),O&&u(C,null==x?void 0:x.splitKey).forEach((function(e){return O.removeHotkey(c(e,null==x?void 0:x.combinationKey,null==x?void 0:x.description))}))}}}),[p,C,x,H]),k},exports.useHotkeysContext=h,exports.useRecordHotkeys=function(){var t=e.useState(new Set),n=t[0],o=t[1],r=e.useState(!1),u=r[0],c=r[1],a=e.useCallback((function(e){void 0!==e.key&&(e.preventDefault(),e.stopPropagation(),o((function(t){var n=new Set(t);return n.add(i(e.code)),n})))}),[]),l=e.useCallback((function(){"undefined"!=typeof document&&(document.removeEventListener("keydown",a),c(!1))}),[a]),s=e.useCallback((function(){o(new Set),"undefined"!=typeof document&&(l(),document.addEventListener("keydown",a),c(!0))}),[a,l]),d=e.useCallback((function(){o(new Set)}),[]);return[n,{start:s,stop:l,resetKeys:d,isRecording:u}]};
37+
+"use strict";var e=require("react"),t=require("react/jsx-runtime");function n(){return(n=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var o in n)({}).hasOwnProperty.call(n,o)&&(e[o]=n[o])}return e}).apply(null,arguments)}var o=["shift","alt","meta","mod","ctrl"],r={esc:"escape",return:"enter",".":"period",",":"comma","-":"slash"," ":"space","`":"backquote","#":"backslash","+":"bracketright",ShiftLeft:"shift",ShiftRight:"shift",AltLeft:"alt",AltRight:"alt",MetaLeft:"meta",MetaRight:"meta",OSLeft:"meta",OSRight:"meta",ControlLeft:"ctrl",ControlRight:"ctrl"};function i(e){return(e&&r[e]||e||"").trim().toLowerCase().replace(/key|digit|numpad|arrow/,"")}function u(e,t){return void 0===t&&(t=","),e.split(t)}function c(e,t,r){void 0===t&&(t="+");var u=e.toLocaleLowerCase().split(t).map((function(e){return i(e)}));return n({},{alt:u.includes("alt"),ctrl:u.includes("ctrl")||u.includes("control"),shift:u.includes("shift"),meta:u.includes("meta"),mod:u.includes("mod")},{keys:u.filter((function(e){return!o.includes(e)})),description:r,hotkey:e})}"undefined"!=typeof document&&(document.addEventListener("keydown",(function(e){void 0!==e.key&&d([i(e.key),i(e.code)])})),document.addEventListener("keyup",(function(e){void 0!==e.key&&f([i(e.key),i(e.code)])}))),"undefined"!=typeof window&&window.addEventListener("blur",(function(){a.clear()}));var a=new Set;function l(e){return Array.isArray(e)}function s(e,t){return void 0===t&&(t=","),(l(e)?e:e.split(t)).every((function(e){return a.has(e.trim().toLowerCase())}))}function d(e){var t=Array.isArray(e)?e:[e];a.has("meta")&&a.forEach((function(e){return!function(e){return o.includes(e)}(e)&&a.delete(e.toLowerCase())})),t.forEach((function(e){return a.add(e.toLowerCase())}))}function f(e){var t=Array.isArray(e)?e:[e];"meta"===e?a.clear():t.forEach((function(e){return a.delete(e.toLowerCase())}))}function v(e,t){void 0===t&&(t=!1);var n,o,r=e.target,i=e.composed;return o=(n=r).tagName&&!n.tagName.startsWith("-")&&n.tagName.includes("-")&&i?e.composedPath()[0]&&e.composedPath()[0].tagName:r&&r.tagName,l(t)?Boolean(o&&t&&t.some((function(e){var t;return e.toLowerCase()===(null==(t=o)?void 0:t.toLowerCase())}))):Boolean(o&&t&&t)}var y=e.createContext(void 0);function p(e){return t.jsx(y.Provider,{value:{addHotkey:e.addHotkey,removeHotkey:e.removeHotkey},children:e.children})}function m(e,t){return e&&t&&"object"==typeof e&&"object"==typeof t?Object.keys(e).length===Object.keys(t).length&&Object.keys(e).reduce((function(n,o){return n&&m(e[o],t[o])}),!0):e===t}var k=e.createContext({hotkeys:[],enabledScopes:[],toggleScope:function(){},enableScope:function(){},disableScope:function(){}}),h=function(){return e.useContext(k)},b=function(e){e.stopPropagation(),e.preventDefault(),e.stopImmediatePropagation()},g="undefined"!=typeof window?e.useLayoutEffect:e.useEffect;exports.HotkeysProvider=function(n){var o=n.initiallyActiveScopes,r=void 0===o?["*"]:o,i=n.children,u=e.useState((null==r?void 0:r.length)>0?r:["*"]),c=u[0],a=u[1],l=e.useState([]),s=l[0],d=l[1],f=e.useCallback((function(e){a((function(t){return t.includes("*")?[e]:Array.from(new Set([].concat(t,[e])))}))}),[]),v=e.useCallback((function(e){a((function(t){return 0===t.filter((function(t){return t!==e})).length?["*"]:t.filter((function(t){return t!==e}))}))}),[]),y=e.useCallback((function(e){a((function(t){return t.includes(e)?0===t.filter((function(t){return t!==e})).length?["*"]:t.filter((function(t){return t!==e})):t.includes("*")?[e]:Array.from(new Set([].concat(t,[e])))}))}),[]),h=e.useCallback((function(e){d((function(t){return[].concat(t,[e])}))}),[]),b=e.useCallback((function(e){d((function(t){return t.filter((function(t){return!m(t,e)}))}))}),[]);return t.jsx(k.Provider,{value:{enabledScopes:c,hotkeys:s,enableScope:f,disableScope:v,toggleScope:y},children:t.jsx(p,{addHotkey:h,removeHotkey:b,children:i})})},exports.isHotkeyPressed=s,exports.useHotkeys=function(t,n,o,r){var a=e.useState(null),p=a[0],k=a[1],w=e.useRef(!1),L=o instanceof Array?r instanceof Array?void 0:r:o,C=l(t)?t.join(null==L?void 0:L.splitKey):t,S=o instanceof Array?o:r instanceof Array?r:void 0,E=e.useCallback(n,null!=S?S:[]),A=e.useRef(E);A.current=S?E:n;var x=function(t){var n=e.useRef(void 0);return m(n.current,t)||(n.current=t),n.current}(L),H=h().enabledScopes,O=e.useContext(y);return g((function(){if(!1!==(null==x?void 0:x.enabled)&&(t=null==x?void 0:x.scopes,0===(e=H).length&&t?(console.warn('A hotkey has the "scopes" option set, however no active scopes were found. If you want to use the global scopes feature, you need to wrap your app in a <HotkeysProvider>'),1):!t||e.some((function(e){return t.includes(e)}))||e.includes("*"))){var e,t,n=function(e,t){var n;if(void 0===t&&(t=!1),!v(e,["input","textarea","select"])||v(e,null==x?void 0:x.enableOnFormTags)){if(null!==p){var o=p.getRootNode();if((o instanceof Document||o instanceof ShadowRoot)&&o.activeElement!==p&&!p.contains(o.activeElement))return void b(e)}(null==(n=e.target)||!n.isContentEditable||null!=x&&x.enableOnContentEditable)&&u(C,null==x?void 0:x.splitKey).forEach((function(n){var o,r=c(n,null==x?void 0:x.combinationKey);if(function(e,t,n){void 0===n&&(n=!1);var o=t.alt,r=t.meta,u=t.mod,c=t.shift,a=t.ctrl,l=t.keys,d=e.key,f=e.ctrlKey,v=e.metaKey,y=e.shiftKey,p=e.altKey,m=/^[a-z0-9]$/.test(i(d))?i(d):i(e.code),k=d.toLowerCase();if(!(null!=l&&l.includes(m)||null!=l&&l.includes(k)||["ctrl","control","unknown","meta","alt","shift","os"].includes(m)))return!1;if(!n){if(o===!p&&"alt"!==k)return!1;if(c===!y&&"shift"!==k)return!1;if(u){if(!v&&!f)return!1}else{if(r===!v&&"meta"!==k&&"os"!==k)return!1;if(a===!f&&"ctrl"!==k&&"control"!==k)return!1}}return!(!l||1!==l.length||!l.includes(k)&&!l.includes(m))||(l?s(l):!l)}(e,r,null==x?void 0:x.ignoreModifiers)||null!=(o=r.keys)&&o.includes("*")){if(null!=x&&null!=x.ignoreEventWhen&&x.ignoreEventWhen(e))return;if(t&&w.current)return;if(function(e,t,n){("function"==typeof n&&n(e,t)||!0===n)&&e.preventDefault()}(e,r,null==x?void 0:x.preventDefault),!function(e,t,n){return"function"==typeof n?n(e,t):!0===n||void 0===n}(e,r,null==x?void 0:x.enabled))return void b(e);A.current(e,r),t||(w.current=!0)}}))}},o=function(e){void 0!==e.key&&(d(i(e.code)),(void 0===(null==x?void 0:x.keydown)&&!0!==(null==x?void 0:x.keyup)||null!=x&&x.keydown)&&n(e))},r=function(e){void 0!==e.key&&(f(i(e.code)),w.current=!1,null!=x&&x.keyup&&n(e,!0))},a=p||(null==L?void 0:L.document)||document;return a.addEventListener("keyup",r,null==L?void 0:L.eventListenerOptions),a.addEventListener("keydown",o,null==L?void 0:L.eventListenerOptions),O&&u(C,null==x?void 0:x.splitKey).forEach((function(e){return O.addHotkey(c(e,null==x?void 0:x.combinationKey,null==x?void 0:x.description))})),function(){a.removeEventListener("keyup",r,null==L?void 0:L.eventListenerOptions),a.removeEventListener("keydown",o,null==L?void 0:L.eventListenerOptions),O&&u(C,null==x?void 0:x.splitKey).forEach((function(e){return O.removeHotkey(c(e,null==x?void 0:x.combinationKey,null==x?void 0:x.description))}))}}}),[p,C,x,H]),k},exports.useHotkeysContext=h,exports.useRecordHotkeys=function(){var t=e.useState(new Set),n=t[0],o=t[1],r=e.useState(!1),u=r[0],c=r[1],a=e.useCallback((function(e){void 0!==e.key&&(e.preventDefault(),e.stopPropagation(),o((function(t){var n=new Set(t);return n.add(i(e.code)),n})))}),[]),l=e.useCallback((function(){"undefined"!=typeof document&&(document.removeEventListener("keydown",a),c(!1))}),[a]),s=e.useCallback((function(){o(new Set),"undefined"!=typeof document&&(l(),document.addEventListener("keydown",a),c(!0))}),[a,l]),d=e.useCallback((function(){o(new Set)}),[]);return[n,{start:s,stop:l,resetKeys:d,isRecording:u}]};
38+
//# sourceMappingURL=react-hotkeys-hook.cjs.production.min.js.map

0 commit comments

Comments
 (0)