Files
onnx-voice-changer/frontend/src/hooks/useKeyboardShortcuts.ts
T

65 lines
2.0 KiB
TypeScript

import { useEffect, useRef, useCallback } from 'react';
export interface ShortcutBinding {
keys: string; // e.g. "Control+k", " ", "m", "alt+1"
description: string;
action: () => void;
}
export const useKeyboardShortcuts = (bindings: ShortcutBinding[], enabled: boolean = true) => {
const bindingsRef = useRef<ShortcutBinding[]>(bindings);
useEffect(() => {
bindingsRef.current = bindings;
}, [bindings]);
const handleKeyDown = useCallback((e: KeyboardEvent) => {
if (!enabled) return;
// Avoid hijacking keystrokes when editing inputs
const active = document.activeElement;
if (active) {
const name = active.tagName.toLowerCase();
if (name === 'input' || name === 'textarea' || active.getAttribute('contenteditable') === 'true') {
return;
}
}
const pressedKey = e.key.toLowerCase();
const isCtrl = e.ctrlKey || e.metaKey;
const isAlt = e.altKey;
const isShift = e.shiftKey;
for (const binding of bindingsRef.current) {
const keys = binding.keys.toLowerCase().split('+');
const requiresCtrl = keys.includes('control') || keys.includes('ctrl');
const requiresAlt = keys.includes('alt');
const requiresShift = keys.includes('shift');
const baseKey = keys.filter(k => !['control', 'ctrl', 'alt', 'shift'].includes(k))[0];
const matchesCtrl = requiresCtrl ? isCtrl : !isCtrl;
const matchesAlt = requiresAlt ? isAlt : !isAlt;
const matchesShift = requiresShift ? isShift : !isShift;
const normalizedBaseKey = baseKey === 'space' ? ' ' : baseKey;
const matchesBase = pressedKey === normalizedBaseKey;
if (matchesCtrl && matchesAlt && matchesShift && matchesBase) {
e.preventDefault();
binding.action();
break;
}
}
}, [enabled]);
useEffect(() => {
window.addEventListener('keydown', handleKeyDown);
return () => {
window.removeEventListener('keydown', handleKeyDown);
};
}, [handleKeyDown]);
};
export default useKeyboardShortcuts;