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.
This commit is contained in:
Sam Lantinga
2025-02-25 18:21:47 -08:00
parent 049a7a04de
commit 34c3734953
4 changed files with 21 additions and 4 deletions

View File

@@ -70,6 +70,8 @@ static bool HIDAPI_DriverCombined_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Jo
for (i = 0; i < device->num_children; ++i) { for (i = 0; i < device->num_children; ++i) {
SDL_HIDAPI_Device *child = device->children[i]; SDL_HIDAPI_Device *child = device->children[i];
if (!child->driver->OpenJoystick(child, joystick)) { if (!child->driver->OpenJoystick(child, joystick)) {
child->broken = true;
while (i-- > 0) { while (i-- > 0) {
child = device->children[i]; child = device->children[i];
child->driver->CloseJoystick(child, joystick); child->driver->CloseJoystick(child, joystick);

View File

@@ -2727,6 +2727,7 @@ static bool HIDAPI_DriverSwitch_UpdateDevice(SDL_HIDAPI_Device *device)
// Reconnect the Bluetooth device once the USB device is gone // Reconnect the Bluetooth device once the USB device is gone
if (device->num_joysticks == 0 && device->is_bluetooth && packet_count > 0 && if (device->num_joysticks == 0 && device->is_bluetooth && packet_count > 0 &&
!device->parent &&
!HIDAPI_HasConnectedUSBDevice(device->serial)) { !HIDAPI_HasConnectedUSBDevice(device->serial)) {
HIDAPI_JoystickConnected(device, NULL); HIDAPI_JoystickConnected(device, NULL);
} }

View File

@@ -363,7 +363,7 @@ static SDL_HIDAPI_Device *HIDAPI_GetDeviceByIndex(int device_index, SDL_Joystick
SDL_AssertJoysticksLocked(); SDL_AssertJoysticksLocked();
for (device = SDL_HIDAPI_devices; device; device = device->next) { for (device = SDL_HIDAPI_devices; device; device = device->next) {
if (device->parent) { if (device->parent || device->broken) {
continue; continue;
} }
if (device->driver) { if (device->driver) {
@@ -685,7 +685,7 @@ bool HIDAPI_HasConnectedUSBDevice(const char *serial)
} }
for (device = SDL_HIDAPI_devices; device; device = device->next) { for (device = SDL_HIDAPI_devices; device; device = device->next) {
if (!device->driver) { if (!device->driver || device->broken) {
continue; continue;
} }
@@ -711,7 +711,7 @@ void HIDAPI_DisconnectBluetoothDevice(const char *serial)
} }
for (device = SDL_HIDAPI_devices; device; device = device->next) { for (device = SDL_HIDAPI_devices; device; device = device->next) {
if (!device->driver) { if (!device->driver || device->broken) {
continue; continue;
} }
@@ -1016,6 +1016,10 @@ static bool HIDAPI_CreateCombinedJoyCons(void)
// This device is already part of a combined device // This device is already part of a combined device
continue; continue;
} }
if (device->broken) {
// This device can't be used
continue;
}
SDL_GetJoystickGUIDInfo(device->guid, &vendor, &product, NULL, NULL); SDL_GetJoystickGUIDInfo(device->guid, &vendor, &product, NULL, NULL);
@@ -1136,6 +1140,12 @@ check_removed:
SDL_HIDAPI_change_count = 0; 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; device = next;
} }
@@ -1478,7 +1488,7 @@ static bool HIDAPI_JoystickOpen(SDL_Joystick *joystick, int device_index)
SDL_AssertJoysticksLocked(); SDL_AssertJoysticksLocked();
if (!device || !device->driver) { if (!device || !device->driver || device->broken) {
// This should never happen - validated before being called // This should never happen - validated before being called
return SDL_SetError("Couldn't find HIDAPI device at index %d", device_index); return SDL_SetError("Couldn't find HIDAPI device at index %d", device_index);
} }

View File

@@ -101,6 +101,10 @@ typedef struct SDL_HIDAPI_Device
// Used to flag that the device is being updated // Used to flag that the device is being updated
bool updating; 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; struct SDL_HIDAPI_Device *parent;
int num_children; int num_children;
struct SDL_HIDAPI_Device **children; struct SDL_HIDAPI_Device **children;