[PATCH v2] touchpad: add wobbling detection
Konstantin Kharlamov
hi-angel at yandex.ru
Tue Feb 20 14:31:09 UTC 2018
On 20.02.2018 13:44, Konstantin Kharlamov wrote:
> 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?
Although I did find what's the matter. Turns out, the last_motion_time
have been assigned at tp_maybe_disable_hysteresis() which I did remove.
But even there it's been guarded by if:
if (tp->queued & TOUCHPAD_EVENT_MOTION)
tp->hysteresis.last_motion_time = time;
What does that condition mean?
More information about the wayland-devel
mailing list