touchpad: only try thumb detection in the lowest 15/8mm
authorPeter Hutterer <peter.hutterer@who-t.net>
Fri, 17 Jul 2015 01:17:22 +0000 (11:17 +1000)
committerPeter Hutterer <peter.hutterer@who-t.net>
Thu, 23 Jul 2015 22:50:17 +0000 (08:50 +1000)
That's the most likely area it will be resting in, if it's sitting anywhere
above that it's likely part of an interaction.

A thumb in the lowest 15mm needs to trigger the pressure threshold before it's
labelled a thumb. A thumb in the lowest 8mm is considered a thumb if it
remains there for 300ms. Regardless of the pressure, since we can't reliably
get pressure here. If a thumb moves out of the area, or starts outside of that
area it is never a thumb.

If edge scrolling is enabled, the 8mm threshold is ineffective since we'll
have normal interaction in that zone for horizontal scrolling.

The thumb tests now require all touchpads to be switched to clickfinger, if we
test for thumb detection on the bottom of the pad we won't get expected
motion events due to the software button area.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
doc/Makefile.am
doc/palm-detection.dox
doc/svg/thumb-detection.svg [new file with mode: 0644]
src/evdev-mt-touchpad-buttons.c
src/evdev-mt-touchpad-tap.c
src/evdev-mt-touchpad.c
src/evdev-mt-touchpad.h
test/touchpad.c

index 95a96e4..ddda230 100644 (file)
@@ -39,6 +39,7 @@ diagram_files = \
        $(srcdir)/svg/pinch-gestures.svg \
        $(srcdir)/svg/swipe-gestures.svg \
        $(srcdir)/svg/tap-n-drag.svg \
+       $(srcdir)/svg/thumb-detection.svg \
        $(srcdir)/svg/top-software-buttons.svg \
        $(srcdir)/svg/touchscreen-gestures.svg \
        $(srcdir)/svg/twofinger-scrolling.svg
index d787455..1a5e657 100644 (file)
@@ -80,4 +80,32 @@ Notable behaviors of libinput's disable-while-typing feature:
 - Physical buttons work even while the touchpad is disabled. This includes
   software-emulated buttons.
 
+@section thumb-detection Thumb detection
+
+Many users rest their thumb on the touchpad while using the index finger to
+move the finger around. For clicks, often the thumb is used rather than the
+finger. The thumb should otherwise be ignored as a touch, i.e. it should not
+count towards @ref clickfinger and it should not cause a single-finger
+movement to trigger @ref twofinger_scrolling.
+
+libinput uses two triggers for thumb detection: pressure and
+location. A touch exceeding a pressure threshold is considered a thumb if it
+is within the thumb detection zone.
+
+@note "Pressure" on touchpads is synonymous with "contact area", a large
+touch surface area has a higher pressure and thus hints at a thumb or palm
+touching the surface.
+
+Pressure readings are unreliable at the far bottom of the touchpad as a
+thumb hanging mostly off the touchpad will have a small surface area.
+libinput has a definitive thumb zone where any touch is considered a resting
+thumb.
+
+@image html thumb-detection.svg
+
+The picture above shows the two detection areas. In the larger (light red)
+area, a touch is labelled as thumb when it exceeds a device-specific
+pressure threshold. In the lower (dark red) area, a touch is labelled as
+thumb if it remains in that area for a time without moving outside.
+
 */
diff --git a/doc/svg/thumb-detection.svg b/doc/svg/thumb-detection.svg
new file mode 100644 (file)
index 0000000..bc74698
--- /dev/null
@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="89.829216mm"
+   height="59.06765mm"
+   viewBox="0 0 318.2925 209.29482"
+   id="svg4184"
+   version="1.1"
+   inkscape:version="0.91 r13725"
+   sodipodi:docname="thumb-detection.svg">
+  <defs
+     id="defs4186" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="1.979899"
+     inkscape:cx="270.39655"
+     inkscape:cy="139.75035"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1920"
+     inkscape:window-height="1136"
+     inkscape:window-x="0"
+     inkscape:window-y="27"
+     inkscape:window-maximized="1"
+     fit-margin-top="0"
+     fit-margin-left="0"
+     fit-margin-right="0"
+     fit-margin-bottom="0" />
+  <metadata
+     id="metadata4189">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-257.99662,-299.41313)">
+    <rect
+       width="313.09872"
+       height="167.89594"
+       x="260.59351"
+       y="302.01001"
+       id="rect2858-0"
+       style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#b3b3b3;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:5.19376326;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker:none;enable-background:accumulate" />
+    <rect
+       style="opacity:0.92000002;fill:#7b0000;fill-opacity:0.2983426;stroke:#000000;stroke-width:0.97031647;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="rect4788"
+       width="307.88782"
+       height="45.628574"
+       x="262.8418"
+       y="421.0347" />
+    <rect
+       y="445.40848"
+       x="262.68912"
+       height="21.407471"
+       width="308.19318"
+       id="rect4149"
+       style="opacity:0.92000002;fill:#7b0000;fill-opacity:0.2983426;stroke:#000000;stroke-width:0.66495597;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+    <g
+       id="g4151">
+      <path
+         sodipodi:nodetypes="sszzzcss"
+         d="m 353.70196,495.15765 c -24.01774,-7.29937 -29.0012,-10.10221 -30.51977,-10.54973 -10.67294,-3.14527 -18.27051,-5.54063 -23.77758,-13.4704 -5.50707,-7.92977 -5.34967,-20.78347 8.87612,-26.31604 14.2258,-5.53257 39.34351,8.79597 60.13061,16.16341 20.7871,7.36744 33.04563,11.44545 39.33422,13.87551 -8.10022,18.05041 -7.22129,21.15857 -10.11054,33.34117 -0.0481,0.20261 -17.87459,-5.12433 -43.93306,-13.04392 z"
+         id="path2824-1-1-3"
+         style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffccaa;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.00100005;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker:none;enable-background:accumulate"
+         inkscape:connector-curvature="0" />
+      <path
+         sodipodi:nodetypes="ccccc"
+         d="m 324.44991,483.39364 c -10.67294,-1.94747 -17.88441,-5.64478 -21.62691,-8.75386 -8.11652,-9.03765 -6.31775,-15.03428 -3.3272,-13.99784 8.90495,-0.9097 30.20384,9.01528 33.86042,10.17935 -5.80268,11.37909 -1.08919,13.70271 -8.90631,12.57235 z"
+         id="path2824-7-1-4-3"
+         style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.92000002;fill:#ffe6d5;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.2;marker:none;enable-background:accumulate"
+         inkscape:connector-curvature="0" />
+    </g>
+    <g
+       transform="matrix(0.79657897,0.11742288,-0.14814182,0.631399,276.6631,-158.96703)"
+       id="g3663-9-5">
+      <path
+         d="m 388.57143,893.79076 -57.14285,-130 c 0,0 -30.0247,-58.84827 4.28571,-70.00001 27.07438,-8.79984 37.32196,9.59496 40,14.64286 27.54455,51.91936 84.64285,173.21429 84.64285,173.21429 l -0.71428,0 -71.07143,12.14286 z"
+         id="path2820-6-6"
+         style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+         inkscape:connector-curvature="0" />
+      <path
+         d="m 360.32021,827.78041 c -15.74169,-35.7991 -29.44655,-66.92657 -30.45523,-69.17214 -7.08929,-15.78239 -10.8761,-32.88254 -9.6176,-43.43026 1.39575,-11.69796 7.19746,-18.50389 18.22574,-21.38044 5.18218,-1.35169 8.54724,-1.76827 12.41155,-1.53649 4.43642,0.26609 6.95929,0.93715 11.03011,2.93391 3.93491,1.9301 8.0085,5.56248 10.68932,9.53159 3.68818,5.46055 26.56068,50.9623 49.57778,98.62829 16.60192,34.38082 37.06388,77.41994 36.89013,77.59369 -0.13286,0.13286 -69.01932,11.92114 -69.66286,11.92114 -0.27909,0 -12.00972,-26.24842 -29.08894,-65.08929 z"
+         id="path2824-1-1"
+         style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffccaa;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.002;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker:none;enable-background:accumulate"
+         inkscape:connector-curvature="0" />
+      <path
+         d="m 334.75785,756.75053 c -7.08929,-15.78239 -10.28437,-26.89033 -9.02587,-37.43805 1.39575,-11.69796 5.8085,-16.73613 16.83678,-19.61268 12.44766,-3.59459 20.03902,-1.91353 27.39013,8.75815 11.42622,25.66382 13.40166,29.05484 15.06365,35.48866 -0.13286,0.13286 -42.89663,15.49027 -44.57776,16.18518 -1.72922,0.71479 -4.94789,-2.09377 -5.68693,-3.38126 z"
+         id="path2824-7-1-4"
+         style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.92000002;fill:#ffe6d5;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.2;marker:none;enable-background:accumulate"
+         inkscape:connector-curvature="0" />
+    </g>
+  </g>
+</svg>
index 687a613..77abc55 100644 (file)
@@ -810,7 +810,8 @@ tp_check_clickfinger_distance(struct tp_dispatch *tp,
        if (!t1 || !t2)
                return 0;
 
-       if (t1->is_thumb || t2->is_thumb)
+       if (t1->thumb.state == THUMB_STATE_YES ||
+           t2->thumb.state == THUMB_STATE_YES)
                return 0;
 
        x = abs(t1->point.x - t2->point.x);
@@ -872,7 +873,7 @@ tp_clickfinger_set_button(struct tp_dispatch *tp)
                if (t->state != TOUCH_BEGIN && t->state != TOUCH_UPDATE)
                        continue;
 
-               if (t->is_thumb)
+               if (t->thumb.state == THUMB_STATE_YES)
                        continue;
 
                if (!first)
index 1354e89..b297754 100644 (file)
@@ -740,7 +740,7 @@ tp_tap_handle_state(struct tp_dispatch *tp, uint64_t time)
                        /* The simple version: if a touch is a thumb on
                         * begin we ignore it. All other thumb touches
                         * follow the normal tap state for now */
-                       if (t->is_thumb) {
+                       if (t->thumb.state == THUMB_STATE_YES) {
                                t->tap.is_thumb = true;
                                continue;
                        }
@@ -772,7 +772,7 @@ tp_tap_handle_state(struct tp_dispatch *tp, uint64_t time)
 
                        tp_tap_handle_event(tp, t, TAP_EVENT_MOTION, time);
                } else if (tp->tap.state != TAP_STATE_IDLE &&
-                          t->is_thumb &&
+                          t->thumb.state == THUMB_STATE_YES &&
                           !t->tap.is_thumb) {
                        tp_tap_handle_event(tp, t, TAP_EVENT_THUMB, time);
                }
index c7f55c3..c06b517 100644 (file)
@@ -208,7 +208,8 @@ tp_begin_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
        t->millis = time;
        tp->nfingers_down++;
        t->palm.time = time;
-       t->is_thumb = false;
+       t->thumb.state = THUMB_STATE_MAYBE;
+       t->thumb.first_touch_time = time;
        t->tap.is_thumb = false;
        assert(tp->nfingers_down >= 1);
 }
@@ -462,7 +463,7 @@ tp_touch_active(struct tp_dispatch *tp, struct tp_touch *t)
        return (t->state == TOUCH_BEGIN || t->state == TOUCH_UPDATE) &&
                t->palm.state == PALM_NONE &&
                !t->pinned.is_pinned &&
-               !t->is_thumb &&
+               t->thumb.state != THUMB_STATE_YES &&
                tp_button_touch_active(tp, t) &&
                tp_edge_scroll_touch_active(tp, t);
 }
@@ -604,20 +605,47 @@ out:
                  t->palm.state == PALM_TYPING ? "typing" : "trackpoint");
 }
 
+static inline const char*
+thumb_state_to_str(enum tp_thumb_state state)
+{
+       switch(state){
+       CASE_RETURN_STRING(THUMB_STATE_NO);
+       CASE_RETURN_STRING(THUMB_STATE_YES);
+       CASE_RETURN_STRING(THUMB_STATE_MAYBE);
+       }
+
+       return NULL;
+}
+
 static void
-tp_thumb_detect(struct tp_dispatch *tp, struct tp_touch *t)
+tp_thumb_detect(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
 {
-       /* once a thumb, always a thumb */
-       if (!tp->thumb.detect_thumbs || t->is_thumb)
+       enum tp_thumb_state state = t->thumb.state;
+
+       /* once a thumb, always a thumb, once ruled out always ruled out */
+       if (!tp->thumb.detect_thumbs ||
+           t->thumb.state != THUMB_STATE_MAYBE)
                return;
 
+       if (t->point.y < tp->thumb.upper_thumb_line) {
+               /* if a potential thumb is above the line, it won't ever
+                * label as thumb */
+               t->thumb.state = THUMB_STATE_NO;
+               goto out;
+       }
+
        /* Note: a thumb at the edge of the touchpad won't trigger the
-        * threshold, the surface area is usually too small.
+        * threshold, the surface area is usually too small. So we have a
+        * two-stage detection: pressure and time within the area.
+        * A finger that remains at the very bottom of the touchpad becomes
+        * a thumb.
         */
-       if (t->pressure < tp->thumb.threshold)
-               return;
-
-       t->is_thumb = true;
+       if (t->pressure > tp->thumb.threshold)
+               t->thumb.state = THUMB_STATE_YES;
+       else if (t->point.y > tp->thumb.lower_thumb_line &&
+                tp->scroll.method != LIBINPUT_CONFIG_SCROLL_EDGE &&
+                t->thumb.first_touch_time + 300 < time)
+               t->thumb.state = THUMB_STATE_YES;
 
        /* now what? we marked it as thumb, so:
         *
@@ -629,6 +657,12 @@ tp_thumb_detect(struct tp_dispatch *tp, struct tp_touch *t)
         * - tapping: honour thumb on begin, ignore it otherwise for now,
         *   this gets a tad complicated otherwise
         */
+out:
+       if (t->thumb.state != state)
+               log_debug(tp_libinput_context(tp),
+                         "thumb state: %s → %s\n",
+                         thumb_state_to_str(state),
+                         thumb_state_to_str(t->thumb.state));
 }
 
 static void
@@ -785,7 +819,7 @@ tp_process_state(struct tp_dispatch *tp, uint64_t time)
                if (!t->dirty)
                        continue;
 
-               tp_thumb_detect(tp, t);
+               tp_thumb_detect(tp, t, time);
                tp_palm_detect(tp, t, time);
 
                tp_motion_hysteresis(tp, t);
@@ -1535,6 +1569,7 @@ tp_init_thumb(struct tp_dispatch *tp)
        const struct input_absinfo *abs;
        double w = 0.0, h = 0.0;
        int xres, yres;
+       int ymax;
        double threshold;
 
        if (!tp->buttons.is_clickpad)
@@ -1567,6 +1602,13 @@ tp_init_thumb(struct tp_dispatch *tp)
        tp->thumb.threshold = max(100, threshold);
        tp->thumb.detect_thumbs = true;
 
+       /* detect thumbs by pressure in the bottom 15mm, detect thumbs by
+        * lingering in the bottom 8mm */
+       ymax = tp->device->abs.absinfo_y->maximum;
+       yres = tp->device->abs.absinfo_y->resolution;
+       tp->thumb.upper_thumb_line = ymax - yres * 15;
+       tp->thumb.lower_thumb_line = ymax - yres * 8;
+
        return 0;
 }
 
index 61c4166..89801d6 100644 (file)
@@ -136,12 +136,17 @@ enum tp_gesture_2fg_state {
        GESTURE_2FG_STATE_PINCH,
 };
 
+enum tp_thumb_state {
+       THUMB_STATE_NO,
+       THUMB_STATE_YES,
+       THUMB_STATE_MAYBE,
+};
+
 struct tp_touch {
        struct tp_dispatch *tp;
        enum touch_state state;
        bool has_ended;                         /* TRACKING_ID == -1 */
        bool dirty;
-       bool is_thumb;
        struct device_coords point;
        uint64_t millis;
        int distance;                           /* distance == 0 means touch */
@@ -195,6 +200,11 @@ struct tp_touch {
        struct {
                struct device_coords initial;
        } gesture;
+
+       struct {
+               enum tp_thumb_state state;
+               uint64_t first_touch_time;
+       } thumb;
 };
 
 struct tp_dispatch {
@@ -324,6 +334,8 @@ struct tp_dispatch {
        struct {
                bool detect_thumbs;
                int threshold;
+               int upper_thumb_line;
+               int lower_thumb_line;
        } thumb;
 };
 
index 27485ae..329eeb3 100644 (file)
@@ -4028,8 +4028,8 @@ START_TEST(touchpad_thumb_begin_no_motion)
 
        litest_drain_events(li);
 
-       litest_touch_down_extended(dev, 0, 50, 50, axes);
-       litest_touch_move_to(dev, 0, 50, 50, 80, 50, 10, 0);
+       litest_touch_down_extended(dev, 0, 50, 99, axes);
+       litest_touch_move_to(dev, 0, 50, 99, 80, 99, 10, 0);
        litest_touch_up(dev, 0);
 
        litest_assert_empty_queue(li);
@@ -4046,18 +4046,19 @@ START_TEST(touchpad_thumb_update_no_motion)
        };
 
        litest_disable_tap(dev->libinput_device);
+       enable_clickfinger(dev);
 
        if (!has_thumb_detect(dev))
                return;
 
        litest_drain_events(li);
 
-       litest_touch_down(dev, 0, 50, 50);
-       litest_touch_move_to(dev, 0, 50, 50, 60, 50, 10, 0);
+       litest_touch_down(dev, 0, 50, 99);
+       litest_touch_move_to(dev, 0, 50, 99, 60, 99, 10, 0);
        litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
 
-       litest_touch_move_extended(dev, 0, 65, 50, axes);
-       litest_touch_move_to(dev, 0, 65, 50, 80, 50, 10, 0);
+       litest_touch_move_extended(dev, 0, 65, 99, axes);
+       litest_touch_move_to(dev, 0, 65, 99, 80, 99, 10, 0);
        litest_touch_up(dev, 0);
 
        litest_assert_empty_queue(li);
@@ -4085,9 +4086,9 @@ START_TEST(touchpad_thumb_clickfinger)
 
        litest_drain_events(li);
 
-       litest_touch_down(dev, 0, 50, 50);
-       litest_touch_down(dev, 1, 60, 50);
-       litest_touch_move_extended(dev, 0, 55, 50, axes);
+       litest_touch_down(dev, 0, 50, 99);
+       litest_touch_down(dev, 1, 60, 99);
+       litest_touch_move_extended(dev, 0, 55, 99, axes);
        litest_button_click(dev, BTN_LEFT, true);
 
        libinput_dispatch(li);
@@ -4105,9 +4106,9 @@ START_TEST(touchpad_thumb_clickfinger)
 
        litest_drain_events(li);
 
-       litest_touch_down(dev, 0, 50, 50);
-       litest_touch_down(dev, 1, 60, 50);
-       litest_touch_move_extended(dev, 1, 65, 50, axes);
+       litest_touch_down(dev, 0, 50, 99);
+       litest_touch_down(dev, 1, 60, 99);
+       litest_touch_move_extended(dev, 1, 65, 99, axes);
        litest_button_click(dev, BTN_LEFT, true);
 
        libinput_dispatch(li);
@@ -4142,8 +4143,8 @@ START_TEST(touchpad_thumb_btnarea)
 
        litest_drain_events(li);
 
-       litest_touch_down(dev, 0, 90, 95);
-       litest_touch_move_extended(dev, 0, 95, 95, axes);
+       litest_touch_down(dev, 0, 90, 99);
+       litest_touch_move_extended(dev, 0, 95, 99, axes);
        litest_button_click(dev, BTN_LEFT, true);
 
        /* button areas work as usual with a thumb */
@@ -4203,17 +4204,18 @@ START_TEST(touchpad_thumb_tap_begin)
                return;
 
        litest_enable_tap(dev->libinput_device);
+       enable_clickfinger(dev);
        litest_drain_events(li);
 
        /* touch down is a thumb */
-       litest_touch_down_extended(dev, 0, 50, 50, axes);
+       litest_touch_down_extended(dev, 0, 50, 99, axes);
        litest_touch_up(dev, 0);
        litest_timeout_tap();
 
        litest_assert_empty_queue(li);
 
        /* make sure normal tap still works */
-       litest_touch_down(dev, 0, 50, 50);
+       litest_touch_down(dev, 0, 50, 99);
        litest_touch_up(dev, 0);
        litest_timeout_tap();
        litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_BUTTON);
@@ -4233,17 +4235,18 @@ START_TEST(touchpad_thumb_tap_touch)
                return;
 
        litest_enable_tap(dev->libinput_device);
+       enable_clickfinger(dev);
        litest_drain_events(li);
 
        /* event after touch down is thumb */
        litest_touch_down(dev, 0, 50, 50);
-       litest_touch_move_extended(dev, 0, 51, 50, axes);
+       litest_touch_move_extended(dev, 0, 51, 99, axes);
        litest_touch_up(dev, 0);
        litest_timeout_tap();
        litest_assert_empty_queue(li);
 
        /* make sure normal tap still works */
-       litest_touch_down(dev, 0, 50, 50);
+       litest_touch_down(dev, 0, 50, 99);
        litest_touch_up(dev, 0);
        litest_timeout_tap();
        litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_BUTTON);
@@ -4263,18 +4266,19 @@ START_TEST(touchpad_thumb_tap_hold)
                return;
 
        litest_enable_tap(dev->libinput_device);
+       enable_clickfinger(dev);
        litest_drain_events(li);
 
        /* event in state HOLD is thumb */
-       litest_touch_down(dev, 0, 50, 50);
+       litest_touch_down(dev, 0, 50, 99);
        litest_timeout_tap();
        libinput_dispatch(li);
-       litest_touch_move_extended(dev, 0, 51, 50, axes);
+       litest_touch_move_extended(dev, 0, 51, 99, axes);
        litest_touch_up(dev, 0);
        litest_assert_empty_queue(li);
 
        /* make sure normal tap still works */
-       litest_touch_down(dev, 0, 50, 50);
+       litest_touch_down(dev, 0, 50, 99);
        litest_touch_up(dev, 0);
        litest_timeout_tap();
        litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_BUTTON);
@@ -4294,13 +4298,14 @@ START_TEST(touchpad_thumb_tap_hold_2ndfg)
                return;
 
        litest_enable_tap(dev->libinput_device);
+       enable_clickfinger(dev);
        litest_drain_events(li);
 
        /* event in state HOLD is thumb */
-       litest_touch_down(dev, 0, 50, 50);
+       litest_touch_down(dev, 0, 50, 99);
        litest_timeout_tap();
        libinput_dispatch(li);
-       litest_touch_move_extended(dev, 0, 51, 50, axes);
+       litest_touch_move_extended(dev, 0, 51, 99, axes);
 
        litest_assert_empty_queue(li);
 
@@ -4319,7 +4324,7 @@ START_TEST(touchpad_thumb_tap_hold_2ndfg)
        litest_assert_empty_queue(li);
 
        /* make sure normal tap still works */
-       litest_touch_down(dev, 0, 50, 50);
+       litest_touch_down(dev, 0, 50, 99);
        litest_touch_up(dev, 0);
        litest_timeout_tap();
        litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_BUTTON);
@@ -4344,10 +4349,10 @@ START_TEST(touchpad_thumb_tap_hold_2ndfg_tap)
        litest_drain_events(li);
 
        /* event in state HOLD is thumb */
-       litest_touch_down(dev, 0, 50, 50);
+       litest_touch_down(dev, 0, 50, 99);
        litest_timeout_tap();
        libinput_dispatch(li);
-       litest_touch_move_extended(dev, 0, 51, 50, axes);
+       litest_touch_move_extended(dev, 0, 51, 99, axes);
 
        litest_assert_empty_queue(li);
 
@@ -4377,7 +4382,7 @@ START_TEST(touchpad_thumb_tap_hold_2ndfg_tap)
        libinput_event_destroy(libinput_event_pointer_get_base_event(ptrev));
 
        /* make sure normal tap still works */
-       litest_touch_down(dev, 0, 50, 50);
+       litest_touch_down(dev, 0, 50, 99);
        litest_touch_up(dev, 0);
        litest_timeout_tap();
        litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_BUTTON);