SDL: Added support for the Xbox Series X controller on iOS and tvOS

From 947ad6e13a7baffa8b1b84258cabd9ea74c7f99a Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Mon, 12 Jul 2021 17:57:21 -0700
Subject: [PATCH] Added support for the Xbox Series X controller on iOS and
 tvOS

---
 src/joystick/SDL_gamecontrollerdb.h       |  1 +
 src/joystick/iphoneos/SDL_mfijoystick.m   | 36 ++++++++++++++++-------
 src/joystick/iphoneos/SDL_mfijoystick_c.h |  1 +
 3 files changed, 28 insertions(+), 10 deletions(-)

diff --git a/src/joystick/SDL_gamecontrollerdb.h b/src/joystick/SDL_gamecontrollerdb.h
index c711e8ef9c..05933db601 100644
--- a/src/joystick/SDL_gamecontrollerdb.h
+++ b/src/joystick/SDL_gamecontrollerdb.h
@@ -864,6 +864,7 @@ static const char *s_ControllerMappings [] =
     "05000000ac0500000300000043006d03,Remote,a:b0,b:b2,leftx:a0,lefty:a1,",
     "050000005e040000050b0000df070001,Xbox Elite 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,paddle1:b10,paddle2:b12,paddle3:b11,paddle4:b13,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,",
     "050000005e040000050b0000ff070001,Xbox Elite 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,paddle1:b11,paddle2:b13,paddle3:b12,paddle4:b14,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,",
+    "050000005e040000130b0000ff870001,Xbox Series X 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,misc1:b11,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_mfijoystick.m b/src/joystick/iphoneos/SDL_mfijoystick.m
index 654f4967a9..9dae6f712b 100644
--- a/src/joystick/iphoneos/SDL_mfijoystick.m
+++ b/src/joystick/iphoneos/SDL_mfijoystick.m
@@ -53,6 +53,7 @@
 
 static id connectObserver = nil;
 static id disconnectObserver = nil;
+static NSString *GCInputXboxShareButton = @"Button Share";
 
 #include <Availability.h>
 #include <objc/message.h>
@@ -228,6 +229,11 @@ @interface GCMicroGamepad (SDL)
                 device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_PADDLE4);
                 ++nbuttons;
             }
+            if (controller.physicalInputProfile.buttons[GCInputXboxShareButton] != nil) {
+                device->has_xbox_share_button = SDL_TRUE;
+                device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_MISC1);
+                ++nbuttons;
+            }
         }
 #endif
 #pragma clang diagnostic pop
@@ -238,6 +244,10 @@ @interface GCMicroGamepad (SDL)
                 /* 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 if (device->has_xbox_share_button) {
+                /* Assume Xbox Series X Controller unless/until GCController flows VID/PID */
+                product = USB_PRODUCT_XBOX_SERIES_X_BLUETOOTH;
+                subtype = 1;
             } else {
                 /* Assume Xbox One S BLE Controller unless/until GCController flows VID/PID */
                 product = USB_PRODUCT_XBOX_ONE_S_REV1_BLUETOOTH;
@@ -255,7 +265,7 @@ @interface GCMicroGamepad (SDL)
         } else if (is_ps5) {
             vendor = USB_VENDOR_SONY;
             product = USB_PRODUCT_SONY_DS5;
-			subtype = 0;
+            subtype = 0;
         } else {
             vendor = USB_VENDOR_APPLE;
             product = 1;
@@ -665,12 +675,12 @@ static int is_macos11(void)
 #ifdef ENABLE_MFI_SYSTEM_GESTURE_STATE
             if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) {
                 GCController *controller = joystick->hwdata->controller;
-				if (controller.extendedGamepad) {
-					GCExtendedGamepad *gamepad = controller.extendedGamepad;
-					if ([gamepad.buttonOptions isBoundToSystemGesture]) {
-						gamepad.buttonOptions.preferredSystemGestureState = GCSystemGestureStateDisabled;
-					}
-				}
+                for (id key in controller.physicalInputProfile.buttons) {
+                    GCControllerButtonInput *button = controller.physicalInputProfile.buttons[key];
+                    if ([button isBoundToSystemGesture]) {
+                        button.preferredSystemGestureState = GCSystemGestureStateDisabled;
+                    }
+                }
             }
 #endif /* ENABLE_MFI_SYSTEM_GESTURE_STATE */
 
@@ -857,6 +867,10 @@ static int is_macos11(void)
                     controller.physicalInputProfile.buttons[GCInputXboxPaddleFour].isPressed);
                 */
             }
+
+            if (joystick->hwdata->has_xbox_share_button) {
+                buttons[button_count++] = controller.physicalInputProfile.buttons[GCInputXboxShareButton].isPressed;
+            }
 #endif
 #pragma clang diagnostic pop
 
@@ -1359,9 +1373,11 @@ -(void)cleanup
 #ifdef ENABLE_MFI_SYSTEM_GESTURE_STATE
             if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) {
                 GCController *controller = joystick->hwdata->controller;
-				if (controller.extendedGamepad) {
-					GCExtendedGamepad *gamepad = controller.extendedGamepad;
-					gamepad.buttonOptions.preferredSystemGestureState = GCSystemGestureStateEnabled;
+                for (id key in controller.physicalInputProfile.buttons) {
+                    GCControllerButtonInput *button = controller.physicalInputProfile.buttons[key];
+                    if ([button isBoundToSystemGesture]) {
+                        button.preferredSystemGestureState = GCSystemGestureStateEnabled;
+                    }
                 }
             }
 #endif /* ENABLE_MFI_SYSTEM_GESTURE_STATE */
diff --git a/src/joystick/iphoneos/SDL_mfijoystick_c.h b/src/joystick/iphoneos/SDL_mfijoystick_c.h
index d5257d8b83..ee30fadf49 100644
--- a/src/joystick/iphoneos/SDL_mfijoystick_c.h
+++ b/src/joystick/iphoneos/SDL_mfijoystick_c.h
@@ -50,6 +50,7 @@ typedef struct joystick_hwdata
     Uint32 button_mask;
     SDL_bool has_dualshock_touchpad;
     SDL_bool has_xbox_paddles;
+    SDL_bool has_xbox_share_button;
 
     struct joystick_hwdata *next;
 } joystick_hwdata;