[PATCH v2] touchpad: add wobbling detection

Konstantin Kharlamov Hi-Angel at yandex.ru
Sun Feb 18 20:14:55 UTC 2018


The details are explained in comment in the code. That aside, I shall
mention the check is so light, that it shouldn't influence CPU
performance even a bit, and can blindly be kept always enabled.

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

v2: rename the function, change comment style, and add calculation of
x_diff (the one that was used is an absolute coordinate).

FWIW, the algorithm don't care that now added "prev_x" is unintialized,
because that happening means the time threshold won't get satisfied
either. It's not like I can't default-init it — it's just that asking
oneself a question "what default value should it have" results in "none".

Signed-off-by: Konstantin Kharlamov <Hi-Angel at yandex.ru>
---
 src/evdev-mt-touchpad.c | 33 +++++++++++++++++++++++++++++++++
 src/evdev-mt-touchpad.h |  2 ++
 2 files changed, 35 insertions(+)

diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c
index ead76456..80f56072 100644
--- a/src/evdev-mt-touchpad.c
+++ b/src/evdev-mt-touchpad.c
@@ -131,6 +131,36 @@ tp_motion_history_push(struct tp_touch *t)
 	t->history.index = motion_index;
 }
 
+static inline void
+tp_detect_wobbling(struct tp_dispatch *tp, int x_diff, uint64_t time)
+{
+	if (tp->hysteresis.enabled)
+		return;
+
+	/* Idea: if we got a tuple of *very* quick moves like {Left, Right, Left}, or
+	 * {Right, Left, Right}, it means touchpad jitters since no human supposed to
+	 * be able to move like that within thresholds
+	 *
+	 * Algo: we encode left moves as zeroes, and right as ones. We also drop the
+	 * array to all zeroes when contraints are not satisfied. Then we search for
+	 * the pattern {1,0,1}. It can't match {Left, Right, Left}, but it does match
+	 * {Left, Right, Left, Right}, so it's okay.
+	 */
+	if (time - tp->hysteresis.last_motion_time > ms2us(20) || x_diff == 0) {
+		tp->hysteresis.x_motion_in_threshold = 0;
+		return;
+	}
+	tp->hysteresis.x_motion_in_threshold <<= 1;
+	if (x_diff > 0) { /* right move */
+		tp->hysteresis.x_motion_in_threshold |= 1;
+		static const char r_l_r = 5; /* {Right, Left, Right} */
+		if (tp->hysteresis.x_motion_in_threshold & r_l_r) {
+			tp->hysteresis.enabled = true;
+			evdev_log_debug(tp->device, "hysteresis enabled\n");
+		}
+	}
+}
+
 static inline void
 tp_motion_hysteresis(struct tp_dispatch *tp,
 		     struct tp_touch *t)
@@ -1405,6 +1435,8 @@ tp_process_state(struct tp_dispatch *tp, uint64_t time)
 		tp_thumb_detect(tp, t, time);
 		tp_palm_detect(tp, t, time);
 
+		tp_detect_wobbling(tp, tp->hysteresis.prev_x - t->point.x, time);
+		tp->hysteresis.prev_x = t->point.x;
 		tp_motion_hysteresis(tp, t);
 		tp_motion_history_push(t);
 
@@ -2918,6 +2950,7 @@ tp_init_hysteresis(struct tp_dispatch *tp)
 	tp->hysteresis.margin.x = res_x/2;
 	tp->hysteresis.margin.y = res_y/2;
 	tp->hysteresis.enabled = false;
+	tp->hysteresis.x_motion_in_threshold = 0;
 }
 
 static void
diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h
index 442f34a3..398a18ed 100644
--- a/src/evdev-mt-touchpad.h
+++ b/src/evdev-mt-touchpad.h
@@ -276,6 +276,8 @@ struct tp_dispatch {
 		struct device_coords margin;
 		unsigned int other_event_count;
 		uint64_t last_motion_time;
+		char x_motion_in_threshold;
+		int prev_x;
 	} hysteresis;
 
 	struct {
-- 
2.15.1



More information about the wayland-devel mailing list