mirror of
https://github.com/SteamDeckHomebrew/decky-loader.git
synced 2026-06-18 09:17:48 +00:00
Compare commits
10 Commits
v2.1.1
...
v2.2.2-pre2
| Author | SHA1 | Date | |
|---|---|---|---|
| 0e409a9f96 | |||
| d58001c323 | |||
| d727ba72f3 | |||
| fa028fa525 | |||
| c947548064 | |||
| 19d5527bdf | |||
| ef51b96f08 | |||
| 617916e8e5 | |||
| 6c4a4d0a44 | |||
| bedcb0fb71 |
@@ -109,7 +109,7 @@ jobs:
|
||||
printf "OUT: ${OUT}\n"
|
||||
elif [[ ! "$VERSION" =~ "-pre" ]]; then
|
||||
printf "previous tag is a release, bumping by a patch\n"
|
||||
OUT=$(semver bump minor "$VERSION")
|
||||
OUT=$(semver bump patch "$VERSION")
|
||||
printf "OUT: ${OUT}\n"
|
||||
fi
|
||||
echo "vOUT: v$OUT"
|
||||
@@ -171,7 +171,7 @@ jobs:
|
||||
OUT=""
|
||||
if [[ ! "$VERSION" =~ "-pre" ]]; then
|
||||
printf "is release, bumping minor version and prerel\n"
|
||||
OUT=$(semver bump minor "$VERSION")
|
||||
OUT=$(semver bump patch "$VERSION")
|
||||
OUT="$OUT-pre"
|
||||
OUT=$(semver bump prerel "$OUT")
|
||||
printf "OUT: ${OUT}\n"
|
||||
|
||||
@@ -14,7 +14,7 @@ Keep an eye on the [Wiki](https://deckbrew.xyz) for more information about Decky
|
||||
7. Make sure you have a password set with the "passwd" command in terminal to install it ([YouTube Guide](https://www.youtube.com/watch?v=1vOMYGj22rQ)).
|
||||
8. Open a terminal ("Konsole" is the pre-installed terminal application) and paste the following command into it:
|
||||
- For the latest release:
|
||||
- `curl -L https://github.com/SteamDeckHomebrew/decky-loader/raw/main/dist/install_prerelease.sh | sh`
|
||||
- `curl -L https://github.com/SteamDeckHomebrew/decky-loader/raw/main/dist/install_release.sh | sh`
|
||||
- For the latest pre-release:
|
||||
- `curl -L https://github.com/SteamDeckHomebrew/decky-loader/raw/main/dist/install_prerelease.sh | sh`
|
||||
- For testers/plugin developers:
|
||||
@@ -24,7 +24,7 @@ Keep an eye on the [Wiki](https://deckbrew.xyz) for more information about Decky
|
||||
|
||||
### Install/Uninstall Plugins
|
||||
- Using the shopping bag button in the top right corner of the plugin menu, you can go to the offical Plugin Store ([Web Preview](https://beta.deckbrew.xyz/)).
|
||||
- Simply copy the plugin's folder into `~/homebrew/plugins`
|
||||
- Install from URL in the settings menu.
|
||||
- Use the settings menu to uninstall plugins, this will not remove any files made in different directories by plugins.
|
||||
|
||||
### Uninstall
|
||||
|
||||
Vendored
+7
-2
@@ -13,8 +13,13 @@ sudo -u $SUDO_USER mkdir -p "${HOMEBREW_FOLDER}/services"
|
||||
sudo -u $SUDO_USER mkdir -p "${HOMEBREW_FOLDER}/plugins"
|
||||
|
||||
# Download latest release and install it
|
||||
curl -L https://github.com/SteamDeckHomebrew/PluginLoader/releases/latest/download/PluginLoader --output "${HOMEBREW_FOLDER}/services/PluginLoader"
|
||||
chmod +x "${HOMEBREW_FOLDER}/services/PluginLoader"
|
||||
RELEASE=$(curl -s 'https://api.github.com/repos/SteamDeckHomebrew/decky-loader/releases' | jq -r "first(.[] | select(.prerelease == "false"))")
|
||||
read VERSION DOWNLOADURL < <(echo $(jq -r '.tag_name, .assets[].browser_download_url' <<< ${RELEASE}))
|
||||
|
||||
printf "Installing version %s...\n" "${VERSION}"
|
||||
curl -L $DOWNLOADURL --output ${HOMEBREW_FOLDER}/services/PluginLoader
|
||||
chmod +x ${HOMEBREW_FOLDER}/services/PluginLoader
|
||||
echo $VERSION > ${HOMEBREW_FOLDER}/services/.loader.version
|
||||
|
||||
systemctl --user stop plugin_loader 2> /dev/null
|
||||
systemctl --user disable plugin_loader 2> /dev/null
|
||||
|
||||
@@ -24,6 +24,7 @@ const Markdown: FunctionComponent<MarkdownProps> = (props) => {
|
||||
aRef?.current?.click();
|
||||
props.onDismiss?.();
|
||||
}}
|
||||
style={{ display: 'inline' }}
|
||||
>
|
||||
<a ref={aRef} {...nodeProps.node.properties}>
|
||||
{nodeProps.children}
|
||||
|
||||
@@ -113,8 +113,19 @@ const PluginCard: FC<PluginCardProps> = ({ plugin }) => {
|
||||
}}
|
||||
className="deckyStoreCardInfo"
|
||||
>
|
||||
<p className={joinClassNames(staticClasses.PanelSectionRow)}>
|
||||
<span>Author: {plugin.author}</span>
|
||||
<p className={joinClassNames(staticClasses.PanelSectionRow)} style={{ marginTop: '0px', marginLeft: '16px'}}>
|
||||
<span style={{ paddingLeft: '0px' }}>Author: {plugin.author}</span>
|
||||
</p>
|
||||
<p
|
||||
className={joinClassNames(staticClasses.PanelSectionRow)}
|
||||
style={{
|
||||
marginLeft: '16px',
|
||||
marginTop: '0px',
|
||||
marginBottom: '0px',
|
||||
marginRight: '16px'
|
||||
}}
|
||||
>
|
||||
<span style={{ paddingLeft: '0px' }}>{plugin.description}</span>
|
||||
</p>
|
||||
<p
|
||||
className={joinClassNames('deckyStoreCardTagsContainer', staticClasses.PanelSectionRow)}
|
||||
|
||||
@@ -1,4 +1,16 @@
|
||||
import { ConfirmModal, ModalRoot, QuickAccessTab, Router, showModal, sleep, staticClasses } from 'decky-frontend-lib';
|
||||
import {
|
||||
ConfirmModal,
|
||||
ModalRoot,
|
||||
Patch,
|
||||
QuickAccessTab,
|
||||
Router,
|
||||
callOriginal,
|
||||
findModuleChild,
|
||||
replacePatch,
|
||||
showModal,
|
||||
sleep,
|
||||
staticClasses,
|
||||
} from 'decky-frontend-lib';
|
||||
import { lazy } from 'react';
|
||||
import { FaPlug } from 'react-icons/fa';
|
||||
|
||||
@@ -39,6 +51,8 @@ class PluginLoader extends Logger {
|
||||
// stores a list of plugin names which requested to be reloaded
|
||||
private pluginReloadQueue: { name: string; version?: string }[] = [];
|
||||
|
||||
private focusWorkaroundPatch?: Patch;
|
||||
|
||||
constructor() {
|
||||
super(PluginLoader.name);
|
||||
this.log('Initialized');
|
||||
@@ -83,6 +97,38 @@ class PluginLoader extends Logger {
|
||||
initFilepickerPatches();
|
||||
|
||||
this.updateVersion();
|
||||
|
||||
const self = this;
|
||||
|
||||
try {
|
||||
// TODO remove all of this once Valve fixes the bug
|
||||
const focusManager = findModuleChild((m) => {
|
||||
if (typeof m !== 'object') return false;
|
||||
for (let prop in m) {
|
||||
if (m[prop]?.prototype?.TakeFocus) return m[prop];
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
this.focusWorkaroundPatch = replacePatch(focusManager.prototype, 'TakeFocus', function () {
|
||||
// @ts-ignore
|
||||
const classList = this.m_node?.m_element.classList;
|
||||
if (
|
||||
// @ts-ignore
|
||||
(this.m_node?.m_element && classList.contains(staticClasses.TabGroupPanel)) ||
|
||||
classList.contains('FriendsListTab') ||
|
||||
classList.contains('FriendsTabList') ||
|
||||
classList.contains('FriendsListAndChatsSteamDeck')
|
||||
) {
|
||||
self.debug('Intercepted friends re-focus');
|
||||
return true;
|
||||
}
|
||||
|
||||
return callOriginal;
|
||||
});
|
||||
} catch (e) {
|
||||
this.error('Friends focus patch failed', e);
|
||||
}
|
||||
}
|
||||
|
||||
public async updateVersion() {
|
||||
@@ -167,6 +213,7 @@ class PluginLoader extends Logger {
|
||||
this.routerHook.removeRoute('/decky/store');
|
||||
this.routerHook.removeRoute('/decky/settings');
|
||||
deinitFilepickerPatches();
|
||||
this.focusWorkaroundPatch?.unpatch();
|
||||
}
|
||||
|
||||
public unloadPlugin(name: string) {
|
||||
|
||||
+18
-11
@@ -47,18 +47,25 @@ class TabsHook extends Logger {
|
||||
const self = this;
|
||||
const tree = (document.getElementById('root') as any)._reactRootContainer._internalRoot.current;
|
||||
let scrollRoot: any;
|
||||
let currentNode = tree;
|
||||
async function findScrollRoot(currentNode: any, iters: number): Promise<any> {
|
||||
if (iters >= 30) {
|
||||
await sleep(5000);
|
||||
return await findScrollRoot(tree, 0);
|
||||
}
|
||||
currentNode = currentNode?.child;
|
||||
if (currentNode?.type?.prototype?.RemoveSmartScrollContainer) return currentNode;
|
||||
if (!currentNode) return null;
|
||||
if (currentNode.sibling) {
|
||||
let node = await findScrollRoot(currentNode.sibling, iters++);
|
||||
if (node !== null) return node;
|
||||
}
|
||||
return await findScrollRoot(currentNode, iters++);
|
||||
}
|
||||
(async () => {
|
||||
let iters = 0;
|
||||
while (!scrollRoot) {
|
||||
iters++;
|
||||
currentNode = currentNode?.child;
|
||||
if (iters >= 30 || !currentNode) {
|
||||
iters = 0;
|
||||
currentNode = tree;
|
||||
await sleep(5000);
|
||||
}
|
||||
if (currentNode?.type?.prototype?.RemoveSmartScrollContainer) scrollRoot = currentNode;
|
||||
scrollRoot = await findScrollRoot(tree, 0);
|
||||
if (!scrollRoot) {
|
||||
this.error('Failed to find scroll root node!');
|
||||
return;
|
||||
}
|
||||
let newQA: any;
|
||||
let newQATabRenderer: any;
|
||||
|
||||
@@ -1,14 +1,4 @@
|
||||
import {
|
||||
Patch,
|
||||
ToastData,
|
||||
afterPatch,
|
||||
callOriginal,
|
||||
findInReactTree,
|
||||
findModuleChild,
|
||||
replacePatch,
|
||||
sleep,
|
||||
staticClasses,
|
||||
} from 'decky-frontend-lib';
|
||||
import { Patch, ToastData, afterPatch, findInReactTree, findModuleChild, sleep } from 'decky-frontend-lib';
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
import Toast from './components/Toast';
|
||||
@@ -37,24 +27,7 @@ class Toaster extends Logger {
|
||||
|
||||
async init() {
|
||||
let instance: any;
|
||||
const self = this;
|
||||
const focusManager = findModuleChild((m) => {
|
||||
if (typeof m !== 'object') return false;
|
||||
for (let prop in m) {
|
||||
if (m[prop]?.prototype?.TakeFocus) return m[prop];
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
const focusWorkaroundPatch = replacePatch(focusManager.prototype, 'BFocusWithin', function () {
|
||||
// @ts-ignore
|
||||
if (this.m_node?.m_element && this.m_node?.m_element.classList.contains(staticClasses.TabGroupPanel)) {
|
||||
self.debug('Intercepted friends re-focus');
|
||||
return true;
|
||||
}
|
||||
|
||||
return callOriginal;
|
||||
});
|
||||
while (true) {
|
||||
instance = findInReactTree(
|
||||
(document.getElementById('root') as any)._reactRootContainer._internalRoot.current,
|
||||
@@ -99,7 +72,6 @@ class Toaster extends Logger {
|
||||
if (typeof m[prop]?.settings && m[prop]?.communityPreferences) return m[prop];
|
||||
}
|
||||
});
|
||||
focusWorkaroundPatch.unpatch();
|
||||
this.log('Initialized');
|
||||
this.ready = true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user