feat(frontend): make keyboard shortcuts layout-independent

Command keys were matched by character (e.key), so on a non-Latin layout
(e.g. Russian) the physical g/f/e/p/x/j/k keys emitted Cyrillic letters
and nothing fired. Letter and digit commands now match by physical
position (e.code: KeyG, Digit1, Slash, …) across the global nav, the file
grid, and the viewer, so the same physical keys work on any layout. Named
keys (arrows, Enter, Esc, Delete), the Mod combos, and the filter's
literal operators (& | ! ( )) stay on e.key, where character matching is
correct.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-11 17:55:39 +03:00
parent 19ec96c544
commit 94d100675e
3 changed files with 59 additions and 37 deletions
@@ -189,11 +189,14 @@
function handleKeydown(e: KeyboardEvent) {
if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement) return;
if (e.key === 'ArrowLeft' || e.key === 'k') {
if (e.ctrlKey || e.metaKey || e.altKey) return;
// Letter keys are matched by physical position (e.code) so j/k/e work on any
// keyboard layout; arrows and Escape are layout-independent already.
if (e.key === 'ArrowLeft' || e.code === 'KeyK') {
if (prevId) onNavigate(prevId);
} else if (e.key === 'ArrowRight' || e.key === 'j') {
} else if (e.key === 'ArrowRight' || e.code === 'KeyJ') {
if (nextId) onNavigate(nextId);
} else if (e.key === 'e') {
} else if (e.code === 'KeyE') {
e.preventDefault();
jumpToTags();
} else if (e.key === 'Escape') {