From cfb87e57a8edb037eb687aa924a389e70d1cd722 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Fri, 28 Nov 2025 09:03:21 -0800
Subject: [PATCH] Added joystick hotplug support
---
game/controls.cpp | 86 ++++++++++++++++++++++++++++++-----------------
game/controls.h | 4 ---
game/gameinfo.h | 8 ++---
3 files changed, 57 insertions(+), 41 deletions(-)
diff --git a/game/controls.cpp b/game/controls.cpp
index 0f03fa2a..516353f3 100644
--- a/game/controls.cpp
+++ b/game/controls.cpp
@@ -234,10 +234,49 @@ static Player *GetKeyboardPlayer()
return GetControlPlayer(CONTROL_KEYBOARD);
}
-static Player *GetJoystickPlayer(Uint8 which)
+#define MAX_JOYSTICKS MAX_PLAYERS
+
+static Uint8 joystickMasks[MAX_JOYSTICKS] = {
+ CONTROL_JOYSTICK1,
+ CONTROL_JOYSTICK2,
+ CONTROL_JOYSTICK3
+};
+static SDL_Joystick *joysticks[MAX_JOYSTICKS];
+static SDL_JoystickID joystickIDs[MAX_JOYSTICKS];
+
+static void OpenJoystick(SDL_JoystickID id)
+{
+ for (int i = 0; i < MAX_JOYSTICKS; ++i) {
+ if (joysticks[i] == NULL) {
+ joysticks[i] = SDL_OpenJoystick(id);
+ if (joysticks[i]) {
+ joystickIDs[i] = id;
+ }
+ break;
+ }
+ }
+}
+
+static void CloseJoystick(SDL_JoystickID id)
+{
+ for (int i = 0; i < MAX_JOYSTICKS; ++i) {
+ if (joystickIDs[i] == id) {
+ SDL_CloseJoystick(joysticks[i]);
+ joysticks[i] = NULL;
+ joystickIDs[i] = 0;
+ break;
+ }
+ }
+}
+
+static Player *GetJoystickPlayer(SDL_JoystickID id)
{
- Uint8 joystickControl = (CONTROL_JOYSTICK1 << which);
- return GetControlPlayer(joystickControl);
+ for (int i = 0; i < MAX_JOYSTICKS; ++i) {
+ if (id == joystickIDs[i]) {
+ return GetControlPlayer(joystickMasks[i]);
+ }
+ }
+ return NULL;
}
static void HandleEvent(SDL_Event *event)
@@ -250,7 +289,16 @@ static void HandleEvent(SDL_Event *event)
}
switch (event->type) {
-#ifdef SDL_INIT_JOYSTICK
+ /* -- Handle joystick added */
+ case SDL_EVENT_JOYSTICK_ADDED:
+ OpenJoystick(event->jdevice.which);
+ break;
+
+ /* -- Handle joystick removed */
+ case SDL_EVENT_JOYSTICK_REMOVED:
+ CloseJoystick(event->jdevice.which);
+ break;
+
/* -- Handle joystick axis motion */
case SDL_EVENT_JOYSTICK_AXIS_MOTION:
player = GetJoystickPlayer(event->jaxis.which);
@@ -327,7 +375,6 @@ static void HandleEvent(SDL_Event *event)
}
}
break;
-#endif
/* -- Handle key presses/releases */
case SDL_EVENT_KEY_DOWN:
@@ -415,35 +462,12 @@ static void HandleEvent(SDL_Event *event)
}
}
-#define MAX_JOYSTICKS MAX_PLAYERS
-
-static Uint8 joystickMasks[MAX_JOYSTICKS] = {
- CONTROL_JOYSTICK1,
- CONTROL_JOYSTICK2,
- CONTROL_JOYSTICK3
-};
-static SDL_Joystick *joysticks[MAX_JOYSTICKS];
-
void InitPlayerControls(void)
{
- Uint8 controlMask = 0;
- int i, count;
-
- SDL_JoystickID *ids = SDL_GetJoysticks(&count);
+ SDL_JoystickID *ids = SDL_GetJoysticks(nullptr);
if (ids) {
- for (i = 0; i < MAX_PLAYERS; ++i) {
- controlMask |= gPlayers[i]->GetControlType();
- }
-
- for (i = 0; i < MAX_JOYSTICKS && i < count; ++i) {
- if (!(controlMask & joystickMasks[i])) {
- continue;
- }
- joysticks[i] = SDL_OpenJoystick(ids[i]);
- if (joysticks[i] == NULL) {
- error("Warning: Couldn't open joystick '%s' : %s\n",
- SDL_GetJoystickNameForID(ids[i]), SDL_GetError());
- }
+ for (int i = 0; ids[i]; ++i) {
+ OpenJoystick(ids[i]);
}
SDL_free(ids);
}
diff --git a/game/controls.h b/game/controls.h
index 8988193c..e0afbf22 100644
--- a/game/controls.h
+++ b/game/controls.h
@@ -25,10 +25,6 @@
#include "../screenlib/UIDialog.h"
-#if defined(__IPHONEOS__) || defined(__ANDROID__)
-#define USE_TOUCHCONTROL
-#endif
-
// Functions from controls.cc
#ifdef USE_JOYSTICK
extern void CalibrateJoystick(char *joystick);
diff --git a/game/gameinfo.h b/game/gameinfo.h
index 55d9d068..b0591353 100644
--- a/game/gameinfo.h
+++ b/game/gameinfo.h
@@ -40,11 +40,7 @@ enum PLAYER_CONTROL {
CONTROL_TOUCH = 0x10,
CONTROL_NETWORK = 0x20,
CONTROL_REPLAY = 0x40,
-#ifdef USE_TOUCHCONTROL
- CONTROL_LOCAL = CONTROL_TOUCH
-#else
- CONTROL_LOCAL = (CONTROL_KEYBOARD|CONTROL_JOYSTICK1)
-#endif
+ CONTROL_LOCAL = (CONTROL_KEYBOARD|CONTROL_JOYSTICK1|CONTROL_JOYSTICK2|CONTROL_JOYSTICK3|CONTROL_TOUCH)
};
enum GAME_MODE {
@@ -52,7 +48,7 @@ enum GAME_MODE {
GAME_MODE_KIDS = 0x02,
};
-#define IS_LOCAL_CONTROL(X) (X != CONTROL_NONE && X != CONTROL_NETWORK && X != CONTROL_REPLAY)
+#define IS_LOCAL_CONTROL(X) (X & CONTROL_LOCAL)
enum NODE_STATE_FLAG {
STATE_NONE = 0x00,