From 29cdb2c9c921e085495b423479c9bf52ed9c5af0 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Wed, 3 Aug 2022 18:01:10 -0700 Subject: [PATCH] Added support for the Nintendo Switch Joy-Con Charging Grip --- src/joystick/SDL_gamecontroller.c | 6 +++- src/joystick/SDL_joystick.c | 16 ++++++++-- src/joystick/SDL_joystick_c.h | 2 ++ src/joystick/hidapi/SDL_hidapi_switch.c | 37 +++++++++++++++++++----- src/joystick/hidapi/SDL_hidapijoystick.c | 10 +++++-- 5 files changed, 57 insertions(+), 14 deletions(-) diff --git a/src/joystick/SDL_gamecontroller.c b/src/joystick/SDL_gamecontroller.c index 626f69174..3c782a1f6 100644 --- a/src/joystick/SDL_gamecontroller.c +++ b/src/joystick/SDL_gamecontroller.c @@ -594,7 +594,8 @@ static ControllerMapping_t *SDL_CreateMappingForHIDAPIController(SDL_JoystickGUI } else if (vendor == USB_VENDOR_NINTENDO && product == USB_PRODUCT_NINTENDO_SNES_CONTROLLER) { SDL_strlcat(mapping_string, "a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,lefttrigger:a4,rightshoulder:b10,righttrigger:a5,start:b6,x:b2,y:b3,", sizeof(mapping_string)); } else if (SDL_IsJoystickNintendoSwitchJoyConLeft(vendor, product) || - SDL_IsJoystickNintendoSwitchJoyConRight(vendor, product)) { + SDL_IsJoystickNintendoSwitchJoyConRight(vendor, product) || + SDL_IsJoystickNintendoSwitchJoyConGrip(vendor, product)) { switch (guid.data[15]) { case 9: case 10: @@ -619,6 +620,9 @@ static ControllerMapping_t *SDL_CreateMappingForHIDAPIController(SDL_JoystickGUI } else if (SDL_IsJoystickSteamController(vendor, product)) { /* Steam controllers have 2 back paddle buttons */ SDL_strlcat(mapping_string, "paddle1:b16,paddle2:b15,", sizeof(mapping_string)); + } else if (SDL_IsJoystickNintendoSwitchJoyConPair(vendor, product)) { + /* The Nintendo Switch Joy-Con combined controller has a share button */ + SDL_strlcat(mapping_string, "misc1:b15,", sizeof(mapping_string)); } else { switch (SDL_GetJoystickGameControllerTypeFromGUID(guid, NULL)) { case SDL_CONTROLLER_TYPE_PS4: diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c index d6f7e0c7e..931aa9e46 100644 --- a/src/joystick/SDL_joystick.c +++ b/src/joystick/SDL_joystick.c @@ -2110,9 +2110,7 @@ SDL_IsJoystickNintendoSwitchPro(Uint16 vendor_id, Uint16 product_id) { EControllerType eType = GuessControllerType(vendor_id, product_id); return (eType == k_eControllerType_SwitchProController || - eType == k_eControllerType_SwitchInputOnlyController || - eType == k_eControllerType_SwitchJoyConPair || - (vendor_id == USB_VENDOR_NINTENDO && product_id == USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_GRIP)); + eType == k_eControllerType_SwitchInputOnlyController); } SDL_bool @@ -2144,6 +2142,18 @@ SDL_IsJoystickNintendoSwitchJoyConRight(Uint16 vendor_id, Uint16 product_id) return (eType == k_eControllerType_SwitchJoyConRight); } +SDL_bool +SDL_IsJoystickNintendoSwitchJoyConGrip(Uint16 vendor_id, Uint16 product_id) +{ + return (vendor_id == USB_VENDOR_NINTENDO && product_id == USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_GRIP); +} + +SDL_bool +SDL_IsJoystickNintendoSwitchJoyConPair(Uint16 vendor_id, Uint16 product_id) +{ + return (vendor_id == USB_VENDOR_NINTENDO && product_id == USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_PAIR); +} + SDL_bool SDL_IsJoystickSteamController(Uint16 vendor_id, Uint16 product_id) { diff --git a/src/joystick/SDL_joystick_c.h b/src/joystick/SDL_joystick_c.h index 0e50758ae..db630c817 100644 --- a/src/joystick/SDL_joystick_c.h +++ b/src/joystick/SDL_joystick_c.h @@ -90,6 +90,8 @@ extern SDL_bool SDL_IsJoystickNintendoSwitchProInputOnly(Uint16 vendor_id, Uint1 extern SDL_bool SDL_IsJoystickNintendoSwitchJoyCon(Uint16 vendor_id, Uint16 product_id); extern SDL_bool SDL_IsJoystickNintendoSwitchJoyConLeft(Uint16 vendor_id, Uint16 product_id); extern SDL_bool SDL_IsJoystickNintendoSwitchJoyConRight(Uint16 vendor_id, Uint16 product_id); +extern SDL_bool SDL_IsJoystickNintendoSwitchJoyConGrip(Uint16 vendor_id, Uint16 product_id); +extern SDL_bool SDL_IsJoystickNintendoSwitchJoyConPair(Uint16 vendor_id, Uint16 product_id); /* Function to return whether a joystick is a Steam Controller */ extern SDL_bool SDL_IsJoystickSteamController(Uint16 vendor_id, Uint16 product_id); diff --git a/src/joystick/hidapi/SDL_hidapi_switch.c b/src/joystick/hidapi/SDL_hidapi_switch.c index d1271f134..4ff8ecaeb 100644 --- a/src/joystick/hidapi/SDL_hidapi_switch.c +++ b/src/joystick/hidapi/SDL_hidapi_switch.c @@ -384,7 +384,8 @@ HIDAPI_DriverJoyCons_IsSupportedDevice(const char *name, SDL_GameControllerType { if (vendor_id == USB_VENDOR_NINTENDO) { if (product_id == USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_LEFT || - product_id == USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_RIGHT) { + product_id == USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_RIGHT || + product_id == USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_GRIP) { return SDL_TRUE; } } @@ -410,11 +411,6 @@ HIDAPI_DriverSwitch_IsSupportedDevice(const char *name, SDL_GameControllerType t return SDL_FALSE; } - if (vendor_id == USB_VENDOR_NINTENDO) { - if (product_id == USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_GRIP) { - return SDL_TRUE; - } - } return (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) ? SDL_TRUE : SDL_FALSE; } @@ -1101,9 +1097,20 @@ HIDAPI_DriverSwitch_InitDevice(SDL_HIDAPI_Device *device) { /* The NES controllers need additional fix up, since we can't detect them without opening the device */ if (device->vendor_id == USB_VENDOR_NINTENDO && - device->product_id == USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_RIGHT) { + (device->product_id == USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_RIGHT || + device->product_id == USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_GRIP)) { ESwitchDeviceInfoControllerType eControllerType = ReadJoyConControllerType(device); switch (eControllerType) { + case k_eSwitchDeviceInfoControllerType_JoyConLeft: + SDL_free(device->name); + device->name = SDL_strdup("Nintendo Switch Joy-Con (L)"); + device->guid.data[15] = eControllerType; + break; + case k_eSwitchDeviceInfoControllerType_JoyConRight: + SDL_free(device->name); + device->name = SDL_strdup("Nintendo Switch Joy-Con (R)"); + device->guid.data[15] = eControllerType; + break; case k_eSwitchDeviceInfoControllerType_NESLeft: SDL_free(device->name); device->name = SDL_strdup("NES Controller (L)"); @@ -1114,6 +1121,19 @@ HIDAPI_DriverSwitch_InitDevice(SDL_HIDAPI_Device *device) device->name = SDL_strdup("NES Controller (R)"); device->guid.data[15] = eControllerType; break; + case k_eSwitchDeviceInfoControllerType_Unknown: + if (device->product_id == USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_GRIP) { + if (device->interface_number == 1) { + SDL_free(device->name); + device->name = SDL_strdup("Nintendo Switch Joy-Con (L)"); + device->guid.data[15] = k_eSwitchDeviceInfoControllerType_JoyConLeft; + } else { + SDL_free(device->name); + device->name = SDL_strdup("Nintendo Switch Joy-Con (R)"); + device->guid.data[15] = k_eSwitchDeviceInfoControllerType_JoyConRight; + } + } + break; default: break; } @@ -1930,7 +1950,8 @@ HIDAPI_DriverSwitch_UpdateDevice(SDL_HIDAPI_Device *device) } } - if (!ctx->m_bInputOnly && !ctx->m_bUsingBluetooth) { + if (!ctx->m_bInputOnly && !ctx->m_bUsingBluetooth && + ctx->device->product_id != USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_GRIP) { const Uint32 INPUT_WAIT_TIMEOUT_MS = 100; if (SDL_TICKS_PASSED(now, ctx->m_unLastInput + INPUT_WAIT_TIMEOUT_MS)) { /* Steam may have put the controller back into non-reporting mode */ diff --git a/src/joystick/hidapi/SDL_hidapijoystick.c b/src/joystick/hidapi/SDL_hidapijoystick.c index 188dac0da..4a9b80fd3 100644 --- a/src/joystick/hidapi/SDL_hidapijoystick.c +++ b/src/joystick/hidapi/SDL_hidapijoystick.c @@ -746,10 +746,16 @@ HIDAPI_CreateCombinedJoyCons() continue; } - if (!joycons[0] && SDL_IsJoystickNintendoSwitchJoyConLeft(device->vendor_id, device->product_id)) { + if (!joycons[0] && + (SDL_IsJoystickNintendoSwitchJoyConLeft(device->vendor_id, device->product_id) || + (SDL_IsJoystickNintendoSwitchJoyConGrip(device->vendor_id, device->product_id) && + SDL_strstr(device->name, "(L)") != NULL))) { joycons[0] = device; } - if (!joycons[1] && SDL_IsJoystickNintendoSwitchJoyConRight(device->vendor_id, device->product_id)) { + if (!joycons[1] && + (SDL_IsJoystickNintendoSwitchJoyConRight(device->vendor_id, device->product_id) || + (SDL_IsJoystickNintendoSwitchJoyConGrip(device->vendor_id, device->product_id) && + SDL_strstr(device->name, "(R)") != NULL))) { joycons[1] = device; } if (joycons[0] && joycons[1]) {