({
canToggleFocus,
isScrollAreaActive: _isScrollAreaActive,
pickerIsOpen,
availableModes,
currentMode,
mode,
sendToExtension,
showInfo,
exit,
cleanup,
toggleFocus,
closePicker,
}: UseGlobalInputOptions)
| 34 | * - Escape: Cancel task (when loading) or close TODO viewer |
| 35 | */ |
| 36 | export function useGlobalInput({ |
| 37 | canToggleFocus, |
| 38 | isScrollAreaActive: _isScrollAreaActive, |
| 39 | pickerIsOpen, |
| 40 | availableModes, |
| 41 | currentMode, |
| 42 | mode, |
| 43 | sendToExtension, |
| 44 | showInfo, |
| 45 | exit, |
| 46 | cleanup, |
| 47 | toggleFocus, |
| 48 | closePicker, |
| 49 | }: UseGlobalInputOptions): void { |
| 50 | const { isLoading, currentTodos } = useCLIStore() |
| 51 | const { |
| 52 | showTodoViewer, |
| 53 | setShowTodoViewer, |
| 54 | showExitHint: _showExitHint, |
| 55 | setShowExitHint, |
| 56 | pendingExit, |
| 57 | setPendingExit, |
| 58 | } = useUIStateStore() |
| 59 | |
| 60 | // Track Ctrl+C presses for "press again to exit" behavior |
| 61 | const exitHintTimeout = useRef<NodeJS.Timeout | null>(null) |
| 62 | |
| 63 | // Cleanup timeout on unmount |
| 64 | useEffect(() => { |
| 65 | return () => { |
| 66 | if (exitHintTimeout.current) { |
| 67 | clearTimeout(exitHintTimeout.current) |
| 68 | } |
| 69 | } |
| 70 | }, []) |
| 71 | |
| 72 | // Handle global keyboard shortcuts |
| 73 | useInput((input, key) => { |
| 74 | // Tab to toggle focus between scroll area and input (only when input is available) |
| 75 | if (key.tab && canToggleFocus && !pickerIsOpen) { |
| 76 | toggleFocus() |
| 77 | return |
| 78 | } |
| 79 | |
| 80 | // Ctrl+M to cycle through modes (only when not loading and we have available modes) |
| 81 | // Uses centralized global input sequence detection |
| 82 | if (matchesGlobalSequence(input, key, "ctrl-m")) { |
| 83 | // Don't allow mode switching while a task is in progress (loading) |
| 84 | if (isLoading) { |
| 85 | showInfo("Cannot switch modes while task is in progress", 2000) |
| 86 | return |
| 87 | } |
| 88 | |
| 89 | // Need at least 2 modes to cycle |
| 90 | if (availableModes.length < 2) { |
| 91 | return |
| 92 | } |
| 93 |
no test coverage detected