From 655f565fbaa737b2508844b7a7b08c5a71a7bfba Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 3 Oct 2018 14:19:11 +1000 Subject: [PATCH] touchpad: if two fingers are within the lower thumb area, they're not thumbs The shape of the average hand implies that two fingers down within the lower thumb area (the bottom few mm of the touchpad) cannot be thumbs without significant contortion. So let's not mark them as thumb. Fixes #126 Signed-off-by: Peter Hutterer --- src/evdev-mt-touchpad.c | 22 +++++++++++++ test/litest.c | 6 ++++ test/litest.h | 3 ++ test/test-touchpad.c | 72 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 103 insertions(+) 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);