Correlate just based on buttons, joystick axes are not as precise and could potentially cause incorrect uncorrelation.

It's okay if the triggers aren't precise until someone presses a button on their controller.
This commit is contained in:
Sam Lantinga 2020-11-27 05:53:56 -08:00
parent e7e615de26
commit 248fc75bd2
1 changed files with 50 additions and 26 deletions

View File

@ -168,7 +168,9 @@ static struct {
} guide_button_candidate; } guide_button_candidate;
typedef struct WindowsMatchState { typedef struct WindowsMatchState {
#ifdef SDL_JOYSTICK_RAWINPUT_MATCH_AXES
SHORT match_axes[4]; SHORT match_axes[4];
#endif
#ifdef SDL_JOYSTICK_RAWINPUT_XINPUT #ifdef SDL_JOYSTICK_RAWINPUT_XINPUT
WORD xinput_buttons; WORD xinput_buttons;
#endif #endif
@ -180,8 +182,12 @@ typedef struct WindowsMatchState {
static void RAWINPUT_FillMatchState(WindowsMatchState *state, Uint32 match_state) static void RAWINPUT_FillMatchState(WindowsMatchState *state, Uint32 match_state)
{ {
#ifdef SDL_JOYSTICK_RAWINPUT_MATCH_AXES
int ii; int ii;
#endif
state->any_data = SDL_FALSE; state->any_data = SDL_FALSE;
#ifdef SDL_JOYSTICK_RAWINPUT_MATCH_AXES
/* SHORT state->match_axes[4] = { /* SHORT state->match_axes[4] = {
(match_state & 0x000F0000) >> 4, (match_state & 0x000F0000) >> 4,
(match_state & 0x00F00000) >> 8, (match_state & 0x00F00000) >> 8,
@ -194,6 +200,7 @@ static void RAWINPUT_FillMatchState(WindowsMatchState *state, Uint32 match_state
state->any_data = SDL_TRUE; state->any_data = SDL_TRUE;
} }
} }
#endif /* SDL_JOYSTICK_RAWINPUT_MATCH_AXES */
#ifdef SDL_JOYSTICK_RAWINPUT_XINPUT #ifdef SDL_JOYSTICK_RAWINPUT_XINPUT
/* Match axes by checking if the distance between the high 4 bits of axis and the 4 bits from match_state is 1 or less */ /* Match axes by checking if the distance between the high 4 bits of axis and the 4 bits from match_state is 1 or less */
@ -337,7 +344,11 @@ RAWINPUT_XInputSlotMatches(const WindowsMatchState *state, Uint8 slot_idx)
{ {
if (xinput_state[slot_idx].connected) { if (xinput_state[slot_idx].connected) {
WORD xinput_buttons = xinput_state[slot_idx].state.Gamepad.wButtons; WORD xinput_buttons = xinput_state[slot_idx].state.Gamepad.wButtons;
if ((xinput_buttons & ~XINPUT_GAMEPAD_GUIDE) == state->xinput_buttons && XInputAxesMatch(xinput_state[slot_idx].state.Gamepad)) { if ((xinput_buttons & ~XINPUT_GAMEPAD_GUIDE) == state->xinput_buttons
#ifdef SDL_JOYSTICK_RAWINPUT_MATCH_AXES
&& XInputAxesMatch(xinput_state[slot_idx].state.Gamepad)
#endif
) {
return SDL_TRUE; return SDL_TRUE;
} }
} }
@ -553,7 +564,11 @@ static SDL_bool
RAWINPUT_WindowsGamingInputSlotMatches(const WindowsMatchState *state, WindowsGamingInputGamepadState *slot) RAWINPUT_WindowsGamingInputSlotMatches(const WindowsMatchState *state, WindowsGamingInputGamepadState *slot)
{ {
Uint32 wgi_buttons = slot->state.Buttons; Uint32 wgi_buttons = slot->state.Buttons;
if ((wgi_buttons & 0x3FFF) == state->wgi_buttons && WindowsGamingInputAxesMatch(slot->state)) { if ((wgi_buttons & 0x3FFF) == state->wgi_buttons
#ifdef SDL_JOYSTICK_RAWINPUT_MATCH_AXES
&& WindowsGamingInputAxesMatch(slot->state)
#endif
) {
return SDL_TRUE; return SDL_TRUE;
} }
return SDL_FALSE; return SDL_FALSE;
@ -1279,13 +1294,7 @@ RAWINPUT_HandleStatePacket(SDL_Joystick *joystick, Uint8 *data, int size)
RAWINPUT_DeviceContext *ctx = joystick->hwdata; RAWINPUT_DeviceContext *ctx = joystick->hwdata;
#ifdef SDL_JOYSTICK_RAWINPUT_MATCHING #ifdef SDL_JOYSTICK_RAWINPUT_MATCHING
/* Map new buttons and axes into game controller controls */ /* Map new buttons and axes into game controller controls */
static int axis_map[] = { static const int button_map[] = {
SDL_CONTROLLER_AXIS_LEFTY,
SDL_CONTROLLER_AXIS_LEFTX,
SDL_CONTROLLER_AXIS_RIGHTY,
SDL_CONTROLLER_AXIS_RIGHTX
};
static int button_map[] = {
SDL_CONTROLLER_BUTTON_A, SDL_CONTROLLER_BUTTON_A,
SDL_CONTROLLER_BUTTON_B, SDL_CONTROLLER_BUTTON_B,
SDL_CONTROLLER_BUTTON_X, SDL_CONTROLLER_BUTTON_X,
@ -1297,12 +1306,35 @@ RAWINPUT_HandleStatePacket(SDL_Joystick *joystick, Uint8 *data, int size)
SDL_CONTROLLER_BUTTON_LEFTSTICK, SDL_CONTROLLER_BUTTON_LEFTSTICK,
SDL_CONTROLLER_BUTTON_RIGHTSTICK SDL_CONTROLLER_BUTTON_RIGHTSTICK
}; };
#define HAT_MASK ((1 << SDL_CONTROLLER_BUTTON_DPAD_UP) | (1 << SDL_CONTROLLER_BUTTON_DPAD_DOWN) | (1 << SDL_CONTROLLER_BUTTON_DPAD_LEFT) | (1 << SDL_CONTROLLER_BUTTON_DPAD_RIGHT))
static const int hat_map[] = {
0,
(1 << SDL_CONTROLLER_BUTTON_DPAD_UP),
(1 << SDL_CONTROLLER_BUTTON_DPAD_UP) | (1 << SDL_CONTROLLER_BUTTON_DPAD_RIGHT),
(1 << SDL_CONTROLLER_BUTTON_DPAD_RIGHT),
(1 << SDL_CONTROLLER_BUTTON_DPAD_DOWN) | (1 << SDL_CONTROLLER_BUTTON_DPAD_RIGHT),
(1 << SDL_CONTROLLER_BUTTON_DPAD_DOWN),
(1 << SDL_CONTROLLER_BUTTON_DPAD_DOWN) | (1 << SDL_CONTROLLER_BUTTON_DPAD_LEFT),
(1 << SDL_CONTROLLER_BUTTON_DPAD_LEFT),
(1 << SDL_CONTROLLER_BUTTON_DPAD_UP) | (1 << SDL_CONTROLLER_BUTTON_DPAD_LEFT),
};
#ifdef SDL_JOYSTICK_RAWINPUT_MATCH_AXES
static const int axis_map[] = {
SDL_CONTROLLER_AXIS_LEFTY,
SDL_CONTROLLER_AXIS_LEFTX,
SDL_CONTROLLER_AXIS_RIGHTY,
SDL_CONTROLLER_AXIS_RIGHTX
};
#endif
Uint32 match_state = ctx->match_state; Uint32 match_state = ctx->match_state;
/* Update match_state with button bit, then fall through */ /* Update match_state with button bit, then fall through */
#define SDL_PrivateJoystickButton(joystick, button, state) if (button < SDL_arraysize(button_map)) { if (state) match_state |= 1 << button_map[button]; else match_state &= ~(1 << button_map[button]); } SDL_PrivateJoystickButton(joystick, button, state) #define SDL_PrivateJoystickButton(joystick, button, state) if (button < SDL_arraysize(button_map)) { if (state) match_state |= 1 << button_map[button]; else match_state &= ~(1 << button_map[button]); } SDL_PrivateJoystickButton(joystick, button, state)
#ifdef SDL_JOYSTICK_RAWINPUT_MATCH_AXES
/* Grab high 4 bits of value, then fall through */ /* Grab high 4 bits of value, then fall through */
#define SDL_PrivateJoystickAxis(joystick, axis, value) if (axis < SDL_arraysize(axis_map)) match_state = (match_state & ~(0xF << (4 * axis_map[axis] + 16))) | ((value) & 0xF000) << (4 * axis_map[axis] + 4); SDL_PrivateJoystickAxis(joystick, axis, value) #define SDL_PrivateJoystickAxis(joystick, axis, value) if (axis < SDL_arraysize(axis_map)) match_state = (match_state & ~(0xF << (4 * axis_map[axis] + 16))) | ((value) & 0xF000) << (4 * axis_map[axis] + 4); SDL_PrivateJoystickAxis(joystick, axis, value)
#endif #endif
#endif /* SDL_JOYSTICK_RAWINPUT_MATCHING */
ULONG data_length = ctx->max_data_length; ULONG data_length = ctx->max_data_length;
int i; int i;
int nbuttons = joystick->nbuttons - (ctx->guide_hack * 1); int nbuttons = joystick->nbuttons - (ctx->guide_hack * 1);
@ -1335,18 +1367,6 @@ RAWINPUT_HandleStatePacket(SDL_Joystick *joystick, Uint8 *data, int size)
for (i = 0; i < nhats; ++i) { for (i = 0; i < nhats; ++i) {
HIDP_DATA *item = GetData(ctx->hat_indices[i], ctx->data, data_length); HIDP_DATA *item = GetData(ctx->hat_indices[i], ctx->data, data_length);
if (item) { if (item) {
#define HAT_MASK ((1 << SDL_CONTROLLER_BUTTON_DPAD_UP) | (1 << SDL_CONTROLLER_BUTTON_DPAD_DOWN) | (1 << SDL_CONTROLLER_BUTTON_DPAD_LEFT) | (1 << SDL_CONTROLLER_BUTTON_DPAD_RIGHT))
const int hat_map[] = {
0,
(1 << SDL_CONTROLLER_BUTTON_DPAD_UP),
(1 << SDL_CONTROLLER_BUTTON_DPAD_UP) | (1 << SDL_CONTROLLER_BUTTON_DPAD_RIGHT),
(1 << SDL_CONTROLLER_BUTTON_DPAD_RIGHT),
(1 << SDL_CONTROLLER_BUTTON_DPAD_DOWN) | (1 << SDL_CONTROLLER_BUTTON_DPAD_RIGHT),
(1 << SDL_CONTROLLER_BUTTON_DPAD_DOWN),
(1 << SDL_CONTROLLER_BUTTON_DPAD_DOWN) | (1 << SDL_CONTROLLER_BUTTON_DPAD_LEFT),
(1 << SDL_CONTROLLER_BUTTON_DPAD_LEFT),
(1 << SDL_CONTROLLER_BUTTON_DPAD_UP) | (1 << SDL_CONTROLLER_BUTTON_DPAD_LEFT),
};
const Uint8 hat_states[] = { const Uint8 hat_states[] = {
SDL_HAT_CENTERED, SDL_HAT_CENTERED,
SDL_HAT_UP, SDL_HAT_UP,
@ -1361,14 +1381,18 @@ RAWINPUT_HandleStatePacket(SDL_Joystick *joystick, Uint8 *data, int size)
ULONG state = item->RawValue; ULONG state = item->RawValue;
if (state < SDL_arraysize(hat_states)) { if (state < SDL_arraysize(hat_states)) {
#ifdef SDL_JOYSTICK_RAWINPUT_MATCHING
match_state = (match_state & ~HAT_MASK) | hat_map[state]; match_state = (match_state & ~HAT_MASK) | hat_map[state];
#endif
SDL_PrivateJoystickHat(joystick, i, hat_states[state]); SDL_PrivateJoystickHat(joystick, i, hat_states[state]);
} }
} }
} }
#ifdef SDL_JOYSTICK_RAWINPUT_MATCHING #ifdef SDL_PrivateJoystickButton
#undef SDL_PrivateJoystickButton #undef SDL_PrivateJoystickButton
#endif
#ifdef SDL_PrivateJoystickAxis
#undef SDL_PrivateJoystickAxis #undef SDL_PrivateJoystickAxis
#endif #endif
@ -1446,7 +1470,7 @@ RAWINPUT_UpdateOtherAPIs(SDL_Joystick *joystick)
let's set it to 3 to be safe. An incorrect un-correlation will simply result in lower precision let's set it to 3 to be safe. An incorrect un-correlation will simply result in lower precision
triggers for a frame. */ triggers for a frame. */
if (ctx->wgi_uncorrelate_count >= 3) { if (ctx->wgi_uncorrelate_count >= 3) {
#ifdef DEBUG_JOYSTICK #ifdef DEBUG_RAWINPUT
SDL_Log("UN-Correlated joystick %d to WindowsGamingInput device #%d\n", joystick->instance_id, ctx->wgi_slot); SDL_Log("UN-Correlated joystick %d to WindowsGamingInput device #%d\n", joystick->instance_id, ctx->wgi_slot);
#endif #endif
RAWINPUT_MarkWindowsGamingInputSlotFree(ctx->wgi_slot); RAWINPUT_MarkWindowsGamingInputSlotFree(ctx->wgi_slot);
@ -1478,7 +1502,7 @@ RAWINPUT_UpdateOtherAPIs(SDL_Joystick *joystick)
if (new_correlation_count == 2) { if (new_correlation_count == 2) {
/* correlation stayed steady and uncontested across multiple frames, guaranteed match */ /* correlation stayed steady and uncontested across multiple frames, guaranteed match */
ctx->wgi_correlated = SDL_TRUE; ctx->wgi_correlated = SDL_TRUE;
#ifdef DEBUG_JOYSTICK #ifdef DEBUG_RAWINPUT
SDL_Log("Correlated joystick %d to WindowsGamingInput device #%d\n", joystick->instance_id, slot_idx); SDL_Log("Correlated joystick %d to WindowsGamingInput device #%d\n", joystick->instance_id, slot_idx);
#endif #endif
correlated = SDL_TRUE; correlated = SDL_TRUE;
@ -1539,7 +1563,7 @@ RAWINPUT_UpdateOtherAPIs(SDL_Joystick *joystick)
let's set it to 3 to be safe. An incorrect un-correlation will simply result in lower precision let's set it to 3 to be safe. An incorrect un-correlation will simply result in lower precision
triggers for a frame. */ triggers for a frame. */
if (ctx->xinput_uncorrelate_count >= 3) { if (ctx->xinput_uncorrelate_count >= 3) {
#ifdef DEBUG_JOYSTICK #ifdef DEBUG_RAWINPUT
SDL_Log("UN-Correlated joystick %d to XInput device #%d\n", joystick->instance_id, ctx->xinput_slot); SDL_Log("UN-Correlated joystick %d to XInput device #%d\n", joystick->instance_id, ctx->xinput_slot);
#endif #endif
RAWINPUT_MarkXInputSlotFree(ctx->xinput_slot); RAWINPUT_MarkXInputSlotFree(ctx->xinput_slot);
@ -1571,7 +1595,7 @@ RAWINPUT_UpdateOtherAPIs(SDL_Joystick *joystick)
if (new_correlation_count == 2) { if (new_correlation_count == 2) {
/* correlation stayed steady and uncontested across multiple frames, guaranteed match */ /* correlation stayed steady and uncontested across multiple frames, guaranteed match */
ctx->xinput_correlated = SDL_TRUE; ctx->xinput_correlated = SDL_TRUE;
#ifdef DEBUG_JOYSTICK #ifdef DEBUG_RAWINPUT
SDL_Log("Correlated joystick %d to XInput device #%d\n", joystick->instance_id, slot_idx); SDL_Log("Correlated joystick %d to XInput device #%d\n", joystick->instance_id, slot_idx);
#endif #endif
correlated = SDL_TRUE; correlated = SDL_TRUE;