Files
pi-agent-integrated/pi-web/hooks/useKeyboardShortcuts.ts
T

74 lines
2.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import { useEffect } from "react";
// ---------------------------------------------------------------------------
// Module-level registry — ChatWindow registers the abort handler here so that
// the global Esc listener in AppShell can call it without prop-drilling.
// ---------------------------------------------------------------------------
let globalAbortHandler: (() => void) | null = null;
/**
* Register (or clear) the abort handler for the global Esc shortcut.
* Call this from ChatWindow whenever agentRunning or handleAbort changes.
*/
export function registerAbortHandler(handler: (() => void) | null): void {
globalAbortHandler = handler;
}
// ---------------------------------------------------------------------------
// Hook: global keyboard shortcuts
// ---------------------------------------------------------------------------
interface UseGlobalKeyboardShortcutsOptions {
/** Called when Ctrl+Alt+N is pressed. Receives current cwd. */
onNewSession?: (cwd: string) => void;
/** The currently selected project directory (sidebar cwd). */
activeCwd?: string | null;
}
/**
* Register global keyboard shortcuts for the application.
*
* Shortcuts handled here:
* Esc – stop the running agent (via module-level abort handler)
* Ctrl+Alt+N – create a new session in the active project directory
*
* Note: Esc inside <textarea> or <input> is deliberately NOT handled here.
* ChatInput manages its own Esc logic (closing slash / @ file menus, stopping
* the agent when no menu is open) because it needs intimate knowledge of menu
* state that is local to that component.
*/
export function useGlobalKeyboardShortcuts(
options: UseGlobalKeyboardShortcutsOptions,
): void {
const { onNewSession, activeCwd } = options;
useEffect(() => {
const handler = (e: KeyboardEvent): void => {
// ---- Esc: stop agent ----
if (e.key === "Escape") {
if (!globalAbortHandler) return;
const tag = (e.target as HTMLElement)?.tagName;
// Let textarea/input handle Esc internally (ChatInput menus / stop).
if (tag === "TEXTAREA" || tag === "INPUT") return;
e.preventDefault();
globalAbortHandler();
return;
}
// ---- Ctrl+Alt+N: new session ----
if (e.key === "n" && e.ctrlKey && e.altKey) {
if (!activeCwd || !onNewSession) return;
e.preventDefault();
onNewSession(activeCwd);
}
};
window.addEventListener("keydown", handler);
return () => window.removeEventListener("keydown", handler);
}, [activeCwd, onNewSession]);
}