Skip to content

Commit

Permalink
Filter jitter on Xbox One controllers when using raw input reports
Browse files Browse the repository at this point in the history
  • Loading branch information
slouken committed Jan 5, 2022
1 parent eca198d commit 16f5b9e
Showing 1 changed file with 45 additions and 17 deletions.
62 changes: 45 additions & 17 deletions src/joystick/hidapi/SDL_hidapi_xboxone.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@
#define CONTROLLER_NEGOTIATION_TIMEOUT_MS 300
#define CONTROLLER_PREPARE_INPUT_TIMEOUT_MS 50

/* Deadzone thresholds */
#define XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE 7849
#define XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE 8689
#define XINPUT_GAMEPAD_TRIGGER_THRESHOLD -25058 /* Uint8 30 scaled to Sint16 full range */

/* Start controller */
static const Uint8 xboxone_init0[] = {
Expand Down Expand Up @@ -474,6 +478,30 @@ HIDAPI_DriverXboxOne_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Jo
return SDL_Unsupported();
}

static Sint16 FilterLeftThumb(Sint16 axis)
{
if (axis <= XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE && axis >= -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) {
return 0;
}
return axis;
}

static Sint16 FilterRightThumb(Sint16 axis)
{
if (axis <= XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE && axis >= -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) {
return 0;
}
return axis;
}

static Sint16 FilterTrigger(Sint16 axis)
{
if (axis <= XINPUT_GAMEPAD_TRIGGER_THRESHOLD) {
return 0;
}
return axis;
}

static void
HIDAPI_DriverXboxOne_HandleStatePacket(SDL_Joystick *joystick, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
{
Expand Down Expand Up @@ -608,7 +636,7 @@ HIDAPI_DriverXboxOne_HandleStatePacket(SDL_Joystick *joystick, SDL_DriverXboxOne
if (axis == -32768 && size == 30 && (data[22] & 0x80) != 0) {
axis = 32767;
}
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, FilterTrigger(axis));

axis = ((int)*(Sint16*)(&data[8]) * 64) - 32768;
if (axis == -32768 && size == 30 && (data[22] & 0x40) != 0) {
Expand All @@ -617,16 +645,16 @@ HIDAPI_DriverXboxOne_HandleStatePacket(SDL_Joystick *joystick, SDL_DriverXboxOne
if (axis == 32704) {
axis = 32767;
}
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, FilterTrigger(axis));

axis = *(Sint16*)(&data[10]);
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, FilterLeftThumb(axis));
axis = *(Sint16*)(&data[12]);
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, ~axis);
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, FilterLeftThumb(~axis));
axis = *(Sint16*)(&data[14]);
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, FilterRightThumb(axis));
axis = *(Sint16*)(&data[16]);
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, ~axis);
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, FilterRightThumb(~axis));

SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
}
Expand Down Expand Up @@ -822,26 +850,26 @@ HIDAPI_DriverXboxOneBluetooth_HandleStatePacket(SDL_Joystick *joystick, SDL_Driv
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, dpad_left);
}

axis = (int)*(Uint16*)(&data[1]) - 0x8000;
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
axis = (int)*(Uint16*)(&data[3]) - 0x8000;
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis);
axis = (int)*(Uint16*)(&data[5]) - 0x8000;
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
axis = (int)*(Uint16*)(&data[7]) - 0x8000;
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis);

axis = ((int)*(Sint16*)(&data[9]) * 64) - 32768;
if (axis == 32704) {
axis = 32767;
}
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, FilterTrigger(axis));

axis = ((int)*(Sint16*)(&data[11]) * 64) - 32768;
if (axis == 32704) {
axis = 32767;
}
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, FilterTrigger(axis));

axis = (int)*(Uint16*)(&data[1]) - 0x8000;
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, FilterLeftThumb(axis));
axis = (int)*(Uint16*)(&data[3]) - 0x8000;
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, FilterLeftThumb(axis));
axis = (int)*(Uint16*)(&data[5]) - 0x8000;
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, FilterRightThumb(axis));
axis = (int)*(Uint16*)(&data[7]) - 0x8000;
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, FilterRightThumb(axis));

SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
}
Expand Down

1 comment on commit 16f5b9e

@Xottab-DUTY
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My Xbox 360 controller also gives some jittering. (i.e. when I'm moving left stick, SDL2 also sends events that right stick was moved, while it wasn't)
Though, I filtered it on application side using dead zone threshold too, maybe there's something we can do about it on SDL side... (but I'm not sure if it's only my controller or that's a common issue)

Please sign in to comment.