Commit 0f57864c9eb60807da20d793290d9f4b1a19d756

JibbSmart 2021-01-18T19:57:29

Hint SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS added so we can recognise a Joy-Con as half a Pro Controller, so we can read its analog input and read its sensors just like we do a Pro Controller.

diff --git a/include/SDL_hints.h b/include/SDL_hints.h
index 8575570..8c0a991 100644
--- a/include/SDL_hints.h
+++ b/include/SDL_hints.h
@@ -685,6 +685,17 @@ extern "C" {
  */
 #define SDL_HINT_JOYSTICK_HIDAPI_SWITCH "SDL_JOYSTICK_HIDAPI_SWITCH"
 
+ /**
+  *  \brief  A variable controlling whether Switch Joy-Cons should be treated the same as Switch Pro Controllers when using the HIDAPI driver.
+  *
+  *  This variable can be set to the following values:
+  *    "0"       - basic Joy-Con support with no analog input (the default)
+  *    "1"       - Joy-Cons treated as half full Pro Controllers with analog inputs and sensors
+  *
+  *  This does not combine Joy-Cons into a single controller. That's up to the user.
+  */
+#define SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS "SDL_JOYSTICK_HIDAPI_JOY_CONS"
+
 /**
  *  \brief  A variable controlling whether the HIDAPI driver for XBox controllers should be used.
  *
diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c
index 1cae14a..67fb10e 100644
--- a/src/joystick/SDL_joystick.c
+++ b/src/joystick/SDL_joystick.c
@@ -1888,6 +1888,10 @@ SDL_GetJoystickGameControllerType(const char *name, Uint16 vendor, Uint16 produc
             case k_eControllerType_SwitchInputOnlyController:
                 type = SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO;
                 break;
+            case k_eControllerType_SwitchJoyConLeft:
+            case k_eControllerType_SwitchJoyConRight:
+                type = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, SDL_FALSE) ? SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO : SDL_CONTROLLER_TYPE_UNKNOWN;
+                break;
             default:
                 type = SDL_CONTROLLER_TYPE_UNKNOWN;
                 break;
@@ -1975,6 +1979,28 @@ SDL_IsJoystickNintendoSwitchProInputOnly(Uint16 vendor_id, Uint16 product_id)
 }
 
 SDL_bool
+SDL_IsJoystickNintendoSwitchJoyCon(Uint16 vendor_id, Uint16 product_id)
+{
+    EControllerType eType = GuessControllerType(vendor_id, product_id);
+    return (eType == k_eControllerType_SwitchJoyConLeft ||
+            eType == k_eControllerType_SwitchJoyConRight);
+}
+
+SDL_bool
+SDL_IsJoystickNintendoSwitchJoyConLeft(Uint16 vendor_id, Uint16 product_id)
+{
+    EControllerType eType = GuessControllerType(vendor_id, product_id);
+    return (eType == k_eControllerType_SwitchJoyConLeft);
+}
+
+SDL_bool
+SDL_IsJoystickNintendoSwitchJoyConRight(Uint16 vendor_id, Uint16 product_id)
+{
+    EControllerType eType = GuessControllerType(vendor_id, product_id);
+    return (eType == k_eControllerType_SwitchJoyConRight);
+}
+
+SDL_bool
 SDL_IsJoystickSteamController(Uint16 vendor_id, Uint16 product_id)
 {
     EControllerType eType = GuessControllerType(vendor_id, product_id);
diff --git a/src/joystick/SDL_joystick_c.h b/src/joystick/SDL_joystick_c.h
index 5988364..c724d01 100644
--- a/src/joystick/SDL_joystick_c.h
+++ b/src/joystick/SDL_joystick_c.h
@@ -79,6 +79,9 @@ extern SDL_bool SDL_IsJoystickPS5(Uint16 vendor_id, Uint16 product_id);
 /* Function to return whether a joystick is a Nintendo Switch Pro controller */
 extern SDL_bool SDL_IsJoystickNintendoSwitchPro(Uint16 vendor_id, Uint16 product_id);
 extern SDL_bool SDL_IsJoystickNintendoSwitchProInputOnly(Uint16 vendor_id, Uint16 product_id);
+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);
 
 /* 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/controller_type.h b/src/joystick/controller_type.h
index 8887245..7fbed25 100644
--- a/src/joystick/controller_type.h
+++ b/src/joystick/controller_type.h
@@ -522,11 +522,9 @@ static const ControllerDescription_t arrControllers[] = {
 	{ MAKE_CONTROLLER_ID( 0x05ac, 0x0001 ), k_eControllerType_AppleController, NULL },	// MFI Extended Gamepad (generic entry for iOS/tvOS)
 	{ MAKE_CONTROLLER_ID( 0x05ac, 0x0002 ), k_eControllerType_AppleController, NULL },	// MFI Standard Gamepad (generic entry for iOS/tvOS)
 
-    // We currently don't support using a pair of Switch Joy-Con's as a single
-    // controller and we don't want to support using them individually for the
-    // time being, so these should be disabled until one of the above is true
-    // { MAKE_CONTROLLER_ID( 0x057e, 0x2006 ), k_eControllerType_SwitchJoyConLeft, NULL },    // Nintendo Switch Joy-Con (Left)
-    // { MAKE_CONTROLLER_ID( 0x057e, 0x2007 ), k_eControllerType_SwitchJoyConRight, NULL },   // Nintendo Switch Joy-Con (Right)
+    // We now support Joy-Cons if SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS is set to "1", but they won't be combined into one controller.
+    { MAKE_CONTROLLER_ID( 0x057e, 0x2006 ), k_eControllerType_SwitchJoyConLeft, NULL },    // Nintendo Switch Joy-Con (Left)
+    { MAKE_CONTROLLER_ID( 0x057e, 0x2007 ), k_eControllerType_SwitchJoyConRight, NULL },   // Nintendo Switch Joy-Con (Right)
 
     // This same controller ID is spoofed by many 3rd-party Switch controllers.
     // The ones we currently know of are:
diff --git a/src/joystick/hidapi/SDL_hidapi_switch.c b/src/joystick/hidapi/SDL_hidapi_switch.c
index 920fa67..9102b49 100644
--- a/src/joystick/hidapi/SDL_hidapi_switch.c
+++ b/src/joystick/hidapi/SDL_hidapi_switch.c
@@ -322,6 +322,16 @@ static const char *
 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_LEFT) {
+            return "Nintendo Switch Joy-Con Left";
+        }
+
+        if (product_id == USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_RIGHT) {
+            return "Nintendo Switch Joy-Con Right";
+        }
+    }
+
     return "Nintendo Switch Pro Controller";
 }
 
@@ -840,7 +850,9 @@ HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joysti
          * level and we only care about battery level over bluetooth anyway.
          */
         if (device->vendor_id == USB_VENDOR_NINTENDO &&
-            device->product_id == USB_PRODUCT_NINTENDO_SWITCH_PRO) {
+                (device->product_id == USB_PRODUCT_NINTENDO_SWITCH_PRO ||
+                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;
         }
         
@@ -1358,6 +1370,12 @@ static void HandleFullControllerState(SDL_Joystick *joystick, SDL_DriverSwitch_C
         data[0] /= -3.f;
         data[1] /= 3.f;
         data[2] /= -3.f;
+        /* Right Joy-Con flips some axes, so let's flip them back for consistency */
+        if (ctx->m_eControllerType == k_eSwitchDeviceInfoControllerType_JoyConRight) {
+            data[0] = -data[0];
+            data[1] = -data[1];
+        }
+
         SDL_PrivateJoystickSensor(joystick, SDL_SENSOR_GYRO, data, 3);
 
         data[0] = HIDAPI_DriverSwitch_ScaleAccel(packet->imuState[0].sAccelY);
@@ -1372,6 +1390,12 @@ static void HandleFullControllerState(SDL_Joystick *joystick, SDL_DriverSwitch_C
         data[0] /= -3.f;
         data[1] /= 3.f;
         data[2] /= -3.f;
+        /* Right Joy-Con flips some axes, so let's flip them back for consistency */
+        if (ctx->m_eControllerType == k_eSwitchDeviceInfoControllerType_JoyConRight) {
+            data[0] = -data[0];
+            data[1] = -data[1];
+        }
+
         SDL_PrivateJoystickSensor(joystick, SDL_SENSOR_ACCEL, data, 3);
     }
 
diff --git a/src/joystick/usb_ids.h b/src/joystick/usb_ids.h
index ed7c640..cea02f6 100644
--- a/src/joystick/usb_ids.h
+++ b/src/joystick/usb_ids.h
@@ -39,6 +39,8 @@
 #define USB_PRODUCT_EVORETRO_GAMECUBE_ADAPTER           0x1846
 #define USB_PRODUCT_NINTENDO_GAMECUBE_ADAPTER           0x0337
 #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_RAZER_PANTHERA                      0x0401
 #define USB_PRODUCT_RAZER_PANTHERA_EVO                  0x1008
 #define USB_PRODUCT_RAZER_ATROX                         0x0a00