Files
Netcatty/application/state/useMainWindowInputFocusRecovery.ts
T
陈大猫 f95cc754e7 fix(windows): restore main-window input focus on show/hide hotkey (#1722)
Route global hotkey/tray show paths through restoreWindowInputFocus, recover renderer focus on visibility/show, dismiss transient overlays before native hide, and cancel deferred focus callbacks on hide.

Closes #1722
2026-06-26 18:01:57 +08:00

70 lines
1.9 KiB
TypeScript

import { useEffect } from "react";
import { netcattyBridge } from "../../infrastructure/services/netcattyBridge";
import {
scheduleWindowInputFocus,
type ScheduledWindowInputFocus,
} from "./windowInputFocus";
export type MainWindowInputFocusRecoveryOptions = {
/** Close transient overlays before the window hides (#1722). */
onPageHidden?: () => void;
};
/**
* Recover OS/renderer input focus when the main window returns from hide,
* another app, or a virtual desktop (#760, #1714, #1722).
*/
export function useMainWindowInputFocusRecovery(
options: MainWindowInputFocusRecoveryOptions = {},
): void {
const { onPageHidden } = options;
useEffect(() => {
let pendingFocusRecovery: ScheduledWindowInputFocus | null = null;
const cancelPendingFocusRecovery = () => {
pendingFocusRecovery?.cancel();
pendingFocusRecovery = null;
};
const recoverFocus = () => {
if (document.visibilityState !== "visible") return;
cancelPendingFocusRecovery();
pendingFocusRecovery = scheduleWindowInputFocus();
};
const dismissTransientUi = () => {
cancelPendingFocusRecovery();
onPageHidden?.();
};
const onVisibilityChange = () => {
if (document.visibilityState === "hidden") {
dismissTransientUi();
return;
}
recoverFocus();
};
document.addEventListener("visibilitychange", onVisibilityChange);
window.addEventListener("focus", recoverFocus);
const bridge = netcattyBridge.get();
const unsubscribeShown = bridge?.onWindowShown?.(() => {
recoverFocus();
});
const unsubscribeWillHide = bridge?.onWindowWillHide?.(() => {
dismissTransientUi();
});
return () => {
cancelPendingFocusRecovery();
document.removeEventListener("visibilitychange", onVisibilityChange);
window.removeEventListener("focus", recoverFocus);
unsubscribeShown?.();
unsubscribeWillHide?.();
};
}, [onPageHidden]);
}