mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-20 12:51:13 -05:00
66 lines
1.8 KiB
TypeScript
66 lines
1.8 KiB
TypeScript
import { useEffect, useCallback } from 'react';
|
|
|
|
interface KeyboardShortcut {
|
|
key: string;
|
|
ctrlOrCmd?: boolean;
|
|
shift?: boolean;
|
|
alt?: boolean;
|
|
handler: () => void;
|
|
description: string;
|
|
}
|
|
|
|
interface UseKeyboardShortcutsOptions {
|
|
shortcuts: KeyboardShortcut[];
|
|
enabled?: boolean;
|
|
}
|
|
|
|
/**
|
|
* Hook for registering keyboard shortcuts
|
|
* Automatically handles Cmd (Mac) vs Ctrl (Windows/Linux)
|
|
*/
|
|
export function useKeyboardShortcuts({ shortcuts, enabled = true }: UseKeyboardShortcutsOptions) {
|
|
const handleKeyDown = useCallback(
|
|
(event: KeyboardEvent) => {
|
|
if (!enabled) return;
|
|
|
|
// Ignore shortcuts when typing in input fields
|
|
const target = event.target as HTMLElement;
|
|
if (
|
|
target.tagName === 'INPUT' ||
|
|
target.tagName === 'TEXTAREA' ||
|
|
target.isContentEditable
|
|
) {
|
|
return;
|
|
}
|
|
|
|
for (const shortcut of shortcuts) {
|
|
const matchesKey = event.key.toLowerCase() === shortcut.key.toLowerCase();
|
|
const matchesCtrl = !shortcut.ctrlOrCmd || (event.ctrlKey || event.metaKey);
|
|
const matchesShift = !shortcut.shift || event.shiftKey;
|
|
const matchesAlt = !shortcut.alt || event.altKey;
|
|
|
|
if (matchesKey && matchesCtrl && matchesShift && matchesAlt) {
|
|
event.preventDefault();
|
|
shortcut.handler();
|
|
break;
|
|
}
|
|
}
|
|
},
|
|
[shortcuts, enabled]
|
|
);
|
|
|
|
useEffect(() => {
|
|
if (!enabled) return;
|
|
|
|
window.addEventListener('keydown', handleKeyDown);
|
|
return () => window.removeEventListener('keydown', handleKeyDown);
|
|
}, [handleKeyDown, enabled]);
|
|
|
|
return {
|
|
shortcuts: shortcuts.map(s => ({
|
|
...s,
|
|
displayKey: `${s.ctrlOrCmd ? '⌘/Ctrl + ' : ''}${s.shift ? 'Shift + ' : ''}${s.alt ? 'Alt + ' : ''}${s.key.toUpperCase()}`,
|
|
})),
|
|
};
|
|
}
|