From 7668e7276bedbcfd1c7ef79fbf8fd4e837102679 Mon Sep 17 00:00:00 2001 From: Eduardo Aleixo Date: Sat, 13 Jan 2024 18:31:00 +0000 Subject: [PATCH 1/3] fixes --- forks/Controller.js/source/Controller.ts | 10 ++++-- forks/Controller.js/source/lib/GC_Errors.ts | 14 +++++--- forks/Controller.js/source/lib/GC_Layouts.ts | 26 ++++++++++++-- src/gamepad/index.ts | 37 ++++++++++++++++++++ src/types/controllerjs.d.ts | 1 - 5 files changed, 79 insertions(+), 9 deletions(-) delete mode 100644 src/types/controllerjs.d.ts diff --git a/forks/Controller.js/source/Controller.ts b/forks/Controller.js/source/Controller.ts index 3b1dc9c..6bad1de 100644 --- a/forks/Controller.js/source/Controller.ts +++ b/forks/Controller.js/source/Controller.ts @@ -9,7 +9,7 @@ import { mapAnalogToShape, } from "./lib/settings"; -import "./lib/GC_Errors"; +import { GC_Errors } from "./lib/GC_Errors"; // No turning back now… @@ -66,6 +66,12 @@ function Controller(HTMLgamepad) { // Gets the gamepad for this frame gamepad = this.constructor.gamepads[index]; + if (!gamepad) { + console.warn( + `Gamepad at index ${index} was not found. Skipping this frame.` + ); + return; + } // Updates timestamp lastUpdated = performance.now(); @@ -1044,7 +1050,7 @@ Controller.search = function (options?: any) { return; } - for (let index in this.gamepads) { + for (let index in Array.from(this.gamepads)) { index = parseInt(index, 10); if (isNaN(index)) { diff --git a/forks/Controller.js/source/lib/GC_Errors.ts b/forks/Controller.js/source/lib/GC_Errors.ts index 3f27ca0..b6d5fe2 100644 --- a/forks/Controller.js/source/lib/GC_Errors.ts +++ b/forks/Controller.js/source/lib/GC_Errors.ts @@ -1,7 +1,13 @@ // Defines all error messages -const GC_Errors = { - get GAMEPAD() {return 'This browser does not support the Gamepad API.';}, - get DEFINEPROPERTY() {return 'This browser does not suppoert Object.defineProperty().';}, - get MAP() {return 'No matching map found. Using "Standard".';} +export const GC_Errors = { + get GAMEPAD() { + return "This browser does not support the Gamepad API."; + }, + get DEFINEPROPERTY() { + return "This browser does not suppoert Object.defineProperty()."; + }, + get MAP() { + return 'No matching map found. Using "Standard".'; + }, }; diff --git a/forks/Controller.js/source/lib/GC_Layouts.ts b/forks/Controller.js/source/lib/GC_Layouts.ts index bd03d39..93172e9 100644 --- a/forks/Controller.js/source/lib/GC_Layouts.ts +++ b/forks/Controller.js/source/lib/GC_Layouts.ts @@ -27,12 +27,34 @@ export const GC_Layouts = { layouts.list[id.toLowerCase()] = map; }, - has: function (name) { + has: function has(name) { + // TODO: added by me + // Support regex as matchers + for (let i in Controller.layouts.list) { + const matchFn = Controller.layouts.list[i].matchFn; + if (typeof matchFn === "function") { + if (matchFn(name)) { + return true; + } + } + } + name = name.toLowerCase(); return name in Controller.layouts.list; }, - get: function (name) { + get: function get(name) { + // TODO: added by me + // Support regex as matchers + for (let i in Controller.layouts.list) { + const matchFn = Controller.layouts.list[i].matchFn; + if (typeof matchFn === "function") { + if (matchFn(name)) { + return Controller.layouts.list[i]; + } + } + } + name = name.toLowerCase(); return Controller.layouts.list[name]; }, diff --git a/src/gamepad/index.ts b/src/gamepad/index.ts index 741b4c5..2f7f80c 100644 --- a/src/gamepad/index.ts +++ b/src/gamepad/index.ts @@ -19,12 +19,48 @@ const lastValidPress: Record< const THROTTLE_MS = 200; export function initGamepad() { + const steamLayout = { + match: "Microsoft X-Box 360 pad", + matchFn: (name: string) => { + return /Microsoft X-Box 360 pad \d/.test(name); + }, + name: "Steam Deck Controller", + description: "", + buttons: { + FACE_1: 0, + FACE_2: 1, + FACE_3: 2, + FACE_4: 3, + LEFT_SHOULDER: 4, + RIGHT_SHOULDER: 5, + LEFT_ANALOG_BUTTON: 9, + RIGHT_ANALOG_BUTTON: 11, + START: 11, + SELECT: 10, + }, + // The dpad is actually considered an axe + // So what this + useAnalogAsDpad effectively do + // is to enable dpad! + axes: { + LEFT_ANALOG_STICK_VERT: 7, + LEFT_ANALOG_STICK_HOR: 6, + }, + options: { + useAnalogAsDpad: "left", + }, + }; + + Controller.layouts.register(Controller, steamLayout); + Controller.globalSettings.useAnalogAsDpad = "left"; Controller.search(); window.addEventListener( "gc.controller.found", function (event) { + // Controller.unwatchAll(); + // Controller.watchAll(); + const ci: ControllerInfo = { layout: identifyLayout(event.detail.controller.name), name: event.detail.controller.name, @@ -87,6 +123,7 @@ export function initGamepad() { } window.addEventListener("gc.button.press", (ev) => { + console.log("press ev", ev.detail); onPress(ev); }); } diff --git a/src/types/controllerjs.d.ts b/src/types/controllerjs.d.ts deleted file mode 100644 index 8176551..0000000 --- a/src/types/controllerjs.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare module "@controllerjs"; From 9759dacaf2fdc24b4fc9d4bdbb4c8ff17462cdd1 Mon Sep 17 00:00:00 2001 From: Eduardo Aleixo Date: Sat, 13 Jan 2024 19:22:54 +0000 Subject: [PATCH 2/3] don't do anything if window is not in focus --- src/electron.ts | 9 +++++++++ src/gamepad/index.ts | 4 ++++ src/inject.ts | 7 +++++++ 3 files changed, 20 insertions(+) diff --git a/src/electron.ts b/src/electron.ts index cf3f314..5da3fd4 100644 --- a/src/electron.ts +++ b/src/electron.ts @@ -1,3 +1,12 @@ +const name = "electron"; +const win = require(name); + +export function hasFocus() { + // TODO: this is deprecated and should be removed in electron 14 + // https://www.electronjs.org/docs/latest/breaking-changes#removed-remote-module + return win.remote.BrowserWindow.getAllWindows()[0].isFocused(); +} + // https://stackoverflow.com/a/61725416 export function isElectron() { // Renderer process diff --git a/src/gamepad/index.ts b/src/gamepad/index.ts index 2f7f80c..3362092 100644 --- a/src/gamepad/index.ts +++ b/src/gamepad/index.ts @@ -4,6 +4,7 @@ import { toKeyboardEvent } from "@app/gamepad/buttons"; import { identifyLayout } from "@app/gamepad/layouts/identify"; import { findFirstFocusableChild } from "@app/dom"; import { ControllerButtonPressed } from "@app/gamepad/events"; +import { hasFocus } from "@app/electron"; type ControllerInfo = { name: string; @@ -94,6 +95,9 @@ export function initGamepad() { }); function onPress(event: ControllerButtonPressed) { + if (!hasFocus()) { + return; + } const activeElement = document.activeElement; // If nothing is focused, navigation won't work diff --git a/src/inject.ts b/src/inject.ts index 6e6da45..af3b398 100644 --- a/src/inject.ts +++ b/src/inject.ts @@ -6,6 +6,8 @@ import * as aboutPage from "./pages/about"; import * as lobbyPage from "./pages/lobby"; import "./devOnly"; import { startOOBNavigator } from "@app/oobNavigator"; +// Needed for its side effects +import "./electron"; const initialized = { sidebar: false, @@ -43,6 +45,11 @@ const observer = new MutationObserver(function (mr: MutationRecord[]) { // TODO: only do this if gamepad is detected makeExternalLinksNotFocusable(); + // TODO: disable Make all inputs non focusable for steam deck + document.querySelectorAll("input").forEach((el) => { + el.setAttribute("tabindex", "-1"); + }); + if (!initialized.gamepad) { initGamepad(); initialized.gamepad = true; From f336d973cdb4eb5dbf841092dda04dbae240efa5 Mon Sep 17 00:00:00 2001 From: Eduardo Aleixo Date: Sun, 14 Jan 2024 12:16:39 +0000 Subject: [PATCH 3/3] cleanup --- src/devOnly.ts | 3 +++ src/electron.ts | 23 ++++++++++++++++++----- src/gamepad/index.ts | 5 +---- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/devOnly.ts b/src/devOnly.ts index 3be4979..5939706 100644 --- a/src/devOnly.ts +++ b/src/devOnly.ts @@ -42,6 +42,9 @@ function init() { } }); } +export function isDev() { + return FGN_DEBUG; +} if (FGN_DEBUG) { init(); diff --git a/src/electron.ts b/src/electron.ts index 5da3fd4..8b7836e 100644 --- a/src/electron.ts +++ b/src/electron.ts @@ -1,10 +1,23 @@ -const name = "electron"; -const win = require(name); +import { isDev } from "@app/devOnly"; + +function tryRequire(name: string) { + try { + return require(name); + } catch (e) { + return {}; + } +} +const electronName = "electron"; +const win = tryRequire(electronName); export function hasFocus() { - // TODO: this is deprecated and should be removed in electron 14 - // https://www.electronjs.org/docs/latest/breaking-changes#removed-remote-module - return win.remote.BrowserWindow.getAllWindows()[0].isFocused(); + if (!isDev()) { + // TODO: this is deprecated and should be removed in electron 14 + // https://www.electronjs.org/docs/latest/breaking-changes#removed-remote-module + return win.remote.BrowserWindow.getAllWindows()[0].isFocused(); + } + + return true; } // https://stackoverflow.com/a/61725416 diff --git a/src/gamepad/index.ts b/src/gamepad/index.ts index 3362092..905d826 100644 --- a/src/gamepad/index.ts +++ b/src/gamepad/index.ts @@ -59,9 +59,6 @@ export function initGamepad() { window.addEventListener( "gc.controller.found", function (event) { - // Controller.unwatchAll(); - // Controller.watchAll(); - const ci: ControllerInfo = { layout: identifyLayout(event.detail.controller.name), name: event.detail.controller.name, @@ -79,6 +76,7 @@ export function initGamepad() { window.addEventListener( "gc.controller.lost", function (event) { + console.log("disconnected controller", event.detail); notify(`[DISCONNECTED]: Controller at index ${event.detail.index}`); }, false @@ -127,7 +125,6 @@ export function initGamepad() { } window.addEventListener("gc.button.press", (ev) => { - console.log("press ev", ev.detail); onPress(ev); }); }