mirror of
https://github.com/libretro/RetroArch.git
synced 2026-11-08 08:10:30 -10:00
input: Enable PS3 analog buttons
This commit is contained in:
1 parent
6e1f1858fa
commit
ed489ffbf6
8 files changed
+453
-23
No files matched your search
@@ -39,7 +39,10 @@
|
||||
- INPUT/MFI: Controller disconnection fix
|
||||
- INPUT/SDL: Fix controller vid/pid detection on Windows
|
||||
- INPUT/SDL: Add wiimote sensor capabilities
|
||||
- INPUT: Remapped pressure sensitive buttons keep their pressure
|
||||
- INPUT/SDL: Enable pressure sensitive buttons for PS3 controllers when SDL_JOYSTICK_HIDAPI_PS3=1
|
||||
- INPUT/SDL3: Add SDL3 input driver
|
||||
- INPUT/SDL3: Enable pressure sensitive buttons for PS3 controllers when SDL_JOYSTICK_HIDAPI_PS3=1
|
||||
- INPUT/UDEV: Fix multi-touch detection
|
||||
- INPUT/UDEV: Gyroscope and accelerometer sensor support
|
||||
- INPUT/UDEV: Add wiimote sensor capabilities
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#define SDL_SUPPORTS_RUMBLE SDL_VERSION_ATLEAST(2, 0, 9)
|
||||
#define SDL_SUPPORTS_SENSORS SDL_VERSION_ATLEAST(2, 0, 14)
|
||||
#define SDL_SUPPORTS_HIDAPI_WII SDL_VERSION_ATLEAST(2, 26, 0)
|
||||
#define SDL_SUPPORTS_HIDAPI_PS3 SDL_VERSION_ATLEAST(2, 26, 0)
|
||||
|
||||
typedef struct _sdl2_joypad
|
||||
{
|
||||
@@ -81,10 +82,33 @@ static int16_t sdl2_pad_get_axis(sdl2_joypad_t *pad, unsigned axis)
|
||||
{
|
||||
/* TODO: see if a rarch <-> sdl translation is needed. */
|
||||
if (pad->controller)
|
||||
{
|
||||
/* SDL's HIDAPI driver for PS3 controllers exposes additional axes
|
||||
* past the Controller API's six, representing pressure sensitive
|
||||
* buttons. */
|
||||
if (axis >= SDL_CONTROLLER_AXIS_MAX)
|
||||
{
|
||||
/* Ensure pressure sensitive buttons rest at 0, like triggers do. */
|
||||
int32_t pressure = SDL_JoystickGetAxis(pad->joypad, axis);
|
||||
return (int16_t)((pressure + 32768) / 2);
|
||||
}
|
||||
return SDL_GameControllerGetAxis(pad->controller, (SDL_GameControllerAxis)axis);
|
||||
}
|
||||
return SDL_JoystickGetAxis(pad->joypad, axis);
|
||||
}
|
||||
|
||||
#if SDL_SUPPORTS_HIDAPI_PS3
|
||||
static bool sdl2_pad_has_pressure_axes(sdl2_joypad_t *pad,
|
||||
int32_t vendor, int32_t product)
|
||||
{
|
||||
/* 0x054c/0x0268 is a PS3 controller. */
|
||||
return vendor == 0x054c
|
||||
&& product == 0x0268
|
||||
&& SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_PS3, SDL_FALSE)
|
||||
&& SDL_JoystickNumAxes(pad->joypad) > SDL_CONTROLLER_AXIS_MAX;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void sdl2_pad_connect(unsigned id)
|
||||
{
|
||||
sdl2_joypad_t *pad = (sdl2_joypad_t*)&sdl2_pads[id];
|
||||
@@ -169,6 +193,14 @@ static void sdl2_pad_connect(unsigned id)
|
||||
pad->num_buttons = SDL_CONTROLLER_BUTTON_MAX;
|
||||
pad->num_hats = 1;
|
||||
pad->num_balls = 0;
|
||||
#if SDL_SUPPORTS_HIDAPI_PS3
|
||||
if (sdl2_pad_has_pressure_axes(pad, vendor, product))
|
||||
{
|
||||
pad->num_axes = SDL_JoystickNumAxes(pad->joypad);
|
||||
RARCH_LOG("[SDL] Pad #%u: reading %u pressure-sensitive button axes.\n",
|
||||
id, pad->num_axes - SDL_CONTROLLER_AXIS_MAX);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* SDL Device supports Game Controller API. */
|
||||
}
|
||||
|
||||
@@ -83,12 +83,33 @@ static uint8_t sdl3_joypad_get_hat(sdl3_joypad_t *pad, unsigned hat)
|
||||
static int16_t sdl3_joypad_get_axis(sdl3_joypad_t *pad, unsigned axis)
|
||||
{
|
||||
if (pad->gamepad)
|
||||
{
|
||||
/* SDL's HIDAPI driver for PS3 controllers exposes additional axes
|
||||
* past the Gamepad API's six, representing pressure sensitive
|
||||
* buttons. */
|
||||
if (axis >= SDL_GAMEPAD_AXIS_COUNT)
|
||||
{
|
||||
/* Ensure pressure sensitive buttons rest at 0, like triggers do. */
|
||||
int32_t pressure = SDL_GetJoystickAxis(pad->joypad, (int)axis);
|
||||
return (int16_t)((pressure + 32768) / 2);
|
||||
}
|
||||
return SDL_GetGamepadAxis(pad->gamepad, (SDL_GamepadAxis)axis);
|
||||
}
|
||||
else if (pad->joypad)
|
||||
return SDL_GetJoystickAxis(pad->joypad, (int)axis);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool sdl3_joypad_has_pressure_axes(SDL_Joystick *joypad,
|
||||
int32_t vendor, int32_t product)
|
||||
{
|
||||
/* 0x054c/0x0268 is a PS3 controller. */
|
||||
return vendor == 0x054c
|
||||
&& product == 0x0268
|
||||
&& SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_PS3, false)
|
||||
&& SDL_GetNumJoystickAxes(joypad) > SDL_GAMEPAD_AXIS_COUNT;
|
||||
}
|
||||
|
||||
static bool sdl3_joypad_set_rumble_gain(unsigned pad, unsigned gain)
|
||||
{
|
||||
if (pad >= MAX_USERS)
|
||||
@@ -256,6 +277,12 @@ static void sdl3_joypad_connect(SDL_JoystickID jid)
|
||||
pad->num_axes = SDL_GAMEPAD_AXIS_COUNT;
|
||||
pad->num_buttons = SDL_GAMEPAD_BUTTON_COUNT;
|
||||
pad->num_hats = 0;
|
||||
if (sdl3_joypad_has_pressure_axes(joypad, vendor, product))
|
||||
{
|
||||
pad->num_axes = (unsigned)SDL_GetNumJoystickAxes(joypad);
|
||||
RARCH_LOG("[SDL3] Pad #%d: reading %u pressure-sensitive button axes.\n",
|
||||
slot, pad->num_axes - SDL_GAMEPAD_AXIS_COUNT);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
+21
-7
@@ -3196,14 +3196,10 @@ static int16_t input_state_internal(
|
||||
{
|
||||
if (id < RARCH_FIRST_CUSTOM_BIND)
|
||||
{
|
||||
/* TODO/FIXME: Analog buttons can only be read as analog
|
||||
* when the default mapping is applied. If the user
|
||||
* remaps any analog buttons, they will become 'digital'
|
||||
* due to the way that mapping is handled elsewhere. We
|
||||
* cannot fix this without rewriting the entire mess that
|
||||
* is the input remapping system... */
|
||||
bool valid_bind = RETRO_KEYBIND_VALID(&(*input_st->libretro_input_binds[mapped_port])[id]) &&
|
||||
(id == settings->uints.input_remap_ids[mapped_port][id]);
|
||||
/* Hardest pressure from buttons remapped onto this one. */
|
||||
int16_t remapped = (int16_t)input_st->mapper.buttons[mapped_port].analog_buttons[id];
|
||||
|
||||
if (valid_bind)
|
||||
{
|
||||
@@ -3223,6 +3219,9 @@ static int16_t input_state_internal(
|
||||
id,
|
||||
&(*input_st->libretro_input_binds[mapped_port])[id]);
|
||||
}
|
||||
|
||||
if (remapped > ret)
|
||||
ret = remapped;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -6204,8 +6203,9 @@ void input_mapper_reset(void *data)
|
||||
handle->analog_value[i][j] = 0;
|
||||
handle->buttons[i].data[j] = 0;
|
||||
handle->buttons[i].analogs[j] = 0;
|
||||
handle->buttons[i].analog_buttons[j] = 0;
|
||||
}
|
||||
for (j = 0; j < ARRAY_SIZE(handle->buttons[i].analog_buttons); j++)
|
||||
handle->buttons[i].analog_buttons[j] = 0;
|
||||
}
|
||||
for (i = 0; i < RETROK_LAST; i++)
|
||||
handle->key_button[i] = 0;
|
||||
@@ -10292,7 +10292,21 @@ void input_driver_poll(void)
|
||||
{
|
||||
if (remap_button < RARCH_FIRST_CUSTOM_BIND)
|
||||
{
|
||||
/* A press with no pressure reading, e.g. from an
|
||||
* overlay or the keyboard, counts as fully pressed. */
|
||||
uint16_t pressure = p_new_state->analog_buttons[j]
|
||||
? p_new_state->analog_buttons[j]
|
||||
: 0x7fff;
|
||||
|
||||
BIT256_SET(handle->buttons[i], remap_button);
|
||||
|
||||
/* If there are multiple physical buttons remapped to
|
||||
* the same virtual button, e.g. A and B on the
|
||||
* controller are both mapped to X, then whichever is
|
||||
* being pressed hardest is what sets the pressure
|
||||
* value for the mapped button. */
|
||||
if (pressure > handle->buttons[i].analog_buttons[remap_button])
|
||||
handle->buttons[i].analog_buttons[remap_button] = pressure;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -1,15 +1,56 @@
|
||||
/* The SDL2 joypad driver, held to what the snapshot bridge assumes of
|
||||
* a driver it serves (see bridge_view.h). This one keeps no pad table
|
||||
* of its own to fill - a read is a call into SDL - so SDL is given two
|
||||
* virtual joysticks, one that it takes for a game controller and one
|
||||
* that it does not, the driver opens them the way it opens any, and
|
||||
* their buttons, axes and hats are set through SDL. */
|
||||
* of its own to fill - a read is a call into SDL - so SDL is given
|
||||
* three virtual joysticks: one it takes for a gamepad, one it does not
|
||||
* and a DualShock 3 with its pressure axes. The driver opens them the
|
||||
* way it opens any, and their buttons, axes and hats are set through
|
||||
* SDL. */
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../../../input/drivers_joypad/sdl2_joypad.c"
|
||||
|
||||
#include "bridge_view.h"
|
||||
|
||||
#if SDL_SUPPORTS_HIDAPI_PS3
|
||||
/* SDL's HIDAPI driver represents a PS3 controller as a game controller
|
||||
* with ten additional axes for the pressure sensitive buttons. */
|
||||
static int attach_ds3(void)
|
||||
{
|
||||
SDL_VirtualJoystickDesc desc;
|
||||
SDL_zero(desc);
|
||||
desc.version = SDL_VIRTUAL_JOYSTICK_DESC_VERSION;
|
||||
desc.type = SDL_JOYSTICK_TYPE_GAMECONTROLLER;
|
||||
desc.naxes = 16;
|
||||
desc.nbuttons = 15;
|
||||
desc.nhats = 0;
|
||||
desc.vendor_id = 0x054c;
|
||||
desc.product_id = 0x0268;
|
||||
return SDL_JoystickAttachVirtualEx(&desc);
|
||||
}
|
||||
|
||||
/* Pressure sensitive buttons read 0 at rest and 32767 when pressed all
|
||||
* the way down, like a trigger. */
|
||||
static unsigned check_pressure(unsigned port)
|
||||
{
|
||||
static const Sint16 raw[3] = { -32768, 0, 32767 };
|
||||
static const int16_t scaled[3] = { 0, 16384, 32767 };
|
||||
sdl2_joypad_t *pad = &sdl2_pads[port];
|
||||
unsigned bad = 0, a, v;
|
||||
|
||||
for (a = SDL_CONTROLLER_AXIS_MAX; a < 16; a++)
|
||||
for (v = 0; v < 3; v++)
|
||||
{
|
||||
SDL_JoystickSetVirtualAxis(pad->joypad, (int)a, raw[v]);
|
||||
SDL_JoystickUpdate();
|
||||
if (sdl2_joypad.axis(port, AXIS_POS(a)) != scaled[v])
|
||||
bad++;
|
||||
if (sdl2_joypad.axis(port, AXIS_NEG(a)) != 0)
|
||||
bad++;
|
||||
}
|
||||
return bad;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void randomise(sdl2_joypad_t *pad)
|
||||
{
|
||||
static const Uint8 hats[] = {
|
||||
@@ -40,9 +81,17 @@ static void randomise(sdl2_joypad_t *pad)
|
||||
int main(void)
|
||||
{
|
||||
unsigned n, bad = 0, pads = 0, controllers = 0, i;
|
||||
unsigned expected = 2;
|
||||
#if SDL_SUPPORTS_HIDAPI_PS3
|
||||
unsigned ds3 = MAX_USERS;
|
||||
expected = 3;
|
||||
#endif
|
||||
|
||||
setenv("SDL_VIDEODRIVER", "dummy", 1);
|
||||
SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1");
|
||||
#if SDL_SUPPORTS_HIDAPI_PS3
|
||||
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS3, "1");
|
||||
#endif
|
||||
|
||||
if (!sdl2_joypad_init(NULL))
|
||||
{
|
||||
@@ -56,6 +105,13 @@ int main(void)
|
||||
printf("FAIL sdl2_checked_test: SDL has no virtual joysticks (%s)\n", SDL_GetError());
|
||||
return 1;
|
||||
}
|
||||
#if SDL_SUPPORTS_HIDAPI_PS3
|
||||
if (attach_ds3() < 0)
|
||||
{
|
||||
printf("FAIL sdl2_checked_test: SDL could not attach a virtual DualShock 3 (%s)\n", SDL_GetError());
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
sdl2_joypad_poll(); /* the driver opens what was attached */
|
||||
|
||||
for (i = 0; i < MAX_USERS; i++)
|
||||
@@ -65,11 +121,22 @@ int main(void)
|
||||
if (sdl2_pads[i].controller)
|
||||
controllers++;
|
||||
}
|
||||
if (pads != 2)
|
||||
if (pads != expected)
|
||||
{
|
||||
printf("FAIL sdl2_checked_test: the driver opened %u of the 2 virtual joysticks\n", pads);
|
||||
printf("FAIL sdl2_checked_test: the driver opened %u of the %u virtual joysticks\n", pads, expected);
|
||||
return 1;
|
||||
}
|
||||
#if SDL_SUPPORTS_HIDAPI_PS3
|
||||
for (i = 0; i < MAX_USERS; i++)
|
||||
if (sdl2_pads[i].controller && sdl2_pads[i].num_axes == 16)
|
||||
ds3 = i;
|
||||
if (ds3 == MAX_USERS)
|
||||
{
|
||||
printf("FAIL sdl2_checked_test: the virtual DualShock 3 was not given its pressure axes\n");
|
||||
return 1;
|
||||
}
|
||||
bad += check_pressure(ds3);
|
||||
#endif
|
||||
|
||||
for (n = 0; n < 1500; n++)
|
||||
for (i = 0; i < MAX_USERS; i++)
|
||||
@@ -87,8 +154,8 @@ int main(void)
|
||||
printf("FAIL sdl2_checked_test: %u disagreements\n", bad);
|
||||
return 1;
|
||||
}
|
||||
printf("PASS sdl2_checked_test: 1500 random states of 2 virtual joysticks"
|
||||
printf("PASS sdl2_checked_test: 1500 random states of %u virtual joysticks"
|
||||
" (%u opened as a game controller); what the bridge would read is"
|
||||
" what the driver says\n", controllers);
|
||||
" what the driver says\n", pads, controllers);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
/* The SDL3 joypad driver, held to what the snapshot bridge assumes of
|
||||
* a driver it serves (see bridge_view.h). As with SDL2 there is no pad
|
||||
* table to fill - a read is a call into SDL - so SDL is given two
|
||||
* virtual joysticks, one it takes for a gamepad and one it does not,
|
||||
* the driver opens them the way it opens any, and their buttons, axes
|
||||
* and hats are set through SDL. */
|
||||
* table to fill - a read is a call into SDL - so SDL is given three
|
||||
* virtual joysticks: one it takes for a gamepad, one it does not
|
||||
* and a DualShock 3 with its pressure axes. The driver opens them the
|
||||
* way it opens any, and their buttons, axes and hats are set through
|
||||
* SDL. */
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../../../input/drivers_joypad/sdl3_joypad.c"
|
||||
@@ -51,11 +52,50 @@ static bool attach(SDL_JoystickType type, int axes, int buttons, int hats)
|
||||
return SDL_AttachVirtualJoystick(&desc) != 0;
|
||||
}
|
||||
|
||||
/* SDL's HIDAPI driver represents a PS3 controller as a gamepad with
|
||||
* ten additional axes for the pressure sensitive buttons. */
|
||||
static bool attach_ds3(void)
|
||||
{
|
||||
SDL_VirtualJoystickDesc desc;
|
||||
SDL_INIT_INTERFACE(&desc);
|
||||
desc.type = SDL_JOYSTICK_TYPE_GAMEPAD;
|
||||
desc.vendor_id = 0x054c;
|
||||
desc.product_id = 0x0268;
|
||||
desc.naxes = 16;
|
||||
desc.nbuttons = 15;
|
||||
desc.nhats = 0;
|
||||
return SDL_AttachVirtualJoystick(&desc) != 0;
|
||||
}
|
||||
|
||||
/* Pressure sensitive buttons read 0 at rest and 32767 when pressed all
|
||||
* the way down, like a trigger. */
|
||||
static unsigned check_pressure(unsigned port)
|
||||
{
|
||||
static const Sint16 raw[3] = { -32768, 0, 32767 };
|
||||
static const int16_t scaled[3] = { 0, 16384, 32767 };
|
||||
sdl3_joypad_t *pad = &sdl3_joypads[port];
|
||||
unsigned bad = 0, a, v;
|
||||
|
||||
for (a = SDL_GAMEPAD_AXIS_COUNT; a < 16; a++)
|
||||
for (v = 0; v < 3; v++)
|
||||
{
|
||||
SDL_SetJoystickVirtualAxis(pad->joypad, (int)a, raw[v]);
|
||||
SDL_UpdateJoysticks();
|
||||
if (sdl3_joypad.axis(port, AXIS_POS(a)) != scaled[v])
|
||||
bad++;
|
||||
if (sdl3_joypad.axis(port, AXIS_NEG(a)) != 0)
|
||||
bad++;
|
||||
}
|
||||
return bad;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
unsigned n, bad = 0, pads = 0, gamepads = 0, i;
|
||||
unsigned ds3 = MAX_USERS;
|
||||
|
||||
SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1");
|
||||
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS3, "1");
|
||||
|
||||
if (!sdl3_joypad_init(NULL))
|
||||
{
|
||||
@@ -69,6 +109,11 @@ int main(void)
|
||||
printf("FAIL sdl3_checked_test: SDL has no virtual joysticks (%s)\n", SDL_GetError());
|
||||
return 1;
|
||||
}
|
||||
if (!attach_ds3())
|
||||
{
|
||||
printf("FAIL sdl3_checked_test: SDL could not attach a virtual DualShock 3 (%s)\n", SDL_GetError());
|
||||
return 1;
|
||||
}
|
||||
sdl3_joypad_poll(); /* the driver opens what was attached */
|
||||
|
||||
for (i = 0; i < MAX_USERS; i++)
|
||||
@@ -78,11 +123,20 @@ int main(void)
|
||||
if (sdl3_joypads[i].gamepad)
|
||||
gamepads++;
|
||||
}
|
||||
if (pads != 2)
|
||||
if (pads != 3)
|
||||
{
|
||||
printf("FAIL sdl3_checked_test: the driver opened %u of the 2 virtual joysticks\n", pads);
|
||||
printf("FAIL sdl3_checked_test: the driver opened %u of the 3 virtual joysticks\n", pads);
|
||||
return 1;
|
||||
}
|
||||
for (i = 0; i < MAX_USERS; i++)
|
||||
if (sdl3_joypads[i].gamepad && sdl3_joypads[i].num_axes == 16)
|
||||
ds3 = i;
|
||||
if (ds3 == MAX_USERS)
|
||||
{
|
||||
printf("FAIL sdl3_checked_test: the virtual DualShock 3 was not given its pressure axes\n");
|
||||
return 1;
|
||||
}
|
||||
bad += check_pressure(ds3);
|
||||
|
||||
for (n = 0; n < 1500; n++)
|
||||
for (i = 0; i < MAX_USERS; i++)
|
||||
@@ -100,8 +154,8 @@ int main(void)
|
||||
printf("FAIL sdl3_checked_test: %u disagreements\n", bad);
|
||||
return 1;
|
||||
}
|
||||
printf("PASS sdl3_checked_test: 1500 random states of 2 virtual joysticks"
|
||||
printf("PASS sdl3_checked_test: 1500 random states of %u virtual joysticks"
|
||||
" (%u opened as a gamepad); what the bridge would read is what the"
|
||||
" driver says\n", gamepads);
|
||||
" driver says\n", pads, gamepads);
|
||||
return 0;
|
||||
}
|
||||
@@ -2092,6 +2092,173 @@ static void lane_triggers(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(HAVE_TEST_DRIVERS) && !defined(_WIN32)
|
||||
/* Remapped pressure lane: the scripted pad's @buttons held and axes 2
|
||||
* and 3 at @a2 and @a3 for a frame; what the core saw of A and B as
|
||||
* buttons, and A's and B's analog values. */
|
||||
static unsigned pressure_frame(uint32_t buttons, int a2, int a3,
|
||||
void (*trace_last)(unsigned*, int*), int *a, int *b)
|
||||
{
|
||||
unsigned seen;
|
||||
int axes[4];
|
||||
syn_buttons = buttons;
|
||||
syn_axes[2] = (int16_t)a2;
|
||||
syn_axes[3] = (int16_t)a3;
|
||||
run_loop_frames(1);
|
||||
trace_last(&seen, axes);
|
||||
*a = input_driver_state_wrapper(0, RETRO_DEVICE_ANALOG,
|
||||
RETRO_DEVICE_INDEX_ANALOG_BUTTON, RETRO_DEVICE_ID_JOYPAD_A);
|
||||
*b = input_driver_state_wrapper(0, RETRO_DEVICE_ANALOG,
|
||||
RETRO_DEVICE_INDEX_ANALOG_BUTTON, RETRO_DEVICE_ID_JOYPAD_B);
|
||||
return seen & ( (1u << RETRO_DEVICE_ID_JOYPAD_A)
|
||||
| (1u << RETRO_DEVICE_ID_JOYPAD_B));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* A button remapped onto another carries its pressure with it. */
|
||||
static void lane_remap_pressure(void)
|
||||
{
|
||||
#if defined(HAVE_TEST_DRIVERS) && !defined(_WIN32)
|
||||
const unsigned A = 1u << RETRO_DEVICE_ID_JOYPAD_A;
|
||||
const unsigned B = 1u << RETRO_DEVICE_ID_JOYPAD_B;
|
||||
input_driver_state_t *input_st = input_state_get_ptr();
|
||||
settings_t *settings = config_get_ptr();
|
||||
unsigned *remap = settings->uints.input_remap_ids[0];
|
||||
struct retro_keybind *a_bind = &input_autoconf_binds[0][RETRO_DEVICE_ID_JOYPAD_A];
|
||||
struct retro_keybind *b_bind = &input_autoconf_binds[0][RETRO_DEVICE_ID_JOYPAD_B];
|
||||
struct retro_keybind saved_a = *a_bind;
|
||||
struct retro_keybind saved_b = *b_bind;
|
||||
bool analog_requested = input_st->analog_requested[0];
|
||||
const input_device_driver_t *joypad_real;
|
||||
void (*trace)(int, int);
|
||||
void (*trace_last)(unsigned*, int*);
|
||||
void *core;
|
||||
unsigned had = failures;
|
||||
unsigned seen;
|
||||
uint32_t a_btn, b_btn;
|
||||
int16_t stick;
|
||||
int a, b, x;
|
||||
|
||||
if ( !(core = dlopen(core_path_g, RTLD_NOW))
|
||||
|| !(trace = (void (*)(int, int))dlsym(core, "harness_core_trace"))
|
||||
|| !(trace_last = (void (*)(unsigned*, int*))dlsym(core, "harness_core_trace_last"))
|
||||
|| !input_st->primary_joypad
|
||||
|| a_bind->joykey >= 32 || b_bind->joykey >= 32)
|
||||
{
|
||||
CHECK(false, "remapped pressure: the harness core's trace entry points,"
|
||||
" the joypad driver or A's and B's buttons");
|
||||
return;
|
||||
}
|
||||
joypad_real = input_st->primary_joypad;
|
||||
syn_joypad = *joypad_real;
|
||||
syn_joypad.button = syn_button;
|
||||
syn_joypad.axis = syn_axis;
|
||||
syn_joypad.state = syn_state;
|
||||
syn_joypad.get_buttons = syn_get_buttons;
|
||||
input_st->primary_joypad = &syn_joypad;
|
||||
input_driver_set_snapshot_bridge(true);
|
||||
syn_hat = 0;
|
||||
syn_buttons = 0;
|
||||
memset(syn_axes, 0, sizeof(syn_axes));
|
||||
fast_forward(true);
|
||||
trace(2, 0);
|
||||
|
||||
a_btn = 1u << a_bind->joykey;
|
||||
b_btn = 1u << b_bind->joykey;
|
||||
a_bind->joyaxis = AXIS_POS(2);
|
||||
b_bind->joyaxis = AXIS_POS(3);
|
||||
|
||||
/* not remapped: as before */
|
||||
pressure_frame(0, 0, 0, trace_last, &a, &b);
|
||||
seen = pressure_frame(a_btn, 20000, 0, trace_last, &a, &b);
|
||||
CHECK(seen == A && a == 20000 && !b,
|
||||
"remapped pressure: not remapped, A's pressure is not A's");
|
||||
seen = pressure_frame(a_btn, 0, 0, trace_last, &a, &b);
|
||||
CHECK(seen == A && a == 0x7fff,
|
||||
"remapped pressure: not remapped, a press without pressure is not a full press");
|
||||
|
||||
/* A onto B */
|
||||
remap[RETRO_DEVICE_ID_JOYPAD_A] = RETRO_DEVICE_ID_JOYPAD_B;
|
||||
pressure_frame(0, 0, 0, trace_last, &a, &b);
|
||||
seen = pressure_frame(a_btn, 20000, 0, trace_last, &a, &b);
|
||||
CHECK(seen == B && b == 20000 && !a,
|
||||
"remapped pressure: A onto B, B's pressure is not A's");
|
||||
seen = pressure_frame(0, 0, 0, trace_last, &a, &b);
|
||||
CHECK(!seen && !a && !b,
|
||||
"remapped pressure: A onto B, released, a press is left behind");
|
||||
|
||||
/* A and B both onto B: the harder press */
|
||||
seen = pressure_frame(a_btn | b_btn, 20000, 10000, trace_last, &a, &b);
|
||||
CHECK(seen == B && b == 20000 && !a,
|
||||
"remapped pressure: A and B onto B, A pressed harder, B is not A's");
|
||||
seen = pressure_frame(a_btn | b_btn, 5000, 10000, trace_last, &a, &b);
|
||||
CHECK(seen == B && b == 10000 && !a,
|
||||
"remapped pressure: A and B onto B, B pressed harder, B is not B's");
|
||||
|
||||
/* swapped */
|
||||
remap[RETRO_DEVICE_ID_JOYPAD_B] = RETRO_DEVICE_ID_JOYPAD_A;
|
||||
seen = pressure_frame(a_btn | b_btn, 20000, 10000, trace_last, &a, &b);
|
||||
CHECK(seen == (A | B) && b == 20000 && a == 10000,
|
||||
"remapped pressure: A and B swapped, the pressures are not swapped");
|
||||
|
||||
/* a button without a pressure axis gives a full press */
|
||||
a_bind->joyaxis = AXIS_NONE;
|
||||
seen = pressure_frame(a_btn, 0, 0, trace_last, &a, &b);
|
||||
CHECK(seen == B && b == 0x7fff && !a,
|
||||
"remapped pressure: A onto B without an axis, not a full press");
|
||||
a_bind->joyaxis = AXIS_POS(2);
|
||||
|
||||
/* A and B both onto X: the harder press */
|
||||
remap[RETRO_DEVICE_ID_JOYPAD_A] = RETRO_DEVICE_ID_JOYPAD_X;
|
||||
remap[RETRO_DEVICE_ID_JOYPAD_B] = RETRO_DEVICE_ID_JOYPAD_X;
|
||||
seen = pressure_frame(a_btn | b_btn, 20000, 10000, trace_last, &a, &b);
|
||||
x = input_driver_state_wrapper(0, RETRO_DEVICE_ANALOG,
|
||||
RETRO_DEVICE_INDEX_ANALOG_BUTTON, RETRO_DEVICE_ID_JOYPAD_X);
|
||||
CHECK(!seen && !a && !b && x == 20000,
|
||||
"remapped pressure: A and B onto X, A pressed harder, X is not A's");
|
||||
seen = pressure_frame(a_btn | b_btn, 5000, 10000, trace_last, &a, &b);
|
||||
x = input_driver_state_wrapper(0, RETRO_DEVICE_ANALOG,
|
||||
RETRO_DEVICE_INDEX_ANALOG_BUTTON, RETRO_DEVICE_ID_JOYPAD_X);
|
||||
CHECK(!seen && !a && !b && x == 10000,
|
||||
"remapped pressure: A and B onto X, B pressed harder, X is not B's");
|
||||
|
||||
/* unmapped: nothing */
|
||||
remap[RETRO_DEVICE_ID_JOYPAD_A] = RARCH_UNMAPPED;
|
||||
remap[RETRO_DEVICE_ID_JOYPAD_B] = RETRO_DEVICE_ID_JOYPAD_B;
|
||||
seen = pressure_frame(a_btn, 20000, 0, trace_last, &a, &b);
|
||||
CHECK(!seen && !a && !b,
|
||||
"remapped pressure: A unmapped, it still reaches the core");
|
||||
|
||||
/* onto a stick, as before */
|
||||
remap[RETRO_DEVICE_ID_JOYPAD_A] = RARCH_ANALOG_LEFT_X_PLUS;
|
||||
pressure_frame(a_btn, 20000, 0, trace_last, &a, &b);
|
||||
stick = input_driver_state_wrapper(0, RETRO_DEVICE_ANALOG,
|
||||
RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X);
|
||||
CHECK(stick == 20000 && !a,
|
||||
"remapped pressure: A onto the left stick, the stick is not A's pressure");
|
||||
|
||||
remap[RETRO_DEVICE_ID_JOYPAD_A] = RETRO_DEVICE_ID_JOYPAD_A;
|
||||
remap[RETRO_DEVICE_ID_JOYPAD_B] = RETRO_DEVICE_ID_JOYPAD_B;
|
||||
*a_bind = saved_a;
|
||||
*b_bind = saved_b;
|
||||
syn_buttons = 0;
|
||||
memset(syn_axes, 0, sizeof(syn_axes));
|
||||
trace(0, 0);
|
||||
fast_forward(false);
|
||||
run_loop_frames(5);
|
||||
input_driver_set_snapshot_bridge(false);
|
||||
input_st->primary_joypad = joypad_real;
|
||||
input_st->analog_requested[0] = analog_requested;
|
||||
dlclose(core);
|
||||
if (failures == had)
|
||||
printf("[pass] remapped pressure: a button remapped onto another"
|
||||
" takes its pressure along, the harder of two presses wins,"
|
||||
" and a button without pressure is a full press\n");
|
||||
#else
|
||||
printf("[skip] remapped pressure: needs the test drivers\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(HAVE_TEST_DRIVERS) && !defined(_WIN32) \
|
||||
&& defined(HAVE_NETWORKING) && defined(HAVE_NETWORKGAMEPAD)
|
||||
#include <sys/socket.h>
|
||||
@@ -3738,6 +3905,7 @@ int main(int argc, char *argv[])
|
||||
lane_remap_idle();
|
||||
lane_input_rotation();
|
||||
lane_triggers();
|
||||
lane_remap_pressure();
|
||||
lane_network_retropad();
|
||||
lane_pointer_capture();
|
||||
lane_menu_combo_gate();
|
||||
|
||||
@@ -85,6 +85,10 @@
|
||||
* input/input_types.h (int16_t analog_value[MAX_USERS][8]). */
|
||||
#define ANALOG_VALUE_PER_USER 8
|
||||
|
||||
/* Mirror: array size of input_bits_t's analog_buttons from
|
||||
* input/input_types.h (uint16_t analog_buttons[16]). */
|
||||
#define ANALOG_BUTTONS_PER_USER 16
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
||||
#endif
|
||||
@@ -171,6 +175,24 @@ static int do_analog_to_analog_write(mock_mapper_t *handle,
|
||||
}
|
||||
/* === end verbatim copy === */
|
||||
|
||||
/* === verbatim copy of the button -> button pressure write from
|
||||
* input/input_driver.c::input_driver_poll(). @source_pressure
|
||||
* is p_new_state->analog_buttons[j]. === */
|
||||
static void do_button_to_button_pressure(uint16_t *analog_buttons,
|
||||
unsigned remap_button, uint16_t source_pressure)
|
||||
{
|
||||
if (remap_button < RARCH_FIRST_CUSTOM_BIND)
|
||||
{
|
||||
uint16_t pressure = source_pressure
|
||||
? source_pressure
|
||||
: 0x7fff;
|
||||
|
||||
if (pressure > analog_buttons[remap_button])
|
||||
analog_buttons[remap_button] = pressure;
|
||||
}
|
||||
}
|
||||
/* === end verbatim copy === */
|
||||
|
||||
/* ---- tests ------------------------------------------------ */
|
||||
|
||||
static void test_validate_accepts_legitimate_button_indices(void)
|
||||
@@ -388,6 +410,48 @@ static void test_remap_port_in_range_kept_out_of_range_reset(void)
|
||||
MAX_USERS - 1);
|
||||
}
|
||||
|
||||
static void test_button_to_button_pressure_values(void)
|
||||
{
|
||||
uint16_t slots[ANALOG_BUTTONS_PER_USER];
|
||||
memset(slots, 0, sizeof(slots));
|
||||
|
||||
/* no pressure axis: a full press */
|
||||
do_button_to_button_pressure(slots, 0, 0);
|
||||
if (slots[0] != 0x7fff)
|
||||
{
|
||||
printf("[ERROR] a press without pressure gave %u, expected 32767\n",
|
||||
(unsigned)slots[0]);
|
||||
failures++;
|
||||
return;
|
||||
}
|
||||
|
||||
/* two sources on one target: the harder press */
|
||||
memset(slots, 0, sizeof(slots));
|
||||
do_button_to_button_pressure(slots, 8, 20000);
|
||||
do_button_to_button_pressure(slots, 8, 10000);
|
||||
if (slots[8] != 20000)
|
||||
{
|
||||
printf("[ERROR] a softer press replaced a harder one (%u)\n",
|
||||
(unsigned)slots[8]);
|
||||
failures++;
|
||||
return;
|
||||
}
|
||||
do_button_to_button_pressure(slots, 8, 30000);
|
||||
if (slots[8] != 30000)
|
||||
{
|
||||
printf("[ERROR] a harder press did not replace a softer one (%u)\n",
|
||||
(unsigned)slots[8]);
|
||||
failures++;
|
||||
return;
|
||||
}
|
||||
|
||||
/* a stick or unmapped target is not a button slot: under ASan a
|
||||
* write to slot 16 or 1024 is a stack-buffer-overflow */
|
||||
do_button_to_button_pressure(slots, RARCH_FIRST_CUSTOM_BIND, 20000);
|
||||
do_button_to_button_pressure(slots, RARCH_UNMAPPED, 20000);
|
||||
printf("[SUCCESS] button -> button pressure: full press, harder press wins\n");
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_validate_accepts_legitimate_button_indices();
|
||||
@@ -398,6 +462,7 @@ int main(void)
|
||||
test_button_to_analog_out_of_range_no_oob();
|
||||
test_analog_to_analog_sizeof_vs_array_size_bug();
|
||||
test_remap_port_in_range_kept_out_of_range_reset();
|
||||
test_button_to_button_pressure_values();
|
||||
|
||||
if (failures)
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user