[PATCH v2 libinput 5/3] touchpad: accumulate the initial scroll edge delta

Peter Hutterer peter.hutterer at who-t.net
Sun Mar 8 17:54:04 PDT 2015


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 <peter.hutterer at who-t.net>
Reviewed-by: Hans de Goede <hdegoede at redhat.com>
---
Changes to v1:
- use TP_MM_TO_DPI_NORMALIZED
- reset dx/dy, not just *delta
- expand commit message that we're using accumulated deltas on the first scroll
- rename the slow_distance test to timeout, that's what we're triggering
  here

 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 28f29c2..3adde8c 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 fc75f93..239bddd 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 4d04b52..3646446 100644
--- a/test/litest.c
+++ b/test/litest.c
@@ -1391,6 +1391,12 @@ litest_timeout_finger_switch(void)
 }
 
 void
+litest_timeout_edgescroll(void)
+{
+	msleep(300);
+}
+
+void
 litest_push_event_frame(struct litest_device *dev)
 {
 	assert(!dev->skip_ev_syn);
diff --git a/test/litest.h b/test/litest.h
index 8f16851..e85b511 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 5c8f579..ff4edb0 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);
-- 
2.1.0



More information about the wayland-devel mailing list