From 34c3734953cc3199e0b11f643bfb1f5303727451 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Tue, 25 Feb 2025 18:21:47 -0800
Subject: [PATCH] Fixed opening one Joy-Con when the other is visible but
disconnected
This can happen on Windows when the controller is turned off directly. It still shows up in the device list and you can send packets to it, but it's off and doesn't respond. We'll mark this device as broken and open the other as a single Joy-Con.
---
src/joystick/hidapi/SDL_hidapi_combined.c | 2 ++
src/joystick/hidapi/SDL_hidapi_switch.c | 1 +
src/joystick/hidapi/SDL_hidapijoystick.c | 18 ++++++++++++++----
src/joystick/hidapi/SDL_hidapijoystick_c.h | 4 ++++
4 files changed, 21 insertions(+), 4 deletions(-)
diff --git a/src/joystick/hidapi/SDL_hidapi_combined.c b/src/joystick/hidapi/SDL_hidapi_combined.c
index abfce17eea9ad..5426edbd71e28 100644
--- a/src/joystick/hidapi/SDL_hidapi_combined.c
+++ b/src/joystick/hidapi/SDL_hidapi_combined.c
@@ -70,6 +70,8 @@ static bool HIDAPI_DriverCombined_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Jo
for (i = 0; i < device->num_children; ++i) {
SDL_HIDAPI_Device *child = device->children[i];
if (!child->driver->OpenJoystick(child, joystick)) {
+ child->broken = true;
+
while (i-- > 0) {
child = device->children[i];
child->driver->CloseJoystick(child, joystick);
diff --git a/src/joystick/hidapi/SDL_hidapi_switch.c b/src/joystick/hidapi/SDL_hidapi_switch.c
index 85f551a4806fc..6e09865df5176 100644
--- a/src/joystick/hidapi/SDL_hidapi_switch.c
+++ b/src/joystick/hidapi/SDL_hidapi_switch.c
@@ -2727,6 +2727,7 @@ static bool HIDAPI_DriverSwitch_UpdateDevice(SDL_HIDAPI_Device *device)
// Reconnect the Bluetooth device once the USB device is gone
if (device->num_joysticks == 0 && device->is_bluetooth && packet_count > 0 &&
+ !device->parent &&
!HIDAPI_HasConnectedUSBDevice(device->serial)) {
HIDAPI_JoystickConnected(device, NULL);
}
diff --git a/src/joystick/hidapi/SDL_hidapijoystick.c b/src/joystick/hidapi/SDL_hidapijoystick.c
index 566eae4a9d532..bec9c90714d8a 100644
--- a/src/joystick/hidapi/SDL_hidapijoystick.c
+++ b/src/joystick/hidapi/SDL_hidapijoystick.c
@@ -363,7 +363,7 @@ static SDL_HIDAPI_Device *HIDAPI_GetDeviceByIndex(int device_index, SDL_Joystick
SDL_AssertJoysticksLocked();
for (device = SDL_HIDAPI_devices; device; device = device->next) {
- if (device->parent) {
+ if (device->parent || device->broken) {
continue;
}
if (device->driver) {
@@ -685,7 +685,7 @@ bool HIDAPI_HasConnectedUSBDevice(const char *serial)
}
for (device = SDL_HIDAPI_devices; device; device = device->next) {
- if (!device->driver) {
+ if (!device->driver || device->broken) {
continue;
}
@@ -711,7 +711,7 @@ void HIDAPI_DisconnectBluetoothDevice(const char *serial)
}
for (device = SDL_HIDAPI_devices; device; device = device->next) {
- if (!device->driver) {
+ if (!device->driver || device->broken) {
continue;
}
@@ -1016,6 +1016,10 @@ static bool HIDAPI_CreateCombinedJoyCons(void)
// This device is already part of a combined device
continue;
}
+ if (device->broken) {
+ // This device can't be used
+ continue;
+ }
SDL_GetJoystickGUIDInfo(device->guid, &vendor, &product, NULL, NULL);
@@ -1136,6 +1140,12 @@ static void HIDAPI_UpdateDeviceList(void)
SDL_HIDAPI_change_count = 0;
}
}
+ if (device->broken && device->parent) {
+ HIDAPI_DelDevice(device->parent);
+
+ // We deleted a different device here, restart the loop
+ goto check_removed;
+ }
device = next;
}
@@ -1478,7 +1488,7 @@ static bool HIDAPI_JoystickOpen(SDL_Joystick *joystick, int device_index)
SDL_AssertJoysticksLocked();
- if (!device || !device->driver) {
+ if (!device || !device->driver || device->broken) {
// This should never happen - validated before being called
return SDL_SetError("Couldn't find HIDAPI device at index %d", device_index);
}
diff --git a/src/joystick/hidapi/SDL_hidapijoystick_c.h b/src/joystick/hidapi/SDL_hidapijoystick_c.h
index f8d77093923b1..9cd9f40065142 100644
--- a/src/joystick/hidapi/SDL_hidapijoystick_c.h
+++ b/src/joystick/hidapi/SDL_hidapijoystick_c.h
@@ -101,6 +101,10 @@ typedef struct SDL_HIDAPI_Device
// Used to flag that the device is being updated
bool updating;
+ // Used to flag devices that failed open
+ // This can happen on Windows with Bluetooth devices that have turned off
+ bool broken;
+
struct SDL_HIDAPI_Device *parent;
int num_children;
struct SDL_HIDAPI_Device **children;