diff --git a/src/custom-hooks/index.ts b/src/custom-hooks/index.ts new file mode 100644 index 0000000..56ae7bf --- /dev/null +++ b/src/custom-hooks/index.ts @@ -0,0 +1 @@ +export * from './usequickaccessvisible'; diff --git a/src/custom-hooks/usequickaccessvisible.tsx b/src/custom-hooks/usequickaccessvisible.tsx new file mode 100644 index 0000000..e66de38 --- /dev/null +++ b/src/custom-hooks/usequickaccessvisible.tsx @@ -0,0 +1,67 @@ +import { useState, useEffect } from 'react'; + +declare global { + var FocusNavController: any; +} + +/** + * Returns state indicating the visibility of quick access menu. + * + * @remarks + * During development it is possible to open the quick access menu without giving it + * focus in some cases. In such cases, the quick access menu state is invisible. + * + * This seems to be impossible to replicate when running the deck normally. Even in + * the edge cases it always seems to have a focus. + * + * @returns `true` if quick access menu is visible (focused) and `false` otherwise. + * + * @example + * import { VFC, useEffect } from "react"; + * import { useQuickAccessVisible } from "decky-frontend-lib"; + * + * export const PluginPanelView: VFC<{}> = ({ }) => { + * const isVisible = useQuickAccessVisible(); + * + * useEffect(() => { + * if (!isVisible) { + * return; + * } + * + * const interval = setInterval(() => console.log("Hello world!"), 1000); + * return () => { + * clearInterval(interval); + * } + * }, [isVisible]) + * + * return ( + *
+ * {isVisible ? "VISIBLE" : "INVISIBLE"} + *
+ * ); + * }; + */ +export function useQuickAccessVisible(): boolean { + // Assuming that the component is rendered in QAM already, so true by default... + const [isVisible, setIsVisible] = useState(true); + + useEffect(() => { + const quickAccessWindow: Window | null = FocusNavController?.GetGamepadNavTreeByID("QuickAccess-NA")?.m_Root?.m_element?.ownerDocument.defaultView ?? null; + if (quickAccessWindow === null) { + console.error("Could not get window of QuickAccess menu!"); + return; + } + + const onBlur = () => setIsVisible(false); + const onFocus = () => setIsVisible(true); + + quickAccessWindow.addEventListener("blur", onBlur); + quickAccessWindow.addEventListener("focus", onFocus); + return () => { + quickAccessWindow.removeEventListener("blur", onBlur); + quickAccessWindow.removeEventListener("focus", onFocus); + }; + }, []); + + return isVisible; +} diff --git a/src/index.ts b/src/index.ts index ad884b4..3ab76d5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,6 @@ // export * from './deck-libs'; export * from './custom-components'; +export * from './custom-hooks'; export * from './deck-components'; export * from './plugin'; export * from './webpack';