diff --git a/frontend/src/lib/components/reader/foliate-view.svelte b/frontend/src/lib/components/reader/foliate-view.svelte index ef122d8..e247fce 100644 --- a/frontend/src/lib/components/reader/foliate-view.svelte +++ b/frontend/src/lib/components/reader/foliate-view.svelte @@ -104,7 +104,46 @@ doc.addEventListener('keydown', onKeydown); } + /** + * Replays a shortcut pressed inside the book on the host window. + * + * Key events do not cross document boundaries, so a shortcut pressed while + * the book has focus never reaches the app's handlers — which are bound on + * the window, as the sidebar's ctrl+B is — and the browser's own default runs + * instead. That is why ctrl+B opened bookmarks in the book but toggled the + * chapter sidebar everywhere else. + * + * The original is only cancelled if an app handler actually claimed the + * replay, so combinations the app does not use — ctrl+C above all — keep + * their normal browser behaviour. + */ + function forwardShortcut(event: KeyboardEvent) { + const source = (event.target as Node | null)?.ownerDocument; + // isTrusted rules out the replay itself, which would otherwise recurse. + if (!event.isTrusted || !source || source === document) return; + + const claimed = !window.dispatchEvent( + new KeyboardEvent('keydown', { + key: event.key, + code: event.code, + ctrlKey: event.ctrlKey, + metaKey: event.metaKey, + shiftKey: event.shiftKey, + altKey: event.altKey, + bubbles: true, + cancelable: true + }) + ); + + if (claimed) event.preventDefault(); + } + function onKeydown(event: KeyboardEvent) { + if (event.ctrlKey || event.metaKey || event.altKey) { + forwardShortcut(event); + return; + } + switch (event.key) { case 'ArrowLeft': case 'PageUp':