diff --git a/src/joystick/SDL_gamecontrollerdb.h b/src/joystick/SDL_gamecontrollerdb.h index 866b03b95..a2514d771 100644 --- a/src/joystick/SDL_gamecontrollerdb.h +++ b/src/joystick/SDL_gamecontrollerdb.h @@ -377,6 +377,7 @@ static const char *s_ControllerMappings [] = "030000006f0e00001302000000010000,Afterglow,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,", "03000000100000008200000011010000,Akishop Customs PS360+ v1.66,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,", "03000000b40400000a01000000010000,CYPRESS USB Gamepad,a:b0,b:b1,back:b5,guide:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,x:b3,y:b4,", + "03000000ffff0000ffff000000010000,Chinese-made Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,", "03000000e82000006058000001010000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,", "03000000260900008888000000010000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,", "03000000a306000022f6000011010000,Cyborg V.3 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,", @@ -567,7 +568,6 @@ static const char *s_ControllerMappings [] = "050000006964726f69643a636f6e0000,idroid:con,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", "03000000b50700001503000010010000,impact,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,", "030000009b2800000300000001010000,raphnet.net 4nes4snes v1.5,a:b0,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,", - "03000000ffff0000ffff000000010000,Chinese-made Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,", #endif #if defined(__ANDROID__) "05000000d6020000e5890000dfff3f00,GPD XD Plus,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,", @@ -588,15 +588,14 @@ static const char *s_ControllerMappings [] = "050000005e04000091020000ff073f00,Xbox Wireless Controller,a:b0,b:b1,back:b4,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,", /* The DPAD doesn't seem to work on this controller on Android TV? */ #endif #if defined(SDL_JOYSTICK_MFI) - "05000000ac0500000100000000006d01,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,x:b2,y:b3,", - "05000000ac0500000200000000006d02,*,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,", - "05000000ac0500000400000000006d04,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,x:b2,y:b3,", - "05000000ac0500000500000000006d05,*,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,", - "030000004c050000cc09000000000000,DUALSHOCK 4 Wireless Controller,a:b1,b:b2,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,", - "05000000ac0500000300000000006d03,Remote,a:b0,b:b2,leftx:a0,lefty:a1,", + "05000000ac050000010000004f066d01,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,x:b2,y:b3,", + "05000000ac05000001000000cf076d01,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,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,", + "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,", - "030000005e040000e002000000000000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b9,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,", #endif #if defined(SDL_JOYSTICK_EMSCRIPTEN) "default,Standard Gamepad,a:b0,b:b1,back:b8,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b16,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,", diff --git a/src/joystick/iphoneos/SDL_sysjoystick.m b/src/joystick/iphoneos/SDL_sysjoystick.m index d4b145ac0..9548b7d87 100644 --- a/src/joystick/iphoneos/SDL_sysjoystick.m +++ b/src/joystick/iphoneos/SDL_sysjoystick.m @@ -52,30 +52,24 @@ static id disconnectObserver = nil; #include #include -// remove compilation warnings for strict builds by defining these selectors, even though -// they are only ever used indirectly through objc_msgSend +/* remove compilation warnings for strict builds by defining these selectors, even though + * they are only ever used indirectly through objc_msgSend + */ @interface GCExtendedGamepad (SDL) -#if (__IPHONE_OS_VERSION_MAX_ALLOWED < 130000) || (__MAC_OS_VERSION_MAX_ALLOWED < 1500000) -@property (nonatomic, readonly) GCControllerButtonInput *buttonMenu; -@property (nonatomic, readonly, nullable) GCControllerButtonInput *buttonOptions; -#endif -#if (__IPHONE_OS_VERSION_MAX_ALLOWED < 121000) || (__MAC_OS_VERSION_MAX_ALLOWED < 1401000) +#if (__IPHONE_OS_VERSION_MAX_ALLOWED < 121000) || (__APPLETV_OS_VERSION_MAX_ALLOWED < 121000) || (__MAC_OS_VERSION_MAX_ALLOWED < 1401000) @property (nonatomic, readonly, nullable) GCControllerButtonInput *leftThumbstickButton; @property (nonatomic, readonly, nullable) GCControllerButtonInput *rightThumbstickButton; #endif +#if (__IPHONE_OS_VERSION_MAX_ALLOWED < 130000) || (__APPLETV_OS_VERSION_MAX_ALLOWED < 130000) || (__MAC_OS_VERSION_MAX_ALLOWED < 1500000) +@property (nonatomic, readonly) GCControllerButtonInput *buttonMenu; +@property (nonatomic, readonly, nullable) GCControllerButtonInput *buttonOptions; +#endif +@end +@interface GCMicroGamepad (SDL) +#if (__IPHONE_OS_VERSION_MAX_ALLOWED < 130000) || (__APPLETV_OS_VERSION_MAX_ALLOWED < 130000) || (__MAC_OS_VERSION_MAX_ALLOWED < 1500000) +@property (nonatomic, readonly) GCControllerButtonInput *buttonMenu; +#endif @end - -#define BUTTON_INDEX_A 0 -#define BUTTON_INDEX_B 1 -#define BUTTON_INDEX_X 2 -#define BUTTON_INDEX_Y 3 -#define BUTTON_INDEX_LEFT_SHOULDER 4 -#define BUTTON_INDEX_RIGHT_SHOULDER 5 -#define BUTTON_INDEX_GUIDE 6 -#define BUTTON_INDEX_LEFT_THUMBSTICK 7 -#define BUTTON_INDEX_RIGHT_THUMBSTICK 8 -#define BUTTON_INDEX_START 9 -#define BUTTON_INDEX_BACK 10 #endif /* SDL_JOYSTICK_MFI */ @@ -116,7 +110,6 @@ IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCController *controlle Uint16 *guid16 = (Uint16 *)device->guid.data; Uint16 vendor = 0; Uint16 product = 0; - Uint16 version = 0; Uint8 subtype = 0; const char *name = NULL; @@ -135,61 +128,104 @@ IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCController *controlle device->name = SDL_strdup(name); if (controller.extendedGamepad) { - int nbuttons = 7; /* ABXY, shoulder buttons, pause button */ + GCExtendedGamepad *gamepad = controller.extendedGamepad; + int nbuttons = 0; - if ([controller.extendedGamepad respondsToSelector:@selector(buttonMenu)] - && ((id (*)(id, SEL))objc_msgSend)(controller.extendedGamepad, @selector(buttonMenu))) { - // if we see .buttonMenu, then .buttonOption, .leftThumbstickButton (L3) & .rightThumbstickButton (R3) - // also exist (ios13+, macOS10.15+), though some may be nil, hold a spot for them - nbuttons = 11; - } else if ([controller.extendedGamepad respondsToSelector:@selector(leftThumbstickButton)] - && ((id (*)(id, SEL))objc_msgSend)(controller.extendedGamepad, @selector(leftThumbstickButton))) { - // if we didn't see .buttonMenu but do see .leftThumbstickButton (L3), then .rightThumbstickButton (R3) - // also exists (ios12.1+, macos10.14.1+). unlikely for R3 to be nil if L3 is not, but update code - // will never report a button change for R3 even so - nbuttons = 9; + /* 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); + device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_X); + device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_Y); + device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_LEFTSHOULDER); + device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_RIGHTSHOULDER); + nbuttons += 6; + + /* These buttons are available on some newer controllers */ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunguarded-availability-new" + if ([gamepad respondsToSelector:@selector(leftThumbstickButton)] && gamepad.leftThumbstickButton) { + device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_LEFTSTICK); + ++nbuttons; } + if ([gamepad respondsToSelector:@selector(rightThumbstickButton)] && gamepad.rightThumbstickButton) { + device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_RIGHTSTICK); + ++nbuttons; + } + if ([gamepad respondsToSelector:@selector(buttonOptions)] && gamepad.buttonOptions) { + device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_BACK); + ++nbuttons; + } + if ([gamepad respondsToSelector:@selector(buttonMenu)] && gamepad.buttonMenu) { + device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_START); + ++nbuttons; + } else { + device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_START); + ++nbuttons; + device->uses_pause_handler = SDL_TRUE; + } +#pragma clang diagnostic pop if ([controller.vendorName containsString: @"Xbox"]) { vendor = VENDOR_MICROSOFT; - product = 0x02E0; // assume Xbox One S BLE Controller unless/until GCController flows VID/PID + product = 0x02E0; /* Assume Xbox One S BLE Controller unless/until GCController flows VID/PID */ } else if ([controller.vendorName containsString: @"DUALSHOCK"]) { vendor = VENDOR_SONY; - product = 0x09CC; // assume DS4 Slim unless/until GCController flows VID/PID - } else if (nbuttons == 9) { - // unknown MFi controller with L3/R3 buttons (e.g. Rotor Riot) - vendor = VENDOR_APPLE; - product = 4; - subtype = 4; - } else if (nbuttons == 11) { - // unkonwn MFi controller with L3/R3 and menu/options buttons (no known instances, future proofing) - vendor = VENDOR_APPLE; - product = 5; - subtype = 5; + product = 0x09CC; /* Assume DS4 Slim unless/until GCController flows VID/PID */ } else { vendor = VENDOR_APPLE; product = 1; subtype = 1; } + device->naxes = 6; /* 2 thumbsticks and 2 triggers */ device->nhats = 1; /* d-pad */ device->nbuttons = nbuttons; + } else if (controller.gamepad) { + int nbuttons = 0; + + /* 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); + device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_X); + device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_Y); + device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_LEFTSHOULDER); + device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_RIGHTSHOULDER); + device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_START); + nbuttons += 7; + device->uses_pause_handler = SDL_TRUE; + vendor = VENDOR_APPLE; product = 2; subtype = 2; device->naxes = 0; /* no traditional analog inputs */ device->nhats = 1; /* d-pad */ - device->nbuttons = 7; /* ABXY, shoulder buttons, pause button */ + device->nbuttons = nbuttons; } #if TARGET_OS_TV else if (controller.microGamepad) { + GCMicroGamepad *gamepad = controller.microGamepad; + int nbuttons = 0; + + device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_A); + device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_B); /* Button X on microGamepad */ + nbuttons += 2; + + if ([gamepad respondsToSelector:@selector(buttonMenu)] && gamepad.buttonMenu) { + device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_START); + ++nbuttons; + } else { + device->button_mask |= (1 << SDL_CONTROLLER_BUTTON_START); + ++nbuttons; + device->uses_pause_handler = SDL_TRUE; + } + vendor = VENDOR_APPLE; product = 3; subtype = 3; device->naxes = 2; /* treat the touch surface as two axes */ device->nhats = 0; /* apparently the touch surface-as-dpad is buggy */ - device->nbuttons = 3; /* AX, pause button */ + device->nbuttons = nbuttons; controller.microGamepad.allowsRotation = SDL_GetHintBoolean(SDL_HINT_APPLE_TV_REMOTE_ALLOW_ROTATION, SDL_FALSE); } @@ -203,12 +239,14 @@ IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCController *controlle *guid16++ = 0; *guid16++ = SDL_SwapLE16(product); *guid16++ = 0; - *guid16++ = SDL_SwapLE16(version); - *guid16++ = 0; - /* Note that this is an MFI controller and what subtype it is */ - device->guid.data[14] = 'm'; - device->guid.data[15] = subtype; + *guid16++ = SDL_SwapLE16(device->button_mask); + + if (subtype != 0) { + /* Note that this is an MFI controller and what subtype it is */ + device->guid.data[14] = 'm'; + device->guid.data[15] = subtype; + } /* This will be set when the first button press of the controller is * detected. */ @@ -425,7 +463,8 @@ IOS_JoystickGetDeviceName(int device_index) static int IOS_JoystickGetDevicePlayerIndex(int device_index) { - return -1; + SDL_JoystickDeviceItem *device = GetDeviceForIndex(device_index); + return device ? (int)device->controller.playerIndex : -1; } static SDL_JoystickGUID @@ -479,12 +518,14 @@ IOS_JoystickOpen(SDL_Joystick * joystick, int device_index) #endif /* !TARGET_OS_TV */ } else { #ifdef SDL_JOYSTICK_MFI - GCController *controller = device->controller; - controller.controllerPausedHandler = ^(GCController *c) { - if (joystick->hwdata) { - ++joystick->hwdata->num_pause_presses; - } - }; + if (device->uses_pause_handler) { + GCController *controller = device->controller; + controller.controllerPausedHandler = ^(GCController *c) { + if (joystick->hwdata) { + ++joystick->hwdata->num_pause_presses; + } + }; + } #endif /* SDL_JOYSTICK_MFI */ } } @@ -574,6 +615,7 @@ IOS_MFIJoystickUpdate(SDL_Joystick * joystick) Uint8 hatstate = SDL_HAT_CENTERED; int i; int updateplayerindex = 0; + int pause_button_index = 0; if (controller.extendedGamepad) { GCExtendedGamepad *gamepad = controller.extendedGamepad; @@ -590,24 +632,37 @@ IOS_MFIJoystickUpdate(SDL_Joystick * joystick) /* Button order matches the XInput Windows mappings. */ Uint8 buttons[joystick->nbuttons]; - buttons[BUTTON_INDEX_A] = gamepad.buttonA.isPressed; - buttons[BUTTON_INDEX_B] = gamepad.buttonB.isPressed; - buttons[BUTTON_INDEX_X] = gamepad.buttonX.isPressed; - buttons[BUTTON_INDEX_Y] = gamepad.buttonY.isPressed; - buttons[BUTTON_INDEX_LEFT_SHOULDER] = gamepad.leftShoulder.isPressed; - buttons[BUTTON_INDEX_RIGHT_SHOULDER] = gamepad.rightShoulder.isPressed; - buttons[BUTTON_INDEX_GUIDE] = joystick->delayed_guide_button; + int button_count = 0; - // previously checked for availability of these iOS12.1+/macOS10.14.1+ or iOS13+/macOS10.15+ - // selectors. they exist but may be nil, in which case objc_msgSend will return 0/false for isPressed - if (joystick->nbuttons > 8) { - buttons[BUTTON_INDEX_LEFT_THUMBSTICK] = ((Uint8 (*)(id, SEL))objc_msgSend)( ((id (*)(id, SEL))objc_msgSend)(gamepad, @selector(leftThumbstickButton)), @selector(isPressed) ); - buttons[BUTTON_INDEX_RIGHT_THUMBSTICK] = ((Uint8 (*)(id, SEL))objc_msgSend)( ((id (*)(id, SEL))objc_msgSend)(gamepad, @selector(rightThumbstickButton)), @selector(isPressed) ); + /* These buttons are part of the original MFi spec */ + buttons[button_count++] = gamepad.buttonA.isPressed; + buttons[button_count++] = gamepad.buttonB.isPressed; + buttons[button_count++] = gamepad.buttonX.isPressed; + buttons[button_count++] = gamepad.buttonY.isPressed; + buttons[button_count++] = gamepad.leftShoulder.isPressed; + buttons[button_count++] = gamepad.rightShoulder.isPressed; + + /* These buttons are available on some newer controllers */ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunguarded-availability-new" + if (joystick->hwdata->button_mask & (1 << SDL_CONTROLLER_BUTTON_LEFTSTICK)) { + buttons[button_count++] = gamepad.leftThumbstickButton.isPressed; } - if (joystick->nbuttons > 10) { - buttons[BUTTON_INDEX_START] = ((Uint8 (*)(id, SEL))objc_msgSend)( ((id (*)(id, SEL))objc_msgSend)(gamepad, @selector(buttonMenu)), @selector(isPressed) ); - buttons[BUTTON_INDEX_BACK] = ((Uint8 (*)(id, SEL))objc_msgSend)( ((id (*)(id, SEL))objc_msgSend)(gamepad, @selector(buttonOptions)), @selector(isPressed) ); + if (joystick->hwdata->button_mask & (1 << SDL_CONTROLLER_BUTTON_RIGHTSTICK)) { + buttons[button_count++] = gamepad.rightThumbstickButton.isPressed; } + if (joystick->hwdata->button_mask & (1 << SDL_CONTROLLER_BUTTON_BACK)) { + buttons[button_count++] = gamepad.buttonOptions.isPressed; + } + /* This must be the last button, so we can optionally handle it with pause_button_index below */ + if (joystick->hwdata->button_mask & (1 << SDL_CONTROLLER_BUTTON_START)) { + if (joystick->hwdata->uses_pause_handler) { + pause_button_index = button_count; + } else { + buttons[button_count++] = gamepad.buttonMenu.isPressed; + } + } +#pragma clang diagnostic pop hatstate = IOS_MFIJoystickHatStateForDPad(gamepad.dpad); @@ -621,7 +676,7 @@ IOS_MFIJoystickUpdate(SDL_Joystick * joystick) SDL_PrivateJoystickAxis(joystick, i, axes[i]); } - for (i = 0; i < SDL_arraysize(buttons); i++) { + for (i = 0; i < button_count; i++) { updateplayerindex |= (joystick->buttons[i] != buttons[i]); SDL_PrivateJoystickButton(joystick, i, buttons[i]); } @@ -629,17 +684,19 @@ IOS_MFIJoystickUpdate(SDL_Joystick * joystick) GCGamepad *gamepad = controller.gamepad; /* Button order matches the XInput Windows mappings. */ - Uint8 buttons[] = { - gamepad.buttonA.isPressed, gamepad.buttonB.isPressed, - gamepad.buttonX.isPressed, gamepad.buttonY.isPressed, - gamepad.leftShoulder.isPressed, - gamepad.rightShoulder.isPressed, - joystick->delayed_guide_button, - }; + Uint8 buttons[joystick->nbuttons]; + int button_count = 0; + buttons[button_count++] = gamepad.buttonA.isPressed; + buttons[button_count++] = gamepad.buttonB.isPressed; + buttons[button_count++] = gamepad.buttonX.isPressed; + buttons[button_count++] = gamepad.buttonY.isPressed; + buttons[button_count++] = gamepad.leftShoulder.isPressed; + buttons[button_count++] = gamepad.rightShoulder.isPressed; + pause_button_index = button_count; hatstate = IOS_MFIJoystickHatStateForDPad(gamepad.dpad); - for (i = 0; i < SDL_arraysize(buttons); i++) { + for (i = 0; i < button_count; i++) { updateplayerindex |= (joystick->buttons[i] != buttons[i]); SDL_PrivateJoystickButton(joystick, i, buttons[i]); } @@ -658,13 +715,23 @@ IOS_MFIJoystickUpdate(SDL_Joystick * joystick) SDL_PrivateJoystickAxis(joystick, i, axes[i]); } - Uint8 buttons[] = { - gamepad.buttonA.isPressed, - gamepad.buttonX.isPressed, - joystick->delayed_guide_button, - }; + Uint8 buttons[joystick->nbuttons]; + int button_count = 0; + buttons[button_count++] = gamepad.buttonA.isPressed; + buttons[button_count++] = gamepad.buttonX.isPressed; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunguarded-availability-new" + /* This must be the last button, so we can optionally handle it with pause_button_index below */ + if (joystick->hwdata->button_mask & (1 << SDL_CONTROLLER_BUTTON_START)) { + if (joystick->hwdata->uses_pause_handler) { + pause_button_index = button_count; + } else { + buttons[button_count++] = gamepad.buttonMenu.isPressed; + } + } +#pragma clang diagnostic pop - for (i = 0; i < SDL_arraysize(buttons); i++) { + for (i = 0; i < button_count; i++) { updateplayerindex |= (joystick->buttons[i] != buttons[i]); SDL_PrivateJoystickButton(joystick, i, buttons[i]); } @@ -676,12 +743,14 @@ IOS_MFIJoystickUpdate(SDL_Joystick * joystick) SDL_PrivateJoystickHat(joystick, 0, hatstate); } - for (i = 0; i < joystick->hwdata->num_pause_presses; i++) { - SDL_PrivateJoystickButton(joystick, BUTTON_INDEX_GUIDE, SDL_PRESSED); - SDL_PrivateJoystickButton(joystick, BUTTON_INDEX_GUIDE, SDL_RELEASED); - updateplayerindex = YES; + if (joystick->hwdata->uses_pause_handler) { + for (i = 0; i < joystick->hwdata->num_pause_presses; i++) { + SDL_PrivateJoystickButton(joystick, pause_button_index, SDL_PRESSED); + SDL_PrivateJoystickButton(joystick, pause_button_index, SDL_RELEASED); + updateplayerindex = YES; + } + joystick->hwdata->num_pause_presses = 0; } - joystick->hwdata->num_pause_presses = 0; if (updateplayerindex && controller.playerIndex == -1) { BOOL usedPlayerIndexSlots[4] = {NO, NO, NO, NO}; diff --git a/src/joystick/iphoneos/SDL_sysjoystick_c.h b/src/joystick/iphoneos/SDL_sysjoystick_c.h index d8df85802..38e9a0ef1 100644 --- a/src/joystick/iphoneos/SDL_sysjoystick_c.h +++ b/src/joystick/iphoneos/SDL_sysjoystick_c.h @@ -34,6 +34,7 @@ typedef struct joystick_hwdata SDL_bool remote; GCController __unsafe_unretained *controller; + SDL_bool uses_pause_handler; int num_pause_presses; Uint32 pause_button_down_time; @@ -45,6 +46,7 @@ typedef struct joystick_hwdata int naxes; int nbuttons; int nhats; + Uint16 button_mask; struct joystick_hwdata *next; } joystick_hwdata;