mirror of
https://github.com/Ryujinx/SDL.git
synced 2025-03-23 21:55:12 +00:00
linux: Improve gamepad mapping heuristic to accept Android conventions
This heuristic for gamepads without a more specific mapping already tried two incompatible conventions for handling triggers: the Linux Gamepad Specification uses hat switch 2 for the triggers (for whatever reason), but the de facto standard set by the drivers for older Xbox and Playstation controllers represents each trigger as the Z-axis of the nearest analog stick. Android documentation encourages Bluetooth gamepad manufacturers to use a third incompatible convention where the left and right triggers are represented as the brake and gas pedals of a driving simulator controller. The Android convention also changes the representation of the right stick: instead of using X and Y rotation as a second pair of axes, Android uses Z position as a second horizontal axis, and Z rotation as a second vertical axis. Try to cope gracefully with all of these. This will hopefully resolve the issue described in #5406 (when using unpatched kernels). Signed-off-by: Simon McVittie <smcv@collabora.com> (cherry picked from commit cf1dc66e2cfc7a65374c5fea681dd31c50363a2c)
This commit is contained in:
parent
26a38a0b20
commit
36ff6327b0
|
@ -1671,6 +1671,8 @@ static void LINUX_JoystickQuit(void)
|
||||||
/*
|
/*
|
||||||
This is based on the Linux Gamepad Specification
|
This is based on the Linux Gamepad Specification
|
||||||
available at: https://www.kernel.org/doc/html/v4.15/input/gamepad.html
|
available at: https://www.kernel.org/doc/html/v4.15/input/gamepad.html
|
||||||
|
and the Android gamepad documentation,
|
||||||
|
https://developer.android.com/develop/ui/views/touch-and-input/game-controllers/controller-input
|
||||||
*/
|
*/
|
||||||
static SDL_bool LINUX_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out)
|
static SDL_bool LINUX_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out)
|
||||||
{
|
{
|
||||||
|
@ -1891,14 +1893,35 @@ static SDL_bool LINUX_JoystickGetGamepadMapping(int device_index, SDL_GamepadMap
|
||||||
/* Prefer analog triggers, but settle for digital hat or buttons. */
|
/* Prefer analog triggers, but settle for digital hat or buttons. */
|
||||||
mapped = 0;
|
mapped = 0;
|
||||||
|
|
||||||
|
/* Unfortunately there are several conventions for how analog triggers
|
||||||
|
* are represented as absolute axes:
|
||||||
|
*
|
||||||
|
* - Linux Gamepad Specification:
|
||||||
|
* LT = ABS_HAT2Y, RT = ABS_HAT2X
|
||||||
|
* - Android (and therefore many Bluetooth controllers):
|
||||||
|
* LT = ABS_BRAKE, RT = ABS_GAS
|
||||||
|
* - De facto standard for older Xbox and Playstation controllers:
|
||||||
|
* LT = ABS_Z, RT = ABS_RZ
|
||||||
|
*
|
||||||
|
* We try each one in turn. */
|
||||||
if (joystick->hwdata->has_abs[ABS_HAT2Y]) {
|
if (joystick->hwdata->has_abs[ABS_HAT2Y]) {
|
||||||
|
/* Linux Gamepad Specification */
|
||||||
out->lefttrigger.kind = EMappingKind_Axis;
|
out->lefttrigger.kind = EMappingKind_Axis;
|
||||||
out->lefttrigger.target = joystick->hwdata->abs_map[ABS_HAT2Y];
|
out->lefttrigger.target = joystick->hwdata->abs_map[ABS_HAT2Y];
|
||||||
mapped |= MAPPED_TRIGGER_LEFT;
|
mapped |= MAPPED_TRIGGER_LEFT;
|
||||||
#ifdef DEBUG_GAMEPAD_MAPPING
|
#ifdef DEBUG_GAMEPAD_MAPPING
|
||||||
SDL_Log("Mapped LEFTTRIGGER to axis %d (ABS_HAT2Y)", out->lefttrigger.target);
|
SDL_Log("Mapped LEFTTRIGGER to axis %d (ABS_HAT2Y)", out->lefttrigger.target);
|
||||||
|
#endif
|
||||||
|
} else if (joystick->hwdata->has_abs[ABS_BRAKE]) {
|
||||||
|
/* Android convention */
|
||||||
|
out->lefttrigger.kind = EMappingKind_Axis;
|
||||||
|
out->lefttrigger.target = joystick->hwdata->abs_map[ABS_BRAKE];
|
||||||
|
mapped |= MAPPED_TRIGGER_LEFT;
|
||||||
|
#ifdef DEBUG_GAMEPAD_MAPPING
|
||||||
|
SDL_Log("Mapped LEFTTRIGGER to axis %d (ABS_BRAKE)", out->lefttrigger.target);
|
||||||
#endif
|
#endif
|
||||||
} else if (joystick->hwdata->has_abs[ABS_Z]) {
|
} else if (joystick->hwdata->has_abs[ABS_Z]) {
|
||||||
|
/* De facto standard for Xbox 360 and Playstation gamepads */
|
||||||
out->lefttrigger.kind = EMappingKind_Axis;
|
out->lefttrigger.kind = EMappingKind_Axis;
|
||||||
out->lefttrigger.target = joystick->hwdata->abs_map[ABS_Z];
|
out->lefttrigger.target = joystick->hwdata->abs_map[ABS_Z];
|
||||||
mapped |= MAPPED_TRIGGER_LEFT;
|
mapped |= MAPPED_TRIGGER_LEFT;
|
||||||
|
@ -1908,13 +1931,23 @@ static SDL_bool LINUX_JoystickGetGamepadMapping(int device_index, SDL_GamepadMap
|
||||||
}
|
}
|
||||||
|
|
||||||
if (joystick->hwdata->has_abs[ABS_HAT2X]) {
|
if (joystick->hwdata->has_abs[ABS_HAT2X]) {
|
||||||
|
/* Linux Gamepad Specification */
|
||||||
out->righttrigger.kind = EMappingKind_Axis;
|
out->righttrigger.kind = EMappingKind_Axis;
|
||||||
out->righttrigger.target = joystick->hwdata->abs_map[ABS_HAT2X];
|
out->righttrigger.target = joystick->hwdata->abs_map[ABS_HAT2X];
|
||||||
mapped |= MAPPED_TRIGGER_RIGHT;
|
mapped |= MAPPED_TRIGGER_RIGHT;
|
||||||
#ifdef DEBUG_GAMEPAD_MAPPING
|
#ifdef DEBUG_GAMEPAD_MAPPING
|
||||||
SDL_Log("Mapped RIGHTTRIGGER to axis %d (ABS_HAT2X)", out->righttrigger.target);
|
SDL_Log("Mapped RIGHTTRIGGER to axis %d (ABS_HAT2X)", out->righttrigger.target);
|
||||||
|
#endif
|
||||||
|
} else if (joystick->hwdata->has_abs[ABS_GAS]) {
|
||||||
|
/* Android convention */
|
||||||
|
out->righttrigger.kind = EMappingKind_Axis;
|
||||||
|
out->righttrigger.target = joystick->hwdata->abs_map[ABS_GAS];
|
||||||
|
mapped |= MAPPED_TRIGGER_RIGHT;
|
||||||
|
#ifdef DEBUG_GAMEPAD_MAPPING
|
||||||
|
SDL_Log("Mapped RIGHTTRIGGER to axis %d (ABS_GAS)", out->righttrigger.target);
|
||||||
#endif
|
#endif
|
||||||
} else if (joystick->hwdata->has_abs[ABS_RZ]) {
|
} else if (joystick->hwdata->has_abs[ABS_RZ]) {
|
||||||
|
/* De facto standard for Xbox 360 and Playstation gamepads */
|
||||||
out->righttrigger.kind = EMappingKind_Axis;
|
out->righttrigger.kind = EMappingKind_Axis;
|
||||||
out->righttrigger.target = joystick->hwdata->abs_map[ABS_RZ];
|
out->righttrigger.target = joystick->hwdata->abs_map[ABS_RZ];
|
||||||
mapped |= MAPPED_TRIGGER_RIGHT;
|
mapped |= MAPPED_TRIGGER_RIGHT;
|
||||||
|
@ -2035,7 +2068,16 @@ static SDL_bool LINUX_JoystickGetGamepadMapping(int device_index, SDL_GamepadMap
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The Linux Gamepad Specification uses the RX and RY axes,
|
||||||
|
* originally intended to represent X and Y rotation, as a second
|
||||||
|
* joystick. This is common for USB gamepads, and also many Bluetooth
|
||||||
|
* gamepads, particularly older ones.
|
||||||
|
*
|
||||||
|
* The Android mapping convention used by many Bluetooth controllers
|
||||||
|
* instead uses the Z axis as a secondary X axis, and the RZ axis as
|
||||||
|
* a secondary Y axis. */
|
||||||
if (joystick->hwdata->has_abs[ABS_RX] && joystick->hwdata->has_abs[ABS_RY]) {
|
if (joystick->hwdata->has_abs[ABS_RX] && joystick->hwdata->has_abs[ABS_RY]) {
|
||||||
|
/* Linux Gamepad Specification, Xbox 360, Playstation etc. */
|
||||||
out->rightx.kind = EMappingKind_Axis;
|
out->rightx.kind = EMappingKind_Axis;
|
||||||
out->righty.kind = EMappingKind_Axis;
|
out->righty.kind = EMappingKind_Axis;
|
||||||
out->rightx.target = joystick->hwdata->abs_map[ABS_RX];
|
out->rightx.target = joystick->hwdata->abs_map[ABS_RX];
|
||||||
|
@ -2043,6 +2085,16 @@ static SDL_bool LINUX_JoystickGetGamepadMapping(int device_index, SDL_GamepadMap
|
||||||
#ifdef DEBUG_GAMEPAD_MAPPING
|
#ifdef DEBUG_GAMEPAD_MAPPING
|
||||||
SDL_Log("Mapped RIGHTX to axis %d (ABS_RX)", out->rightx.target);
|
SDL_Log("Mapped RIGHTX to axis %d (ABS_RX)", out->rightx.target);
|
||||||
SDL_Log("Mapped RIGHTY to axis %d (ABS_RY)", out->righty.target);
|
SDL_Log("Mapped RIGHTY to axis %d (ABS_RY)", out->righty.target);
|
||||||
|
#endif
|
||||||
|
} else if (joystick->hwdata->has_abs[ABS_Z] && joystick->hwdata->has_abs[ABS_RZ]) {
|
||||||
|
/* Android convention */
|
||||||
|
out->rightx.kind = EMappingKind_Axis;
|
||||||
|
out->righty.kind = EMappingKind_Axis;
|
||||||
|
out->rightx.target = joystick->hwdata->abs_map[ABS_Z];
|
||||||
|
out->righty.target = joystick->hwdata->abs_map[ABS_RZ];
|
||||||
|
#ifdef DEBUG_GAMEPAD_MAPPING
|
||||||
|
SDL_Log("Mapped RIGHTX to axis %d (ABS_Z)", out->rightx.target);
|
||||||
|
SDL_Log("Mapped RIGHTY to axis %d (ABS_RZ)", out->righty.target);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue