mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-10-21 05:01:26 -07:00
fix(hachidori): treat only an open pane as an open popup for lookup controls
This commit is contained in:
2 files changed
+38
-12
No files matched your search
@@ -1288,6 +1288,31 @@ test('Hachidori attention without an open popup pane still forwards imported mpv
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('keyboard mode: lookup toggle opens a lookup during Hachidori attention without a pane', async () => {
|
||||||
|
const { ctx, handlers, testGlobals } = createKeyboardHandlerHarness();
|
||||||
|
|
||||||
|
try {
|
||||||
|
await handlers.setupMpvInputForwarding();
|
||||||
|
handlers.handleKeyboardModeToggleRequested();
|
||||||
|
ctx.state.keyboardSelectedWordIndex = 1;
|
||||||
|
handlers.syncKeyboardTokenSelection();
|
||||||
|
ctx.state.hachidoriReaderSeen = true;
|
||||||
|
ctx.state.yomitanPopupVisible = true;
|
||||||
|
|
||||||
|
handlers.handleLookupWindowToggleRequested();
|
||||||
|
await wait(0);
|
||||||
|
|
||||||
|
assert.equal(ctx.dom.subtitleRoot.classList.contains('has-selection'), true);
|
||||||
|
assert.deepEqual(
|
||||||
|
testGlobals.commandEvents.filter((event) => event.type === 'setVisible'),
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
ctx.state.keyboardDrivenModeEnabled = false;
|
||||||
|
testGlobals.restore();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
test('configured subtitle-jump keybinding preserves pause when pause state is unknown', async () => {
|
test('configured subtitle-jump keybinding preserves pause when pause state is unknown', async () => {
|
||||||
const { handlers, testGlobals } = createKeyboardHandlerHarness();
|
const { handlers, testGlobals } = createKeyboardHandlerHarness();
|
||||||
|
|
||||||
|
|||||||
@@ -520,8 +520,7 @@ export function createKeyboardHandlers(
|
|||||||
pendingSelectionAnchorAfterSubtitleSeek = null;
|
pendingSelectionAnchorAfterSubtitleSeek = null;
|
||||||
resetSelectionToStartOnNextSubtitleSync = false;
|
resetSelectionToStartOnNextSubtitleSync = false;
|
||||||
const shouldRefreshLookup =
|
const shouldRefreshLookup =
|
||||||
pendingLookupRefreshAfterSubtitleSeek &&
|
pendingLookupRefreshAfterSubtitleSeek && isLookupPopupOpen(ctx.state, document);
|
||||||
(ctx.state.yomitanPopupVisible || isYomitanPopupVisible(document));
|
|
||||||
pendingLookupRefreshAfterSubtitleSeek = false;
|
pendingLookupRefreshAfterSubtitleSeek = false;
|
||||||
if (shouldRefreshLookup) {
|
if (shouldRefreshLookup) {
|
||||||
queueMicrotask(() => {
|
queueMicrotask(() => {
|
||||||
@@ -713,7 +712,7 @@ export function createKeyboardHandlers(
|
|||||||
if (lookupScanFallbackTimer !== null) clearTimeout(lookupScanFallbackTimer);
|
if (lookupScanFallbackTimer !== null) clearTimeout(lookupScanFallbackTimer);
|
||||||
lookupScanFallbackTimer = setTimeout(() => {
|
lookupScanFallbackTimer = setTimeout(() => {
|
||||||
lookupScanFallbackTimer = null;
|
lookupScanFallbackTimer = null;
|
||||||
if (ctx.state.yomitanPopupVisible || isYomitanPopupVisible(document)) {
|
if (isLookupPopupOpen(ctx.state, document)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Dispatch directly on the selected token span; when overlay pointer-events are disabled,
|
// Dispatch directly on the selected token span; when overlay pointer-events are disabled,
|
||||||
@@ -743,13 +742,15 @@ export function createKeyboardHandlers(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleLookupWindowToggleRequested(): void {
|
function handleLookupWindowToggleRequested(): void {
|
||||||
if (ctx.state.yomitanPopupVisible || isYomitanPopupVisible(document)) {
|
if (isLookupPopupOpen(ctx.state, document)) {
|
||||||
closeLookupWindow();
|
closeLookupWindow();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
triggerLookupForSelectedWord();
|
triggerLookupForSelectedWord();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Also clears Hachidori attention without an open pane, so callers like the
|
||||||
|
// Kiku modal opener leave no popup state behind.
|
||||||
function closeLookupWindow(): boolean {
|
function closeLookupWindow(): boolean {
|
||||||
if (!ctx.state.yomitanPopupVisible && !isYomitanPopupVisible(document)) {
|
if (!ctx.state.yomitanPopupVisible && !isYomitanPopupVisible(document)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -775,7 +776,7 @@ export function createKeyboardHandlers(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const popupVisible = ctx.state.yomitanPopupVisible || isYomitanPopupVisible(document);
|
const popupVisible = isLookupPopupOpen(ctx.state, document);
|
||||||
const result = moveKeyboardSelection(delta);
|
const result = moveKeyboardSelection(delta);
|
||||||
if (result === 'no-words') {
|
if (result === 'no-words') {
|
||||||
seekAdjacentSubtitleAndQueueSelection(delta, popupVisible);
|
seekAdjacentSubtitleAndQueueSelection(delta, popupVisible);
|
||||||
@@ -796,7 +797,7 @@ export function createKeyboardHandlers(
|
|||||||
code: string,
|
code: string,
|
||||||
repeat: boolean = true,
|
repeat: boolean = true,
|
||||||
): boolean {
|
): boolean {
|
||||||
if (!ctx.state.yomitanPopupVisible && !isYomitanPopupVisible(document)) {
|
if (!isLookupPopupOpen(ctx.state, document)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
dispatchYomitanPopupKeydown(key, code, [], repeat);
|
dispatchYomitanPopupKeydown(key, code, [], repeat);
|
||||||
@@ -804,7 +805,7 @@ export function createKeyboardHandlers(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function mineSelectedFromController(): boolean {
|
function mineSelectedFromController(): boolean {
|
||||||
if (!ctx.state.yomitanPopupVisible && !isYomitanPopupVisible(document)) {
|
if (!isLookupPopupOpen(ctx.state, document)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
dispatchYomitanPopupMineSelected();
|
dispatchYomitanPopupMineSelected();
|
||||||
@@ -812,7 +813,7 @@ export function createKeyboardHandlers(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function cyclePopupAudioSourceForController(direction: -1 | 1): boolean {
|
function cyclePopupAudioSourceForController(direction: -1 | 1): boolean {
|
||||||
if (!ctx.state.yomitanPopupVisible && !isYomitanPopupVisible(document)) {
|
if (!isLookupPopupOpen(ctx.state, document)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
dispatchYomitanPopupCycleAudioSource(direction);
|
dispatchYomitanPopupCycleAudioSource(direction);
|
||||||
@@ -820,7 +821,7 @@ export function createKeyboardHandlers(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function playCurrentAudioForController(): boolean {
|
function playCurrentAudioForController(): boolean {
|
||||||
if (!ctx.state.yomitanPopupVisible && !isYomitanPopupVisible(document)) {
|
if (!isLookupPopupOpen(ctx.state, document)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
dispatchYomitanPopupPlayCurrentAudio();
|
dispatchYomitanPopupPlayCurrentAudio();
|
||||||
@@ -828,7 +829,7 @@ export function createKeyboardHandlers(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function scrollPopupByController(deltaX: number, deltaY: number): boolean {
|
function scrollPopupByController(deltaX: number, deltaY: number): boolean {
|
||||||
if (!ctx.state.yomitanPopupVisible && !isYomitanPopupVisible(document)) {
|
if (!isLookupPopupOpen(ctx.state, document)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
dispatchYomitanPopupScrollBy(deltaX, deltaY);
|
dispatchYomitanPopupScrollBy(deltaX, deltaY);
|
||||||
@@ -855,7 +856,7 @@ export function createKeyboardHandlers(
|
|||||||
if (!ctx.state.keyboardDrivenModeEnabled) {
|
if (!ctx.state.keyboardDrivenModeEnabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!ctx.state.yomitanPopupVisible && !isYomitanPopupVisible(document)) {
|
if (!isLookupPopupOpen(ctx.state, document)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
restoreOverlayKeyboardFocus();
|
restoreOverlayKeyboardFocus();
|
||||||
@@ -900,7 +901,7 @@ export function createKeyboardHandlers(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const key = e.code;
|
const key = e.code;
|
||||||
const popupVisible = ctx.state.yomitanPopupVisible || isYomitanPopupVisible(document);
|
const popupVisible = isLookupPopupOpen(ctx.state, document);
|
||||||
if (key === 'ArrowLeft' || key === 'KeyH') {
|
if (key === 'ArrowLeft' || key === 'KeyH') {
|
||||||
const result = moveKeyboardSelection(-1);
|
const result = moveKeyboardSelection(-1);
|
||||||
if (result === 'start-boundary' || result === 'no-words') {
|
if (result === 'start-boundary' || result === 'no-words') {
|
||||||
|
|||||||
Reference in new issue
Block a user