SDL: Added support for the Joy-Con Charging Grip when SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS is enabled

From 9fdb06450d0363ad2af083497ebdbe50f98fe160 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Wed, 4 Aug 2021 11:33:28 -0700
Subject: [PATCH] Added support for the Joy-Con Charging Grip when
 SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS is enabled

---
 src/joystick/SDL_gamecontroller.c       | 3 +--
 src/joystick/SDL_joystick.c             | 6 +++++-
 src/joystick/hidapi/SDL_hidapi_switch.c | 8 +++++++-
 src/joystick/usb_ids.h                  | 1 +
 test/testgamecontroller.c               | 1 +
 5 files changed, 15 insertions(+), 4 deletions(-)

diff --git a/src/joystick/SDL_gamecontroller.c b/src/joystick/SDL_gamecontroller.c
index 76db18dd7..e6ae4fb8f 100644
--- a/src/joystick/SDL_gamecontroller.c
+++ b/src/joystick/SDL_gamecontroller.c
@@ -615,8 +615,7 @@ static ControllerMapping_t *SDL_CreateMappingForHIDAPIController(SDL_JoystickGUI
                 /* Joy-Cons have extra buttons in the same place as paddles */
                 if (SDL_IsJoystickNintendoSwitchJoyConLeft(vendor, product)) {
                     SDL_strlcat(mapping_string, "paddle2:b17,paddle4:b19,", sizeof(mapping_string));
-                }
-                else if (SDL_IsJoystickNintendoSwitchJoyConRight(vendor, product)) {
+                } else if (SDL_IsJoystickNintendoSwitchJoyConRight(vendor, product)) {
                     SDL_strlcat(mapping_string, "paddle1:b16,paddle3:b18,", sizeof(mapping_string));
                 }
                 break;
diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c
index d3521418d..1bab305b0 100644
--- a/src/joystick/SDL_joystick.c
+++ b/src/joystick/SDL_joystick.c
@@ -1906,6 +1906,9 @@ SDL_GetJoystickGameControllerType(const char *name, Uint16 vendor, Uint16 produc
         } else if (vendor == USB_VENDOR_GOOGLE && product == USB_PRODUCT_GOOGLE_STADIA_CONTROLLER) {
             type = SDL_CONTROLLER_TYPE_GOOGLE_STADIA;
 
+        } else if (vendor == USB_VENDOR_NINTENDO && product == USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_GRIP) {
+                type = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, SDL_FALSE) ? SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO : SDL_CONTROLLER_TYPE_UNKNOWN;
+
         } else {
             switch (GuessControllerType(vendor, product)) {
             case k_eControllerType_XBox360Controller:
@@ -2012,7 +2015,8 @@ 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_SwitchInputOnlyController ||
+            (vendor_id == USB_VENDOR_NINTENDO && product_id == USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_GRIP));
 }
 
 SDL_bool
diff --git a/src/joystick/hidapi/SDL_hidapi_switch.c b/src/joystick/hidapi/SDL_hidapi_switch.c
index aef17c8de..150fde6f2 100644
--- a/src/joystick/hidapi/SDL_hidapi_switch.c
+++ b/src/joystick/hidapi/SDL_hidapi_switch.c
@@ -323,6 +323,10 @@ HIDAPI_DriverSwitch_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
 {
     /* Give a user friendly name for this controller */
     if (vendor_id == USB_VENDOR_NINTENDO) {
+        if (product_id == USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_GRIP) {
+            return "Nintendo Switch Joy-Con Grip";
+        }
+
         if (product_id == USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_LEFT) {
             return "Nintendo Switch Joy-Con Left";
         }
@@ -642,7 +646,8 @@ static SDL_bool BTrySetupUSB(SDL_DriverSwitch_Context *ctx)
         /*return SDL_FALSE;*/
     }
     if (!WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_Handshake, NULL, 0, SDL_TRUE)) {
-        return SDL_FALSE;
+        /* This fails on the right Joy-Con when plugged into the charging grip */
+        /*return SDL_FALSE;*/
     }
     if (!WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_ForceUSB, NULL, 0, SDL_FALSE)) {
         return SDL_FALSE;
@@ -892,6 +897,7 @@ HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joysti
          */
         if (device->vendor_id == USB_VENDOR_NINTENDO &&
                 (device->product_id == USB_PRODUCT_NINTENDO_SWITCH_PRO ||
+                device->product_id == USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_GRIP ||
                 device->product_id == USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_LEFT ||
                 device->product_id == USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_RIGHT)) {
             input_mode = k_eSwitchInputReportIDs_FullControllerState;
diff --git a/src/joystick/usb_ids.h b/src/joystick/usb_ids.h
index 34a815db0..e3160c7e7 100644
--- a/src/joystick/usb_ids.h
+++ b/src/joystick/usb_ids.h
@@ -46,6 +46,7 @@
 #define USB_PRODUCT_NINTENDO_SWITCH_PRO                 0x2009
 #define USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_LEFT        0x2006
 #define USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_RIGHT       0x2007
+#define USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_GRIP        0x200e
 #define USB_PRODUCT_RAZER_PANTHERA                      0x0401
 #define USB_PRODUCT_RAZER_PANTHERA_EVO                  0x1008
 #define USB_PRODUCT_RAZER_ATROX                         0x0a00
diff --git a/test/testgamecontroller.c b/test/testgamecontroller.c
index 2a88745df..d0fb99075 100644
--- a/test/testgamecontroller.c
+++ b/test/testgamecontroller.c
@@ -518,6 +518,7 @@ main(int argc, char *argv[])
     char guid[64];
 
     SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, "0");
+    SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1");
     SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1");
     SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1");
     SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1");