diff --git a/src/App.tsx b/src/App.tsx index d16461ba..780ca57e 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -66,7 +66,7 @@ import { useThemeStore } from './store/themeStore'; import { useThemeScheduler } from './hooks/useThemeScheduler'; import { useFontStore } from './store/fontStore'; import { useEqStore } from './store/eqStore'; -import { useKeybindingsStore } from './store/keybindingsStore'; +import { useKeybindingsStore, matchInAppBinding, buildInAppBinding } from './store/keybindingsStore'; import { useGlobalShortcutsStore } from './store/globalShortcutsStore'; import { useZipDownloadStore } from './store/zipDownloadStore'; import ZipDownloadOverlay from './components/ZipDownloadOverlay'; @@ -457,15 +457,18 @@ function TauriEventBridge() { const onKey = (e: KeyboardEvent) => { const tag = (e.target as HTMLElement)?.tagName; if (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT') return; - // Global shortcuts use modifier combos — skip in-app bindings for those - // (X11 GrabModeAsync delivers the key to both the grabber and the focused WebView) - if (e.ctrlKey || e.altKey || e.metaKey) return; + + const chord = buildInAppBinding(e); + if (chord) { + const registered = Object.values(useGlobalShortcutsStore.getState().shortcuts); + if (registered.includes(chord)) return; + } const { bindings } = useKeybindingsStore.getState(); const { togglePlay, next, previous, setVolume, seek, toggleQueue, toggleFullscreen } = usePlayerStore.getState(); const action = (Object.entries(bindings) as [string, string | null][]) - .find(([, code]) => code === e.code)?.[0]; + .find(([, b]) => matchInAppBinding(e, b))?.[0]; if (!action) return; e.preventDefault(); @@ -478,12 +481,16 @@ function TauriEventBridge() { case 'volume-down': setVolume(Math.max(0, usePlayerStore.getState().volume - 0.05)); break; case 'seek-forward': { const s = usePlayerStore.getState(); - seek(Math.min(s.currentTrack?.duration ?? 0, s.currentTime + 10)); + const dur = s.currentTrack?.duration ?? 0; + if (!dur) break; + seek(Math.min(1, (s.currentTime + 10) / dur)); break; } case 'seek-backward': { const s = usePlayerStore.getState(); - seek(Math.max(0, s.currentTime - 10)); + const dur = s.currentTrack?.duration ?? 0; + if (!dur) break; + seek(Math.max(0, (s.currentTime - 10) / dur)); break; } case 'toggle-queue': toggleQueue(); break; diff --git a/src/pages/Settings.tsx b/src/pages/Settings.tsx index 0c1a3b34..fc6e42ca 100644 --- a/src/pages/Settings.tsx +++ b/src/pages/Settings.tsx @@ -25,7 +25,7 @@ import { SeekbarPreview } from '../components/WaveformSeek'; import { IS_LINUX } from '../utils/platform'; import { useThemeStore } from '../store/themeStore'; import { useFontStore, FontId } from '../store/fontStore'; -import { useKeybindingsStore, KeyAction, formatKeyCode, DEFAULT_BINDINGS } from '../store/keybindingsStore'; +import { useKeybindingsStore, KeyAction, formatBinding, buildInAppBinding } from '../store/keybindingsStore'; import { useGlobalShortcutsStore, GlobalAction, buildGlobalShortcut, formatGlobalShortcut } from '../store/globalShortcutsStore'; import { useSidebarStore, DEFAULT_SIDEBAR_ITEMS, SidebarItemConfig } from '../store/sidebarStore'; import { useHomeStore, HomeSectionId } from '../store/homeStore'; @@ -1577,13 +1577,17 @@ export default function Settings() { const handler = (e: KeyboardEvent) => { e.preventDefault(); e.stopPropagation(); - if (e.code !== 'Escape') { - // unbind any existing action with this key first - const existing = (Object.entries(kb.bindings) as [KeyAction, string | null][]) - .find(([, c]) => c === e.code)?.[0]; - if (existing && existing !== action) kb.setBinding(existing, null); - kb.setBinding(action, e.code); + if (e.code === 'Escape') { + setListeningFor(null); + window.removeEventListener('keydown', handler, true); + return; } + const chord = buildInAppBinding(e); + if (!chord) return; + const existing = (Object.entries(kb.bindings) as [KeyAction, string | null][]) + .find(([, c]) => c === chord)?.[0]; + if (existing && existing !== action) kb.setBinding(existing, null); + kb.setBinding(action, chord); setListeningFor(null); window.removeEventListener('keydown', handler, true); }; @@ -1599,7 +1603,7 @@ export default function Settings() { cursor: 'pointer', }} > - {isListening ? t('settings.shortcutListening') : bound ? formatKeyCode(bound) : t('settings.shortcutUnbound')} + {isListening ? t('settings.shortcutListening') : bound ? formatBinding(bound) : t('settings.shortcutUnbound')} {bound && !isListening && (