[PATCH libinput 5/5] touchpad: revert to pointer movement when stopping twofinger scrolling

Peter Hutterer peter.hutterer at who-t.net
Thu Dec 18 15:24:54 PST 2014


Add a boolean state machine for two-finger scrolling so we know when we're
currently scrolling. If we were scrolling and it stops, pick the active
touch as pointer touch so we can go back to pointer movement without having to
lift the finger off the touchpad.

https://bugs.freedesktop.org/show_bug.cgi?id=86807

Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
 src/evdev-mt-touchpad.c | 40 ++++++++++++++++++++++++++++++++++------
 src/evdev-mt-touchpad.h |  6 ++++++
 test/touchpad.c         | 39 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 79 insertions(+), 6 deletions(-)

diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c
index 964900d..0f3e72a 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 e284928..5807f08 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 1a0414c..8602e03 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);
-- 
2.1.0



More information about the wayland-devel mailing list