[PATCH libinput 2/9] touchpad: after a click, lock the finger to its current position

Peter Hutterer peter.hutterer at who-t.net
Thu Mar 27 23:23:51 PDT 2014


On clickpads, releasing the button usually causes some motion events. To avoid
erroneous movements, lock the finger into position on the up event and don't
allow for motion events until we move past a given threshold (currently 2% of
the touchpad diagonal).

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

diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c
index 8021db2..5318b8f 100644
--- a/src/evdev-mt-touchpad.c
+++ b/src/evdev-mt-touchpad.c
@@ -32,6 +32,7 @@
 #define DEFAULT_MIN_ACCEL_FACTOR 0.16
 #define DEFAULT_MAX_ACCEL_FACTOR 1.0
 #define DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR 700.0
+#define DEFAULT_BUTTON_MOTION_THRESHOLD 0.02 /* in percent of size */
 
 static inline int
 tp_hysteresis(int in, int center, int margin)
@@ -346,16 +347,36 @@ tp_process_key(struct tp_dispatch *tp,
 }
 
 static void
-tp_unpin_finger(struct tp_dispatch *tp)
+tp_unpin_finger(struct tp_dispatch *tp, struct tp_touch *t)
+{
+	unsigned int xdist, ydist;
+
+	if (t->pinned.state != PIN_STATE_UP)
+		return;
+
+	xdist = abs(t->x - t->pinned.center_x);
+	ydist = abs(t->y - t->pinned.center_y);
+
+	if (xdist * xdist + ydist * ydist <
+			tp->buttons.motion_dist * tp->buttons.motion_dist)
+		return;
+
+	t->pinned.state = PIN_STATE_NONE;
+
+	if (t->state != TOUCH_END && tp->nfingers_down == 1)
+		t->is_pointer = true;
+}
+
+static void
+tp_lift_pinned_finger(struct tp_dispatch *tp)
 {
 	struct tp_touch *t;
+
 	tp_for_each_touch(tp, t) {
-		if (t->is_pinned) {
-			t->is_pinned = false;
-
-			if (t->state != TOUCH_END &&
-			    tp->nfingers_down == 1)
-				t->is_pointer = true;
+		if (t->pinned.state == PIN_STATE_DOWN) {
+			t->pinned.state = PIN_STATE_UP;
+			t->pinned.center_x = t->x;
+			t->pinned.center_y = t->y;
 			break;
 		}
 	}
@@ -368,15 +389,14 @@ tp_pin_finger(struct tp_dispatch *tp)
 			*pinned = NULL;
 
 	tp_for_each_touch(tp, t) {
-		if (t->is_pinned) {
+		if (t->pinned.state != PIN_STATE_NONE) {
 			pinned = t;
 			break;
 		}
 	}
 
-	assert(!pinned);
-
-	pinned = tp_current_touch(tp);
+	if (!pinned)
+		pinned = tp_current_touch(tp);
 
 	if (tp->nfingers_down != 1) {
 		tp_for_each_touch(tp, t) {
@@ -388,7 +408,7 @@ tp_pin_finger(struct tp_dispatch *tp)
 		}
 	}
 
-	pinned->is_pinned = true;
+	pinned->pinned.state = PIN_STATE_DOWN;
 	pinned->is_pointer = false;
 }
 
@@ -409,16 +429,21 @@ tp_process_state(struct tp_dispatch *tp, uint32_t time)
 
 		tp_motion_hysteresis(tp, t);
 		tp_motion_history_push(t);
+
+		tp_unpin_finger(tp, t);
 	}
 
-	/* We have a physical button down event on a clickpad. For drag and
-	   drop, this means we try to identify which finger pressed the
-	   physical button and "pin" it, i.e. remove pointer-moving
-	   capabilities from it.
-	 */
-	if ((tp->queued & TOUCHPAD_EVENT_BUTTON_PRESS) &&
-	    !tp->buttons.has_buttons)
-		tp_pin_finger(tp);
+	if (!tp->buttons.has_buttons) {
+		/* We have a physical button down event on a clickpad. For drag and
+		   drop, this means we try to identify which finger pressed the
+		   physical button and "pin" it, i.e. remove pointer-moving
+		   capabilities from it.
+		 */
+		if (tp->queued & TOUCHPAD_EVENT_BUTTON_PRESS)
+			tp_pin_finger(tp);
+		else if ((tp->queued & TOUCHPAD_EVENT_BUTTON_RELEASE))
+			tp_lift_pinned_finger(tp);
+	}
 }
 
 static void
@@ -441,9 +466,6 @@ tp_post_process_state(struct tp_dispatch *tp, uint32_t time)
 
 	tp->buttons.old_state = tp->buttons.state;
 
-	if (tp->queued & TOUCHPAD_EVENT_BUTTON_RELEASE)
-		tp_unpin_finger(tp);
-
 	tp->queued = TOUCHPAD_EVENT_NONE;
 }
 
@@ -796,6 +818,8 @@ tp_init(struct tp_dispatch *tp,
 	tp->hysteresis.margin_y =
 		diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
 
+	tp->buttons.motion_dist = diagonal * DEFAULT_BUTTON_MOTION_THRESHOLD;
+
 	if (libevdev_has_event_code(device->evdev, EV_KEY, BTN_MIDDLE) ||
 	    libevdev_has_event_code(device->evdev, EV_KEY, BTN_RIGHT))
 		tp->buttons.has_buttons = true;
diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h
index 2bdb329..51e7702 100644
--- a/src/evdev-mt-touchpad.h
+++ b/src/evdev-mt-touchpad.h
@@ -51,6 +51,12 @@ enum scroll_state {
 	SCROLL_STATE_SCROLLING
 };
 
+enum pin_state {
+	PIN_STATE_NONE,
+	PIN_STATE_DOWN,
+	PIN_STATE_UP,
+};
+
 enum tp_tap_state {
 	TAP_STATE_IDLE = 4,
 	TAP_STATE_TOUCH,
@@ -77,7 +83,6 @@ struct tp_touch {
 	bool dirty;
 	bool fake;				/* a fake touch */
 	bool is_pointer;			/* the pointer-controlling touch */
-	bool is_pinned;				/* holds the phys. button */
 	int32_t x;
 	int32_t y;
 	uint32_t millis;
@@ -92,6 +97,16 @@ struct tp_touch {
 		int32_t center_x;
 		int32_t center_y;
 	} hysteresis;
+
+	/* A pinned touchpoint is the one that pressed the physical button
+	 * on a clickpad. After the release, it won't move until the center
+	 * moves more than a threshold away from the original coordinates
+	 */
+	struct {
+		enum pin_state state;
+		int32_t center_x;
+		int32_t center_y;
+	} pinned;
 };
 
 struct tp_dispatch {
@@ -122,6 +137,7 @@ struct tp_dispatch {
 		bool has_buttons;		/* true for physical LMR buttons */
 		uint32_t state;
 		uint32_t old_state;
+		uint32_t motion_dist;		/* for pinned touches */
 	} buttons;				/* physical buttons */
 
 	struct {
-- 
1.8.5.3



More information about the wayland-devel mailing list