From d34d48f1b55d63282c4f17a0d8a14bcdb2b870f2 Mon Sep 17 00:00:00 2001 From: Greenlamp Date: Thu, 9 May 2024 17:02:07 +0200 Subject: [PATCH] remove localStorage for gamepads connected + fix lost focus effect on controller change + disconnect/reconnect handling --- src/inputs-controller.ts | 101 +++++++++++++++++++------- src/system/settings-gamepad.ts | 9 +-- src/ui/settings-gamepad-ui-handler.ts | 10 +++ src/utils.ts | 9 ++- 4 files changed, 92 insertions(+), 37 deletions(-) diff --git a/src/inputs-controller.ts b/src/inputs-controller.ts index 9e2be0e2a..e887a7e6c 100644 --- a/src/inputs-controller.ts +++ b/src/inputs-controller.ts @@ -6,6 +6,8 @@ import pad_unlicensedSNES from "./configs/pad_unlicensedSNES"; import pad_xbox360 from "./configs/pad_xbox360"; import pad_dualshock from "./configs/pad_dualshock"; import {Button} from "./enums/buttons"; +import {Mode} from "./ui/ui"; +import SettingsGamepadUiHandler from "./ui/settings-gamepad-ui-handler"; export interface GamepadMapping { [key: string]: number; @@ -34,17 +36,19 @@ export class InputsController { private buttonLock2: Button; private interactions: Map> = new Map(); private time: Time; - private player: Map = new Map(); + private player; private gamepadSupport: boolean = true; public customGamepadMapping = new Map(); public chosenGamepad: String; + private disconnectedGamepads: Array = new Array(); constructor(scene: Phaser.Scene) { this.scene = scene; this.time = this.scene.time; this.buttonKeys = []; + this.player = {}; for (const b of Utils.getEnumValues(Button)) { this.interactions[b] = { @@ -74,6 +78,10 @@ export class InputsController { this.scene.input.gamepad.on('connected', function (thisGamepad) { this.refreshGamepads(); this.setupGamepad(thisGamepad); + this.onReconnect(thisGamepad); + }, this); + this.scene.input.gamepad.on('disconnected', function (thisGamepad) { + this.onDisconnect(thisGamepad); }, this); // Check to see if the gamepad has already been setup by the browser @@ -108,7 +116,7 @@ export class InputsController { setChosenGamepad(gamepad: String): void { this.deactivatePressedKey(); - this.chosenGamepad = gamepad; + this.initChosenGamepad(gamepad) } update(): void { @@ -136,17 +144,52 @@ export class InputsController { } getGamepadsName(): Array { - return this.gamepads.map(g => g.id); + return this.gamepads.filter(g => !this.disconnectedGamepads.includes(g.id)).map(g => g.id); + } + + initChosenGamepad(gamepadName?: String): void { + let name = gamepadName; + if (gamepadName) + this.chosenGamepad = gamepadName; + else + name = this.chosenGamepad; + localStorage.setItem('chosenGamepad', name); + const handler = this.scene.ui?.handlers[Mode.SETTINGS_GAMEPAD] as SettingsGamepadUiHandler; + handler && handler.updateChosenGamepadDisplay() + } + + clearChosenGamepad() { + this.chosenGamepad = null; + if (localStorage.hasOwnProperty('chosenGamepad')) + localStorage.removeItem('chosenGamepad'); + } + + onDisconnect(thisGamepad: Phaser.Input.Gamepad.Gamepad): void { + this.disconnectedGamepads.push(thisGamepad.id); + const gamepadsLeft = this.gamepads.filter(g => !this.disconnectedGamepads.includes(g.id)).map(g => g); + const chosenIsConnected = gamepadsLeft.some(g => g.id === this.chosenGamepad); + if (!chosenIsConnected && gamepadsLeft?.length) { + this.clearChosenGamepad(); + this.setChosenGamepad(gamepadsLeft[0].id); + return; + } + } + + onReconnect(thisGamepad: Phaser.Input.Gamepad.Gamepad): void { + if (this.disconnectedGamepads.some(g => g === thisGamepad.id)) { + this.disconnectedGamepads = this.disconnectedGamepads.filter(g => g !== thisGamepad.id); + } } setupGamepad(thisGamepad: Phaser.Input.Gamepad.Gamepad): void { - let gamepadID = this.chosenGamepad?.toLowerCase() || thisGamepad.id.toLowerCase(); - const mappedPad = this.mapGamepad(gamepadID); - this.player['mapping'] = mappedPad.gamepadMapping; - if (!this.chosenGamepad) { - this.chosenGamepad = thisGamepad.id; - localStorage.setItem('chosenGamepad', this.chosenGamepad); + const allGamepads = this.getGamepadsName(); + for (const gamepad of allGamepads) { + const gamepadID = gamepad.toLowerCase(); + const mappedPad = this.mapGamepad(gamepadID); + if (!this.player[gamepad]) this.player[gamepad] = {}; + this.player[gamepad]['mapping'] = mappedPad.gamepadMapping; } + if (this.chosenGamepad === thisGamepad.id) this.initChosenGamepad(this.chosenGamepad) } refreshGamepads(): void { @@ -162,29 +205,31 @@ export class InputsController { getActionGamepadMapping(): ActionGamepadMapping { const gamepadMapping = {}; - if (!this.player?.mapping) return gamepadMapping; - gamepadMapping[this.player.mapping.LC_N] = Button.UP; - gamepadMapping[this.player.mapping.LC_S] = Button.DOWN; - gamepadMapping[this.player.mapping.LC_W] = Button.LEFT; - gamepadMapping[this.player.mapping.LC_E] = Button.RIGHT; - gamepadMapping[this.player.mapping.TOUCH] = Button.SUBMIT; - gamepadMapping[this.player.mapping.RC_S] = this.scene.abSwapped ? Button.CANCEL : Button.ACTION; - gamepadMapping[this.player.mapping.RC_E] = this.scene.abSwapped ? Button.ACTION : Button.CANCEL; - gamepadMapping[this.player.mapping.SELECT] = Button.STATS; - gamepadMapping[this.player.mapping.START] = Button.MENU; - gamepadMapping[this.player.mapping.RB] = Button.RB; - gamepadMapping[this.player.mapping.LB] = Button.LB; - gamepadMapping[this.player.mapping.LT] = Button.CYCLE_GENDER; - gamepadMapping[this.player.mapping.RT] = Button.CYCLE_ABILITY; - gamepadMapping[this.player.mapping.RC_W] = Button.CYCLE_NATURE; - gamepadMapping[this.player.mapping.RC_N] = Button.CYCLE_VARIANT; - gamepadMapping[this.player.mapping.LS] = Button.SPEED_UP; - gamepadMapping[this.player.mapping.RS] = Button.SLOW_DOWN; + if (!this.player[this.chosenGamepad] || !this.player[this.chosenGamepad]?.mapping || !this.chosenGamepad) return gamepadMapping; + gamepadMapping[this.player[this.chosenGamepad].mapping.LC_N] = Button.UP; + gamepadMapping[this.player[this.chosenGamepad].mapping.LC_S] = Button.DOWN; + gamepadMapping[this.player[this.chosenGamepad].mapping.LC_W] = Button.LEFT; + gamepadMapping[this.player[this.chosenGamepad].mapping.LC_E] = Button.RIGHT; + gamepadMapping[this.player[this.chosenGamepad].mapping.TOUCH] = Button.SUBMIT; + gamepadMapping[this.player[this.chosenGamepad].mapping.RC_S] = this.scene.abSwapped ? Button.CANCEL : Button.ACTION; + gamepadMapping[this.player[this.chosenGamepad].mapping.RC_E] = this.scene.abSwapped ? Button.ACTION : Button.CANCEL; + gamepadMapping[this.player[this.chosenGamepad].mapping.SELECT] = Button.STATS; + gamepadMapping[this.player[this.chosenGamepad].mapping.START] = Button.MENU; + gamepadMapping[this.player[this.chosenGamepad].mapping.RB] = Button.RB; + gamepadMapping[this.player[this.chosenGamepad].mapping.LB] = Button.LB; + gamepadMapping[this.player[this.chosenGamepad].mapping.LT] = Button.CYCLE_GENDER; + gamepadMapping[this.player[this.chosenGamepad].mapping.RT] = Button.CYCLE_ABILITY; + gamepadMapping[this.player[this.chosenGamepad].mapping.RC_W] = Button.CYCLE_NATURE; + gamepadMapping[this.player[this.chosenGamepad].mapping.RC_N] = Button.CYCLE_VARIANT; + gamepadMapping[this.player[this.chosenGamepad].mapping.LS] = Button.SPEED_UP; + gamepadMapping[this.player[this.chosenGamepad].mapping.RS] = Button.SLOW_DOWN; return gamepadMapping; } gamepadButtonDown(pad: Phaser.Input.Gamepad.Gamepad, button: Phaser.Input.Gamepad.Button, value: number): void { + if (!this.chosenGamepad) + this.setChosenGamepad(pad.id); if (!this.gamepadSupport || pad.id.toLowerCase() !== this.chosenGamepad.toLowerCase()) return; const actionMapping = this.getActionGamepadMapping(); const buttonDown = actionMapping.hasOwnProperty(button.index) && actionMapping[button.index]; @@ -198,7 +243,7 @@ export class InputsController { } gamepadButtonUp(pad: Phaser.Input.Gamepad.Gamepad, button: Phaser.Input.Gamepad.Button, value: number): void { - if (!this.gamepadSupport || pad.id.toLowerCase() !== this.chosenGamepad.toLowerCase()) return; + if (!this.gamepadSupport || pad.id !== this.chosenGamepad) return; const actionMapping = this.getActionGamepadMapping(); const buttonUp = actionMapping.hasOwnProperty(button.index) && actionMapping[button.index]; if (buttonUp !== undefined) { diff --git a/src/system/settings-gamepad.ts b/src/system/settings-gamepad.ts index 1b22b4dae..e22cbd71e 100644 --- a/src/system/settings-gamepad.ts +++ b/src/system/settings-gamepad.ts @@ -2,6 +2,7 @@ import BattleScene from "../battle-scene"; import {SettingDefaults, SettingOptions} from "#app/system/settings"; import SettingsGamepadUiHandler from "#app/ui/settings-gamepad-ui-handler"; import {Mode} from "#app/ui/ui"; +import {truncateString} from "../utils"; export enum SettingGamepad { Default_Controller = "DEFAULT_CONTROLLER", @@ -57,13 +58,6 @@ export const settingGamepadDefaults: SettingDefaults = { // [SettingGamepad.Button_Slow_Down]: Button.SLOW_DOWN, }; -function truncateString(str: String, maxLength: number = 10) { - if (str.length > maxLength) { - return str.slice(0, maxLength - 3) + "..."; // Subtract 3 to accommodate the ellipsis - } - return str; -} - export function setSettingGamepad(scene: BattleScene, setting: SettingGamepad, value: integer): boolean { switch (setting) { case SettingGamepad.Gamepad_Support: @@ -97,7 +91,6 @@ export function setSettingGamepad(scene: BattleScene, setting: SettingGamepad, v }; const changeGamepadHandler = (gamepad: string) => { scene.inputController.setChosenGamepad(gamepad); - localStorage.setItem('chosenGamepad', gamepad); cancelHandler(); return true; }; diff --git a/src/ui/settings-gamepad-ui-handler.ts b/src/ui/settings-gamepad-ui-handler.ts index ca56a7d94..98a3ad991 100644 --- a/src/ui/settings-gamepad-ui-handler.ts +++ b/src/ui/settings-gamepad-ui-handler.ts @@ -10,6 +10,7 @@ import { settingGamepadDefaults, settingGamepadOptions } from "../system/settings-gamepad"; +import {truncateString} from "../utils"; export default class SettingsGamepadUiHandler extends UiHandler { private settingsContainer: Phaser.GameObjects.Container; @@ -193,6 +194,15 @@ export default class SettingsGamepadUiHandler extends UiHandler { return ret; } + updateChosenGamepadDisplay(): void { + for (const [index, key] of Object.keys(SettingGamepad).entries()) { + const setting = SettingGamepad[key] + if (setting === SettingGamepad.Default_Controller) { + this.optionValueLabels[index][0].setText(truncateString(this.scene.inputController.chosenGamepad, 30)); + } + } + } + setOptionCursor(settingIndex: integer, cursor: integer, save?: boolean): boolean { const setting = SettingGamepad[Object.keys(SettingGamepad)[settingIndex]]; diff --git a/src/utils.ts b/src/utils.ts index ef277630d..01656b8ed 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -356,4 +356,11 @@ export function rgbHexToRgba(hex: string) { export function rgbaToInt(rgba: integer[]): integer { return (rgba[0] << 24) + (rgba[1] << 16) + (rgba[2] << 8) + rgba[3]; -} \ No newline at end of file +} + +export function truncateString(str: String, maxLength: number = 10) { + if (str.length > maxLength) { + return str.slice(0, maxLength - 3) + "..."; // Subtract 3 to accommodate the ellipsis + } + return str; +}