fix(dictionary): sync Hachidori deck to ankiConnect.deck for polling

- Always set the first Hachidori Anki template deck to ankiConnect.deck so polling mode enriches Hachidori cards; other custom template settings stay intact
- Treat right-clicks retargeted to the Hachidori popup shadow host as overlay interactions so they no longer raise mpv or toggle pause
- Update anki-integration docs and changelog fragment
This commit is contained in:
2026-09-22 21:43:53 -07:00
parent 2ba820f41a
commit 9a5fb02cbd
6 changed files with 45 additions and 11 deletions
+25
View File
@@ -5,6 +5,7 @@ import test from 'node:test';
import { createKeyboardHandlers } from './keyboard.js';
import { createRendererState } from '../state.js';
import { YOMITAN_POPUP_HOST_SELECTOR } from '../yomitan-popup.js';
import type { CompiledSessionBinding } from '../../types';
import type { MpvInputBindingsSnapshot } from '../../types/session-bindings';
import { DEFAULT_KEYBINDINGS, SPECIAL_COMMANDS } from '../../config/definitions';
@@ -442,6 +443,13 @@ function installKeyboardTestGlobals() {
target.closest = (selector: string) => (selector.includes('.modal') ? target : null);
return target;
},
// Events inside Hachidori's shadow root reach the document retargeted to its host.
createDictionaryPopupHostTarget: () => {
const target = new TestElement();
target.closest = (selector: string) =>
selector === YOMITAN_POPUP_HOST_SELECTOR ? target : null;
return target;
},
setGetSessionBindings: (value: () => Promise<CompiledSessionBinding[]>) => {
getSessionBindingsImpl = value;
},
@@ -683,6 +691,23 @@ test('right-clicking interactive overlay controls does not raise playback window
}
});
test('right-clicking inside a dictionary popup host does not raise playback window or toggle pause', async () => {
const { handlers, testGlobals } = createKeyboardHandlerHarness();
const popupHost = testGlobals.createDictionaryPopupHostTarget();
try {
await handlers.setupMpvInputForwarding();
testGlobals.dispatchDocumentMouseDown({ button: 2, target: popupHost });
await wait(0);
assert.deepEqual(testGlobals.interactionActivations, []);
assert.deepEqual(testGlobals.mpvCommands, []);
} finally {
testGlobals.restore();
}
});
test('mpv input forwarding retries a transient keyboard config IPC failure', async () => {
const { handlers, testGlobals } = createKeyboardHandlerHarness();
let calls = 0;
+3
View File
@@ -4,6 +4,7 @@ import { createMpvInputForwarding } from './mpv-input-forwarding';
import {
registerDictionaryPopupVisibilityListener,
YOMITAN_POPUP_COMMAND_EVENT,
YOMITAN_POPUP_HOST_SELECTOR,
isYomitanPopupVisible,
isYomitanPopupIframe,
} from '../yomitan-popup.js';
@@ -82,6 +83,8 @@ export function createKeyboardHandlers(
if (target.closest('.modal')) return true;
if (ctx.dom.subtitleContainer.contains(target)) return true;
if (isYomitanPopupIframe(target)) return true;
// Hachidori's popup lives in a shadow root, so its events arrive retargeted to the host.
if (target.closest(YOMITAN_POPUP_HOST_SELECTOR)) return true;
if (target.closest && target.closest('iframe.yomitan-popup, iframe[id^="yomitan-popup"]'))
return true;
return false;