From 9da4bfc141d191fcf7941c2423c6a72663d1455d Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Tue, 22 Oct 2019 10:57:07 -0700 Subject: [PATCH] Added support for the Power A Nintendo Switch Enhanced Wireless Controller --- src/joystick/android/SDL_sysjoystick.c | 2 +- src/joystick/darwin/SDL_sysjoystick.c | 2 +- src/joystick/hidapi/SDL_hidapi_ps4.c | 2 +- src/joystick/hidapi/SDL_hidapi_switch.c | 24 ++++++++++++++++------ src/joystick/hidapi/SDL_hidapi_xbox360.c | 2 +- src/joystick/hidapi/SDL_hidapi_xboxone.c | 2 +- src/joystick/hidapi/SDL_hidapijoystick.c | 14 ++++++++----- src/joystick/hidapi/SDL_hidapijoystick_c.h | 4 ++-- src/joystick/linux/SDL_sysjoystick.c | 2 +- src/joystick/windows/SDL_dinputjoystick.c | 2 +- src/joystick/windows/SDL_xinputjoystick.c | 2 +- 11 files changed, 37 insertions(+), 21 deletions(-) diff --git a/src/joystick/android/SDL_sysjoystick.c b/src/joystick/android/SDL_sysjoystick.c index b9ca30803..158c38a4c 100644 --- a/src/joystick/android/SDL_sysjoystick.c +++ b/src/joystick/android/SDL_sysjoystick.c @@ -344,7 +344,7 @@ Android_AddJoystick(int device_id, const char *name, const char *desc, int vendo } #ifdef SDL_JOYSTICK_HIDAPI - if (HIDAPI_IsDevicePresent(vendor_id, product_id, 0)) { + if (HIDAPI_IsDevicePresent(vendor_id, product_id, 0, name)) { /* The HIDAPI driver is taking care of this device */ return -1; } diff --git a/src/joystick/darwin/SDL_sysjoystick.c b/src/joystick/darwin/SDL_sysjoystick.c index 6cfc9ec13..5ee8ecee8 100644 --- a/src/joystick/darwin/SDL_sysjoystick.c +++ b/src/joystick/darwin/SDL_sysjoystick.c @@ -451,7 +451,7 @@ GetDeviceInfo(IOHIDDeviceRef hidDevice, recDevice *pDevice) } #ifdef SDL_JOYSTICK_HIDAPI - if (HIDAPI_IsDevicePresent(vendor, product, version)) { + if (HIDAPI_IsDevicePresent(vendor, product, version, pDevice->product)) { /* The HIDAPI driver is taking care of this device */ return 0; } diff --git a/src/joystick/hidapi/SDL_hidapi_ps4.c b/src/joystick/hidapi/SDL_hidapi_ps4.c index befe883c4..af17ad316 100644 --- a/src/joystick/hidapi/SDL_hidapi_ps4.c +++ b/src/joystick/hidapi/SDL_hidapi_ps4.c @@ -139,7 +139,7 @@ static Uint32 crc32(Uint32 crc, const void *data, int count) } static SDL_bool -HIDAPI_DriverPS4_IsSupportedDevice(Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number) +HIDAPI_DriverPS4_IsSupportedDevice(Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, const char *name) { return SDL_IsJoystickPS4(vendor_id, product_id); } diff --git a/src/joystick/hidapi/SDL_hidapi_switch.c b/src/joystick/hidapi/SDL_hidapi_switch.c index 935c27be9..b3c023ab6 100644 --- a/src/joystick/hidapi/SDL_hidapi_switch.c +++ b/src/joystick/hidapi/SDL_hidapi_switch.c @@ -193,6 +193,7 @@ typedef struct typedef struct { hid_device *dev; SDL_bool m_bInputOnly; + SDL_bool m_bHasHomeLED; SDL_bool m_bUsingBluetooth; SDL_bool m_bUseButtonLabels; Uint8 m_nCommandNumber; @@ -222,8 +223,17 @@ typedef struct { static SDL_bool -HIDAPI_DriverSwitch_IsSupportedDevice(Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number) +HIDAPI_DriverSwitch_IsSupportedDevice(Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, const char *name) { + if (vendor_id == 0 && product_id == 0) { + /* Some devices are only identifiable by their name */ + if (SDL_strcmp(name, "Lic Pro Controller") == 0 || + SDL_strcmp(name, "Nintendo Wireless Gamepad") == 0 || + SDL_strcmp(name, "Wireless Gamepad") == 0) { + /* HORI or PowerA Switch Pro Controller clone */ + return SDL_TRUE; + } + } return SDL_IsJoystickNintendoSwitchPro(vendor_id, product_id); } @@ -231,10 +241,7 @@ static const char * HIDAPI_DriverSwitch_GetDeviceName(Uint16 vendor_id, Uint16 product_id) { /* Give a user friendly name for this controller */ - if (SDL_IsJoystickNintendoSwitchPro(vendor_id, product_id)) { - return "Nintendo Switch Pro Controller"; - } - return NULL; + return "Nintendo Switch Pro Controller"; } static int ReadInput(SDL_DriverSwitch_Context *ctx) @@ -624,6 +631,9 @@ HIDAPI_DriverSwitch_Init(SDL_Joystick *joystick, hid_device *dev, Uint16 vendor_ /* Find out whether or not we can send output reports */ ctx->m_bInputOnly = SDL_IsJoystickNintendoSwitchProInputOnly(vendor_id, product_id); if (!ctx->m_bInputOnly) { + /* The Power A Nintendo Switch Pro controllers don't have a Home LED */ + ctx->m_bHasHomeLED = (vendor_id != 0 && product_id != 0) ? SDL_TRUE : SDL_FALSE; + /* Initialize rumble data */ SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[0]); SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[1]); @@ -668,7 +678,9 @@ HIDAPI_DriverSwitch_Init(SDL_Joystick *joystick, hid_device *dev, Uint16 vendor_ } /* Set the LED state */ - SetHomeLED(ctx, 100); + if (ctx->m_bHasHomeLED) { + SetHomeLED(ctx, 100); + } SetSlotLED(ctx, (joystick->instance_id % 4)); } diff --git a/src/joystick/hidapi/SDL_hidapi_xbox360.c b/src/joystick/hidapi/SDL_hidapi_xbox360.c index 535e53f61..afc21d2ba 100644 --- a/src/joystick/hidapi/SDL_hidapi_xbox360.c +++ b/src/joystick/hidapi/SDL_hidapi_xbox360.c @@ -247,7 +247,7 @@ HIDAPI_DriverXbox360_QuitWindowsGamingInput(SDL_DriverXbox360_Context *ctx) #endif /* SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT */ static SDL_bool -HIDAPI_DriverXbox360_IsSupportedDevice(Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number) +HIDAPI_DriverXbox360_IsSupportedDevice(Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, const char *name) { #if defined(__MACOSX__) || defined(__WIN32__) if (vendor_id == 0x045e && product_id == 0x028e && version == 1) { diff --git a/src/joystick/hidapi/SDL_hidapi_xboxone.c b/src/joystick/hidapi/SDL_hidapi_xboxone.c index fde74bb23..5645ee5e8 100644 --- a/src/joystick/hidapi/SDL_hidapi_xboxone.c +++ b/src/joystick/hidapi/SDL_hidapi_xboxone.c @@ -131,7 +131,7 @@ typedef struct { static SDL_bool -HIDAPI_DriverXboxOne_IsSupportedDevice(Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number) +HIDAPI_DriverXboxOne_IsSupportedDevice(Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, const char *name) { return SDL_IsJoystickXboxOne(vendor_id, product_id); } diff --git a/src/joystick/hidapi/SDL_hidapijoystick.c b/src/joystick/hidapi/SDL_hidapijoystick.c index 9739742f9..212383db7 100644 --- a/src/joystick/hidapi/SDL_hidapijoystick.c +++ b/src/joystick/hidapi/SDL_hidapijoystick.c @@ -564,13 +564,13 @@ HIDAPI_XboxControllerName(Uint16 vendor_id, Uint16 product_id) } static SDL_bool -HIDAPI_IsDeviceSupported(Uint16 vendor_id, Uint16 product_id, Uint16 version) +HIDAPI_IsDeviceSupported(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name) { int i; for (i = 0; i < SDL_arraysize(SDL_HIDAPI_drivers); ++i) { SDL_HIDAPI_DeviceDriver *driver = SDL_HIDAPI_drivers[i]; - if (driver->enabled && driver->IsSupportedDevice(vendor_id, product_id, version, -1)) { + if (driver->enabled && driver->IsSupportedDevice(vendor_id, product_id, version, -1, name)) { return SDL_TRUE; } } @@ -599,7 +599,7 @@ HIDAPI_GetDeviceDriver(SDL_HIDAPI_Device *device) for (i = 0; i < SDL_arraysize(SDL_HIDAPI_drivers); ++i) { SDL_HIDAPI_DeviceDriver *driver = SDL_HIDAPI_drivers[i]; - if (driver->enabled && driver->IsSupportedDevice(device->vendor_id, device->product_id, device->version, device->interface_number)) { + if (driver->enabled && driver->IsSupportedDevice(device->vendor_id, device->product_id, device->version, device->interface_number, device->name)) { return driver; } } @@ -914,7 +914,7 @@ HIDAPI_UpdateDeviceList(void) } SDL_bool -HIDAPI_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version) +HIDAPI_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name) { SDL_HIDAPI_Device *device; @@ -924,13 +924,17 @@ HIDAPI_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version) } /* Don't update the device list for devices we know aren't supported */ - if (!HIDAPI_IsDeviceSupported(vendor_id, product_id, version)) { + if (!HIDAPI_IsDeviceSupported(vendor_id, product_id, version, name)) { return SDL_FALSE; } /* Make sure the device list is completely up to date when we check for device presence */ HIDAPI_UpdateDeviceList(); + /* Note that this isn't a perfect check - there may be multiple devices with 0 VID/PID, + or a different name than we have it listed here, etc, but if we support the device + and we have something similar in our device list, mark it as present. + */ device = SDL_HIDAPI_devices; while (device) { if (device->vendor_id == vendor_id && device->product_id == product_id && device->driver) { diff --git a/src/joystick/hidapi/SDL_hidapijoystick_c.h b/src/joystick/hidapi/SDL_hidapijoystick_c.h index a8e707393..72fad9c9d 100644 --- a/src/joystick/hidapi/SDL_hidapijoystick_c.h +++ b/src/joystick/hidapi/SDL_hidapijoystick_c.h @@ -47,7 +47,7 @@ typedef struct _SDL_HIDAPI_DeviceDriver { const char *hint; SDL_bool enabled; - SDL_bool (*IsSupportedDevice)(Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number); + SDL_bool (*IsSupportedDevice)(Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, const char *name); const char *(*GetDeviceName)(Uint16 vendor_id, Uint16 product_id); SDL_bool (*Init)(SDL_Joystick *joystick, hid_device *dev, Uint16 vendor_id, Uint16 product_id, void **context); int (*Rumble)(SDL_Joystick *joystick, hid_device *dev, void *context, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms); @@ -64,7 +64,7 @@ extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360; extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXboxOne; /* 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); +extern SDL_bool HIDAPI_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name); /* Return the name of an Xbox 360 or Xbox One controller */ extern const char *HIDAPI_XboxControllerName(Uint16 vendor_id, Uint16 product_id); diff --git a/src/joystick/linux/SDL_sysjoystick.c b/src/joystick/linux/SDL_sysjoystick.c index ad8309196..6bd5330b4 100644 --- a/src/joystick/linux/SDL_sysjoystick.c +++ b/src/joystick/linux/SDL_sysjoystick.c @@ -120,7 +120,7 @@ IsJoystick(int fd, char *namebuf, const size_t namebuflen, SDL_JoystickGUID *gui } #ifdef SDL_JOYSTICK_HIDAPI - if (HIDAPI_IsDevicePresent(inpid.vendor, inpid.product, inpid.version)) { + if (HIDAPI_IsDevicePresent(inpid.vendor, inpid.product, inpid.version, namebuf)) { /* The HIDAPI driver is taking care of this device */ return 0; } diff --git a/src/joystick/windows/SDL_dinputjoystick.c b/src/joystick/windows/SDL_dinputjoystick.c index 5b3089b6c..f03c80096 100644 --- a/src/joystick/windows/SDL_dinputjoystick.c +++ b/src/joystick/windows/SDL_dinputjoystick.c @@ -535,7 +535,7 @@ EnumJoysticksCallback(const DIDEVICEINSTANCE * pdidInstance, VOID * pContext) } #ifdef SDL_JOYSTICK_HIDAPI - if (HIDAPI_IsDevicePresent(vendor, product, 0)) { + if (HIDAPI_IsDevicePresent(vendor, product, 0, pNewJoystick->joystickname)) { /* The HIDAPI driver is taking care of this device */ SDL_free(pNewJoystick); return DIENUM_CONTINUE; diff --git a/src/joystick/windows/SDL_xinputjoystick.c b/src/joystick/windows/SDL_xinputjoystick.c index 22e557f5d..30244fa5b 100644 --- a/src/joystick/windows/SDL_xinputjoystick.c +++ b/src/joystick/windows/SDL_xinputjoystick.c @@ -260,7 +260,7 @@ AddXInputDevice(Uint8 userid, BYTE SubType, JoyStick_DeviceData **pContext) } #ifdef SDL_JOYSTICK_HIDAPI - if (HIDAPI_IsDevicePresent(vendor, product, version)) { + if (HIDAPI_IsDevicePresent(vendor, product, version, pNewJoystick->joystickname)) { /* The HIDAPI driver is taking care of this device */ SDL_free(pNewJoystick); return;