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". v3: * style fixes (empty line after a block, declaration at top) * s/x_diff/dx * s/x_motion_in_threashold/x_motion_history * compare with r_l_r instead of & * store whole point instead of just x * move x_motion_history and prev_coords into tp_touch * move everything around tp_detect_wobbling() call into the function, use goto for that purpose. * per request: add a comparison for when previous coordinates don't actually have the prev. coordinates yet. * increased timeout from 20ms to 40ms just in case — it's still out of human ability anyway, and in fact can be increased even further * ignore Y-only changes, again just in case — it could happen that Y and X events would be sent separately, and break the heuristic. Signed-off-by: Konstantin Kharlamov <hi-an...@yandex.ru> --- src/evdev-mt-touchpad.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- src/evdev-mt-touchpad.h | 2 ++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index ead76456..e32597d4 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -131,6 +131,52 @@ tp_motion_history_push(struct tp_touch *t) t->history.index = motion_index; } +static inline void +tp_detect_wobbling(struct tp_dispatch *tp, + struct tp_touch *t, + uint64_t time) +{ + int dx = (!t->prev_coords.x)? 0 /* first invocation */ + : t->prev_coords.x - t->point.x; + + if (!(tp->queued & TOUCHPAD_EVENT_MOTION) || 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 (!dx && t->prev_coords.y != t->point.y) { /* ignore Y-only changes */ + t->prev_coords.y = t->point.y; + return; + } + + if (time - tp->hysteresis.last_motion_time > ms2us(40) || dx == 0) { + t->x_motion_history = 0; + goto out; + } + + t->x_motion_history <<= 1; + if (dx > 0) { /* right move */ + static const char r_l_r = 5; /* {Right, Left, Right} */ + + t->x_motion_history |= 1; + if (t->x_motion_history == r_l_r) { + tp->hysteresis.enabled = true; + evdev_log_debug(tp->device, "hysteresis enabled\n"); + } + } + +out: + tp->hysteresis.last_motion_time = time; + t->prev_coords = t->point; +} + static inline void tp_motion_hysteresis(struct tp_dispatch *tp, struct tp_touch *t) @@ -260,6 +306,7 @@ tp_new_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time) t->time = time; t->speed.last_speed = 0; t->speed.exceeded_count = 0; + t->x_motion_history = 0; tp->queued |= TOUCHPAD_EVENT_MOTION; } @@ -1404,7 +1451,7 @@ 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, t, time); tp_motion_hysteresis(tp, t); tp_motion_history_push(t); diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index 442f34a3..48161efb 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -151,6 +151,8 @@ struct tp_touch { int pressure; bool is_tool_palm; /* MT_TOOL_PALM */ int major, minor; + char x_motion_history; + struct device_coords prev_coords; bool was_down; /* if distance == 0, false for pure hovering touches */ -- 2.15.1 _______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/wayland-devel