[PATCH 3/4] touchpad: Create fake touches for BTN_TOOL_FOO on multi-touch pads too

Hans de Goede hdegoede at redhat.com
Fri Jul 18 02:06:38 PDT 2014


Multi-touch pads may track less touches then they can report fingers being
present through BTN_TOOL_FOO. So create fake touches for fingers reported
by BTN_TOOL_FOO on multi-touch pads too (when necessary).

This fixes e.g. 3 finger tap not working on the T440s.

Signed-off-by: Hans de Goede <hdegoede at redhat.com>
---
 src/evdev-mt-touchpad.c | 74 +++++++++++++++++++++++++------------------------
 src/evdev-mt-touchpad.h |  4 +--
 2 files changed, 40 insertions(+), 38 deletions(-)

diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c
index 6f5ce26..1e2f58d 100644
--- a/src/evdev-mt-touchpad.c
+++ b/src/evdev-mt-touchpad.c
@@ -247,7 +247,7 @@ tp_process_fake_touch(struct tp_dispatch *tp,
 	struct tp_touch *t;
 	unsigned int fake_touches;
 	unsigned int nfake_touches;
-	unsigned int i;
+	unsigned int i, start;
 	unsigned int shift;
 
 	if (e->code != BTN_TOUCH &&
@@ -268,16 +268,18 @@ tp_process_fake_touch(struct tp_dispatch *tp,
 		fake_touches >>= 1;
 	}
 
-	for (i = 0; i < tp->ntouches; i++) {
+	/* For single touch tps we use BTN_TOUCH for begin / end of touch 0 */
+	start = tp->has_mt ? tp->real_touches : 0;
+	for (i = start; i < tp->ntouches; i++) {
 		t = tp_get_touch(tp, i);
-		if (i < nfake_touches) {
+		if (i < nfake_touches)
 			tp_begin_touch(tp, t, time);
-			t->fake =true;
-		} else
+		else
 			tp_end_touch(tp, t, time);
 	}
 
-	assert(tp->nfingers_down == nfake_touches);
+	/* On mt the actual touch info may arrive after BTN_TOOL_FOO */
+	assert(tp->has_mt || tp->nfingers_down == nfake_touches);
 }
 
 static void
@@ -295,8 +297,7 @@ tp_process_key(struct tp_dispatch *tp,
 		case BTN_TOOL_DOUBLETAP:
 		case BTN_TOOL_TRIPLETAP:
 		case BTN_TOOL_QUADTAP:
-			if (!tp->has_mt)
-				tp_process_fake_touch(tp, e, time);
+			tp_process_fake_touch(tp, e, time);
 			break;
 	}
 }
@@ -401,9 +402,11 @@ 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_for_each_touch(tp, t) {
-		if (!tp->has_mt && t != first && first->fake) {
+	for (i = 0; i < tp->ntouches; i++) {
+		t = tp_get_touch(tp, i);
+		if (i >= tp->real_touches && t->state != TOUCH_NONE) {
 			t->x = first->x;
 			t->y = first->y;
 			if (!t->dirty)
@@ -443,10 +446,9 @@ tp_post_process_state(struct tp_dispatch *tp, uint64_t time)
 		if (!t->dirty)
 			continue;
 
-		if (t->state == TOUCH_END) {
+		if (t->state == TOUCH_END)
 			t->state = TOUCH_NONE;
-			t->fake = false;
-		} else if (t->state == TOUCH_BEGIN)
+		else if (t->state == TOUCH_BEGIN)
 			t->state = TOUCH_UPDATE;
 
 		t->dirty = false;
@@ -642,41 +644,41 @@ static int
 tp_init_slots(struct tp_dispatch *tp,
 	      struct evdev_device *device)
 {
-	size_t i;
 	const struct input_absinfo *absinfo;
+	struct map {
+		unsigned int code;
+		int ntouches;
+	} max_touches[] = {
+		{ BTN_TOOL_QUINTTAP, 5 },
+		{ BTN_TOOL_QUADTAP, 4 },
+		{ BTN_TOOL_TRIPLETAP, 3 },
+		{ BTN_TOOL_DOUBLETAP, 2 },
+	};
+	struct map *m;
+	unsigned int i, n_btn_tool_touches = 1;
 
 	absinfo = libevdev_get_abs_info(device->evdev, ABS_MT_SLOT);
 	if (absinfo) {
-		tp->ntouches = absinfo->maximum + 1;
+		tp->real_touches = absinfo->maximum + 1;
 		tp->slot = absinfo->value;
 		tp->has_mt = true;
 	} else {
-		struct map {
-			unsigned int code;
-			int ntouches;
-		} max_touches[] = {
-			{ BTN_TOOL_QUINTTAP, 5 },
-			{ BTN_TOOL_QUADTAP, 4 },
-			{ BTN_TOOL_TRIPLETAP, 3 },
-			{ BTN_TOOL_DOUBLETAP, 2 },
-		};
-		struct map *m;
-
+		tp->real_touches = 1;
 		tp->slot = 0;
 		tp->has_mt = false;
-		tp->ntouches = 1;
+	}
 
-		ARRAY_FOR_EACH(max_touches, m) {
-			if (libevdev_has_event_code(device->evdev,
-						    EV_KEY,
-						    m->code)) {
-				tp->ntouches = m->ntouches;
-				break;
-			}
+	ARRAY_FOR_EACH(max_touches, m) {
+		if (libevdev_has_event_code(device->evdev,
+					    EV_KEY,
+					    m->code)) {
+			n_btn_tool_touches = m->ntouches;
+			break;
 		}
 	}
-	tp->touches = calloc(tp->ntouches,
-			     sizeof(struct tp_touch));
+
+	tp->ntouches = max(tp->real_touches, n_btn_tool_touches);
+	tp->touches = calloc(tp->ntouches, sizeof(struct tp_touch));
 	if (!tp->touches)
 		return -1;
 
diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h
index 4779120..f745cde 100644
--- a/src/evdev-mt-touchpad.h
+++ b/src/evdev-mt-touchpad.h
@@ -101,7 +101,6 @@ struct tp_touch {
 	struct tp_dispatch *tp;
 	enum touch_state state;
 	bool dirty;
-	bool fake;				/* a fake touch */
 	bool is_pointer;			/* the pointer-controlling touch */
 	int32_t x;
 	int32_t y;
@@ -154,7 +153,8 @@ struct tp_dispatch {
 	unsigned int slot;			/* current slot */
 	bool has_mt;
 
-	unsigned int ntouches;			/* number of slots */
+	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 */
 
-- 
2.0.1



More information about the wayland-devel mailing list