diff --git a/changes/honor-configured-controller-shortcuts-and-modal-routing.md b/changes/honor-configured-controller-shortcuts-and-modal-routing.md index 3e4d8afd..4e5d98d7 100644 --- a/changes/honor-configured-controller-shortcuts-and-modal-routing.md +++ b/changes/honor-configured-controller-shortcuts-and-modal-routing.md @@ -4,3 +4,4 @@ area: overlay - Added configurable overlay shortcuts for session help, controller select, and controller debug actions. - Added mpv/plugin and CLI routing for session help, controller utilities, and subtitle sidebar toggling through the shared session-action path. - Improved dedicated overlay modal retry and focus handling for runtime options, Jimaku, session help, controller tools, and the playlist browser. +- Fixed controller configuration and controller debug shortcut opens so configured bindings bring up their modals again instead of tripping renderer recovery. diff --git a/src/renderer/handlers/keyboard.test.ts b/src/renderer/handlers/keyboard.test.ts index 59f86aae..73d43d1c 100644 --- a/src/renderer/handlers/keyboard.test.ts +++ b/src/renderer/handlers/keyboard.test.ts @@ -326,6 +326,8 @@ function createKeyboardHandlerHarness() { const testGlobals = installKeyboardTestGlobals(); const subtitleRootClassList = createClassList(); let controllerSelectKeydownCount = 0; + let openControllerSelectCount = 0; + let openControllerDebugCount = 0; let playlistBrowserKeydownCount = 0; const createWordNode = (left: number) => ({ @@ -373,6 +375,12 @@ function createKeyboardHandlerHarness() { }, handleSessionHelpKeydown: () => false, openSessionHelpModal: () => {}, + openControllerSelectModal: () => { + openControllerSelectCount += 1; + }, + openControllerDebugModal: () => { + openControllerDebugCount += 1; + }, appendClipboardVideoToQueue: () => {}, getPlaybackPaused: () => testGlobals.getPlaybackPaused(), }); @@ -382,6 +390,8 @@ function createKeyboardHandlerHarness() { handlers, testGlobals, controllerSelectKeydownCount: () => controllerSelectKeydownCount, + openControllerSelectCount: () => openControllerSelectCount, + openControllerDebugCount: () => openControllerDebugCount, playlistBrowserKeydownCount: () => playlistBrowserKeydownCount, setWordCount: (count: number) => { wordNodes = Array.from({ length: count }, (_, index) => createWordNode(10 + index * 70)); @@ -735,8 +745,36 @@ test('keyboard mode: controller helpers dispatch popup audio play/cycle and scro } }); -test('keyboard mode: configured controller debug binding dispatches session action', async () => { - const { testGlobals, handlers } = createKeyboardHandlerHarness(); +test('keyboard mode: configured controller select binding opens locally without dispatching a session action', async () => { + const { testGlobals, handlers, openControllerSelectCount } = createKeyboardHandlerHarness(); + + try { + await handlers.setupMpvInputForwarding(); + handlers.updateSessionBindings([ + { + sourcePath: 'shortcuts.openControllerSelect', + originalKey: 'Alt+D', + key: { code: 'KeyD', modifiers: ['alt'] }, + actionType: 'session-action', + actionId: 'openControllerSelect', + }, + ] as never); + + testGlobals.dispatchKeydown({ + key: 'd', + code: 'KeyD', + altKey: true, + }); + + assert.equal(openControllerSelectCount(), 1); + assert.deepEqual(testGlobals.sessionActions, []); + } finally { + testGlobals.restore(); + } +}); + +test('keyboard mode: configured controller debug binding opens locally without dispatching a session action', async () => { + const { testGlobals, handlers, openControllerDebugCount } = createKeyboardHandlerHarness(); try { await handlers.setupMpvInputForwarding(); @@ -757,14 +795,15 @@ test('keyboard mode: configured controller debug binding dispatches session acti shiftKey: true, }); - assert.deepEqual(testGlobals.sessionActions, [{ actionId: 'openControllerDebug', payload: undefined }]); + assert.equal(openControllerDebugCount(), 1); + assert.deepEqual(testGlobals.sessionActions, []); } finally { testGlobals.restore(); } }); test('keyboard mode: configured controller debug binding is not swallowed while popup is visible', async () => { - const { ctx, testGlobals, handlers } = createKeyboardHandlerHarness(); + const { ctx, testGlobals, handlers, openControllerDebugCount } = createKeyboardHandlerHarness(); try { await handlers.setupMpvInputForwarding(); @@ -787,7 +826,8 @@ test('keyboard mode: configured controller debug binding is not swallowed while shiftKey: true, }); - assert.deepEqual(testGlobals.sessionActions, [{ actionId: 'openControllerDebug', payload: undefined }]); + assert.equal(openControllerDebugCount(), 1); + assert.deepEqual(testGlobals.sessionActions, []); } finally { testGlobals.restore(); } diff --git a/src/renderer/handlers/keyboard.ts b/src/renderer/handlers/keyboard.ts index 93e735b9..1a858b2c 100644 --- a/src/renderer/handlers/keyboard.ts +++ b/src/renderer/handlers/keyboard.ts @@ -25,6 +25,8 @@ export function createKeyboardHandlers( fallbackUsed: boolean; fallbackUnavailable: boolean; }) => void; + openControllerSelectModal?: () => void; + openControllerDebugModal?: () => void; appendClipboardVideoToQueue: () => void; getPlaybackPaused: () => Promise; toggleSubtitleSidebarModal?: () => void; @@ -182,6 +184,16 @@ export function createKeyboardHandlers( return; } + if (binding.actionType === 'session-action' && binding.actionId === 'openControllerSelect') { + options.openControllerSelectModal?.(); + return; + } + + if (binding.actionType === 'session-action' && binding.actionId === 'openControllerDebug') { + options.openControllerDebugModal?.(); + return; + } + if (binding.actionType === 'mpv-command') { dispatchConfiguredMpvCommand(binding.command); return; diff --git a/src/renderer/renderer.ts b/src/renderer/renderer.ts index 9b01546e..699ddd72 100644 --- a/src/renderer/renderer.ts +++ b/src/renderer/renderer.ts @@ -174,6 +174,12 @@ const keyboardHandlers = createKeyboardHandlers(ctx, { handleControllerDebugKeydown: controllerDebugModal.handleControllerDebugKeydown, handleSessionHelpKeydown: sessionHelpModal.handleSessionHelpKeydown, openSessionHelpModal: sessionHelpModal.openSessionHelpModal, + openControllerSelectModal: () => { + controllerSelectModal.openControllerSelectModal(); + }, + openControllerDebugModal: () => { + controllerDebugModal.openControllerDebugModal(); + }, appendClipboardVideoToQueue: () => { void window.electronAPI.appendClipboardVideoToQueue(); },