[PATCH v2] touchpad: add wobbling detection
Konstantin Kharlamov
hi-angel at yandex.ru
Tue Feb 20 10:44:28 UTC 2018
On 20.02.2018 09:34, Peter Hutterer wrote:
> On Sun, Feb 18, 2018 at 11:14:55PM +0300, Konstantin Kharlamov wrote:
>> +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.
>> + */
>
> the interesting bit here will be whether there are touchpads that wobble but
> with more than one event per direction. I suspect there are but this should
> be simple enough that it catches the first RLR movement (bound to happen at
> some point) and enable it then. The main question is whether there is a
> noticeable period of wobbling until this happens.
> I honestly don't know, we won't know until ppl start shouting at us...
My touchpad definitely does; however it does so many events for every
touch that I feel like it produces every possible combination within a
second or two. The more that the number for the three slots is 2³ = 8,
which isn't much.
>> + if (time - tp->hysteresis.last_motion_time > ms2us(20) || x_diff == 0) {
>> + tp->hysteresis.x_motion_in_threshold = 0;
>> + return;
>> + }
>
> empty line here please.
>
>> + tp->hysteresis.x_motion_in_threshold <<= 1;
>> + if (x_diff > 0) { /* right move */
>
> s/x_diff/dx/, we use that everywhere else for deltas.
>
>> + tp->hysteresis.x_motion_in_threshold |= 1;
>> + static const char r_l_r = 5; /* {Right, Left, Right} */
>
> declarations at the top of the block please, separated by an empty line. See
> CODING_STYLE in the repository.
>
>> + if (tp->hysteresis.x_motion_in_threshold & r_l_r) {
>
> this one will trigger on the first right movement, you need
> if ((tp->hysteresis.x_motion_in_threshold & r_l_r) == r_l_r)
>
> With that change, it seems to work correctly on my non-wobbling touchpad
> here. Does it still work for you when you add this?
Thank you, nice catch!
>> + 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;
>
> the dx calculation should happen within tp_detect_wobbling, just pass the
> touch in and do the subtraction there. Plus that way you can do a simple:
> if (tp->prev.x == 0) dx = 0;
> which makes things more obvious.
Well, not really can, the comparison for zero here would check
coordinate of previous x, whereas I need to check whether the delta
between prev. and curr. positions is zero, e.g. if a finger is still and
FW filters.
>> 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;
>
> 'threshold' usually refers to a distance in libinput, here it's more a
> timeout. But calling it x_motion_history would be best here, IMO.
>
>> }
>>
>> 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;
>
> both of these need to be in the struct tp_touch, otherwise 2-finger
> scrolling may enable the hysteresis when the fingers move independently from
> each other but you're adding them to the same bitmask.
Thanks for you comments!
I tried addressing them, and found that the result of the time
calculation "time - tp->hysteresis.last_motion_time" whilst my finger is
down is constantly increasing, i.e. like "20, 30, 50, 100, 120…". It
looks as if "tp->hysteresis.last_motion_time" is not the last motion
time, but the last finger-down time.
Do you happen to know anything about that?
> Cheers,
> Peter
>
>> } hysteresis;
>>
>> struct {
>> --
>> 2.15.1
More information about the wayland-devel
mailing list