mirror of
https://github.com/Vencord/Vesktop.git
synced 2025-02-23 13:45:09 +00:00
SteamOS: fixes & official controller layout (#194)
This commit is contained in:
parent
3262e083fa
commit
1e9c70eed9
7 changed files with 131 additions and 10 deletions
|
@ -38,6 +38,7 @@
|
||||||
"dotenv": "^16.3.1",
|
"dotenv": "^16.3.1",
|
||||||
"electron": "^27.0.0",
|
"electron": "^27.0.0",
|
||||||
"electron-builder": "^24.6.4",
|
"electron-builder": "^24.6.4",
|
||||||
|
"electron-builder-sandbox-fix": "^1.0.10",
|
||||||
"esbuild": "^0.19.4",
|
"esbuild": "^0.19.4",
|
||||||
"eslint": "^8.51.0",
|
"eslint": "^8.51.0",
|
||||||
"eslint-config-prettier": "^9.0.0",
|
"eslint-config-prettier": "^9.0.0",
|
||||||
|
@ -61,6 +62,7 @@
|
||||||
"build": {
|
"build": {
|
||||||
"appId": "dev.vencord.desktop",
|
"appId": "dev.vencord.desktop",
|
||||||
"productName": "Vesktop",
|
"productName": "Vesktop",
|
||||||
|
"afterPack": "electron-builder-sandbox-fix",
|
||||||
"files": [
|
"files": [
|
||||||
"!*",
|
"!*",
|
||||||
"dist/js",
|
"dist/js",
|
||||||
|
|
9
pnpm-lock.yaml
generated
9
pnpm-lock.yaml
generated
|
@ -42,6 +42,9 @@ devDependencies:
|
||||||
electron-builder:
|
electron-builder:
|
||||||
specifier: ^24.6.4
|
specifier: ^24.6.4
|
||||||
version: 24.6.4
|
version: 24.6.4
|
||||||
|
electron-builder-sandbox-fix:
|
||||||
|
specifier: ^1.0.10
|
||||||
|
version: 1.0.10
|
||||||
esbuild:
|
esbuild:
|
||||||
specifier: ^0.19.4
|
specifier: ^0.19.4
|
||||||
version: 0.19.4
|
version: 0.19.4
|
||||||
|
@ -1822,6 +1825,12 @@ packages:
|
||||||
jake: 10.8.7
|
jake: 10.8.7
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/electron-builder-sandbox-fix@1.0.10:
|
||||||
|
resolution: {integrity: sha512-fxZD8etQFXkXOlxe/nYEbPsDXcKJHhadxzLyXq7IEucELPE0GK8jYnNt1y577FsfRQvuhOAd4oZNdIdICVi5nQ==}
|
||||||
|
dependencies:
|
||||||
|
chalk: 4.1.2
|
||||||
|
dev: true
|
||||||
|
|
||||||
/electron-builder@24.6.4:
|
/electron-builder@24.6.4:
|
||||||
resolution: {integrity: sha512-uNWQoU7pE7qOaIQ6CJHpBi44RJFVG8OHRBIadUxrsDJVwLLo8Nma3K/EEtx5/UyWAQYdcK4nVPYKoRqBb20hbA==}
|
resolution: {integrity: sha512-uNWQoU7pE7qOaIQ6CJHpBi44RJFVG8OHRBIadUxrsDJVwLLo8Nma3K/EEtx5/UyWAQYdcK4nVPYKoRqBb20hbA==}
|
||||||
engines: {node: '>=14.0.0'}
|
engines: {node: '>=14.0.0'}
|
||||||
|
|
|
@ -34,3 +34,8 @@ const UserAgents = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const UserAgent = UserAgents[process.platform] || UserAgents.windows;
|
export const UserAgent = UserAgents[process.platform] || UserAgents.windows;
|
||||||
|
|
||||||
|
export const enum MessageBoxChoice {
|
||||||
|
Default,
|
||||||
|
Cancel
|
||||||
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ import {
|
||||||
DATA_DIR,
|
DATA_DIR,
|
||||||
DEFAULT_HEIGHT,
|
DEFAULT_HEIGHT,
|
||||||
DEFAULT_WIDTH,
|
DEFAULT_WIDTH,
|
||||||
|
MessageBoxChoice,
|
||||||
MIN_HEIGHT,
|
MIN_HEIGHT,
|
||||||
MIN_WIDTH,
|
MIN_WIDTH,
|
||||||
UserAgent,
|
UserAgent,
|
||||||
|
@ -36,11 +37,14 @@ import {
|
||||||
import { Settings, VencordSettings } from "./settings";
|
import { Settings, VencordSettings } from "./settings";
|
||||||
import { createSplashWindow } from "./splash";
|
import { createSplashWindow } from "./splash";
|
||||||
import { makeLinksOpenExternally } from "./utils/makeLinksOpenExternally";
|
import { makeLinksOpenExternally } from "./utils/makeLinksOpenExternally";
|
||||||
|
import { applyDeckKeyboardFix, askToApplySteamLayout, isDeckGameMode } from "./utils/steamOS";
|
||||||
import { downloadVencordFiles, ensureVencordFiles } from "./utils/vencordLoader";
|
import { downloadVencordFiles, ensureVencordFiles } from "./utils/vencordLoader";
|
||||||
|
|
||||||
let isQuitting = false;
|
let isQuitting = false;
|
||||||
let tray: Tray;
|
let tray: Tray;
|
||||||
|
|
||||||
|
applyDeckKeyboardFix();
|
||||||
|
|
||||||
app.on("before-quit", () => {
|
app.on("before-quit", () => {
|
||||||
isQuitting = true;
|
isQuitting = true;
|
||||||
});
|
});
|
||||||
|
@ -128,11 +132,6 @@ function initTray(win: BrowserWindow) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const enum MessageBoxChoice {
|
|
||||||
Default,
|
|
||||||
Cancel
|
|
||||||
}
|
|
||||||
|
|
||||||
async function clearData(win: BrowserWindow) {
|
async function clearData(win: BrowserWindow) {
|
||||||
const { response } = await dialog.showMessageBox(win, {
|
const { response } = await dialog.showMessageBox(win, {
|
||||||
message: "Are you sure you want to reset Vesktop?",
|
message: "Are you sure you want to reset Vesktop?",
|
||||||
|
@ -266,6 +265,9 @@ function initMenuBar(win: BrowserWindow) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getWindowBoundsOptions(): BrowserWindowConstructorOptions {
|
function getWindowBoundsOptions(): BrowserWindowConstructorOptions {
|
||||||
|
// We want the default window behaivour to apply in game mode since it expects everything to be fullscreen and maximized.
|
||||||
|
if (isDeckGameMode) return {};
|
||||||
|
|
||||||
const { x, y, width, height } = Settings.store.windowBounds ?? {};
|
const { x, y, width, height } = Settings.store.windowBounds ?? {};
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
|
@ -405,7 +407,7 @@ function createMainWindow() {
|
||||||
win.setMenuBarVisibility(false);
|
win.setMenuBarVisibility(false);
|
||||||
|
|
||||||
win.on("close", e => {
|
win.on("close", e => {
|
||||||
const useTray = Settings.store.minimizeToTray !== false && Settings.store.tray !== false;
|
const useTray = !isDeckGameMode && Settings.store.minimizeToTray !== false && Settings.store.tray !== false;
|
||||||
if (isQuitting || (process.platform !== "darwin" && !useTray)) return;
|
if (isQuitting || (process.platform !== "darwin" && !useTray)) return;
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
@ -419,7 +421,7 @@ function createMainWindow() {
|
||||||
if (Settings.store.staticTitle) win.on("page-title-updated", e => e.preventDefault());
|
if (Settings.store.staticTitle) win.on("page-title-updated", e => e.preventDefault());
|
||||||
|
|
||||||
initWindowBoundsListeners(win);
|
initWindowBoundsListeners(win);
|
||||||
if ((Settings.store.tray ?? true) && process.platform !== "darwin") initTray(win);
|
if (!isDeckGameMode && (Settings.store.tray ?? true) && process.platform !== "darwin") initTray(win);
|
||||||
initMenuBar(win);
|
initMenuBar(win);
|
||||||
makeLinksOpenExternally(win);
|
makeLinksOpenExternally(win);
|
||||||
initSettingsListeners(win);
|
initSettingsListeners(win);
|
||||||
|
@ -441,19 +443,27 @@ const runVencordMain = once(() => require(join(VENCORD_FILES_DIR, "vencordDeskto
|
||||||
|
|
||||||
export async function createWindows() {
|
export async function createWindows() {
|
||||||
const splash = createSplashWindow();
|
const splash = createSplashWindow();
|
||||||
|
// SteamOS letterboxes and scales it terribly, so just full screen it
|
||||||
|
if (isDeckGameMode) splash.setFullScreen(true);
|
||||||
await ensureVencordFiles();
|
await ensureVencordFiles();
|
||||||
runVencordMain();
|
runVencordMain();
|
||||||
|
|
||||||
mainWin = createMainWindow();
|
mainWin = createMainWindow();
|
||||||
|
|
||||||
mainWin.once("ready-to-show", () => {
|
mainWin.webContents.on("did-finish-load", () => {
|
||||||
splash.destroy();
|
splash.destroy();
|
||||||
mainWin!.show();
|
mainWin!.show();
|
||||||
|
|
||||||
if (Settings.store.maximized) {
|
if (Settings.store.maximized && !isDeckGameMode) {
|
||||||
mainWin!.maximize();
|
mainWin!.maximize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isDeckGameMode) {
|
||||||
|
// always use entire display
|
||||||
|
mainWin!.setFullScreen(true);
|
||||||
|
|
||||||
|
askToApplySteamLayout(mainWin);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
initArRPC();
|
initArRPC();
|
||||||
|
|
84
src/main/utils/steamOS.ts
Normal file
84
src/main/utils/steamOS.ts
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0
|
||||||
|
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||||
|
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { exec as callbackExec } from "child_process";
|
||||||
|
import { BrowserWindow, dialog } from "electron";
|
||||||
|
import { promisify } from "util";
|
||||||
|
|
||||||
|
import { sleep } from "../../shared/utils/sleep";
|
||||||
|
import { MessageBoxChoice } from "../constants";
|
||||||
|
import { Settings } from "../settings";
|
||||||
|
|
||||||
|
const exec = promisify(callbackExec);
|
||||||
|
|
||||||
|
// Bump this to re-show the prompt
|
||||||
|
const layoutVersion = 1;
|
||||||
|
// Get this from "show details" on the profile after exporting as a shared personal layout or using share with community
|
||||||
|
const layoutId = "3063409873"; // Vesktop Layout v1
|
||||||
|
const numberRegex = /^[0-9]*$/;
|
||||||
|
|
||||||
|
export const isDeckGameMode = process.env.SteamOS === "1" && process.env.SteamGamepadUI === "1";
|
||||||
|
|
||||||
|
export function applyDeckKeyboardFix() {
|
||||||
|
if (!isDeckGameMode) return;
|
||||||
|
// Prevent constant virtual keyboard spam that eventually crashes Steam.
|
||||||
|
process.env.GTK_IM_MODULE = "None";
|
||||||
|
}
|
||||||
|
|
||||||
|
// For some reason SteamAppId is always 0 for non-steam apps so we do this insanity instead.
|
||||||
|
function getAppId(): string | null {
|
||||||
|
// /home/deck/.local/share/Steam/steamapps/shadercache/APPID/fozmediav1
|
||||||
|
const path = process.env.STEAM_COMPAT_MEDIA_PATH;
|
||||||
|
if (!path) return null;
|
||||||
|
const pathElems = path?.split("/");
|
||||||
|
const appId = pathElems[pathElems.length - 2];
|
||||||
|
if (appId.match(numberRegex)) {
|
||||||
|
console.log(`Got Steam App ID ${appId}`);
|
||||||
|
return appId;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function execSteamURL(url: string): Promise<void> {
|
||||||
|
await exec(`steam -ifrunning ${url}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function showLayout(appId: string) {
|
||||||
|
await execSteamURL(`steam://controllerconfig/${appId}/${layoutId}`);
|
||||||
|
// because the UI doesn't consistently reload after the data for the config has loaded...
|
||||||
|
// HOW HAS NOBODY AT VALVE RUN INTO THIS YET
|
||||||
|
await sleep(300);
|
||||||
|
await execSteamURL(`steam://controllerconfig/${appId}/${layoutId}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function askToApplySteamLayout(win: BrowserWindow) {
|
||||||
|
const appId = getAppId();
|
||||||
|
if (!appId) return;
|
||||||
|
if (Settings.store.steamOSLayoutVersion === layoutVersion) return;
|
||||||
|
const update = Boolean(Settings.store.steamOSLayoutVersion);
|
||||||
|
|
||||||
|
// Touch screen breaks in some menus when native touch mode is enabled on latest SteamOS beta, remove most of the update specific text once that's fixed.
|
||||||
|
const { response } = await dialog.showMessageBox(win, {
|
||||||
|
message: `${update ? "Update" : "Apply"} Vesktop Steam Input Layout?`,
|
||||||
|
detail: `Would you like to ${update ? "Update" : "Apply"} Vesktop's recommended Steam Deck controller settings?
|
||||||
|
${update ? "Click yes using the touchpad" : "Tap yes"}, then press the X button or tap Apply Layout to confirm.${
|
||||||
|
update ? " Doing so will undo any customizations you have made." : ""
|
||||||
|
}
|
||||||
|
${update ? "Click" : "Tap"} no to keep your current layout.`,
|
||||||
|
buttons: ["Yes", "No"],
|
||||||
|
cancelId: MessageBoxChoice.Cancel,
|
||||||
|
defaultId: MessageBoxChoice.Default,
|
||||||
|
type: "question"
|
||||||
|
});
|
||||||
|
|
||||||
|
if (Settings.store.steamOSLayoutVersion !== layoutVersion) {
|
||||||
|
Settings.store.steamOSLayoutVersion = layoutVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response === MessageBoxChoice.Cancel) return;
|
||||||
|
|
||||||
|
await showLayout(appId);
|
||||||
|
}
|
2
src/shared/settings.d.ts
vendored
2
src/shared/settings.d.ts
vendored
|
@ -31,4 +31,6 @@ export interface Settings {
|
||||||
splashTheming?: boolean;
|
splashTheming?: boolean;
|
||||||
splashColor?: string;
|
splashColor?: string;
|
||||||
splashBackground?: string;
|
splashBackground?: string;
|
||||||
|
|
||||||
|
steamOSLayoutVersion?: number;
|
||||||
}
|
}
|
||||||
|
|
9
src/shared/utils/sleep.ts
Normal file
9
src/shared/utils/sleep.ts
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0
|
||||||
|
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||||
|
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||||
|
*/
|
||||||
|
|
||||||
|
export function sleep(ms: number): Promise<void> {
|
||||||
|
return new Promise(r => setTimeout(r, ms));
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue