diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index c22293c1..3e62a1c3 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -1143,6 +1143,28 @@ tp_thumb_detect(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time) } } + /* If the finger is below the upper thumb line and we have another + * finger in the same area, neither finger is a thumb (unless we've + * already labeled it as such). + */ + if (t->point.y > tp->thumb.upper_thumb_line && + tp->nfingers_down > 1) { + struct tp_touch *other; + + tp_for_each_touch(tp, other) { + if (other->state != TOUCH_BEGIN && + other->state != TOUCH_UPDATE) + continue; + + if (other->point.y > tp->thumb.upper_thumb_line) { + t->thumb.state = THUMB_STATE_NO; + if (other->thumb.state == THUMB_STATE_MAYBE) + other->thumb.state = THUMB_STATE_NO; + break; + } + } + } + /* Note: a thumb at the edge of the touchpad won't trigger the * threshold, the surface area is usually too small. So we have a * two-stage detection: pressure and time within the area. diff --git a/test/litest.c b/test/litest.c index 1efe6094..458ca793 100644 --- a/test/litest.c +++ b/test/litest.c @@ -3570,6 +3570,12 @@ litest_timeout_hysteresis(void) msleep(90); } +void +litest_timeout_thumb(void) +{ + msleep(320); +} + void litest_push_event_frame(struct litest_device *dev) { diff --git a/test/litest.h b/test/litest.h index 7b525c7a..8e6f4447 100644 --- a/test/litest.h +++ b/test/litest.h @@ -819,6 +819,9 @@ litest_timeout_touch_arbitration(void); void litest_timeout_hysteresis(void); +void +litest_timeout_thumb(void); + void litest_push_event_frame(struct litest_device *dev); diff --git a/test/test-touchpad.c b/test/test-touchpad.c index 00794dbc..8ad695ce 100644 --- a/test/test-touchpad.c +++ b/test/test-touchpad.c @@ -5199,6 +5199,76 @@ START_TEST(touchpad_thumb_move_and_tap) } END_TEST +START_TEST(touchpad_thumb_no_doublethumb) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + + litest_disable_tap(dev->libinput_device); + litest_enable_clickfinger(dev); + + if (!has_thumb_detect(dev)) + return; + + litest_drain_events(li); + + litest_touch_down(dev, 0, 50, 99); + litest_touch_down(dev, 1, 70, 99); + /* move touch to trigger the thumb detection */ + litest_touch_move(dev, 0, 50, 99.2); + + libinput_dispatch(li); + litest_timeout_thumb(); + libinput_dispatch(li); + + /* move touch to trigger the thumb detection */ + litest_touch_move(dev, 1, 70, 99.2); + libinput_dispatch(li); + + litest_touch_move_two_touches(dev, 50, 99, 70, 99, 0, -20, 10); + litest_touch_up(dev, 0); + litest_touch_up(dev, 1); + + litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_AXIS); +} +END_TEST + +START_TEST(touchpad_thumb_no_doublethumb_with_timeout) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + + litest_disable_tap(dev->libinput_device); + litest_enable_clickfinger(dev); + + if (!has_thumb_detect(dev)) + return; + + litest_drain_events(li); + + litest_touch_down(dev, 0, 50, 99.9); + libinput_dispatch(li); + litest_timeout_thumb(); + libinput_dispatch(li); + /* Thumbs don't have a timeout handler, so we have to move the thumb + * a bit to trigger. */ + litest_touch_move(dev, 0, 50, 99.8); + + /* first touch should now be a thumb */ + + litest_touch_down(dev, 1, 70, 99.9); + libinput_dispatch(li); + litest_timeout_thumb(); + libinput_dispatch(li); + litest_touch_move(dev, 1, 70, 99.8); + litest_touch_move_two_touches(dev, 50, 99, 70, 99, 0, -20, 10); + litest_touch_up(dev, 0); + litest_touch_up(dev, 1); + + litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION); +} +END_TEST + START_TEST(touchpad_tool_tripletap_touch_count) { struct litest_device *dev = litest_current_device(); @@ -6783,6 +6853,8 @@ TEST_COLLECTION(touchpad) litest_add("touchpad:thumb", touchpad_thumb_tap_hold_2ndfg, LITEST_CLICKPAD, LITEST_SINGLE_TOUCH); litest_add("touchpad:thumb", touchpad_thumb_tap_hold_2ndfg_tap, LITEST_CLICKPAD, LITEST_SINGLE_TOUCH); litest_add("touchpad:thumb", touchpad_thumb_move_and_tap, LITEST_CLICKPAD, LITEST_ANY); + litest_add("touchpad:thumb", touchpad_thumb_no_doublethumb, LITEST_CLICKPAD, LITEST_ANY); + litest_add("touchpad:thumb", touchpad_thumb_no_doublethumb_with_timeout, LITEST_CLICKPAD, LITEST_ANY); litest_add_for_device("touchpad:bugs", touchpad_tool_tripletap_touch_count, LITEST_SYNAPTICS_TOPBUTTONPAD); litest_add_for_device("touchpad:bugs", touchpad_tool_tripletap_touch_count_late, LITEST_SYNAPTICS_TOPBUTTONPAD);