Skip to content

Clear other axis that is in deadzone threshold

Fredrik Fornwall requested to merge fornwall/gilrs:fix-deadzone into master

Clear the second axis when an axis event causes a second axis to be within the deadzone threshold.

I'm seeing drift on multiple gamepads due to what I believe is an issue with the deadzone filter, as describe by the below flow, with tiny_* here meaning drift values).

  1. You press the gamepad axis - two events are received by gilrs
    1. axis_x = large_value_x - gilrs stores that as state, and sends event through
    2. axis_y = large_value_y - gilrs stores that as state, and sends event through
  2. You release the gamepad axis - but it has a slight drift. Now, if the x axis event comes before y (and same thing the other way around), gilrs receives these two events:
    1. axis_x = tiny_value_x - gilrs sees that the new axis value would be new_axis_state = (tiny_value_x, large_value_y), and checks magnitude(new_axis_state) > deadzone_threshold, so it updates state and sends a axis_x=tiny_value_x event through.
    2. axis_y = tiny_value_y - gilrs sees that the new axis value would be new_axis_state = (tiny_value_x, tiny_value_y), and checks magnitude(new_axis_state) < deadzone_threshold - so it sets new_axis_state = (tiny_value_x, 0.0), and sends a axis_y=0.0 event.

Now the gilrs state is incorrectly (axis_x, axis_y) = (tiny_value_x, 0.0), and the latest axis_x event delivered was axis_x = tiny_value_x, which causes drift.

This change only applies the fix if update_state is true, as otherwise we risk an infinite loop, since we do not know what state we currently have. A more invasive change could be to add a field like Event::synthetic , so that the deadzone filter knows not to send the additional event once it encounters a synthetic event. Let me know if you want that approach, or some alternative solution.

Edited by Fredrik Fornwall

Merge request reports