From 30e7e975729f948593bc0df811d667e66d4879c6 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Sun, 8 Mar 2026 10:06:54 -0700
Subject: [PATCH] Maintain the gamepad list outside of an active game
This ensures the setup in the multiplayer lobby matches in-game controls.
---
game/controls.cpp | 36 ++++++++++++++++++++++++++----------
game/controls.h | 1 +
game/game.cpp | 3 ---
game/init.cpp | 2 ++
game/lobby.cpp | 20 +-------------------
5 files changed, 30 insertions(+), 32 deletions(-)
diff --git a/game/controls.cpp b/game/controls.cpp
index 12482de4..bc997681 100644
--- a/game/controls.cpp
+++ b/game/controls.cpp
@@ -272,6 +272,11 @@ static void UpdateGamepadHandle(SDL_JoystickID id)
}
}
+unsigned int GetNumGamepads()
+{
+ return gamepads.length();
+}
+
static void CloseGamepad(SDL_JoystickID id)
{
for (unsigned int i = 0; i < gamepads.length(); ++i) {
@@ -391,16 +396,6 @@ static void HandleEvent(SDL_Event *event)
}
switch (event->type) {
- /* -- Handle joystick added */
- case SDL_EVENT_GAMEPAD_ADDED:
- OpenGamepad(event->gdevice.which);
- break;
-
- /* -- Handle joystick removed */
- case SDL_EVENT_GAMEPAD_REMOVED:
- CloseGamepad(event->gdevice.which);
- break;
-
/* -- Handle joystick axis motion */
case SDL_EVENT_GAMEPAD_AXIS_MOTION:
player = GetJoystickPlayer(event->gaxis.which);
@@ -527,6 +522,25 @@ static void HandleEvent(SDL_Event *event)
}
}
+static bool SDLCALL GamepadEventWatch(void *userdata, SDL_Event *event)
+{
+ switch (event->type) {
+ /* -- Handle joystick added */
+ case SDL_EVENT_GAMEPAD_ADDED:
+ OpenGamepad(event->gdevice.which);
+ break;
+
+ /* -- Handle joystick removed */
+ case SDL_EVENT_GAMEPAD_REMOVED:
+ CloseGamepad(event->gdevice.which);
+ break;
+
+ default:
+ break;
+ }
+ return true;
+}
+
void InitPlayerControls(void)
{
SDL_JoystickID *ids = SDL_GetJoysticks(nullptr);
@@ -536,10 +550,12 @@ void InitPlayerControls(void)
}
SDL_free(ids);
}
+ SDL_AddEventWatch(GamepadEventWatch, nullptr);
}
void QuitPlayerControls(void)
{
+ SDL_RemoveEventWatch(GamepadEventWatch, nullptr);
for (unsigned int i = 0; i < gamepads.length(); ++i) {
Gamepad *gamepad = &gamepads[i];
SDL_CloseGamepad(gamepad->gamepad);
diff --git a/game/controls.h b/game/controls.h
index a6b0b84a..53cac236 100644
--- a/game/controls.h
+++ b/game/controls.h
@@ -32,6 +32,7 @@ extern void LoadControls(void);
extern void SaveControls(void);
extern void InitPlayerControls(void);
extern void QuitPlayerControls(void);
+extern unsigned int GetNumGamepads();
extern void HandleEvents(int timeout);
extern int DropEvents(void);
diff --git a/game/game.cpp b/game/game.cpp
index f6b798aa..8d42445d 100644
--- a/game/game.cpp
+++ b/game/game.cpp
@@ -122,7 +122,6 @@ void NewGame(void)
if ( !SetupPlayers() ) {
return;
}
- InitPlayerControls();
/* Send a "NEW_GAME" packet onto the network */
if ( gGameInfo.IsMultiplayer() && gGameInfo.IsHosting() ) {
@@ -1061,8 +1060,6 @@ GamePanelDelegate::GameOver()
{
CloseSocket();
- QuitPlayerControls();
-
DisableRemoteInput();
ui->ShowPanel(PANEL_GAMEOVER);
diff --git a/game/init.cpp b/game/init.cpp
index d560ac4e..b21e34ec 100644
--- a/game/init.cpp
+++ b/game/init.cpp
@@ -713,6 +713,7 @@ void CleanUp(void)
{
FreeScores();
SaveControls();
+ QuitPlayerControls();
if ( gReplayFile ) {
SDL_free( gReplayFile );
gReplayFile = NULL;
@@ -771,6 +772,7 @@ int DoInitializations(Uint32 window_flags)
// -- Load our controls
LoadControls();
+ InitPlayerControls();
/* Load the Maelstrom icon */
icon = SDL_LoadSurface_IO(OpenRead("icon.png"), true);
diff --git a/game/lobby.cpp b/game/lobby.cpp
index 561ea70f..899c9499 100644
--- a/game/lobby.cpp
+++ b/game/lobby.cpp
@@ -102,7 +102,7 @@ class ControlClickCallback : public UIClickCallback
}
// Show the control dialog
- int num_gamepads = GetNumGamepads();
+ unsigned int num_gamepads = GetNumGamepads();
SetControl(CONTROL_NONE, (m_index > 0) && m_game.IsHosting());
SetControl(CONTROL_LOCAL, true);
SetControl(CONTROL_JOYSTICK1, num_gamepads >= 1);
@@ -117,24 +117,6 @@ class ControlClickCallback : public UIClickCallback
}
private:
- int GetNumGamepads()
- {
- int num_gamepads = 0;
- SDL_JoystickID* gamepads = SDL_GetGamepads(nullptr);
- if (gamepads) {
- for (int i = 0; gamepads[i]; ++i) {
- SDL_Gamepad* gamepad = SDL_OpenGamepad(gamepads[i]);
- if (gamepad) {
- if (!GetRemoteSessionForGamepad(gamepad)) {
- ++num_gamepads;
- }
- SDL_CloseGamepad(gamepad);
- }
- }
- SDL_free(gamepads);
- }
- return num_gamepads;
- }
void SetControl(Uint8 control, bool enabled) {
char name[128];
UIElement *element;