Improved GCController handling on Apple platforms

Automatically map controllers as gamepads when using the GCController framework and prefer the physicalInputProfile when possible.

Testing with macOS 13.4.1, macOS 14.1.1, iOS 15.7.4, tvOS 17.1:
* iBuffalo Classic USB Gamepad (macOS only)
* Logitech F310 (macOS only)
* Apple TV remote (tvOS only)
* Nimbus MFi controller
* PS4 DualShock controller
* PS5 DualSense controller
* Xbox Series X controller
* Xbox Elite Series 2 controller
* Nintendo Switch Pro controller
* Nintendo Switch Joy-Con controllers

(cherry picked from commit 0fe5713964287b17e05eb09dd4f83d8580dba254)
Author: Sam Lantinga <slouken@libsdl.org>
Date:   Tue Nov 14 12:58:33 2023 -0800
This commit is contained in:
Sam Lantinga 2023-11-21 15:17:53 -08:00
parent 2d81beb819
commit dcd21d042f
5 changed files with 642 additions and 334 deletions

View file

@ -813,7 +813,7 @@ static ControllerMapping_t *SDL_PrivateGetControllerMappingForGUID(SDL_JoystickG
/* Try harder to get the best match, or create a mapping */ /* Try harder to get the best match, or create a mapping */
if (vendor && product) { if (SDL_JoystickGUIDUsesVersion(guid)) {
/* Try again, ignoring the version */ /* Try again, ignoring the version */
if (crc) { if (crc) {
mapping = SDL_PrivateMatchControllerMappingForGUID(guid, SDL_TRUE, SDL_FALSE); mapping = SDL_PrivateMatchControllerMappingForGUID(guid, SDL_TRUE, SDL_FALSE);
@ -1392,7 +1392,11 @@ static void SDL_PrivateAppendToMappingString(char *mapping_string,
(void)SDL_snprintf(buffer, sizeof(buffer), "b%i", mapping->target); (void)SDL_snprintf(buffer, sizeof(buffer), "b%i", mapping->target);
break; break;
case EMappingKind_Axis: case EMappingKind_Axis:
(void)SDL_snprintf(buffer, sizeof(buffer), "a%i", mapping->target); (void)SDL_snprintf(buffer, sizeof(buffer), "%sa%i%s",
mapping->half_axis_positive ? "+" :
mapping->half_axis_negative ? "-" : "",
mapping->target,
mapping->axis_reversed ? "~" : "");
break; break;
case EMappingKind_Hat: case EMappingKind_Hat:
(void)SDL_snprintf(buffer, sizeof(buffer), "h%i.%i", mapping->target >> 4, mapping->target & 0x0F); (void)SDL_snprintf(buffer, sizeof(buffer), "h%i.%i", mapping->target >> 4, mapping->target & 0x0F);
@ -1450,6 +1454,7 @@ static ControllerMapping_t *SDL_PrivateGenerateAutomaticControllerMapping(const
SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "righty", &raw_map->righty); SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "righty", &raw_map->righty);
SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "lefttrigger", &raw_map->lefttrigger); SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "lefttrigger", &raw_map->lefttrigger);
SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "righttrigger", &raw_map->righttrigger); SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "righttrigger", &raw_map->righttrigger);
SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "touchpad", &raw_map->touchpad);
return SDL_PrivateAddMappingForGUID(guid, mapping, &existing, SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT); return SDL_PrivateAddMappingForGUID(guid, mapping, &existing, SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT);
} }

View file

@ -2285,6 +2285,22 @@ SDL_GameControllerType SDL_GetJoystickGameControllerTypeFromGUID(SDL_JoystickGUI
return type; return type;
} }
SDL_bool SDL_JoystickGUIDUsesVersion(SDL_JoystickGUID guid)
{
Uint16 vendor, product;
if (SDL_IsJoystickMFI(guid)) {
/* The version bits are used as button capability mask */
return SDL_FALSE;
}
SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL, NULL);
if (vendor && product) {
return SDL_TRUE;
}
return SDL_FALSE;
}
SDL_bool SDL_IsJoystickXboxOne(Uint16 vendor_id, Uint16 product_id) SDL_bool SDL_IsJoystickXboxOne(Uint16 vendor_id, Uint16 product_id)
{ {
EControllerType eType = GuessControllerType(vendor_id, product_id); EControllerType eType = GuessControllerType(vendor_id, product_id);
@ -2463,6 +2479,11 @@ SDL_bool SDL_IsJoystickHIDAPI(SDL_JoystickGUID guid)
return (guid.data[14] == 'h') ? SDL_TRUE : SDL_FALSE; return (guid.data[14] == 'h') ? SDL_TRUE : SDL_FALSE;
} }
SDL_bool SDL_IsJoystickMFI(SDL_JoystickGUID guid)
{
return (guid.data[14] == 'm') ? SDL_TRUE : SDL_FALSE;
}
SDL_bool SDL_IsJoystickRAWINPUT(SDL_JoystickGUID guid) SDL_bool SDL_IsJoystickRAWINPUT(SDL_JoystickGUID guid)
{ {
return (guid.data[14] == 'r') ? SDL_TRUE : SDL_FALSE; return (guid.data[14] == 'r') ? SDL_TRUE : SDL_FALSE;

View file

@ -91,6 +91,9 @@ extern void SDL_SetJoystickGUIDCRC(SDL_JoystickGUID *guid, Uint16 crc);
extern SDL_GameControllerType SDL_GetJoystickGameControllerTypeFromVIDPID(Uint16 vendor, Uint16 product, const char *name, SDL_bool forUI); extern SDL_GameControllerType SDL_GetJoystickGameControllerTypeFromVIDPID(Uint16 vendor, Uint16 product, const char *name, SDL_bool forUI);
extern SDL_GameControllerType SDL_GetJoystickGameControllerTypeFromGUID(SDL_JoystickGUID guid, const char *name); extern SDL_GameControllerType SDL_GetJoystickGameControllerTypeFromGUID(SDL_JoystickGUID guid, const char *name);
/* Function to return whether a joystick GUID uses the version field */
extern SDL_bool SDL_JoystickGUIDUsesVersion(SDL_JoystickGUID guid);
/* Function to return whether a joystick is an Xbox One controller */ /* Function to return whether a joystick is an Xbox One controller */
extern SDL_bool SDL_IsJoystickXboxOne(Uint16 vendor_id, Uint16 product_id); extern SDL_bool SDL_IsJoystickXboxOne(Uint16 vendor_id, Uint16 product_id);
@ -131,6 +134,9 @@ extern SDL_bool SDL_IsJoystickWGI(SDL_JoystickGUID guid);
/* Function to return whether a joystick guid comes from the HIDAPI driver */ /* Function to return whether a joystick guid comes from the HIDAPI driver */
extern SDL_bool SDL_IsJoystickHIDAPI(SDL_JoystickGUID guid); extern SDL_bool SDL_IsJoystickHIDAPI(SDL_JoystickGUID guid);
/* Function to return whether a joystick guid comes from the MFI driver */
extern SDL_bool SDL_IsJoystickMFI(SDL_JoystickGUID guid);
/* Function to return whether a joystick guid comes from the RAWINPUT driver */ /* Function to return whether a joystick guid comes from the RAWINPUT driver */
extern SDL_bool SDL_IsJoystickRAWINPUT(SDL_JoystickGUID guid); extern SDL_bool SDL_IsJoystickRAWINPUT(SDL_JoystickGUID guid);
@ -175,16 +181,19 @@ extern SDL_bool SDL_PrivateJoystickValid(SDL_Joystick *joystick);
typedef enum typedef enum
{ {
EMappingKind_None = 0, EMappingKind_None,
EMappingKind_Button = 1, EMappingKind_Button,
EMappingKind_Axis = 2, EMappingKind_Axis,
EMappingKind_Hat = 3 EMappingKind_Hat,
} EMappingKind; } EMappingKind;
typedef struct _SDL_InputMapping typedef struct _SDL_InputMapping
{ {
EMappingKind kind; EMappingKind kind;
Uint8 target; Uint8 target;
SDL_bool axis_reversed;
SDL_bool half_axis_positive;
SDL_bool half_axis_negative;
} SDL_InputMapping; } SDL_InputMapping;
typedef struct _SDL_GamepadMapping typedef struct _SDL_GamepadMapping
@ -215,6 +224,7 @@ typedef struct _SDL_GamepadMapping
SDL_InputMapping righty; SDL_InputMapping righty;
SDL_InputMapping lefttrigger; SDL_InputMapping lefttrigger;
SDL_InputMapping righttrigger; SDL_InputMapping righttrigger;
SDL_InputMapping touchpad;
} SDL_GamepadMapping; } SDL_GamepadMapping;
/* Function to get autodetected gamepad controller mapping from the driver */ /* Function to get autodetected gamepad controller mapping from the driver */

File diff suppressed because it is too large Load diff

View file

@ -26,18 +26,18 @@
#include "SDL_stdinc.h" #include "SDL_stdinc.h"
#include "../SDL_sysjoystick.h" #include "../SDL_sysjoystick.h"
#include <CoreFoundation/CoreFoundation.h>
@class GCController; @class GCController;
typedef struct joystick_hwdata typedef struct joystick_hwdata
{ {
SDL_bool accelerometer; SDL_bool accelerometer;
SDL_bool remote;
GCController __unsafe_unretained *controller; GCController __unsafe_unretained *controller;
void *rumble; void *rumble;
SDL_bool uses_pause_handler; int pause_button_index;
int num_pause_presses; Uint32 pause_button_pressed;
Uint32 pause_button_down_time;
char *name; char *name;
SDL_Joystick *joystick; SDL_Joystick *joystick;
@ -48,6 +48,20 @@ typedef struct joystick_hwdata
int nbuttons; int nbuttons;
int nhats; int nhats;
Uint32 button_mask; Uint32 button_mask;
SDL_bool is_xbox;
SDL_bool is_ps4;
SDL_bool is_ps5;
SDL_bool is_switch_pro;
SDL_bool is_switch_joycon_pair;
SDL_bool is_switch_joyconL;
SDL_bool is_switch_joyconR;
SDL_bool is_stadia;
SDL_bool is_backbone_one;
int is_siri_remote;
NSArray *axes;
NSArray *buttons;
SDL_bool has_dualshock_touchpad; SDL_bool has_dualshock_touchpad;
SDL_bool has_xbox_paddles; SDL_bool has_xbox_paddles;
SDL_bool has_xbox_share_button; SDL_bool has_xbox_share_button;