From d104c0dcd4687f0de8bf574c7e67a5167ea86f4a Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 9 Aug 2016 14:33:03 +1000 Subject: [PATCH libinput] touchpad: reset the motion history when we release a finger Releasing a finger can cause pointer motion, not necesarily because of the touchpad but because finger shapes and position change as users move their hands. This caused pointer jumps, mainly at the end of a 2fg tap sequence. In particular, the event sequence looks like this: - first finger down - second finger down, causes light movement in the first finger - second finger up, causes light movement in the first finger - first finger up Because we don't know until the tap timeout expires whether we had an actual tap, we may generate motion events between the two finger up events. Avoid this by resetting the motion history whenever we release a second/third/... finger from a touchpad. Since the finger release usually means the end of a tap, 2fg scroll, gesture, clickpad click anyway, having the pointer movement pause for a few events is low impact. We don't do this on finger down so that a pointer movement 'interrupted' by a finger down in the button area does not pause. Signed-off-by: Peter Hutterer --- src/evdev-mt-touchpad.c | 24 +++++++++++++--------- test/touchpad-tap.c | 54 +++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 62 insertions(+), 16 deletions(-) diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 2c73428..1fe1410 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -957,17 +957,21 @@ tp_need_motion_history_reset(struct tp_dispatch *tp) { bool rc = false; - /* semi-mt finger postions may "jump" when nfingers changes */ - if (tp->semi_mt && tp->nfingers_down != tp->old_nfingers_down) - return true; + if (tp->nfingers_down != tp->old_nfingers_down) { + /* semi-mt finger postions may "jump" when nfingers changes */ + if (tp->semi_mt) + return true; - /* if we're transitioning between slots and fake touches in either - * direction, we may get a coordinate jump - */ - if (tp->nfingers_down != tp->old_nfingers_down && - (tp->nfingers_down > tp->num_slots || - tp->old_nfingers_down > tp->num_slots)) - return true; + /* if we're transitioning between slots and fake + touches in either direction, we may get a coordinate jump */ + if ((tp->nfingers_down > tp->num_slots || + tp->old_nfingers_down > tp->num_slots)) + return true; + + /* when we release a finger we likely get a jump */ + if (tp->nfingers_down < tp->old_nfingers_down) + return true; + } /* Quirk: if we had multiple events without x/y axis information, the next x/y event is going to be a jump. So we diff --git a/test/touchpad-tap.c b/test/touchpad-tap.c index 3dcca8f..05fdd71 100644 --- a/test/touchpad-tap.c +++ b/test/touchpad-tap.c @@ -607,7 +607,7 @@ START_TEST(touchpad_1fg_tap_n_drag) litest_touch_down(dev, 0, 50, 50); litest_touch_up(dev, 0); litest_touch_down(dev, 0, 50, 50); - litest_touch_move_to(dev, 0, 50, 50, 80, 80, 5, 40); + litest_touch_move_to(dev, 0, 50, 50, 80, 80, 10, 40); libinput_dispatch(li); @@ -649,7 +649,7 @@ START_TEST(touchpad_1fg_tap_n_drag_draglock) litest_touch_down(dev, 0, 50, 50); litest_touch_up(dev, 0); litest_touch_down(dev, 0, 50, 50); - litest_touch_move_to(dev, 0, 50, 50, 80, 80, 5, 40); + litest_touch_move_to(dev, 0, 50, 50, 80, 80, 10, 40); litest_touch_up(dev, 0); libinput_dispatch(li); @@ -663,7 +663,7 @@ START_TEST(touchpad_1fg_tap_n_drag_draglock) /* lift finger, set down again, should continue dragging */ litest_touch_down(dev, 0, 50, 50); - litest_touch_move_to(dev, 0, 50, 50, 80, 80, 5, 40); + litest_touch_move_to(dev, 0, 50, 50, 80, 80, 10, 40); litest_touch_up(dev, 0); litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION); @@ -690,7 +690,7 @@ START_TEST(touchpad_1fg_tap_n_drag_draglock_tap) litest_touch_down(dev, 0, 50, 50); litest_touch_up(dev, 0); litest_touch_down(dev, 0, 50, 50); - litest_touch_move_to(dev, 0, 50, 50, 80, 80, 5, 40); + litest_touch_move_to(dev, 0, 50, 50, 80, 80, 10, 40); litest_touch_up(dev, 0); libinput_dispatch(li); @@ -704,7 +704,7 @@ START_TEST(touchpad_1fg_tap_n_drag_draglock_tap) /* lift finger, set down again, should continue dragging */ litest_touch_down(dev, 0, 50, 50); - litest_touch_move_to(dev, 0, 50, 50, 80, 80, 5, 40); + litest_touch_move_to(dev, 0, 50, 50, 80, 80, 10, 40); litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION); @@ -732,7 +732,7 @@ START_TEST(touchpad_1fg_tap_n_drag_draglock_tap_click) litest_touch_down(dev, 0, 50, 50); litest_touch_up(dev, 0); litest_touch_down(dev, 0, 50, 50); - litest_touch_move_to(dev, 0, 50, 50, 80, 80, 5, 40); + litest_touch_move_to(dev, 0, 50, 50, 80, 80, 10, 40); libinput_dispatch(li); litest_assert_button_event(li, BTN_LEFT, @@ -1251,6 +1251,47 @@ START_TEST(touchpad_no_first_fg_tap_after_move) } END_TEST +START_TEST(touchpad_2fg_tap_no_move_after_release) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + int i; + + litest_enable_tap(dev->libinput_device); + + litest_drain_events(dev->libinput); + + /* two-finger tap, but the first finger moves + * during the tap (but not enough to go beyond the tap move + * threshold. + * on second finger release, the first finger moves again. + */ + litest_touch_down(dev, 0, 50, 50); + litest_touch_down(dev, 1, 70, 50); + libinput_dispatch(li); + for (i = 0; i < 5; i++) { + litest_touch_move(dev, 0, 50, 50 + i * 0.1); + libinput_dispatch(li); + } + litest_push_event_frame(dev); + litest_touch_move(dev, 0, 50, 51); + litest_touch_up(dev, 1); + litest_pop_event_frame(dev); + libinput_dispatch(li); + litest_touch_up(dev, 0); + libinput_dispatch(li); + + litest_timeout_tap(); + libinput_dispatch(li); + + litest_assert_button_event(li, BTN_RIGHT, + LIBINPUT_BUTTON_STATE_PRESSED); + litest_assert_button_event(li, BTN_RIGHT, + LIBINPUT_BUTTON_STATE_RELEASED); + litest_assert_empty_queue(li); +} +END_TEST + START_TEST(touchpad_1fg_double_tap_click) { struct litest_device *dev = litest_current_device(); @@ -1991,6 +2032,7 @@ litest_setup_tests_touchpad_tap(void) litest_add("tap-2fg:2fg", touchpad_no_2fg_tap_after_timeout, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_SEMI_MT); litest_add("tap-2fg:2fg", touchpad_no_first_fg_tap_after_move, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); litest_add("tap-2fg:2fg", touchpad_no_first_fg_tap_after_move, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); + litest_add("tap-2fg:2fg", touchpad_2fg_tap_no_move_after_release, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); litest_add("tap-3fg:3fg", touchpad_3fg_tap_btntool, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); litest_add("tap-3fg:3fg", touchpad_3fg_tap_btntool_inverted, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); litest_add("tap-3fg:3fg", touchpad_3fg_tap, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); -- 2.7.4