diff --git a/src/joystick/hidapi/SDL_hidapijoystick.c b/src/joystick/hidapi/SDL_hidapijoystick.c index c8f34c203e..3c7a993474 100644 --- a/src/joystick/hidapi/SDL_hidapijoystick.c +++ b/src/joystick/hidapi/SDL_hidapijoystick.c @@ -1110,6 +1110,40 @@ HIDAPI_IsEquivalentToDevice(Uint16 vendor_id, Uint16 product_id, SDL_HIDAPI_Devi return SDL_FALSE; } +SDL_bool +HIDAPI_IsDeviceTypePresent(SDL_GameControllerType type) +{ + SDL_HIDAPI_Device *device; + SDL_bool result = SDL_FALSE; + + /* Make sure we're initialized, as this could be called from other drivers during startup */ + if (HIDAPI_JoystickInit() < 0) { + return SDL_FALSE; + } + + if (SDL_AtomicTryLock(&SDL_HIDAPI_spinlock)) { + HIDAPI_UpdateDeviceList(); + SDL_AtomicUnlock(&SDL_HIDAPI_spinlock); + } + + SDL_LockJoysticks(); + device = SDL_HIDAPI_devices; + while (device) { + if (device->driver && + SDL_GetJoystickGameControllerType(device->name, device->vendor_id, device->product_id, device->interface_number, device->interface_class, device->interface_subclass, device->interface_protocol) == type) { + result = SDL_TRUE; + break; + } + device = device->next; + } + SDL_UnlockJoysticks(); + +#ifdef DEBUG_HIDAPI + SDL_Log("HIDAPI_IsDeviceTypePresent() returning %s for %d\n", result ? "true" : "false", type); +#endif + return result; +} + SDL_bool HIDAPI_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name) { @@ -1152,6 +1186,7 @@ HIDAPI_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, cons if (device->driver && HIDAPI_IsEquivalentToDevice(vendor_id, product_id, device)) { result = SDL_TRUE; + break; } device = device->next; } diff --git a/src/joystick/hidapi/SDL_hidapijoystick_c.h b/src/joystick/hidapi/SDL_hidapijoystick_c.h index b80c6be4b3..9722775ee1 100644 --- a/src/joystick/hidapi/SDL_hidapijoystick_c.h +++ b/src/joystick/hidapi/SDL_hidapijoystick_c.h @@ -119,6 +119,9 @@ extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360; extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360W; extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXboxOne; +/* Return true if a HID device is present and supported as a joystick of the given type */ +extern SDL_bool HIDAPI_IsDeviceTypePresent(SDL_GameControllerType type); + /* Return true if a HID device is present and supported as a joystick */ extern SDL_bool HIDAPI_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name); diff --git a/src/joystick/iphoneos/SDL_mfijoystick.m b/src/joystick/iphoneos/SDL_mfijoystick.m index 2e8c137c6d..7aee4f566c 100644 --- a/src/joystick/iphoneos/SDL_mfijoystick.m +++ b/src/joystick/iphoneos/SDL_mfijoystick.m @@ -27,6 +27,7 @@ #include "SDL_stdinc.h" #include "../SDL_sysjoystick.h" #include "../SDL_joystick_c.h" +#include "../hidapi/SDL_hidapijoystick_c.h" #include "../usb_ids.h" #include "SDL_mfijoystick_c.h" @@ -128,7 +129,49 @@ GetDeviceForIndex(int device_index) } #ifdef SDL_JOYSTICK_MFI -static void +static BOOL +IsControllerPS4(GCController *controller) +{ + if (@available(macOS 10.15, iOS 13.0, tvOS 13.0, *)) { + if ([controller.productCategory isEqualToString:@"DualShock 4"]) { + return TRUE; + } + } else { + if ([controller.vendorName containsString: @"DUALSHOCK"]) { + return TRUE; + } + } + return FALSE; +} +static BOOL +IsControllerPS5(GCController *controller) +{ + if (@available(macOS 10.15, iOS 13.0, tvOS 13.0, *)) { + if ([controller.productCategory isEqualToString:@"DualSense"]) { + return TRUE; + } + } else { + if ([controller.vendorName containsString: @"DualSense"]) { + return TRUE; + } + } + return FALSE; +} +static BOOL +IsControllerXbox(GCController *controller) +{ + if (@available(macOS 10.15, iOS 13.0, tvOS 13.0, *)) { + if ([controller.productCategory isEqualToString:@"Xbox One"]) { + return TRUE; + } + } else { + if ([controller.vendorName containsString: @"Xbox"]) { + return TRUE; + } + } + return FALSE; +} +static BOOL IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCController *controller) { Uint16 *guid16 = (Uint16 *)device->guid.data; @@ -153,14 +196,23 @@ IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCController *controlle if (controller.extendedGamepad) { GCExtendedGamepad *gamepad = controller.extendedGamepad; - BOOL is_xbox = [controller.vendorName containsString: @"Xbox"]; - BOOL is_ps4 = [controller.vendorName containsString: @"DUALSHOCK"]; - BOOL is_ps5 = [controller.vendorName containsString: @"DualSense"]; + BOOL is_xbox = IsControllerXbox(controller); + BOOL is_ps4 = IsControllerPS4(controller); + BOOL is_ps5 = IsControllerPS5(controller); #if TARGET_OS_TV BOOL is_MFi = (!is_xbox && !is_ps4 && !is_ps5); #endif int nbuttons = 0; +#ifdef SDL_JOYSTICK_HIDAPI + if ((is_xbox && HIDAPI_IsDeviceTypePresent(SDL_CONTROLLER_TYPE_XBOXONE)) || + (is_ps4 && HIDAPI_IsDeviceTypePresent(SDL_CONTROLLER_TYPE_PS4)) || + (is_ps5 && HIDAPI_IsDeviceTypePresent(SDL_CONTROLLER_TYPE_PS5))) { + /* The HIDAPI driver is taking care of this device */ + return FALSE; + } +#endif + /* These buttons are part of the original MFi spec */ device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_A); device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_B); @@ -342,6 +394,7 @@ IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCController *controlle /* This will be set when the first button press of the controller is * detected. */ controller.playerIndex = -1; + return TRUE; } #endif /* SDL_JOYSTICK_MFI */ @@ -390,7 +443,10 @@ IOS_AddJoystickDevice(GCController *controller, SDL_bool accelerometer) #endif /* SDL_JOYSTICK_iOS_ACCELEROMETER */ } else if (controller) { #ifdef SDL_JOYSTICK_MFI - IOS_AddMFIJoystickDevice(device, controller); + if (!IOS_AddMFIJoystickDevice(device, controller)) { + SDL_free(device); + return; + } #else SDL_free(device); return;