[PATCH libinput 3/6] touchpad: add a TOUCH_HOVERING state

Peter Hutterer peter.hutterer at who-t.net
Mon Dec 15 19:14:48 PST 2014


Some touchpads provide touch information while the finger hovers over the
touchpad, i.e. before BTN_TOUCH. Add a touch state for those touchpads so we
can ignore the touches until they actually start.

The approach is now: instead of BEGIN we mark a new touch as HOVERING.
Use the BTN_TOOL_FINGER, BTN_TOOL_DOUBLETAP information during
tp_process_state() to mark any touches that are hovering as down or ended.

i.e. provided BTN_TOUCH is down: if BTN_TOOL_FINGER is down, one hovering
touch gets marked as down, if DOUBLETAP is down, two touches are marked as
down, etc.

When ending touches, switch them back into HOVERING if the BTN_TOOL_FINGER
is still set, otherwise end them properly.

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

Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
 src/evdev-mt-touchpad-edge-scroll.c |  1 +
 src/evdev-mt-touchpad.c             | 81 ++++++++++++++++++++++++++++++++-----
 src/evdev-mt-touchpad.h             |  8 +++-
 3 files changed, 78 insertions(+), 12 deletions(-)

diff --git a/src/evdev-mt-touchpad-edge-scroll.c b/src/evdev-mt-touchpad-edge-scroll.c
index 616080f..55720f8 100644
--- a/src/evdev-mt-touchpad-edge-scroll.c
+++ b/src/evdev-mt-touchpad-edge-scroll.c
@@ -294,6 +294,7 @@ tp_edge_scroll_handle_state(struct tp_dispatch *tp, uint64_t time)
 
 		switch (t->state) {
 		case TOUCH_NONE:
+		case TOUCH_HOVERING:
 			break;
 		case TOUCH_BEGIN:
 			tp_edge_scroll_handle_event(tp, t, SCROLL_EVENT_TOUCH);
diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c
index c80d314..4898950 100644
--- a/src/evdev-mt-touchpad.c
+++ b/src/evdev-mt-touchpad.c
@@ -180,24 +180,36 @@ tp_fake_finger_set(struct tp_dispatch *tp,
 static inline void
 tp_begin_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
 {
-	if (t->state == TOUCH_BEGIN || t->state == TOUCH_UPDATE)
+	if (t->state == TOUCH_BEGIN ||
+	    t->state == TOUCH_UPDATE ||
+	    t->state == TOUCH_HOVERING)
 		return;
 
+	/* we begin the touch as hovering because until BTN_TOUCH happens we
+	 * don't know if it's a touch down or not. And BTN_TOUCH may happen
+	 * after ABS_MT_TRACKING_ID */
 	tp_motion_history_reset(t);
 	t->dirty = true;
-	t->state = TOUCH_BEGIN;
+	t->state = TOUCH_HOVERING;
 	t->pinned.is_pinned = false;
 	t->millis = time;
-	tp->nfingers_down++;
-	assert(tp->nfingers_down >= 1);
 	tp->queued |= TOUCHPAD_EVENT_MOTION;
 }
 
 static inline void
 tp_end_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
 {
-	if (t->state == TOUCH_END || t->state == TOUCH_NONE)
+	switch (t->state) {
+	case TOUCH_HOVERING:
+		t->state = TOUCH_NONE;
+	case TOUCH_NONE:
+	case TOUCH_END:
 		return;
+	case TOUCH_BEGIN:
+	case TOUCH_UPDATE:
+		break;
+
+	}
 
 	t->dirty = true;
 	t->is_pointer = false;
@@ -310,9 +322,6 @@ tp_process_fake_touch(struct tp_dispatch *tp,
 		else
 			tp_end_touch(tp, t, time);
 	}
-
-	/* On mt the actual touch info may arrive after BTN_TOOL_FOO */
-	assert(tp->has_mt || tp->nfingers_down == nfake_touches);
 }
 
 static void
@@ -327,6 +336,7 @@ tp_process_key(struct tp_dispatch *tp,
 			tp_process_button(tp, e, time);
 			break;
 		case BTN_TOUCH:
+		case BTN_TOOL_FINGER:
 		case BTN_TOOL_DOUBLETAP:
 		case BTN_TOOL_TRIPLETAP:
 		case BTN_TOOL_QUADTAP:
@@ -543,12 +553,56 @@ tp_remove_scroll(struct tp_dispatch *tp)
 }
 
 static void
+tp_unhover_touches(struct tp_dispatch *tp, uint64_t time)
+{
+	struct tp_touch *t;
+	unsigned int nfake_touches;
+	unsigned int i;
+
+	if (!tp->fake_touches && !tp->nfingers_down)
+		return;
+
+	nfake_touches = tp_fake_finger_count(tp);
+	if (tp->nfingers_down == nfake_touches &&
+	    ((tp->nfingers_down == 0 && !tp_fake_finger_is_touching(tp)) ||
+	     (tp->nfingers_down > 0 && tp_fake_finger_is_touching(tp))))
+		return;
+
+	for (i = 0; i < tp->ntouches; i++) {
+		t = tp_get_touch(tp, i);
+
+		/* if BTN_TOUCH is set, switch each hovering touch to BEGIN
+		 * until nfingers_down matches nfake_touches (or end touches
+		 * until that happens).
+		 * if BTN_TOUCH is unset, end all touches, we're hovering
+		 * all fingers now
+		 */
+		if (t->state == TOUCH_HOVERING) {
+			if (tp_fake_finger_is_touching(tp)) {
+				t->state = TOUCH_BEGIN;
+				tp->nfingers_down++;
+				assert(tp->nfingers_down >= 1);
+			}
+		} else if (tp->nfingers_down > nfake_touches ||
+			   !tp_fake_finger_is_touching(tp)) {
+			tp_end_touch(tp, t, time);
+		}
+
+		if (tp_fake_finger_is_touching(tp) &&
+		    tp->nfingers_down == nfake_touches)
+			break;
+	}
+}
+
+static void
 tp_process_state(struct tp_dispatch *tp, uint64_t time)
 {
 	struct tp_touch *t;
 	struct tp_touch *first = tp_get_touch(tp, 0);
 	unsigned int i;
 
+	tp_unhover_touches(tp, time);
+
 	for (i = 0; i < tp->ntouches; i++) {
 		t = tp_get_touch(tp, i);
 
@@ -597,10 +651,15 @@ tp_post_process_state(struct tp_dispatch *tp, uint64_t time)
 		if (!t->dirty)
 			continue;
 
-		if (t->state == TOUCH_END)
-			t->state = TOUCH_NONE;
-		else if (t->state == TOUCH_BEGIN)
+		if (t->state == TOUCH_END) {
+			if (!tp_fake_finger_is_touching(tp) &&
+			    tp_fake_finger_count(tp) > 0)
+				t->state = TOUCH_HOVERING;
+			else
+				t->state = TOUCH_NONE;
+		} else if (t->state == TOUCH_BEGIN) {
 			t->state = TOUCH_UPDATE;
+		}
 
 		t->dirty = false;
 	}
diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h
index 1450288..cdbf804 100644
--- a/src/evdev-mt-touchpad.h
+++ b/src/evdev-mt-touchpad.h
@@ -53,6 +53,7 @@ enum touchpad_model {
 
 enum touch_state {
 	TOUCH_NONE = 0,
+	TOUCH_HOVERING,
 	TOUCH_BEGIN,
 	TOUCH_UPDATE,
 	TOUCH_END
@@ -192,7 +193,12 @@ struct tp_dispatch {
 	unsigned int real_touches;		/* number of slots */
 	unsigned int ntouches;			/* no slots inc. fakes */
 	struct tp_touch *touches;		/* len == ntouches */
-	unsigned int fake_touches;		/* fake touch mask */
+	/* bit 0: BTN_TOUCH
+	 * bit 1: BTN_TOOL_FINGER
+	 * bit 2: BTN_TOOL_DOUBLETAP
+	 * ...
+	 */
+	unsigned int fake_touches;
 
 	struct {
 		int32_t margin_x;
-- 
2.1.0



More information about the wayland-devel mailing list