diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 8c6b3964..fdc53192 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -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 diff --git a/test/touchpad.c b/test/touchpad.c index ea719a34..0b1cd0e9 100644 --- a/test/touchpad.c +++ b/test/touchpad.c @@ -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);