[PATCH libinput 15/19] touchpad: add fake-touch support for BTN_TOOL_DOUBLETAP and friends

Peter Hutterer peter.hutterer at who-t.net
Sun Feb 16 22:48:34 PST 2014


This enables two-finger scrolling and two- and three-finger tapping on a
single-touch touchpad if BTN_TOOL_DOUBLETAP and BTN_TOOL_TRIPLETAP is set.

These require a bit of special processing:
BTN_TOUCH is set with the first finger down, but somewhat randomly unset and
re-set when switching between the various BTN_TOOL_*TAP values.
BTN_TOOL_<N>TAP is only set for N fingers down, thus a double->triple move
will see a release for DOUBLETAP and a press for TRIPLETAP. This may happen in
the same event, or across two consecutive events.

This patch adds a fake_touches mask to the touchpad struct. The mask is set
for each matching BTN_* event and used to count the number of expected
fake touchpoints. From that we begin/end the number of actual touchpoints
required. Fake touchpoints take their x/y coordinates from the first
touchpoint, which reads ABS_X/ABS_Y.

Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
 src/evdev-mt-touchpad.c | 78 ++++++++++++++++++++++++++++++++++++++++++-------
 src/evdev-mt-touchpad.h |  1 +
 2 files changed, 68 insertions(+), 11 deletions(-)

diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c
index f8edb8c..d0864fe 100644
--- a/src/evdev-mt-touchpad.c
+++ b/src/evdev-mt-touchpad.c
@@ -142,6 +142,13 @@ tp_current_touch(struct tp_dispatch *tp)
 	return &tp->touches[min(tp->slot, tp->ntouches)];
 }
 
+static inline struct tp_touch *
+tp_get_touch(struct tp_dispatch *tp, unsigned int slot)
+{
+	assert(slot < tp->ntouches);
+	return &tp->touches[slot];
+}
+
 static inline void
 tp_begin_touch(struct tp_dispatch *tp, struct tp_touch *t)
 {
@@ -248,6 +255,54 @@ tp_process_absolute_st(struct tp_dispatch *tp,
 }
 
 static void
+tp_process_fake_touch(struct tp_dispatch *tp,
+		      const struct input_event *e,
+		      uint32_t time)
+{
+	struct tp_touch *t;
+	unsigned int fake_touches;
+	unsigned int nfake_touches;
+	unsigned int i;
+	unsigned int shift;
+
+	if (e->code != BTN_TOUCH &&
+	    (e->code < BTN_TOOL_DOUBLETAP || e->code > BTN_TOOL_QUADTAP))
+		return;
+
+	shift = e->code == BTN_TOUCH ? 0 : (e->code - BTN_TOOL_DOUBLETAP + 1);
+
+	if (e->value)
+		tp->fake_touches |= 1 << shift;
+	else
+		tp->fake_touches &= ~(0x1 << shift);
+
+	fake_touches = tp->fake_touches;
+	nfake_touches = 0;
+	while (fake_touches) {
+		nfake_touches++;
+		fake_touches >>= 1;
+	}
+
+	for (i = 0; i < tp->ntouches; i++) {
+		t = tp_get_touch(tp, i);
+		if (i >= nfake_touches) {
+			if (t->state != TOUCH_NONE) {
+				tp_end_touch(tp, t);
+				t->millis = time;
+			}
+		} else if (t->state != TOUCH_UPDATE &&
+			   t->state != TOUCH_BEGIN) {
+			t->state = TOUCH_NONE;
+			tp_begin_touch(tp, t);
+			t->millis = time;
+			t->fake =true;
+		}
+	}
+
+	assert(tp->nfingers_down == nfake_touches);
+}
+
+static void
 tp_process_key(struct tp_dispatch *tp,
 	       const struct input_event *e,
 	       uint32_t time)
@@ -268,16 +323,11 @@ tp_process_key(struct tp_dispatch *tp,
 			}
 			break;
 		case BTN_TOUCH:
-			if (!tp->has_mt) {
-				struct tp_touch *t = tp_current_touch(tp);
-				if (e->value) {
-					tp_begin_touch(tp, t);
-					t->fake = true;
-				} else {
-					tp_end_touch(tp, t);
-				}
-				t->millis = time;
-			}
+		case BTN_TOOL_DOUBLETAP:
+		case BTN_TOOL_TRIPLETAP:
+		case BTN_TOOL_QUADTAP:
+			if (!tp->has_mt)
+				tp_process_fake_touch(tp, e, time);
 			break;
 	}
 }
@@ -286,9 +336,15 @@ static void
 tp_process_state(struct tp_dispatch *tp, uint32_t time)
 {
 	struct tp_touch *t;
+	struct tp_touch *first = tp_get_touch(tp, 0);
 
 	tp_for_each_touch(tp, t) {
-		if (!t->dirty)
+		if (!tp->has_mt && t != first && first->fake) {
+			t->x = first->x;
+			t->y = first->y;
+			if (!t->dirty)
+				t->dirty = first->dirty;
+		} else if (!t->dirty)
 			continue;
 
 		tp_motion_hysteresis(tp, t);
diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h
index 1e09497..84d8cec 100644
--- a/src/evdev-mt-touchpad.h
+++ b/src/evdev-mt-touchpad.h
@@ -101,6 +101,7 @@ struct tp_dispatch {
 
 	unsigned int ntouches;			/* number of slots */
 	struct tp_touch *touches;		/* len == ntouches */
+	unsigned int fake_touches;		/* fake touch mask */
 
 	struct {
 		int32_t margin_x;
-- 
1.8.4.2



More information about the wayland-devel mailing list