Commit faeac6e86c207de9d2340e93e08503cf672c8541

Sam Lantinga 2020-11-06T16:42:46

Added additional game controller button support on iOS/tvOS

diff --git a/src/joystick/SDL_gamecontrollerdb.h b/src/joystick/SDL_gamecontrollerdb.h
index 359d4ca..204c2bd 100644
--- a/src/joystick/SDL_gamecontrollerdb.h
+++ b/src/joystick/SDL_gamecontrollerdb.h
@@ -827,11 +827,13 @@ static const char *s_ControllerMappings [] =
     "05000000ac05000001000000df076d01,*,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,",
     "05000000ac05000001000000ff076d01,*,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,",
     "05000000ac050000020000004f066d02,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b2,y:b3,",
-    "050000004c050000cc090000df070000,DUALSHOCK 4 Wireless Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,",
-    "050000004c050000cc090000ff070000,DUALSHOCK 4 Wireless Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,",
+    "050000004c050000cc090000df070000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,",
+    "050000004c050000cc090000ff070000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,",
+    "050000004c050000cc090000ff876d01,PS4 Controller,a:b0,aux1:b11,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,",
     "05000000ac0500000300000043006d03,Remote,a:b0,b:b2,leftx:a0,lefty:a1,",
     "05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,",
     "05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,",
+    "050000005e040000050b0000ff876d01,Xbox Elite Wireless Controller,a:b0,aux1:b11,aux2:b12,aux3:b13,aux4:b13,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,",
     "050000005e040000e0020000df070000,Xbox Wireless Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,",
     "050000005e040000e0020000ff070000,Xbox Wireless Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,",
 #endif
diff --git a/src/joystick/iphoneos/SDL_sysjoystick.m b/src/joystick/iphoneos/SDL_sysjoystick.m
index 9150163..794d31f 100644
--- a/src/joystick/iphoneos/SDL_sysjoystick.m
+++ b/src/joystick/iphoneos/SDL_sysjoystick.m
@@ -33,6 +33,7 @@
 #include "SDL_stdinc.h"
 #include "../SDL_sysjoystick.h"
 #include "../SDL_joystick_c.h"
+#include "../usb_ids.h"
 
 
 #if !SDL_EVENTS_DISABLED
@@ -77,6 +78,7 @@ static id disconnectObserver = nil;
 #if (__IPHONE_OS_VERSION_MAX_ALLOWED >= 140000) || (__APPLETV_OS_VERSION_MAX_ALLOWED >= 140000) || (__MAC_OS_VERSION_MAX_ALLOWED > 1500000)
 #define ENABLE_MFI_BATTERY
 #define ENABLE_MFI_RUMBLE
+#define ENABLE_PHYSICAL_INPUT_PROFILE
 #endif
 
 #ifdef ENABLE_MFI_RUMBLE
@@ -116,9 +118,6 @@ static void
 IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCController *controller)
 {
 #ifdef SDL_JOYSTICK_MFI
-    const Uint16 VENDOR_APPLE = 0x05AC;
-    const Uint16 VENDOR_MICROSOFT = 0x045e;
-    const Uint16 VENDOR_SONY = 0x054C;
     Uint16 *guid16 = (Uint16 *)device->guid.data;
     Uint16 vendor = 0;
     Uint16 product = 0;
@@ -188,16 +187,60 @@ IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCController *controlle
         if (!has_direct_menu) {
             device->uses_pause_handler = SDL_TRUE;
         }
+
+#ifdef ENABLE_PHYSICAL_INPUT_PROFILE
+        if ([controller respondsToSelector:@selector(physicalInputProfile)]) {
+            if (controller.physicalInputProfile.buttons[GCInputDualShockTouchpadButton] != nil) {
+                device->has_dualshock_touchpad = SDL_TRUE;
+                device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_AUX1);
+                ++nbuttons;
+            }
+            if (controller.physicalInputProfile.buttons[GCInputXboxPaddleOne] != nil) {
+                device->has_xbox_paddles = SDL_TRUE;
+                device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_AUX1);
+                ++nbuttons;
+            }
+            if (controller.physicalInputProfile.buttons[GCInputXboxPaddleTwo] != nil) {
+                device->has_xbox_paddles = SDL_TRUE;
+                device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_AUX2);
+                ++nbuttons;
+            }
+            if (controller.physicalInputProfile.buttons[GCInputXboxPaddleThree] != nil) {
+                device->has_xbox_paddles = SDL_TRUE;
+                device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_AUX3);
+                ++nbuttons;
+            }
+            if (controller.physicalInputProfile.buttons[GCInputXboxPaddleFour] != nil) {
+                device->has_xbox_paddles = SDL_TRUE;
+                device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_AUX4);
+                ++nbuttons;
+            }
+        }
+#endif
 #pragma clang diagnostic pop
 
         if (is_xbox) {
-            vendor = VENDOR_MICROSOFT;
-            product = 0x02E0; /* Assume Xbox One S BLE Controller unless/until GCController flows VID/PID */
+            vendor = USB_VENDOR_MICROSOFT;
+            if (device->has_xbox_paddles) {
+                /* Assume Xbox One Elite Series 2 Controller unless/until GCController flows VID/PID */
+                product = USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2_BLUETOOTH;
+                subtype = 1;
+            } else {
+                /* Assume Xbox One S BLE Controller unless/until GCController flows VID/PID */
+                product = USB_PRODUCT_XBOX_ONE_S_REV1_BLUETOOTH;
+                subtype = 0;
+            }
         } else if (is_ps4) {
-            vendor = VENDOR_SONY;
-            product = 0x09CC; /* Assume DS4 Slim unless/until GCController flows VID/PID */
+            /* Assume DS4 Slim unless/until GCController flows VID/PID */
+            vendor = USB_VENDOR_SONY;
+            product = USB_PRODUCT_SONY_DS4_SLIM;
+            if ( device->has_dualshock_touchpad ) {
+                subtype = 1;
+            } else {
+                subtype = 0;
+            }
         } else {
-            vendor = VENDOR_APPLE;
+            vendor = USB_VENDOR_APPLE;
             product = 1;
             subtype = 1;
         }
@@ -220,7 +263,7 @@ IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCController *controlle
         nbuttons += 7;
         device->uses_pause_handler = SDL_TRUE;
 
-        vendor = VENDOR_APPLE;
+        vendor = USB_VENDOR_APPLE;
         product = 2;
         subtype = 2;
         device->naxes = 0; /* no traditional analog inputs */
@@ -239,7 +282,7 @@ IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCController *controlle
         ++nbuttons;
         device->uses_pause_handler = SDL_TRUE;
 
-        vendor = VENDOR_APPLE;
+        vendor = USB_VENDOR_APPLE;
         product = 3;
         subtype = 3;
         device->naxes = 2; /* treat the touch surface as two axes */
@@ -700,6 +743,37 @@ IOS_MFIJoystickUpdate(SDL_Joystick * joystick)
                     buttons[button_count++] = gamepad.buttonMenu.isPressed;
                 }
             }
+
+#ifdef ENABLE_PHYSICAL_INPUT_PROFILE
+            if (joystick->hwdata->has_dualshock_touchpad) {
+                if (joystick->hwdata->button_mask & (1 << SDL_CONTROLLER_BUTTON_AUX1)) {
+                    buttons[button_count++] = controller.physicalInputProfile.buttons[GCInputDualShockTouchpadButton].isPressed;
+                }
+            }
+
+            if (joystick->hwdata->has_xbox_paddles) {
+                if (joystick->hwdata->button_mask & (1 << SDL_CONTROLLER_BUTTON_AUX1)) {
+                    buttons[button_count++] = controller.physicalInputProfile.buttons[GCInputXboxPaddleOne].isPressed;
+                }
+                if (joystick->hwdata->button_mask & (1 << SDL_CONTROLLER_BUTTON_AUX2)) {
+                    buttons[button_count++] = controller.physicalInputProfile.buttons[GCInputXboxPaddleTwo].isPressed;
+                }
+                if (joystick->hwdata->button_mask & (1 << SDL_CONTROLLER_BUTTON_AUX3)) {
+                    buttons[button_count++] = controller.physicalInputProfile.buttons[GCInputXboxPaddleThree].isPressed;
+                }
+                if (joystick->hwdata->button_mask & (1 << SDL_CONTROLLER_BUTTON_AUX4)) {
+                    buttons[button_count++] = controller.physicalInputProfile.buttons[GCInputXboxPaddleFour].isPressed;
+                }
+
+                /*
+                SDL_Log("Paddles: [%d,%d,%d,%d]",
+                    controller.physicalInputProfile.buttons[GCInputXboxPaddleOne].isPressed,
+                    controller.physicalInputProfile.buttons[GCInputXboxPaddleTwo].isPressed,
+                    controller.physicalInputProfile.buttons[GCInputXboxPaddleThree].isPressed,
+                    controller.physicalInputProfile.buttons[GCInputXboxPaddleFour].isPressed);
+                */
+            }
+#endif
 #pragma clang diagnostic pop
 
             hatstate = IOS_MFIJoystickHatStateForDPad(gamepad.dpad);
diff --git a/src/joystick/iphoneos/SDL_sysjoystick_c.h b/src/joystick/iphoneos/SDL_sysjoystick_c.h
index 8dcdecc..c004fda 100644
--- a/src/joystick/iphoneos/SDL_sysjoystick_c.h
+++ b/src/joystick/iphoneos/SDL_sysjoystick_c.h
@@ -47,7 +47,9 @@ typedef struct joystick_hwdata
     int naxes;
     int nbuttons;
     int nhats;
-    Uint16 button_mask;
+    Uint32 button_mask;
+    SDL_bool has_dualshock_touchpad;
+    SDL_bool has_xbox_paddles;
 
     struct joystick_hwdata *next;
 } joystick_hwdata;
diff --git a/src/joystick/usb_ids.h b/src/joystick/usb_ids.h
index 9762730..d1981b4 100644
--- a/src/joystick/usb_ids.h
+++ b/src/joystick/usb_ids.h
@@ -24,6 +24,7 @@
 
 /* Definitions of useful USB VID/PID values */
 
+#define USB_VENDOR_APPLE        0x05ac
 #define USB_VENDOR_HYPERKIN     0x2e24
 #define USB_VENDOR_MICROSOFT    0x045e
 #define USB_VENDOR_NINTENDO     0x057e