mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2025-12-20 08:00:08 +01:00
touchpad: never reduce the slot count to 0
Where a user releases all touches during a SYN_DROPPED and then puts more than one finger back down before we sync, we end up with nonzero fake touches but a zero slot count. This is caused by a wrong event sequences provided by libevdev in that case. This really needs to be fixed in libevdev, see https://gitlab.freedesktop.org/libevdev/libevdev/merge_requests/19 In the meantime, put a check in to ignore that case and never reduce the slot count to 0. It still leaves us open for some issues where 3fg gestures may stop working if the right sequences are triggered during SYN_DROPPED but updating libevdev will eventually make that go away too. Fixes #422 Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
parent
0da2e744ea
commit
1e1b9c0e60
2 changed files with 74 additions and 0 deletions
|
|
@ -650,8 +650,20 @@ tp_process_fake_touches(struct tp_dispatch *tp,
|
|||
*
|
||||
* All touchpad devices have at least one slot so we only do this
|
||||
* for 2 touches or higher.
|
||||
*
|
||||
* There's an bug in libevdev < 1.9.0 affecting slots after a
|
||||
* SYN_DROPPED. Where a user release one or more touches during
|
||||
* SYN_DROPPED and places new ones on the touchpad, we may end up
|
||||
* with fake touches but no active slots.
|
||||
* So let's check for nactive_slots > 0 to make sure we don't lose
|
||||
* all fingers. That's a workaround only, this must be fixed in
|
||||
* libevdev.
|
||||
*
|
||||
* For a long explanation of what happens, see
|
||||
* https://gitlab.freedesktop.org/libevdev/libevdev/merge_requests/19
|
||||
*/
|
||||
if (nfake_touches > 1 && tp->has_mt &&
|
||||
tp->nactive_slots > 0 &&
|
||||
nfake_touches > tp->nactive_slots &&
|
||||
tp->nactive_slots < tp->num_slots) {
|
||||
evdev_log_bug_kernel(tp->device,
|
||||
|
|
|
|||
|
|
@ -3570,6 +3570,67 @@ START_TEST(touchpad_initial_state)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
/* This just tests that we don't completely screw up in one specific case.
|
||||
* The test likely needs to be removed if it starts failing in the future.
|
||||
*
|
||||
* Where we get touch releases during SYN_DROPPED, libevdev < 1.9.0 gives us
|
||||
* wrong event sequence during sync, see
|
||||
* https://gitlab.freedesktop.org/libevdev/libevdev/merge_requests/19
|
||||
*
|
||||
* libinput 1.15.1 ended up dropping our slot count to 0, making the
|
||||
* touchpad unusable, see #422. This test just checks that we can still move
|
||||
* the pointer and scroll where we trigger such a sequence. This tests for
|
||||
* the worst-case scenario - where we previously reset to a slot count of 0.
|
||||
*
|
||||
* However, the exact behavior depends on how many slots were
|
||||
* stopped/restarted during SYN_DROPPED, a single test is barely useful.
|
||||
* libinput will still do the wrong thing if you start with e.g. 3fg on the
|
||||
* touchpad and release one or two of them. But since this needs to be fixed
|
||||
* in libevdev, here is the most important test.
|
||||
*/
|
||||
START_TEST(touchpad_state_after_syn_dropped_2fg_change)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
|
||||
litest_drain_events(li);
|
||||
litest_disable_tap(dev->libinput_device);
|
||||
|
||||
litest_touch_down(dev, 0, 10, 10);
|
||||
libinput_dispatch(li);
|
||||
|
||||
/* Force a SYN_DROPPED */
|
||||
for (int i = 0; i < 500; i++)
|
||||
litest_touch_move(dev, 0, 10 + 0.1 * i, 10 + 0.1 * i);
|
||||
|
||||
/* still within SYN_DROPPED */
|
||||
litest_touch_up(dev, 0);
|
||||
litest_touch_down(dev, 0, 50, 50);
|
||||
litest_touch_down(dev, 1, 70, 50);
|
||||
|
||||
libinput_dispatch(li);
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_touch_up(dev, 0);
|
||||
litest_touch_up(dev, 1);
|
||||
|
||||
/* 2fg scrolling still works? */
|
||||
litest_touch_down(dev, 0, 50, 50);
|
||||
litest_touch_down(dev, 1, 70, 50);
|
||||
litest_touch_move_two_touches(dev, 50, 50, 70, 50, 0, -20, 10);
|
||||
litest_touch_up(dev, 0);
|
||||
litest_touch_up(dev, 1);
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_AXIS);
|
||||
|
||||
/* pointer motion still works? */
|
||||
litest_touch_down(dev, 0, 50, 50);
|
||||
for (int i = 0; i < 10; i++)
|
||||
litest_touch_move(dev, 0, 10 + 0.1 * i, 10 + 0.1 * i);
|
||||
litest_touch_up(dev, 0);
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(touchpad_dwt)
|
||||
{
|
||||
struct litest_device *touchpad = litest_current_device();
|
||||
|
|
@ -6991,6 +7052,7 @@ TEST_COLLECTION(touchpad)
|
|||
litest_add_for_device("touchpad:trackpoint", touchpad_trackpoint_no_trackpoint, LITEST_SYNAPTICS_TRACKPOINT_BUTTONS);
|
||||
|
||||
litest_add_ranged("touchpad:state", touchpad_initial_state, LITEST_TOUCHPAD, LITEST_ANY, &axis_range);
|
||||
litest_add("touchpad:state", touchpad_state_after_syn_dropped_2fg_change, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
|
||||
|
||||
litest_add("touchpad:dwt", touchpad_dwt, LITEST_TOUCHPAD, LITEST_ANY);
|
||||
litest_add_for_device("touchpad:dwt", touchpad_dwt_ext_and_int_keyboard, LITEST_SYNAPTICS_I2C);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue