Added support for the Nintendo Switch Joy-Con Controllers on iOS and tvOS 16
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
diff --git a/src/joystick/SDL_gamecontrollerdb.h b/src/joystick/SDL_gamecontrollerdb.h
index 1fa0347..1e7f1f4 100644
--- a/src/joystick/SDL_gamecontrollerdb.h
+++ b/src/joystick/SDL_gamecontrollerdb.h
@@ -913,6 +913,11 @@ 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,",
+ "050000007e050000062000004f060000,Nintendo Switch Joy-Con (L),+leftx:h0.1,+lefty:h0.2,-leftx:h0.4,-lefty:h0.8,dpdown:b2,dpleft:b0,dpright:b3,dpup:b1,leftshoulder:b4,misc1:b6,rightshoulder:b5,",
+ "050000007e0500000e200000df070000,Nintendo Switch Joy-Con (L/R),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,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
+ "050000007e0500000e200000df070000,Nintendo Switch Joy-Con (L/R),a:b1,b:b0,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:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
+ "050000007e050000072000004f060000,Nintendo Switch Joy-Con (R),+rightx:h0.4,+righty:h0.8,-rightx:h0.1,-righty:h0.2,a:b0,b:b1,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b2,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
+ "050000007e050000072000004f060000,Nintendo Switch Joy-Con (R),+rightx:h0.4,+righty:h0.8,-rightx:h0.1,-righty:h0.2,a:b1,b:b0,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000007e05000009200000ff870000,Nintendo Switch Pro Controller,a:b1,b:b0,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:b3,y:b2,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000007e05000009200000ff870000,Nintendo Switch Pro 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,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"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,",
diff --git a/src/joystick/iphoneos/SDL_mfijoystick.m b/src/joystick/iphoneos/SDL_mfijoystick.m
index 639ee27..ad54284 100644
--- a/src/joystick/iphoneos/SDL_mfijoystick.m
+++ b/src/joystick/iphoneos/SDL_mfijoystick.m
@@ -188,6 +188,36 @@ IsControllerSwitchPro(GCController *controller)
return FALSE;
}
static BOOL
+IsControllerSwitchJoyConL(GCController *controller)
+{
+ if (@available(macOS 10.15, iOS 13.0, tvOS 13.0, *)) {
+ if ([controller.productCategory isEqualToString:@"Nintendo Switch Joy-Con (L)"]) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+static BOOL
+IsControllerSwitchJoyConR(GCController *controller)
+{
+ if (@available(macOS 10.15, iOS 13.0, tvOS 13.0, *)) {
+ if ([controller.productCategory isEqualToString:@"Nintendo Switch Joy-Con (R)"]) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+static BOOL
+IsControllerSwitchJoyConPair(GCController *controller)
+{
+ if (@available(macOS 10.15, iOS 13.0, tvOS 13.0, *)) {
+ if ([controller.productCategory isEqualToString:@"Nintendo Switch Joy-Con (L/R)"]) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+static BOOL
IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCController *controller)
{
Uint16 *guid16 = (Uint16 *)device->guid.data;
@@ -222,8 +252,9 @@ IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCController *controlle
BOOL is_ps4 = IsControllerPS4(controller);
BOOL is_ps5 = IsControllerPS5(controller);
BOOL is_switch_pro = IsControllerSwitchPro(controller);
+ BOOL is_switch_joycon_pair = IsControllerSwitchJoyConPair(controller);
#if TARGET_OS_TV
- BOOL is_MFi = (!is_xbox && !is_ps4 && !is_ps5 && !is_switch_pro);
+ BOOL is_MFi = (!is_xbox && !is_ps4 && !is_ps5 && !is_switch_pro && !is_switch_joycon_pair);
#endif
int nbuttons = 0;
BOOL has_direct_menu;
@@ -262,7 +293,8 @@ IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCController *controlle
device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_BACK);
++nbuttons;
}
- if ([gamepad respondsToSelector:@selector(buttonHome)] && gamepad.buttonHome) {
+ /* The Nintendo Switch JoyCon home button doesn't ever show as being held down */
+ if ([gamepad respondsToSelector:@selector(buttonHome)] && gamepad.buttonHome && !is_switch_joycon_pair) {
device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_GUIDE);
++nbuttons;
}
@@ -347,6 +379,10 @@ IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCController *controlle
vendor = USB_VENDOR_NINTENDO;
product = USB_PRODUCT_NINTENDO_SWITCH_PRO;
subtype = 0;
+ } else if (is_switch_joycon_pair) {
+ vendor = USB_VENDOR_NINTENDO;
+ product = USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_GRIP;
+ subtype = 0;
} else {
vendor = USB_VENDOR_APPLE;
product = 1;
@@ -367,8 +403,24 @@ IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCController *controlle
device->nbuttons = nbuttons;
} else if (controller.gamepad) {
+ BOOL is_switch_joyconL = IsControllerSwitchJoyConL(controller);
+ BOOL is_switch_joyconR = IsControllerSwitchJoyConR(controller);
int nbuttons = 0;
+ if (is_switch_joyconL) {
+ vendor = USB_VENDOR_NINTENDO;
+ product = USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_LEFT;
+ subtype = 0;
+ } else if (is_switch_joyconR) {
+ vendor = USB_VENDOR_NINTENDO;
+ product = USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_RIGHT;
+ subtype = 0;
+ } else {
+ vendor = USB_VENDOR_APPLE;
+ product = 2;
+ subtype = 2;
+ }
+
/* These buttons are part of the original MFi spec */
device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_A);
device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_B);
@@ -380,9 +432,6 @@ IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCController *controlle
nbuttons += 7;
device->uses_pause_handler = SDL_TRUE;
- vendor = USB_VENDOR_APPLE;
- product = 2;
- subtype = 2;
device->naxes = 0; /* no traditional analog inputs */
device->nhats = 1; /* d-pad */
device->nbuttons = nbuttons;
@@ -877,6 +926,23 @@ IOS_MFIJoystickUpdate(SDL_Joystick *joystick)
int i;
int pause_button_index = 0;
+#ifdef DEBUG_CONTROLLER_STATE
+ if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) {
+ if (controller.physicalInputProfile) {
+ for (id key in controller.physicalInputProfile.buttons) {
+ GCControllerButtonInput *button = controller.physicalInputProfile.buttons[key];
+ if (button.isPressed)
+ NSLog(@"Button %@ = %s\n", key, button.isPressed ? "pressed" : "released");
+ }
+ for (id key in controller.physicalInputProfile.axes) {
+ GCControllerAxisInput *axis = controller.physicalInputProfile.axes[key];
+ if (axis.value != 0.0f)
+ NSLog(@"Axis %@ = %.2f\n", key, axis.value);
+ }
+ }
+ }
+#endif
+
if (controller.extendedGamepad) {
GCExtendedGamepad *gamepad = controller.extendedGamepad;