diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 964900d2..0f3e72a6 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -436,6 +436,33 @@ tp_post_twofinger_scroll(struct tp_dispatch *tp, uint64_t time) tp_filter_motion(tp, &dx, &dy, NULL, NULL, time); evdev_post_scroll(tp->device, time, dx, dy); + tp->scroll.twofinger_state = TWOFINGER_SCROLL_STATE_ACTIVE; +} + +static void +tp_twofinger_stop_scroll(struct tp_dispatch *tp, uint64_t time) +{ + struct tp_touch *t, *ptr = NULL; + int nfingers_down = 0; + + evdev_stop_scroll(tp->device, time); + + /* If we were scrolling and now there's exactly 1 active finger, + switch back to pointer movement */ + if (tp->scroll.twofinger_state == TWOFINGER_SCROLL_STATE_ACTIVE) { + tp_for_each_touch(tp, t) { + if (tp_touch_active(tp, t)) { + nfingers_down++; + if (ptr == NULL) + ptr = t; + } + } + + if (nfingers_down == 1) + tp_set_pointer(tp, ptr); + } + + tp->scroll.twofinger_state = TWOFINGER_SCROLL_STATE_NONE; } static int @@ -458,13 +485,14 @@ tp_twofinger_scroll_post_events(struct tp_dispatch *tp, uint64_t time) nfingers_down++; } - if (nfingers_down != 2) { - evdev_stop_scroll(tp->device, time); - return 0; + if (nfingers_down == 2) { + tp_post_twofinger_scroll(tp, time); + return 1; } - tp_post_twofinger_scroll(tp, time); - return 1; + tp_twofinger_stop_scroll(tp, time); + + return 0; } static void @@ -504,7 +532,7 @@ tp_stop_scroll_events(struct tp_dispatch *tp, uint64_t time) case LIBINPUT_CONFIG_SCROLL_NO_SCROLL: break; case LIBINPUT_CONFIG_SCROLL_2FG: - evdev_stop_scroll(tp->device, time); + tp_twofinger_stop_scroll(tp, time); break; case LIBINPUT_CONFIG_SCROLL_EDGE: tp_edge_scroll_stop_events(tp, time); diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index e2849280..5807f08c 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -117,6 +117,11 @@ enum tp_edge_scroll_touch_state { EDGE_SCROLL_TOUCH_STATE_AREA, }; +enum tp_twofinger_scroll_state { + TWOFINGER_SCROLL_STATE_NONE, + TWOFINGER_SCROLL_STATE_ACTIVE, +}; + struct tp_motion { int32_t x; int32_t y; @@ -238,6 +243,7 @@ struct tp_dispatch { enum libinput_config_scroll_method method; int32_t right_edge; int32_t bottom_edge; + enum tp_twofinger_scroll_state twofinger_state; } scroll; enum touchpad_event queued; diff --git a/test/touchpad.c b/test/touchpad.c index 1a0414cc..8602e039 100644 --- a/test/touchpad.c +++ b/test/touchpad.c @@ -1461,6 +1461,44 @@ START_TEST(touchpad_2fg_scroll_slow_distance) } END_TEST +START_TEST(touchpad_2fg_scroll_return_to_motion) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + + litest_drain_events(li); + + /* start with motion */ + litest_touch_down(dev, 0, 70, 70); + litest_touch_move_to(dev, 0, 70, 70, 47, 50, 10, 0); + litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION); + + /* 2fg scroll */ + litest_touch_down(dev, 1, 53, 50); + litest_touch_move_to(dev, 0, 47, 50, 47, 70, 5, 0); + litest_touch_move_to(dev, 1, 53, 50, 53, 70, 5, 0); + litest_touch_up(dev, 1); + litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_AXIS); + + litest_touch_move_to(dev, 0, 47, 70, 47, 50, 10, 0); + litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION); + + /* back to 2fg scroll, lifting the other finger */ + litest_touch_down(dev, 1, 50, 50); + litest_touch_move_to(dev, 0, 47, 50, 47, 70, 5, 0); + litest_touch_move_to(dev, 1, 53, 50, 53, 70, 5, 0); + litest_touch_up(dev, 0); + litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_AXIS); + + /* move with second finger */ + litest_touch_move_to(dev, 1, 53, 70, 53, 50, 10, 0); + litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION); + + litest_touch_up(dev, 1); + litest_assert_empty_queue(li); +} +END_TEST + START_TEST(touchpad_scroll_natural_defaults) { struct litest_device *dev = litest_current_device(); @@ -2059,6 +2097,7 @@ int main(int argc, char **argv) { litest_add("touchpad:scroll", touchpad_2fg_scroll, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); litest_add("touchpad:scroll", touchpad_2fg_scroll_slow_distance, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); + litest_add("touchpad:scroll", touchpad_2fg_scroll_return_to_motion, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); litest_add("touchpad:scroll", touchpad_scroll_natural_defaults, LITEST_TOUCHPAD, LITEST_ANY); litest_add("touchpad:scroll", touchpad_scroll_natural_enable_config, LITEST_TOUCHPAD, LITEST_ANY); litest_add("touchpad:scroll", touchpad_scroll_natural, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);