touchpad: stop palm detection when a second finger is detected

This avoids accidental palm detection during two-finger scrolling if one
finger is inside the edge exclusion zone.

Palm detection is designed to avoid accidental touches while typing. If a
non-palm finger is on the touchpad already the user is unlikely to be typing.
So stop palm detection in this case and process the fingers as normal.

This implementation has a minor bug: if both palm touches start within the
palm exclusion zone within the same frame, neither will be labelled as palm
due to how we check the other touches. Since this is an extremeley niche case
we can live with that.

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

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
This commit is contained in:
Peter Hutterer 2016-06-13 16:41:43 +10:00
parent 4bb0adfc1c
commit 7860a9ed77
2 changed files with 99 additions and 5 deletions

View file

@ -652,6 +652,35 @@ tp_palm_detect_move_out_of_edge(struct tp_dispatch *tp,
return false;
}
static inline bool
tp_palm_detect_multifinger(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
{
struct tp_touch *other;
if (tp->nfingers_down < 2)
return false;
/* If we have at least one other active non-palm touch make this
* touch non-palm too. This avoids palm detection during two-finger
* scrolling.
*
* Note: if both touches start in the palm zone within the same
* frame the second touch will still be PALM_NONE and thus detected
* here as non-palm touch. This is too niche to worry about for now.
*/
tp_for_each_touch(tp, other) {
if (other == t)
continue;
if (tp_touch_active(tp, other) &&
other->palm.state == PALM_NONE) {
return true;
}
}
return false;
}
static void
tp_palm_detect(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
{
@ -662,17 +691,24 @@ tp_palm_detect(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
if (tp_palm_detect_trackpoint(tp, t, time))
goto out;
/* If labelled a touch as palm, we unlabel as palm when
we move out of the palm edge zone within the timeout, provided
the direction is within 45 degrees of the horizontal.
*/
if (t->palm.state == PALM_EDGE) {
if (tp_palm_detect_move_out_of_edge(tp, t, time)) {
if (tp_palm_detect_multifinger(tp, t, time)) {
t->palm.state = PALM_NONE;
log_debug(tp_libinput_context(tp),
"palm: touch released, multiple fingers\n");
/* If labelled a touch as palm, we unlabel as palm when
we move out of the palm edge zone within the timeout, provided
the direction is within 45 degrees of the horizontal.
*/
} else if (tp_palm_detect_move_out_of_edge(tp, t, time)) {
t->palm.state = PALM_NONE;
log_debug(tp_libinput_context(tp),
"palm: touch released, out of edge zone\n");
}
return;
} else if (tp_palm_detect_multifinger(tp, t, time)) {
return;
}
/* palm must start in exclusion zone, it's ok to move into

View file

@ -1135,6 +1135,62 @@ START_TEST(touchpad_palm_detect_tap_clickfinger)
}
END_TEST
START_TEST(touchpad_no_palm_detect_2fg_scroll)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
if (!touchpad_has_palm_detect_size(dev) ||
!litest_has_2fg_scroll(dev))
return;
litest_enable_2fg_scroll(dev);
litest_drain_events(li);
/* first finger is palm, second finger isn't so we trigger 2fg
* scrolling */
litest_touch_down(dev, 0, 99, 50);
litest_touch_move_to(dev, 0, 99, 50, 99, 40, 10, 0);
litest_touch_move_to(dev, 0, 99, 40, 99, 50, 10, 0);
litest_assert_empty_queue(li);
litest_touch_down(dev, 1, 50, 50);
litest_assert_empty_queue(li);
litest_touch_move_two_touches(dev, 99, 50, 50, 50, 0, -20, 10, 0);
litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_AXIS);
}
END_TEST
START_TEST(touchpad_palm_detect_both_edges)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
if (!touchpad_has_palm_detect_size(dev) ||
!litest_has_2fg_scroll(dev))
return;
litest_enable_2fg_scroll(dev);
litest_drain_events(li);
/* two fingers moving up/down in the left/right palm zone must not
* generate events */
litest_touch_down(dev, 0, 99, 50);
litest_touch_move_to(dev, 0, 99, 50, 99, 40, 10, 0);
litest_touch_move_to(dev, 0, 99, 40, 99, 50, 10, 0);
litest_assert_empty_queue(li);
litest_touch_down(dev, 1, 1, 50);
litest_touch_move_to(dev, 1, 1, 50, 1, 40, 10, 0);
litest_touch_move_to(dev, 1, 1, 40, 1, 50, 10, 0);
litest_assert_empty_queue(li);
litest_touch_move_two_touches(dev, 99, 50, 1, 50, 0, -20, 10, 0);
litest_assert_empty_queue(li);
}
END_TEST
START_TEST(touchpad_left_handed)
{
struct litest_device *dev = litest_current_device();
@ -4102,6 +4158,8 @@ litest_setup_tests(void)
litest_add("touchpad:palm", touchpad_palm_detect_tap_softbuttons, LITEST_CLICKPAD, LITEST_ANY);
litest_add("touchpad:palm", touchpad_palm_detect_tap_clickfinger, LITEST_CLICKPAD, LITEST_ANY);
litest_add("touchpad:palm", touchpad_no_palm_detect_at_edge_for_edge_scrolling, LITEST_TOUCHPAD, LITEST_CLICKPAD);
litest_add("touchpad:palm", touchpad_no_palm_detect_2fg_scroll, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
litest_add("touchpad:palm", touchpad_palm_detect_both_edges, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
litest_add("touchpad:left-handed", touchpad_left_handed, LITEST_TOUCHPAD|LITEST_BUTTON, LITEST_CLICKPAD);
litest_add("touchpad:left-handed", touchpad_left_handed_clickpad, LITEST_CLICKPAD, LITEST_APPLE_CLICKPAD);