[PATCH libinput] touchpad: fix clickfinger behavior with a thumb being present

Friedrich Schöller code at schoeller.se
Fri May 19 17:32:28 UTC 2017


With a thumb on the touchpad, a two-finger click was always treated as
a middle-click. This patch takes the thumb into account and treats the
click as a right-click, if the touchpad supports tracking of at least
three fingers.
---
 src/evdev-mt-touchpad-buttons.c | 90 +++++++++++++++++++++++++++++------------
 1 file changed, 65 insertions(+), 25 deletions(-)

diff --git a/src/evdev-mt-touchpad-buttons.c b/src/evdev-mt-touchpad-buttons.c
index 895cf0e..30c2948 100644
--- a/src/evdev-mt-touchpad-buttons.c
+++ b/src/evdev-mt-touchpad-buttons.c
@@ -978,54 +978,94 @@ out:
 	return within_distance;
 }
 
+static inline bool
+tp_clickfinger_within_distance_3(struct tp_dispatch *tp,
+				 struct tp_touch *t1,
+				 struct tp_touch *t2,
+				 struct tp_touch *t3)
+{
+	if (!t1 || !t2 || !t3)
+		return false;
+
+	double d12 =
+		(t1->point.x - t2->point.x) * (t1->point.x - t2->point.x) +
+		(t1->point.y - t2->point.y) * (t1->point.y - t2->point.y);
+	double d23 =
+		(t2->point.x - t3->point.x) * (t2->point.x - t3->point.x) +
+		(t2->point.y - t3->point.y) * (t2->point.y - t3->point.y);
+	double d31 =
+		(t3->point.x - t1->point.x) * (t3->point.x - t1->point.x) +
+		(t3->point.y - t1->point.y) * (t3->point.y - t1->point.y);
+
+	if (d12 > d23 && d12 > d31) {
+		return tp_clickfinger_within_distance(tp, t2, t3) &&
+		       tp_clickfinger_within_distance(tp, t3, t1);
+	}
+
+	if (d23 > d31 && d23 > d12) {
+		return tp_clickfinger_within_distance(tp, t3, t1) &&
+		       tp_clickfinger_within_distance(tp, t1, t2);
+	}
+
+	return tp_clickfinger_within_distance(tp, t1, t2) &&
+	       tp_clickfinger_within_distance(tp, t2, t3);
+}
+
 static uint32_t
 tp_clickfinger_set_button(struct tp_dispatch *tp)
 {
-	uint32_t button;
+	bool thumb_detected = false;
 	unsigned int nfingers = tp->nfingers_down;
 	struct tp_touch *t;
 	struct tp_touch *first = NULL,
-			*second = NULL;
+	                *second = NULL,
+	                *third = NULL;
 
-	if (nfingers != 2)
-		goto out;
+	if (nfingers < 2)
+		return BTN_LEFT;
+	if (nfingers > 3)
+		return BTN_MIDDLE;
+
+	/* Thumb detection is unreliable if the number of fingers on the
+	 * touchpad is greater than the number of touches that can be
+	 * tracked. */
+	if (nfingers == 3 && tp->num_slots < 3)
+		return BTN_MIDDLE;
 
-	/* two fingers down on the touchpad. Check for distance
-	 * between the fingers. */
 	tp_for_each_touch(tp, t) {
 		if (t->state != TOUCH_BEGIN && t->state != TOUCH_UPDATE)
 			continue;
 
-		if (t->thumb.state == THUMB_STATE_YES)
+		if (t->thumb.state == THUMB_STATE_YES) {
+			thumb_detected = true;
 			continue;
+		}
 
 		if (!first)
 			first = t;
 		else if (!second)
 			second = t;
+		else if (!third)
+			third = t;
 	}
 
-	if (!first || !second) {
-		nfingers = 1;
-		goto out;
-	}
+	if (nfingers == 2) {
+		if (thumb_detected)
+			return BTN_LEFT;
 
-	if (tp_clickfinger_within_distance(tp, first, second))
-		nfingers = 2;
-	else
-		nfingers = 1;
+		if (tp_clickfinger_within_distance(tp, first, second))
+			return BTN_RIGHT;
+		else
+			return BTN_LEFT;
+	} else {
+		if (thumb_detected)
+			return BTN_RIGHT;
 
-out:
-	switch (nfingers) {
-	case 0:
-	case 1: button = BTN_LEFT; break;
-	case 2: button = BTN_RIGHT; break;
-	default:
-		button = BTN_MIDDLE; break;
-		break;
+		if (tp_clickfinger_within_distance_3(tp, first, second, third))
+			return BTN_MIDDLE;
+		else
+			return BTN_RIGHT;
 	}
-
-	return button;
 }
 
 static int
-- 
2.9.4



More information about the wayland-devel mailing list