Skip to content

Commit

Permalink
SteamOS: fixes & official controller layout (#194)
Browse files Browse the repository at this point in the history
  • Loading branch information
AAGaming00 committed Oct 31, 2023
1 parent 3262e08 commit 1e9c70e
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 10 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"dotenv": "^16.3.1",
"electron": "^27.0.0",
"electron-builder": "^24.6.4",
"electron-builder-sandbox-fix": "^1.0.10",
"esbuild": "^0.19.4",
"eslint": "^8.51.0",
"eslint-config-prettier": "^9.0.0",
Expand All @@ -61,6 +62,7 @@
"build": {
"appId": "dev.vencord.desktop",
"productName": "Vesktop",
"afterPack": "electron-builder-sandbox-fix",
"files": [
"!*",
"dist/js",
Expand Down
9 changes: 9 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/main/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,8 @@ const UserAgents = {
};

export const UserAgent = UserAgents[process.platform] || UserAgents.windows;

export const enum MessageBoxChoice {
Default,
Cancel
}
30 changes: 20 additions & 10 deletions src/main/mainWindow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
DATA_DIR,
DEFAULT_HEIGHT,
DEFAULT_WIDTH,
MessageBoxChoice,
MIN_HEIGHT,
MIN_WIDTH,
UserAgent,
Expand All @@ -36,11 +37,14 @@ import {
import { Settings, VencordSettings } from "./settings";
import { createSplashWindow } from "./splash";
import { makeLinksOpenExternally } from "./utils/makeLinksOpenExternally";
import { applyDeckKeyboardFix, askToApplySteamLayout, isDeckGameMode } from "./utils/steamOS";
import { downloadVencordFiles, ensureVencordFiles } from "./utils/vencordLoader";

let isQuitting = false;
let tray: Tray;

applyDeckKeyboardFix();

app.on("before-quit", () => {
isQuitting = true;
});
Expand Down Expand Up @@ -128,11 +132,6 @@ function initTray(win: BrowserWindow) {
});
}

const enum MessageBoxChoice {
Default,
Cancel
}

async function clearData(win: BrowserWindow) {
const { response } = await dialog.showMessageBox(win, {
message: "Are you sure you want to reset Vesktop?",
Expand Down Expand Up @@ -266,6 +265,9 @@ function initMenuBar(win: BrowserWindow) {
}

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 options = {
Expand Down Expand Up @@ -405,7 +407,7 @@ function createMainWindow() {
win.setMenuBarVisibility(false);

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;

e.preventDefault();
Expand All @@ -419,7 +421,7 @@ function createMainWindow() {
if (Settings.store.staticTitle) win.on("page-title-updated", e => e.preventDefault());

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);
makeLinksOpenExternally(win);
initSettingsListeners(win);
Expand All @@ -441,19 +443,27 @@ const runVencordMain = once(() => require(join(VENCORD_FILES_DIR, "vencordDeskto

export async function createWindows() {
const splash = createSplashWindow();

// SteamOS letterboxes and scales it terribly, so just full screen it
if (isDeckGameMode) splash.setFullScreen(true);
await ensureVencordFiles();
runVencordMain();

mainWin = createMainWindow();

mainWin.once("ready-to-show", () => {
mainWin.webContents.on("did-finish-load", () => {
splash.destroy();
mainWin!.show();

if (Settings.store.maximized) {
if (Settings.store.maximized && !isDeckGameMode) {
mainWin!.maximize();
}

if (isDeckGameMode) {
// always use entire display
mainWin!.setFullScreen(true);

askToApplySteamLayout(mainWin);
}
});

initArRPC();
Expand Down
84 changes: 84 additions & 0 deletions src/main/utils/steamOS.ts
Original file line number Diff line number Diff line change
@@ -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 changes: 2 additions & 0 deletions src/shared/settings.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,6 @@ export interface Settings {
splashTheming?: boolean;
splashColor?: string;
splashBackground?: string;

steamOSLayoutVersion?: number;
}
9 changes: 9 additions & 0 deletions src/shared/utils/sleep.ts
Original file line number Diff line number Diff line change
@@ -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));
}

0 comments on commit 1e9c70e

Please sign in to comment.