From e75fda168ede4b3c6d28e15f7d54128c5accc785 Mon Sep 17 00:00:00 2001 From: cucadmuh <49571317+cucadmuh@users.noreply.github.com> Date: Mon, 13 Apr 2026 21:13:10 +0300 Subject: [PATCH] fix(folder-browser): arrow navigation only without modifiers (#174) Skip column/list arrow handling when any modifier is down. Detect modifiers via nativeEvent and getModifierState (WebKit/WebView), and match arrow keys by both key and code. On row buttons, preventDefault for plain arrows only to avoid native focus/scroll stealing navigation. Filter field ArrowDown uses the same modifier check. --- src/pages/FolderBrowser.tsx | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/src/pages/FolderBrowser.tsx b/src/pages/FolderBrowser.tsx index 7d1714ed..cef8174f 100644 --- a/src/pages/FolderBrowser.tsx +++ b/src/pages/FolderBrowser.tsx @@ -66,6 +66,35 @@ function entryToTrack(e: SubsonicDirectoryEntry): Track { }; } +function isFolderBrowserArrowKey(e: React.KeyboardEvent): boolean { + return ( + e.key === 'ArrowUp' || + e.key === 'ArrowDown' || + e.key === 'ArrowLeft' || + e.key === 'ArrowRight' || + e.code === 'ArrowUp' || + e.code === 'ArrowDown' || + e.code === 'ArrowLeft' || + e.code === 'ArrowRight' + ); +} + +/** Modifiers from native event + getModifierState (WebKit/WebView can miss flags on the synthetic event). */ +function folderBrowserHasKeyModifiers(e: React.KeyboardEvent): boolean { + const n = e.nativeEvent; + if (n.ctrlKey || n.altKey || n.shiftKey || n.metaKey) return true; + if (typeof n.getModifierState === 'function') { + return ( + n.getModifierState('Control') || + n.getModifierState('Alt') || + n.getModifierState('Shift') || + n.getModifierState('Meta') || + n.getModifierState('OS') + ); + } + return false; +} + export default function FolderBrowser() { const { t } = useTranslation(); const [columns, setColumns] = useState([]); @@ -449,6 +478,7 @@ export default function FolderBrowser() { }); return; } + if (isFolderBrowserArrowKey(e) && folderBrowserHasKeyModifiers(e)) return; if (!['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Enter'].includes(key)) return; setKeyboardNavActive(true); const current = keyboardPos ?? fallbackNavPos(columns); @@ -718,7 +748,7 @@ export default function FolderBrowser() { requestAnimationFrame(() => wrapperRef.current?.focus({ preventScroll: true })); return; } - if (e.key === 'ArrowDown') { + if (e.key === 'ArrowDown' && !folderBrowserHasKeyModifiers(e)) { e.preventDefault(); e.stopPropagation(); const rowIndex = preferredRowIndex(colIndex); @@ -777,6 +807,10 @@ export default function FolderBrowser() { if (item.isDir) handleDirClick(colIndex, item); else handleFileClick(colIndex, item); }} + onKeyDown={e => { + if (!isFolderBrowserArrowKey(e) || folderBrowserHasKeyModifiers(e)) return; + e.preventDefault(); + }} onContextMenu={e => { setKeyboardPos({ colIndex, rowIndex }); onRowContextMenu(e, colIndex, rowIndex, col, item);