summaryrefslogtreecommitdiff
path: root/frontend/src/tabs-hook.tsx
diff options
context:
space:
mode:
authorTrainDoctor <traindoctor@protonmail.com>2022-10-30 10:32:05 -0700
committerGitHub <noreply@github.com>2022-10-30 10:32:05 -0700
commitbace5143d28c42ffcc83509b7fcdf02b6cae6934 (patch)
tree5a39a5980a84136df5a6781ba1e200d151112073 /frontend/src/tabs-hook.tsx
parentf5fc2053847d3054d36d3348d21e7de060342698 (diff)
downloaddecky-loader-bace5143d28c42ffcc83509b7fcdf02b6cae6934.tar.gz
decky-loader-bace5143d28c42ffcc83509b7fcdf02b6cae6934.zip
Merge Tabs and Injection Fixes, bring back native Valve toaster (#238)
* Bring back component patch-based tabshook * better injection point * finally fix dumb loading error * fix QAM injection breaking after lock * shut up typescript * fix lock screen focusing issues * Bring back the Valve toaster! * Add support for stable steamos * fix focus bug on lock screen but actually * oops: remove extra console log * shut up typescript again * better fix for lockscreen bug * better probably * actually fix focus issues (WTF) Co-authored-by: AAGaming <aa@mail.catvibers.me>
Diffstat (limited to 'frontend/src/tabs-hook.tsx')
-rw-r--r--frontend/src/tabs-hook.tsx154
1 files changed, 94 insertions, 60 deletions
diff --git a/frontend/src/tabs-hook.tsx b/frontend/src/tabs-hook.tsx
index 5929b8a0..c7790f7e 100644
--- a/frontend/src/tabs-hook.tsx
+++ b/frontend/src/tabs-hook.tsx
@@ -1,22 +1,18 @@
-import { QuickAccessTab, quickAccessMenuClasses, sleep } from 'decky-frontend-lib';
+// TabsHook for versions after the Desktop merge
+import { Patch, QuickAccessTab, afterPatch, findInReactTree, findModule, sleep } from 'decky-frontend-lib';
+import { memo } from 'react';
import { QuickAccessVisibleStateProvider } from './components/QuickAccessVisibleState';
import Logger from './logger';
+import { findSP } from './utils/windows';
declare global {
interface Window {
__TABS_HOOK_INSTANCE: any;
- }
- interface Array<T> {
- __filter: any;
+ securitystore: any;
}
}
-const isTabsArray = (tabs: any) => {
- const length = tabs.length;
- return length >= 7 && tabs[length - 1]?.tab;
-};
-
interface Tab {
id: QuickAccessTab | number;
title: any;
@@ -27,7 +23,9 @@ interface Tab {
class TabsHook extends Logger {
// private keys = 7;
tabs: Tab[] = [];
- private oFilter: (...args: any[]) => any;
+ private qAMRoot?: any;
+ private qamPatch?: Patch;
+ private unsubscribeSecurity?: () => void;
constructor() {
super('TabsHook');
@@ -35,65 +33,90 @@ class TabsHook extends Logger {
this.log('Initialized');
window.__TABS_HOOK_INSTANCE?.deinit?.();
window.__TABS_HOOK_INSTANCE = this;
+ }
- const self = this;
- const oFilter = (this.oFilter = Array.prototype.filter);
- Array.prototype.filter = function patchedFilter(...args: any[]) {
- if (isTabsArray(this)) {
- self.render(this);
+ init() {
+ const tree = (document.getElementById('root') as any)._reactRootContainer._internalRoot.current;
+ let qAMRoot: any;
+ const findQAMRoot = (currentNode: any, iters: number): any => {
+ if (iters >= 55) {
+ // currently 45
+ return null;
+ }
+ if (
+ typeof currentNode?.memoizedProps?.visible == 'boolean' &&
+ currentNode?.type?.toString()?.includes('QuickAccessMenuBrowserView')
+ ) {
+ this.log(`QAM root was found in ${iters} recursion cycles`);
+ return currentNode;
}
- // @ts-ignore
- return oFilter.call(this, ...args);
+ if (currentNode.child) {
+ let node = findQAMRoot(currentNode.child, iters + 1);
+ if (node !== null) return node;
+ }
+ if (currentNode.sibling) {
+ let node = findQAMRoot(currentNode.sibling, iters + 1);
+ if (node !== null) return node;
+ }
+ return null;
};
-
- if (document.title != 'SP')
- try {
- const tree = (document.getElementById('root') as any)._reactRootContainer._internalRoot.current;
- let qAMRoot: any;
- async function findQAMRoot(currentNode: any, iters: number): Promise<any> {
- if (iters >= 60) {
- // currently 44
- return null;
- }
- currentNode = currentNode?.child;
- if (
- currentNode?.memoizedProps?.className &&
- currentNode?.memoizedProps?.className.startsWith(quickAccessMenuClasses.ViewPlaceholder)
- ) {
- self.log(`QAM root was found in ${iters} recursion cycles`);
- return currentNode;
+ (async () => {
+ qAMRoot = findQAMRoot(tree, 0);
+ while (!qAMRoot) {
+ this.error(
+ 'Failed to find QAM root node, reattempting in 5 seconds. A developer may need to increase the recursion limit.',
+ );
+ await sleep(5000);
+ qAMRoot = findQAMRoot(tree, 0);
+ }
+ this.qAMRoot = qAMRoot;
+ let patchedInnerQAM: any;
+ this.qamPatch = afterPatch(qAMRoot.return, 'type', (_: any, ret: any) => {
+ try {
+ if (!qAMRoot?.child) {
+ qAMRoot = findQAMRoot(tree, 0);
+ this.qAMRoot = qAMRoot;
}
- if (!currentNode) return null;
- if (currentNode.sibling) {
- let node = await findQAMRoot(currentNode.sibling, iters + 1);
- if (node !== null) return node;
+ if (qAMRoot?.child && !qAMRoot?.child?.type?.decky) {
+ afterPatch(qAMRoot.child, 'type', (_: any, ret: any) => {
+ try {
+ const qamTabsRenderer = findInReactTree(ret, (x) => x?.props?.onFocusNavDeactivated);
+ if (patchedInnerQAM) {
+ qamTabsRenderer.type = patchedInnerQAM;
+ } else {
+ afterPatch(qamTabsRenderer, 'type', (innerArgs: any, ret: any) => {
+ const tabs = findInReactTree(ret, (x) => x?.props?.tabs);
+ this.render(tabs.props.tabs, innerArgs[0].visible);
+ return ret;
+ });
+ patchedInnerQAM = qamTabsRenderer.type;
+ }
+ } catch (e) {
+ this.error('Error patching QAM inner', e);
+ }
+ return ret;
+ });
+ qAMRoot.child.type.decky = true;
+ qAMRoot.child.alternate.type = qAMRoot.child.type;
}
- return await findQAMRoot(currentNode, iters + 1);
+ } catch (e) {
+ this.error('Error patching QAM', e);
}
- (async () => {
- qAMRoot = await findQAMRoot(tree, 0);
- while (!qAMRoot) {
- this.error(
- 'Failed to find QAM root node, reattempting in 5 seconds. A developer may need to increase the recursion limit.',
- );
- await sleep(5000);
- qAMRoot = await findQAMRoot(tree, 0);
- }
- while (!qAMRoot?.stateNode?.forceUpdate) {
- qAMRoot = qAMRoot.return;
- }
- qAMRoot.stateNode.shouldComponentUpdate = () => true;
- qAMRoot.stateNode.forceUpdate();
- delete qAMRoot.stateNode.shouldComponentUpdate;
- })();
- } catch (e) {
- this.log('Failed to rerender QAM', e);
+ return ret;
+ });
+
+ if (qAMRoot.return.alternate) {
+ qAMRoot.return.alternate.type = qAMRoot.return.type;
}
+ this.log('Finished initial injection');
+ })();
}
deinit() {
- Array.prototype.filter = this.oFilter;
+ this.qamPatch?.unpatch();
+ this.qAMRoot.return.alternate.type = this.qAMRoot.return.type;
+ this.unsubscribeSecurity?.();
}
add(tab: Tab) {
@@ -106,14 +129,25 @@ class TabsHook extends Logger {
this.tabs = this.tabs.filter((tab) => tab.id !== id);
}
- render(existingTabs: any[]) {
+ render(existingTabs: any[], visible: boolean) {
+ let deckyTabAmount = existingTabs.reduce((prev: any, cur: any) => (cur.decky ? prev + 1 : prev), 0);
+ if (deckyTabAmount == this.tabs.length) {
+ for (let tab of existingTabs) {
+ if (tab?.decky) tab.panel.props.setter[0](visible);
+ }
+ return;
+ }
for (const { title, icon, content, id } of this.tabs) {
existingTabs.push({
key: id,
title,
tab: icon,
decky: true,
- panel: <QuickAccessVisibleStateProvider>{content}</QuickAccessVisibleStateProvider>,
+ panel: (
+ <QuickAccessVisibleStateProvider initial={visible} setter={[]}>
+ {content}
+ </QuickAccessVisibleStateProvider>
+ ),
});
}
}