mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-03-22 12:11:27 -07:00
fix(renderer): sync embedded sidebar mouse passthrough
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import type { ModalStateReader, RendererContext } from '../context';
|
import type { ModalStateReader, RendererContext } from '../context';
|
||||||
|
import { syncOverlayMouseIgnoreState } from '../overlay-mouse-ignore.js';
|
||||||
import {
|
import {
|
||||||
YOMITAN_POPUP_HIDDEN_EVENT,
|
YOMITAN_POPUP_HIDDEN_EVENT,
|
||||||
YOMITAN_POPUP_SHOWN_EVENT,
|
YOMITAN_POPUP_SHOWN_EVENT,
|
||||||
@@ -25,6 +26,19 @@ export function createMouseHandlers(
|
|||||||
let pausedBySubtitleHover = false;
|
let pausedBySubtitleHover = false;
|
||||||
let pausedByYomitanPopup = false;
|
let pausedByYomitanPopup = false;
|
||||||
|
|
||||||
|
function isWithinOtherSubtitleContainer(
|
||||||
|
relatedTarget: EventTarget | null,
|
||||||
|
otherContainer: HTMLElement,
|
||||||
|
): boolean {
|
||||||
|
if (relatedTarget === otherContainer) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (typeof Node !== 'undefined' && relatedTarget instanceof Node) {
|
||||||
|
return otherContainer.contains(relatedTarget);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
function maybeResumeHoverPause(): void {
|
function maybeResumeHoverPause(): void {
|
||||||
if (!pausedBySubtitleHover) return;
|
if (!pausedBySubtitleHover) return;
|
||||||
if (pausedByYomitanPopup) return;
|
if (pausedByYomitanPopup) return;
|
||||||
@@ -80,10 +94,7 @@ export function createMouseHandlers(
|
|||||||
function enablePopupInteraction(): void {
|
function enablePopupInteraction(): void {
|
||||||
yomitanPopupVisible = true;
|
yomitanPopupVisible = true;
|
||||||
ctx.state.yomitanPopupVisible = true;
|
ctx.state.yomitanPopupVisible = true;
|
||||||
ctx.dom.overlay.classList.add('interactive');
|
syncOverlayMouseIgnoreState(ctx);
|
||||||
if (ctx.platform.shouldToggleMouseIgnore) {
|
|
||||||
window.electronAPI.setIgnoreMouseEvents(false);
|
|
||||||
}
|
|
||||||
if (ctx.platform.isMacOSPlatform) {
|
if (ctx.platform.isMacOSPlatform) {
|
||||||
window.focus();
|
window.focus();
|
||||||
}
|
}
|
||||||
@@ -101,20 +112,18 @@ export function createMouseHandlers(
|
|||||||
popupPauseRequestId += 1;
|
popupPauseRequestId += 1;
|
||||||
maybeResumeYomitanPopupPause();
|
maybeResumeYomitanPopupPause();
|
||||||
maybeResumeHoverPause();
|
maybeResumeHoverPause();
|
||||||
if (!ctx.state.isOverSubtitle && !options.modalStateReader.isAnyModalOpen()) {
|
syncOverlayMouseIgnoreState(ctx);
|
||||||
ctx.dom.overlay.classList.remove('interactive');
|
|
||||||
if (ctx.platform.shouldToggleMouseIgnore) {
|
|
||||||
window.electronAPI.setIgnoreMouseEvents(true, { forward: true });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleMouseEnter(): Promise<void> {
|
async function handleMouseEnter(
|
||||||
|
_event?: MouseEvent,
|
||||||
|
showSecondaryHover = false,
|
||||||
|
): Promise<void> {
|
||||||
ctx.state.isOverSubtitle = true;
|
ctx.state.isOverSubtitle = true;
|
||||||
ctx.dom.overlay.classList.add('interactive');
|
if (showSecondaryHover) {
|
||||||
if (ctx.platform.shouldToggleMouseIgnore) {
|
ctx.dom.secondarySubContainer.classList.add('secondary-sub-hover-active');
|
||||||
window.electronAPI.setIgnoreMouseEvents(false);
|
|
||||||
}
|
}
|
||||||
|
syncOverlayMouseIgnoreState(ctx);
|
||||||
|
|
||||||
if (yomitanPopupVisible && options.getYomitanPopupAutoPauseEnabled()) {
|
if (yomitanPopupVisible && options.getYomitanPopupAutoPauseEnabled()) {
|
||||||
return;
|
return;
|
||||||
@@ -124,6 +133,10 @@ export function createMouseHandlers(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pausedBySubtitleHover) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const requestId = ++hoverPauseRequestId;
|
const requestId = ++hoverPauseRequestId;
|
||||||
let paused: boolean | null = null;
|
let paused: boolean | null = null;
|
||||||
try {
|
try {
|
||||||
@@ -141,8 +154,22 @@ export function createMouseHandlers(
|
|||||||
pausedBySubtitleHover = true;
|
pausedBySubtitleHover = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleMouseLeave(): Promise<void> {
|
async function handleMouseLeave(
|
||||||
|
_event?: MouseEvent,
|
||||||
|
hideSecondaryHover = false,
|
||||||
|
): Promise<void> {
|
||||||
|
const relatedTarget = _event?.relatedTarget ?? null;
|
||||||
|
const otherContainer = hideSecondaryHover
|
||||||
|
? ctx.dom.subtitleContainer
|
||||||
|
: ctx.dom.secondarySubContainer;
|
||||||
|
if (relatedTarget && isWithinOtherSubtitleContainer(relatedTarget, otherContainer)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ctx.state.isOverSubtitle = false;
|
ctx.state.isOverSubtitle = false;
|
||||||
|
if (hideSecondaryHover) {
|
||||||
|
ctx.dom.secondarySubContainer.classList.remove('secondary-sub-hover-active');
|
||||||
|
}
|
||||||
hoverPauseRequestId += 1;
|
hoverPauseRequestId += 1;
|
||||||
maybeResumeHoverPause();
|
maybeResumeHoverPause();
|
||||||
if (yomitanPopupVisible) return;
|
if (yomitanPopupVisible) return;
|
||||||
@@ -246,6 +273,10 @@ export function createMouseHandlers(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
handlePrimaryMouseEnter: (event?: MouseEvent) => handleMouseEnter(event, false),
|
||||||
|
handlePrimaryMouseLeave: (event?: MouseEvent) => handleMouseLeave(event, false),
|
||||||
|
handleSecondaryMouseEnter: (event?: MouseEvent) => handleMouseEnter(event, true),
|
||||||
|
handleSecondaryMouseLeave: (event?: MouseEvent) => handleMouseLeave(event, true),
|
||||||
handleMouseEnter,
|
handleMouseEnter,
|
||||||
handleMouseLeave,
|
handleMouseLeave,
|
||||||
setupDragging,
|
setupDragging,
|
||||||
|
|||||||
42
src/renderer/overlay-mouse-ignore.ts
Normal file
42
src/renderer/overlay-mouse-ignore.ts
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import type { RendererContext } from './context';
|
||||||
|
import type { RendererState } from './state';
|
||||||
|
|
||||||
|
function isBlockingOverlayModalOpen(state: RendererState): boolean {
|
||||||
|
const embeddedSidebarOpen =
|
||||||
|
state.subtitleSidebarModalOpen && state.subtitleSidebarConfig?.layout === 'embedded';
|
||||||
|
|
||||||
|
return Boolean(
|
||||||
|
state.controllerSelectModalOpen ||
|
||||||
|
state.controllerDebugModalOpen ||
|
||||||
|
state.jimakuModalOpen ||
|
||||||
|
state.kikuModalOpen ||
|
||||||
|
state.runtimeOptionsModalOpen ||
|
||||||
|
state.subsyncModalOpen ||
|
||||||
|
state.sessionHelpModalOpen ||
|
||||||
|
(state.subtitleSidebarModalOpen && !embeddedSidebarOpen),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function syncOverlayMouseIgnoreState(ctx: RendererContext): void {
|
||||||
|
const shouldStayInteractive =
|
||||||
|
ctx.state.isOverSubtitle ||
|
||||||
|
ctx.state.isOverSubtitleSidebar ||
|
||||||
|
ctx.state.yomitanPopupVisible ||
|
||||||
|
isBlockingOverlayModalOpen(ctx.state);
|
||||||
|
|
||||||
|
if (shouldStayInteractive) {
|
||||||
|
ctx.dom.overlay.classList.add('interactive');
|
||||||
|
} else {
|
||||||
|
ctx.dom.overlay.classList.remove('interactive');
|
||||||
|
}
|
||||||
|
if (!ctx.platform?.shouldToggleMouseIgnore) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldStayInteractive) {
|
||||||
|
window.electronAPI.setIgnoreMouseEvents(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.electronAPI.setIgnoreMouseEvents(true, { forward: true });
|
||||||
|
}
|
||||||
@@ -25,6 +25,7 @@ export type ChordAction =
|
|||||||
|
|
||||||
export type RendererState = {
|
export type RendererState = {
|
||||||
isOverSubtitle: boolean;
|
isOverSubtitle: boolean;
|
||||||
|
isOverSubtitleSidebar: boolean;
|
||||||
isDragging: boolean;
|
isDragging: boolean;
|
||||||
dragStartY: number;
|
dragStartY: number;
|
||||||
startYPercent: number;
|
startYPercent: number;
|
||||||
@@ -115,6 +116,7 @@ export type RendererState = {
|
|||||||
export function createRendererState(): RendererState {
|
export function createRendererState(): RendererState {
|
||||||
return {
|
return {
|
||||||
isOverSubtitle: false,
|
isOverSubtitle: false,
|
||||||
|
isOverSubtitleSidebar: false,
|
||||||
isDragging: false,
|
isDragging: false,
|
||||||
dragStartY: 0,
|
dragStartY: 0,
|
||||||
startYPercent: 0,
|
startYPercent: 0,
|
||||||
|
|||||||
Reference in New Issue
Block a user