Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SteamOS: fixes & official controller layout #194

Merged
merged 3 commits into from
Oct 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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));
}