From 1cebdc7a2b3dc8c5d256beddf8e600d184f00b49 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 6 Mar 2015 14:36:31 +1000 Subject: [PATCH] touchpad: accumulate the initial scroll edge delta The previous setting of 10 wasn't 10 mm, it was used against the deltas normalized to a 1000DPI mouse, i.e. closer to 4mm. It was also also per-event, so a slow movement or a high-frequency touchpad can struggle to meet the threshold. Change the trigger to be ~5 mm from the initial touch down, accumulated until we either meet the threshold or the timeout expires. The first scroll event includes the delta since the touch down rather than the most recent delta. This removes the delay otherwise seen in scrolling and makes the scroll motion match the finger motion. This accumulated delta only applies when exceeding the motion threshold, when the timeout triggers the switch to scrolling the first delta posted is the current delta. Signed-off-by: Peter Hutterer Reviewed-by: Hans de Goede --- src/evdev-mt-touchpad-edge-scroll.c | 37 ++++++++++++++++++++++++++--- src/evdev-mt-touchpad.h | 2 ++ test/litest.c | 6 +++++ test/litest.h | 1 + test/touchpad.c | 16 +++++++++---- 5 files changed, 54 insertions(+), 8 deletions(-) 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);