fix(overlay): forward mpv input while subtitle sidebar is open (#300)

This commit is contained in:
sudacode authored and GitHub committed 2026-10-24 23:28:58 -07:00
1 parent 3549e0ed93
commit 9150a60630
3 files changed
+44 -1

No files matched your search

@@ -0,0 +1,4 @@
type: fixed
area: overlay
- mpv keys and mouse buttons (such as `9`/`0` volume and double-click fullscreen) pass through the overlay again while the subtitle sidebar is open; only input inside the sidebar stays with it.
+38
View File
@@ -481,6 +481,8 @@ function installKeyboardTestGlobals() {
setSessionBindings: (value: CompiledSessionBinding[]) => { setSessionBindings: (value: CompiledSessionBinding[]) => {
sessionBindings = value; sessionBindings = value;
}, },
// A plain overlay element over playback, outside any SubMiner UI.
createPlaybackTarget: () => new TestElement(),
createInteractiveTarget: () => { createInteractiveTarget: () => {
const target = new TestElement(); const target = new TestElement();
target.closest = (selector: string) => (selector.includes('.modal') ? target : null); target.closest = (selector: string) => (selector.includes('.modal') ? target : null);
@@ -1297,6 +1299,42 @@ test('Hachidori attention without an open popup pane still forwards imported mpv
} }
}); });
test('an open subtitle sidebar only keeps imported mpv input aimed at the sidebar', async () => {
const { ctx, handlers, testGlobals } = createKeyboardHandlerHarness();
try {
testGlobals.setGetMpvInputBindings(async () => ({
keys: ['0', 'MBTN_LEFT_DBL'],
blockedKeys: [],
}));
await handlers.setupMpvInputForwarding();
await wait(0);
ctx.state.subtitleSidebarModalOpen = true;
const sidebarTarget = testGlobals.createInteractiveTarget();
const playbackTarget = testGlobals.createPlaybackTarget();
// Sidebar input runs first, while no key or button is held, so a held key cannot
// hide a forwarded press. Its release has no matching press to forward.
testGlobals.dispatchKeydown({ key: '0', code: 'Digit0', target: sidebarTarget });
testGlobals.dispatchMousedown({ button: 0, target: sidebarTarget });
testGlobals.dispatchMousedown({ button: 0, type: 'mouseup', target: sidebarTarget });
assert.deepEqual(testGlobals.mpvCommands, []);
testGlobals.dispatchKeydown({ key: '0', code: 'Digit0', target: playbackTarget });
testGlobals.dispatchMousedown({ button: 0, target: playbackTarget });
testGlobals.dispatchMousedown({ button: 0, type: 'mouseup', target: playbackTarget });
assert.deepEqual(testGlobals.mpvCommands, [
['keydown', '0'],
['keydown', 'MBTN_LEFT'],
['keyup', 'MBTN_LEFT'],
]);
} finally {
ctx.state.subtitleSidebarModalOpen = false;
testGlobals.restore();
}
});
test('keyboard mode: lookup toggle opens a lookup during Hachidori attention without a pane', async () => { test('keyboard mode: lookup toggle opens a lookup during Hachidori attention without a pane', async () => {
const { ctx, handlers, testGlobals } = createKeyboardHandlerHarness(); const { ctx, handlers, testGlobals } = createKeyboardHandlerHarness();
+2 -1
View File
@@ -123,12 +123,13 @@ export function createKeyboardHandlers(
} }
// Imported mpv bindings only run when no SubMiner UI could be the input's target. // Imported mpv bindings only run when no SubMiner UI could be the input's target.
// The subtitle sidebar is a side panel over playback, so only input inside it (a
// `.modal` target) stays with SubMiner.
function canForwardToMpv(target: EventTarget | null): boolean { function canForwardToMpv(target: EventTarget | null): boolean {
return ( return (
keyboardConfigLoaded && keyboardConfigLoaded &&
!ctx.state.playlistBrowserModalOpen && !ctx.state.playlistBrowserModalOpen &&
!ctx.state.youtubePickerModalOpen && !ctx.state.youtubePickerModalOpen &&
!ctx.state.subtitleSidebarModalOpen &&
!isLookupPopupOpen(ctx.state, document) && !isLookupPopupOpen(ctx.state, document) &&
!isInteractiveTarget(target) !isInteractiveTarget(target)
); );