mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-10-26 23:35:17 -07:00
feat(dictionary): add Hachidori backend support (#266)
This commit is contained in:
1 parent
e690ffba07
commit
cbaa4626e1
143 files changed
+5564
-305
No files matched your search
@@ -4,9 +4,12 @@ import { createMpvInputForwarding } from './mpv-input-forwarding';
|
||||
import { MPV_MOUSE_BUTTON_BY_BUTTON, wheelEventToMpvWheel } from '../../shared/mpv-input-bindings';
|
||||
import { dispatchConfiguredMpvCommand } from '../utils/mpv-command-dispatch';
|
||||
import {
|
||||
YOMITAN_POPUP_HIDDEN_EVENT,
|
||||
YOMITAN_POPUP_SHOWN_EVENT,
|
||||
registerDictionaryPopupVisibilityListener,
|
||||
HACHIDORI_HOST_SELECTOR,
|
||||
YOMITAN_POPUP_COMMAND_EVENT,
|
||||
YOMITAN_POPUP_HOST_SELECTOR,
|
||||
isHachidoriPopupOpen,
|
||||
isLookupPopupOpen,
|
||||
isYomitanPopupVisible,
|
||||
isYomitanPopupIframe,
|
||||
} from '../yomitan-popup.js';
|
||||
@@ -80,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}, ${HACHIDORI_HOST_SELECTOR}`)) return true;
|
||||
if (target.closest && target.closest('iframe.yomitan-popup, iframe[id^="yomitan-popup"]'))
|
||||
return true;
|
||||
return false;
|
||||
@@ -106,11 +111,13 @@ export function createKeyboardHandlers(
|
||||
}
|
||||
|
||||
// Overlay UI that handles its own mouse input (menus, sidebar, notifications, controls).
|
||||
// Hachidori's popup lives in the overlay document, unlike Yomitan's iframe, so its
|
||||
// wheel events reach these handlers retargeted to its host.
|
||||
function isOverlayControlTarget(target: EventTarget | null): boolean {
|
||||
if (!(target instanceof Element)) return false;
|
||||
return Boolean(
|
||||
target.closest(
|
||||
'.modal, .notification-history, .overlay-notification-stack, button, a, input, select, textarea',
|
||||
`.modal, .notification-history, .overlay-notification-stack, button, a, input, select, textarea, ${YOMITAN_POPUP_HOST_SELECTOR}, ${HACHIDORI_HOST_SELECTOR}`,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -122,8 +129,7 @@ export function createKeyboardHandlers(
|
||||
!ctx.state.playlistBrowserModalOpen &&
|
||||
!ctx.state.youtubePickerModalOpen &&
|
||||
!ctx.state.subtitleSidebarModalOpen &&
|
||||
!ctx.state.yomitanPopupVisible &&
|
||||
!isYomitanPopupVisible(document) &&
|
||||
!isLookupPopupOpen(ctx.state, document) &&
|
||||
!isInteractiveTarget(target)
|
||||
);
|
||||
}
|
||||
@@ -515,8 +521,7 @@ export function createKeyboardHandlers(
|
||||
pendingSelectionAnchorAfterSubtitleSeek = null;
|
||||
resetSelectionToStartOnNextSubtitleSync = false;
|
||||
const shouldRefreshLookup =
|
||||
pendingLookupRefreshAfterSubtitleSeek &&
|
||||
(ctx.state.yomitanPopupVisible || isYomitanPopupVisible(document));
|
||||
pendingLookupRefreshAfterSubtitleSeek && isLookupPopupOpen(ctx.state, document);
|
||||
pendingLookupRefreshAfterSubtitleSeek = false;
|
||||
if (shouldRefreshLookup) {
|
||||
queueMicrotask(() => {
|
||||
@@ -708,7 +713,7 @@ export function createKeyboardHandlers(
|
||||
if (lookupScanFallbackTimer !== null) clearTimeout(lookupScanFallbackTimer);
|
||||
lookupScanFallbackTimer = setTimeout(() => {
|
||||
lookupScanFallbackTimer = null;
|
||||
if (ctx.state.yomitanPopupVisible || isYomitanPopupVisible(document)) {
|
||||
if (isLookupPopupOpen(ctx.state, document)) {
|
||||
return;
|
||||
}
|
||||
// Dispatch directly on the selected token span; when overlay pointer-events are disabled,
|
||||
@@ -738,15 +743,22 @@ export function createKeyboardHandlers(
|
||||
}
|
||||
|
||||
function handleLookupWindowToggleRequested(): void {
|
||||
if (ctx.state.yomitanPopupVisible || isYomitanPopupVisible(document)) {
|
||||
if (isLookupPopupOpen(ctx.state, document)) {
|
||||
closeLookupWindow();
|
||||
return;
|
||||
}
|
||||
triggerLookupForSelectedWord();
|
||||
}
|
||||
|
||||
// Closes any popup state: an open Hachidori pane (its attention may already be
|
||||
// released) and attention without a pane, so callers like the Kiku modal
|
||||
// opener leave nothing behind.
|
||||
function closeLookupWindow(): boolean {
|
||||
if (!ctx.state.yomitanPopupVisible && !isYomitanPopupVisible(document)) {
|
||||
if (
|
||||
!ctx.state.yomitanPopupVisible &&
|
||||
!isYomitanPopupVisible(document) &&
|
||||
!isHachidoriPopupOpen(document)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -770,7 +782,7 @@ export function createKeyboardHandlers(
|
||||
return false;
|
||||
}
|
||||
|
||||
const popupVisible = ctx.state.yomitanPopupVisible || isYomitanPopupVisible(document);
|
||||
const popupVisible = isLookupPopupOpen(ctx.state, document);
|
||||
const result = moveKeyboardSelection(delta);
|
||||
if (result === 'no-words') {
|
||||
seekAdjacentSubtitleAndQueueSelection(delta, popupVisible);
|
||||
@@ -791,7 +803,7 @@ export function createKeyboardHandlers(
|
||||
code: string,
|
||||
repeat: boolean = true,
|
||||
): boolean {
|
||||
if (!ctx.state.yomitanPopupVisible && !isYomitanPopupVisible(document)) {
|
||||
if (!isLookupPopupOpen(ctx.state, document)) {
|
||||
return false;
|
||||
}
|
||||
dispatchYomitanPopupKeydown(key, code, [], repeat);
|
||||
@@ -799,7 +811,7 @@ export function createKeyboardHandlers(
|
||||
}
|
||||
|
||||
function mineSelectedFromController(): boolean {
|
||||
if (!ctx.state.yomitanPopupVisible && !isYomitanPopupVisible(document)) {
|
||||
if (!isLookupPopupOpen(ctx.state, document)) {
|
||||
return false;
|
||||
}
|
||||
dispatchYomitanPopupMineSelected();
|
||||
@@ -807,7 +819,7 @@ export function createKeyboardHandlers(
|
||||
}
|
||||
|
||||
function cyclePopupAudioSourceForController(direction: -1 | 1): boolean {
|
||||
if (!ctx.state.yomitanPopupVisible && !isYomitanPopupVisible(document)) {
|
||||
if (!isLookupPopupOpen(ctx.state, document)) {
|
||||
return false;
|
||||
}
|
||||
dispatchYomitanPopupCycleAudioSource(direction);
|
||||
@@ -815,7 +827,7 @@ export function createKeyboardHandlers(
|
||||
}
|
||||
|
||||
function playCurrentAudioForController(): boolean {
|
||||
if (!ctx.state.yomitanPopupVisible && !isYomitanPopupVisible(document)) {
|
||||
if (!isLookupPopupOpen(ctx.state, document)) {
|
||||
return false;
|
||||
}
|
||||
dispatchYomitanPopupPlayCurrentAudio();
|
||||
@@ -823,7 +835,7 @@ export function createKeyboardHandlers(
|
||||
}
|
||||
|
||||
function scrollPopupByController(deltaX: number, deltaY: number): boolean {
|
||||
if (!ctx.state.yomitanPopupVisible && !isYomitanPopupVisible(document)) {
|
||||
if (!isLookupPopupOpen(ctx.state, document)) {
|
||||
return false;
|
||||
}
|
||||
dispatchYomitanPopupScrollBy(deltaX, deltaY);
|
||||
@@ -850,7 +862,7 @@ export function createKeyboardHandlers(
|
||||
if (!ctx.state.keyboardDrivenModeEnabled) {
|
||||
return;
|
||||
}
|
||||
if (!ctx.state.yomitanPopupVisible && !isYomitanPopupVisible(document)) {
|
||||
if (!isLookupPopupOpen(ctx.state, document)) {
|
||||
return;
|
||||
}
|
||||
restoreOverlayKeyboardFocus();
|
||||
@@ -895,7 +907,7 @@ export function createKeyboardHandlers(
|
||||
}
|
||||
|
||||
const key = e.code;
|
||||
const popupVisible = ctx.state.yomitanPopupVisible || isYomitanPopupVisible(document);
|
||||
const popupVisible = isLookupPopupOpen(ctx.state, document);
|
||||
if (key === 'ArrowLeft' || key === 'KeyH') {
|
||||
const result = moveKeyboardSelection(-1);
|
||||
if (result === 'start-boundary' || result === 'no-words') {
|
||||
@@ -1086,7 +1098,7 @@ export function createKeyboardHandlers(
|
||||
subtree: true,
|
||||
});
|
||||
|
||||
window.addEventListener(YOMITAN_POPUP_HIDDEN_EVENT, () => {
|
||||
registerDictionaryPopupVisibilityListener('hidden', () => {
|
||||
clearNativeSubtitleSelection();
|
||||
if (!ctx.state.keyboardDrivenModeEnabled) {
|
||||
syncKeyboardTokenSelection();
|
||||
@@ -1094,7 +1106,7 @@ export function createKeyboardHandlers(
|
||||
}
|
||||
restoreOverlayKeyboardFocus();
|
||||
});
|
||||
window.addEventListener(YOMITAN_POPUP_SHOWN_EVENT, () => {
|
||||
registerDictionaryPopupVisibilityListener('shown', () => {
|
||||
if (!ctx.state.keyboardDrivenModeEnabled) {
|
||||
return;
|
||||
}
|
||||
@@ -1251,7 +1263,7 @@ export function createKeyboardHandlers(
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx.state.yomitanPopupVisible || isYomitanPopupVisible(document)) {
|
||||
if (isLookupPopupOpen(ctx.state, document)) {
|
||||
if (handleYomitanPopupKeybind(e)) {
|
||||
e.preventDefault();
|
||||
return;
|
||||
|
||||
Reference in new issue
Block a user