mirror of
https://github.com/libsdl-org/SDL.git
synced 2025-05-22 12:48:28 +00:00
Try to dynamically create a default Android game controller mapping based on the buttons and axes on the controller.
Include the controller USB VID/PID in the GUID where possible, as we do on other platforms.
This commit is contained in:
parent
2419d26724
commit
9e651b6915
8 changed files with 404 additions and 81 deletions
|
@ -97,8 +97,8 @@ typedef struct _ControllerMapping_t
|
|||
|
||||
static SDL_JoystickGUID s_zeroGUID;
|
||||
static ControllerMapping_t *s_pSupportedControllers = NULL;
|
||||
static ControllerMapping_t *s_pDefaultMapping = NULL;
|
||||
static ControllerMapping_t *s_pXInputMapping = NULL;
|
||||
static ControllerMapping_t *s_pEmscriptenMapping = NULL;
|
||||
|
||||
/* The SDL game controller structure */
|
||||
struct _SDL_GameController
|
||||
|
@ -869,6 +869,117 @@ SDL_PrivateAddMappingForGUID(SDL_JoystickGUID jGUID, const char *mappingString,
|
|||
return pControllerMapping;
|
||||
}
|
||||
|
||||
#ifdef __ANDROID__
|
||||
/*
|
||||
* Helper function to guess at a mapping based on the elements reported for this controller
|
||||
*/
|
||||
static ControllerMapping_t *SDL_CreateMappingForAndroidController(const char *name, SDL_JoystickGUID guid)
|
||||
{
|
||||
SDL_bool existing;
|
||||
char name_string[128];
|
||||
char mapping_string[1024];
|
||||
int button_mask;
|
||||
int axis_mask;
|
||||
|
||||
button_mask = SDL_SwapLE16(*(Uint16*)(&guid.data[sizeof(guid.data)-4]));
|
||||
axis_mask = SDL_SwapLE16(*(Uint16*)(&guid.data[sizeof(guid.data)-2]));
|
||||
if (!button_mask && !axis_mask) {
|
||||
/* Accelerometer, shouldn't have a game controller mapping */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Remove any commas in the name */
|
||||
SDL_strlcpy(name_string, name, sizeof(name_string));
|
||||
{
|
||||
char *spot;
|
||||
for (spot = name_string; *spot; ++spot) {
|
||||
if (*spot == ',') {
|
||||
*spot = ' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
SDL_snprintf(mapping_string, sizeof(mapping_string), "none,%s,", name_string);
|
||||
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_A)) {
|
||||
SDL_strlcat(mapping_string, "a:b0,", sizeof(mapping_string));
|
||||
}
|
||||
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_B)) {
|
||||
SDL_strlcat(mapping_string, "b:b1,", sizeof(mapping_string));
|
||||
} else if (button_mask & (1 << SDL_CONTROLLER_BUTTON_BACK)) {
|
||||
/* Use the back button as "B" for easy UI navigation with TV remotes */
|
||||
SDL_strlcat(mapping_string, "b:b4,", sizeof(mapping_string));
|
||||
button_mask &= ~(1 << SDL_CONTROLLER_BUTTON_BACK);
|
||||
}
|
||||
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_X)) {
|
||||
SDL_strlcat(mapping_string, "x:b2,", sizeof(mapping_string));
|
||||
}
|
||||
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_Y)) {
|
||||
SDL_strlcat(mapping_string, "y:b3,", sizeof(mapping_string));
|
||||
}
|
||||
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_BACK)) {
|
||||
SDL_strlcat(mapping_string, "back:b4,", sizeof(mapping_string));
|
||||
}
|
||||
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_GUIDE)) {
|
||||
SDL_strlcat(mapping_string, "guide:b5,", sizeof(mapping_string));
|
||||
#if 0 /* Actually this will be done in Steam */
|
||||
} else if (button_mask & (1 << SDL_CONTROLLER_BUTTON_START)) {
|
||||
/* The guide button doesn't exist, use the start button instead,
|
||||
so you can do Steam guide button chords and open the Steam overlay.
|
||||
*/
|
||||
SDL_strlcat(mapping_string, "guide:b6,", sizeof(mapping_string));
|
||||
button_mask &= ~(1 << SDL_CONTROLLER_BUTTON_START);
|
||||
#endif
|
||||
}
|
||||
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_START)) {
|
||||
SDL_strlcat(mapping_string, "start:b6,", sizeof(mapping_string));
|
||||
}
|
||||
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_LEFTSTICK)) {
|
||||
SDL_strlcat(mapping_string, "leftstick:b7,", sizeof(mapping_string));
|
||||
}
|
||||
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_RIGHTSTICK)) {
|
||||
SDL_strlcat(mapping_string, "rightstick:b8,", sizeof(mapping_string));
|
||||
}
|
||||
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_LEFTSHOULDER)) {
|
||||
SDL_strlcat(mapping_string, "leftshoulder:b9,", sizeof(mapping_string));
|
||||
}
|
||||
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_RIGHTSHOULDER)) {
|
||||
SDL_strlcat(mapping_string, "rightshoulder:b10,", sizeof(mapping_string));
|
||||
}
|
||||
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_DPAD_UP)) {
|
||||
SDL_strlcat(mapping_string, "dpup:b11,", sizeof(mapping_string));
|
||||
}
|
||||
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_DPAD_DOWN)) {
|
||||
SDL_strlcat(mapping_string, "dpdown:b12,", sizeof(mapping_string));
|
||||
}
|
||||
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_DPAD_LEFT)) {
|
||||
SDL_strlcat(mapping_string, "dpleft:b13,", sizeof(mapping_string));
|
||||
}
|
||||
if (button_mask & (1 << SDL_CONTROLLER_BUTTON_DPAD_RIGHT)) {
|
||||
SDL_strlcat(mapping_string, "dpright:b14,", sizeof(mapping_string));
|
||||
}
|
||||
if (axis_mask & (1 << SDL_CONTROLLER_AXIS_LEFTX)) {
|
||||
SDL_strlcat(mapping_string, "leftx:a0,", sizeof(mapping_string));
|
||||
}
|
||||
if (axis_mask & (1 << SDL_CONTROLLER_AXIS_LEFTY)) {
|
||||
SDL_strlcat(mapping_string, "lefty:a1,", sizeof(mapping_string));
|
||||
}
|
||||
if (axis_mask & (1 << SDL_CONTROLLER_AXIS_RIGHTX)) {
|
||||
SDL_strlcat(mapping_string, "rightx:a2,", sizeof(mapping_string));
|
||||
}
|
||||
if (axis_mask & (1 << SDL_CONTROLLER_AXIS_RIGHTY)) {
|
||||
SDL_strlcat(mapping_string, "righty:a3,", sizeof(mapping_string));
|
||||
}
|
||||
if (axis_mask & (1 << SDL_CONTROLLER_AXIS_TRIGGERLEFT)) {
|
||||
SDL_strlcat(mapping_string, "lefttrigger:a4,", sizeof(mapping_string));
|
||||
}
|
||||
if (axis_mask & (1 << SDL_CONTROLLER_AXIS_TRIGGERRIGHT)) {
|
||||
SDL_strlcat(mapping_string, "righttrigger:a5,", sizeof(mapping_string));
|
||||
}
|
||||
return SDL_PrivateAddMappingForGUID(guid, mapping_string,
|
||||
&existing, SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT);
|
||||
}
|
||||
#endif /* __ANDROID__ */
|
||||
|
||||
|
||||
/*
|
||||
* Helper function to determine pre-calculated offset to certain joystick mappings
|
||||
*/
|
||||
|
@ -877,13 +988,6 @@ static ControllerMapping_t *SDL_PrivateGetControllerMappingForNameAndGUID(const
|
|||
ControllerMapping_t *mapping;
|
||||
|
||||
mapping = SDL_PrivateGetControllerMappingForGUID(&guid);
|
||||
#if defined(SDL_JOYSTICK_EMSCRIPTEN)
|
||||
if (!mapping && s_pEmscriptenMapping) {
|
||||
mapping = s_pEmscriptenMapping;
|
||||
}
|
||||
#else
|
||||
(void) s_pEmscriptenMapping; /* pacify ARMCC */
|
||||
#endif
|
||||
#ifdef __LINUX__
|
||||
if (!mapping && name) {
|
||||
if (SDL_strstr(name, "Xbox 360 Wireless Receiver")) {
|
||||
|
@ -901,6 +1005,14 @@ static ControllerMapping_t *SDL_PrivateGetControllerMappingForNameAndGUID(const
|
|||
mapping = s_pXInputMapping;
|
||||
}
|
||||
}
|
||||
#ifdef __ANDROID__
|
||||
if (!mapping) {
|
||||
mapping = SDL_CreateMappingForAndroidController(name, guid);
|
||||
}
|
||||
#endif
|
||||
if (!mapping) {
|
||||
mapping = s_pDefaultMapping;
|
||||
}
|
||||
return mapping;
|
||||
}
|
||||
|
||||
|
@ -926,15 +1038,6 @@ static ControllerMapping_t *SDL_PrivateGetControllerMapping(int device_index)
|
|||
mapping = s_pXInputMapping;
|
||||
}
|
||||
#endif
|
||||
#if defined(__ANDROID__)
|
||||
if (!mapping && SDL_SYS_IsDPAD_DeviceIndex(device_index)) {
|
||||
SDL_bool existing;
|
||||
char mapping_string[1024];
|
||||
SDL_snprintf(mapping_string, sizeof(mapping_string), "none,%s,a:b0,b:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,", name);
|
||||
mapping = SDL_PrivateAddMappingForGUID(guid, mapping_string,
|
||||
&existing, SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT);
|
||||
}
|
||||
#endif /* __ANDROID__ */
|
||||
SDL_UnlockJoysticks();
|
||||
return mapping;
|
||||
}
|
||||
|
@ -1018,8 +1121,8 @@ SDL_PrivateGameControllerAddMapping(const char *mappingString, SDL_ControllerMap
|
|||
{
|
||||
char *pchGUID;
|
||||
SDL_JoystickGUID jGUID;
|
||||
SDL_bool is_default_mapping = SDL_FALSE;
|
||||
SDL_bool is_xinput_mapping = SDL_FALSE;
|
||||
SDL_bool is_emscripten_mapping = SDL_FALSE;
|
||||
SDL_bool existing = SDL_FALSE;
|
||||
ControllerMapping_t *pControllerMapping;
|
||||
|
||||
|
@ -1031,12 +1134,11 @@ SDL_PrivateGameControllerAddMapping(const char *mappingString, SDL_ControllerMap
|
|||
if (!pchGUID) {
|
||||
return SDL_SetError("Couldn't parse GUID from %s", mappingString);
|
||||
}
|
||||
if (!SDL_strcasecmp(pchGUID, "xinput")) {
|
||||
if (!SDL_strcasecmp(pchGUID, "default")) {
|
||||
is_default_mapping = SDL_TRUE;
|
||||
} else if (!SDL_strcasecmp(pchGUID, "xinput")) {
|
||||
is_xinput_mapping = SDL_TRUE;
|
||||
}
|
||||
if (!SDL_strcasecmp(pchGUID, "emscripten")) {
|
||||
is_emscripten_mapping = SDL_TRUE;
|
||||
}
|
||||
jGUID = SDL_JoystickGetGUIDFromString(pchGUID);
|
||||
SDL_free(pchGUID);
|
||||
|
||||
|
@ -1048,12 +1150,11 @@ SDL_PrivateGameControllerAddMapping(const char *mappingString, SDL_ControllerMap
|
|||
if (existing) {
|
||||
return 0;
|
||||
} else {
|
||||
if (is_xinput_mapping) {
|
||||
if (is_default_mapping) {
|
||||
s_pDefaultMapping = pControllerMapping;
|
||||
} else if (is_xinput_mapping) {
|
||||
s_pXInputMapping = pControllerMapping;
|
||||
}
|
||||
if (is_emscripten_mapping) {
|
||||
s_pEmscriptenMapping = pControllerMapping;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue