docs/contributing/HOTKEYS.md
This document describes the technical implementation of the customizable hotkeys system in InvokeAI.
Note: For user-facing documentation on how to use customizable hotkeys, see Hotkeys Feature Documentation.
The hotkeys system allows users to customize keyboard shortcuts throughout the application. All hotkeys are:
The customizable hotkeys feature is built on top of the existing hotkey system with the following components:
hotkeysSlice.ts)Location: invokeai/frontend/web/src/features/system/store/hotkeysSlice.ts
Responsibilities:
redux-rememberState Shape:
{
_version: 1,
customHotkeys: {
'app.invoke': ['mod+enter'],
'canvas.undo': ['mod+z'],
// ...
}
}
Actions:
hotkeyChanged(id, hotkeys) - Update a single hotkeyhotkeyReset(id) - Reset a single hotkey to defaultallHotkeysReset() - Reset all hotkeys to defaultsuseHotkeyData.ts)Location: invokeai/frontend/web/src/features/system/components/HotkeysModal/useHotkeyData.ts
Responsibilities:
Key Functions:
useHotkeyData() - Returns all hotkeys organized by categoryuseRegisteredHotkeys() - Hook to register a hotkey in a componentHotkeyEditor.tsx)Location: invokeai/frontend/web/src/features/system/components/HotkeysModal/HotkeyEditor.tsx
Features:
Smart Features:
+ insertion between modifiersHotkeysModal.tsx)Location: invokeai/frontend/web/src/features/system/components/HotkeysModal/HotkeysModal.tsx
Features:
┌─────────────────────────────────────────────────────────────┐
│ 1. User opens Hotkeys Modal │
│ 2. User clicks "Edit Mode" button │
│ 3. User clicks edit icon next to a hotkey │
│ 4. User enters new hotkey(s) using editor │
│ 5. User clicks save or presses Enter │
│ 6. Custom hotkey stored via hotkeyChanged() action │
│ 7. Redux state persisted to IndexedDB (redux-remember) │
│ 8. useHotkeyData() hook picks up the change │
│ 9. All components using useRegisteredHotkeys() get update │
└─────────────────────────────────────────────────────────────┘
Hotkeys use the format from react-hotkeys-hook library:
mod, ctrl, shift, alt, meta+ between keys in a combinationmod+a, ctrl+b)Examples:
mod+enter - Mod key + Entershift+x - Shift + Xctrl+shift+a - Control + Shift + Af1, f2 - F1 or F2 (alternatives)To use a hotkey in a component:
import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData';
const MyComponent = () => {
const handleAction = useCallback(() => {
// Your action here
}, []);
// This automatically uses custom hotkeys if configured
useRegisteredHotkeys({
id: 'myAction',
category: 'app', // or 'canvas', 'viewer', 'gallery', 'workflows'
callback: handleAction,
options: { enabled: true, preventDefault: true },
dependencies: [handleAction]
});
// ...
};
Options:
enabled - Whether the hotkey is activepreventDefault - Prevent default browser behaviorenableOnFormTags - Allow hotkey in form elements (default: false)To add a new hotkey to the system:
In invokeai/frontend/web/public/locales/en.json:
{
"hotkeys": {
"app": {
"myAction": {
"title": "My Action",
"desc": "Description of what this hotkey does"
}
}
}
}
In invokeai/frontend/web/src/features/system/components/HotkeysModal/useHotkeyData.ts:
// Inside the appropriate category builder function
addHotkey('app', 'myAction', ['mod+k']); // Default binding
In your component:
useRegisteredHotkeys({
id: 'myAction',
category: 'app',
callback: handleMyAction,
options: { enabled: true },
dependencies: [handleMyAction]
});
Current categories:
To add a new category, update useHotkeyData.ts and add translations.
Tests are located in invokeai/frontend/web/src/features/system/store/hotkeysSlice.test.ts.
Test Coverage:
Run tests with:
cd invokeai/frontend/web
pnpm test:no-watch
Custom hotkeys are persisted using the same mechanism as other app settings:
hotkeys sliceredux-rememberState Location:
invokehotkeysmod instead of ctrl - Automatically maps to Cmd on Mac, Ctrl elsewhereuseRegisteredHotkeys({
id: 'save',
category: 'app',
callback: handleSave,
options: {
enabled: hasUnsavedChanges && !isLoading, // Only when valid
preventDefault: true
},
dependencies: [hasUnsavedChanges, isLoading, handleSave]
});
// In useHotkeyData.ts
addHotkey('canvas', 'redo', ['mod+shift+z', 'mod+y']); // Two alternatives
import { useFocusRegion } from 'common/hooks/focus';
const MyComponent = () => {
const focusRegionRef = useFocusRegion('myRegion');
// Hotkey only works when this region has focus
useRegisteredHotkeys({
id: 'myAction',
category: 'app',
callback: handleAction,
options: { enabled: true }
});
return <div ref={focusRegionRef}>...</div>;
};