diff --git a/src/evdev-mt-touchpad-edge-scroll.c b/src/evdev-mt-touchpad-edge-scroll.c index 28f29c2f..3adde8c7 100644 --- a/src/evdev-mt-touchpad-edge-scroll.c +++ b/src/evdev-mt-touchpad-edge-scroll.c @@ -34,8 +34,7 @@ avoid accidentally locking in scrolling mode when trying to use the entire touchpad to move the pointer. The user can wait for the timeout to trigger to do a small scroll. */ -/* In mm for touchpads with valid resolution, see tp_init_accel() */ -#define DEFAULT_SCROLL_THRESHOLD 10.0 +#define DEFAULT_SCROLL_THRESHOLD TP_MM_TO_DPI_NORMALIZED(5) enum scroll_event { SCROLL_EVENT_TOUCH, @@ -78,6 +77,8 @@ tp_edge_scroll_set_state(struct tp_dispatch *tp, break; case EDGE_SCROLL_TOUCH_STATE_EDGE_NEW: t->scroll.edge = tp_touch_get_edge(tp, t); + t->scroll.initial_x = t->x; + t->scroll.initial_y = t->y; libinput_timer_set(&t->scroll.timer, t->millis + DEFAULT_SCROLL_LOCK_TIMEOUT); break; @@ -315,6 +316,7 @@ tp_edge_scroll_post_events(struct tp_dispatch *tp, uint64_t time) struct tp_touch *t; enum libinput_pointer_axis axis; double dx, dy, *delta; + double initial_dx, initial_dy, *initial_delta; if (tp->scroll.method != LIBINPUT_CONFIG_SCROLL_EDGE) return 0; @@ -338,10 +340,12 @@ tp_edge_scroll_post_events(struct tp_dispatch *tp, uint64_t time) case EDGE_RIGHT: axis = LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL; delta = &dy; + initial_delta = &initial_dy; break; case EDGE_BOTTOM: axis = LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL; delta = &dx; + initial_delta = &initial_dx; break; default: /* EDGE_RIGHT | EDGE_BOTTOM */ continue; /* Don't know direction yet, skip */ @@ -350,7 +354,34 @@ tp_edge_scroll_post_events(struct tp_dispatch *tp, uint64_t time) tp_get_delta(t, &dx, &dy); tp_filter_motion(tp, &dx, &dy, NULL, NULL, time); - if (fabs(*delta) < t->scroll.threshold) + switch (t->scroll.edge_state) { + case EDGE_SCROLL_TOUCH_STATE_NONE: + case EDGE_SCROLL_TOUCH_STATE_AREA: + log_bug_libinput(device->seat->libinput, + "unexpected scroll state %d\n", + t->scroll.edge_state); + break; + case EDGE_SCROLL_TOUCH_STATE_EDGE_NEW: + initial_dx = t->x - t->scroll.initial_x; + initial_dy = t->y - t->scroll.initial_y; + tp_normalize_delta(tp, + &initial_dx, + &initial_dy); + if (fabs(*initial_delta) < t->scroll.threshold) { + dx = 0.0; + dy = 0.0; + } else { + dx = initial_dx; + dy = initial_dy; + } + break; + case EDGE_SCROLL_TOUCH_STATE_EDGE: + if (fabs(*delta) < t->scroll.threshold) + *delta = 0.0; + break; + } + + if (*delta == 0.0) continue; pointer_notify_axis(device, time, diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index fc75f93b..239bddd8 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -176,6 +176,8 @@ struct tp_touch { int direction; double threshold; struct libinput_timer timer; + int32_t initial_x; /* in device coordinates */ + int32_t initial_y; /* in device coordinates */ } scroll; struct { diff --git a/test/litest.c b/test/litest.c index 4d04b52c..36464462 100644 --- a/test/litest.c +++ b/test/litest.c @@ -1390,6 +1390,12 @@ litest_timeout_finger_switch(void) msleep(120); } +void +litest_timeout_edgescroll(void) +{ + msleep(300); +} + void litest_push_event_frame(struct litest_device *dev) { diff --git a/test/litest.h b/test/litest.h index 8f16851e..e85b511e 100644 --- a/test/litest.h +++ b/test/litest.h @@ -183,6 +183,7 @@ struct libevdev_uinput * litest_create_uinput_abs_device(const char *name, void litest_timeout_tap(void); void litest_timeout_softbuttons(void); void litest_timeout_buttonscroll(void); +void litest_timeout_edgescroll(void); void litest_timeout_finger_switch(void); void litest_push_event_frame(struct litest_device *dev); diff --git a/test/touchpad.c b/test/touchpad.c index 5c8f579e..ff4edb04 100644 --- a/test/touchpad.c +++ b/test/touchpad.c @@ -2057,7 +2057,7 @@ START_TEST(touchpad_edge_scroll) } END_TEST -START_TEST(touchpad_edge_scroll_slow_distance) +START_TEST(touchpad_edge_scroll_timeout) { struct litest_device *dev = litest_current_device(); struct libinput *li = dev->libinput; @@ -2067,6 +2067,10 @@ START_TEST(touchpad_edge_scroll_slow_distance) litest_drain_events(li); litest_touch_down(dev, 0, 99, 20); + libinput_dispatch(li); + litest_timeout_edgescroll(); + libinput_dispatch(li); + litest_touch_move_to(dev, 0, 99, 20, 99, 80, 60, 10); litest_touch_up(dev, 0); libinput_dispatch(li); @@ -2074,6 +2078,8 @@ START_TEST(touchpad_edge_scroll_slow_distance) event = libinput_get_event(li); ck_assert_notnull(event); + litest_wait_for_event_of_type(li, LIBINPUT_EVENT_POINTER_AXIS, -1); + while (libinput_next_event_type(li) != LIBINPUT_EVENT_NONE) { double axisval; ck_assert_int_eq(libinput_event_get_type(event), @@ -2105,10 +2111,10 @@ START_TEST(touchpad_edge_scroll_no_motion) litest_drain_events(li); - litest_touch_down(dev, 0, 99, 20); - litest_touch_move_to(dev, 0, 99, 20, 99, 60, 10, 0); + litest_touch_down(dev, 0, 99, 10); + litest_touch_move_to(dev, 0, 99, 10, 99, 70, 10, 0); /* moving outside -> no motion event */ - litest_touch_move_to(dev, 0, 99, 60, 20, 80, 10, 0); + litest_touch_move_to(dev, 0, 99, 70, 20, 80, 10, 0); /* moving down outside edge once scrolling had started -> scroll */ litest_touch_move_to(dev, 0, 20, 80, 40, 99, 10, 0); litest_touch_up(dev, 0); @@ -3427,7 +3433,7 @@ int main(int argc, char **argv) { litest_add("touchpad:scroll", touchpad_edge_scroll, LITEST_TOUCHPAD|LITEST_SINGLE_TOUCH, LITEST_ANY); litest_add("touchpad:scroll", touchpad_edge_scroll_no_motion, LITEST_TOUCHPAD|LITEST_SINGLE_TOUCH, LITEST_ANY); litest_add("touchpad:scroll", touchpad_edge_scroll_no_edge_after_motion, LITEST_TOUCHPAD|LITEST_SINGLE_TOUCH, LITEST_ANY); - litest_add("touchpad:scroll", touchpad_edge_scroll_slow_distance, LITEST_TOUCHPAD|LITEST_SINGLE_TOUCH, LITEST_ANY); + litest_add("touchpad:scroll", touchpad_edge_scroll_timeout, LITEST_TOUCHPAD|LITEST_SINGLE_TOUCH, LITEST_ANY); litest_add("touchpad:scroll", touchpad_edge_scroll_source, LITEST_TOUCHPAD|LITEST_SINGLE_TOUCH, LITEST_ANY); litest_add("touchpad:palm", touchpad_palm_detect_at_edge, LITEST_TOUCHPAD, LITEST_ANY);