Merge branch 'thumb-detect-improvements'
authorPeter Hutterer <peter.hutterer@who-t.net>
Thu, 23 Jul 2015 23:19:08 +0000 (09:19 +1000)
committerPeter Hutterer <peter.hutterer@who-t.net>
Thu, 23 Jul 2015 23:19:08 +0000 (09:19 +1000)
1  2 
src/evdev-mt-touchpad-buttons.c
src/evdev-mt-touchpad.c
src/evdev-mt-touchpad.h
test/litest.c
test/touchpad-buttons.c
test/touchpad.c

Simple merge
@@@ -760,55 -774,66 +812,91 @@@ tp_unhover_touches(struct tp_dispatch *
  
  }
  
+ static inline void
+ tp_position_fake_touches(struct tp_dispatch *tp)
+ {
+       struct tp_touch *t;
+       struct tp_touch *topmost = NULL;
+       unsigned int start, i;
+       if (tp_fake_finger_count(tp) <= tp->num_slots)
+               return;
+       /* We have at least one fake touch down. Find the top-most real
+        * touch and copy its coordinates over to to all fake touches.
+        * This is more reliable than just taking the first touch.
+        */
+       for (i = 0; i < tp->num_slots; i++) {
+               t = tp_get_touch(tp, i);
+               if (t->state == TOUCH_END ||
+                   t->state == TOUCH_NONE)
+                       continue;
+               if (topmost == NULL || t->point.y < topmost->point.y)
+                       topmost = t;
+       }
+       if (!topmost) {
+               log_bug_libinput(tp_libinput_context(tp),
+                                "Unable to find topmost touch\n");
+               return;
+       }
+       start = tp->has_mt ? tp->num_slots : 1;
+       for (i = start; i < tp->ntouches; i++) {
+               t = tp_get_touch(tp, i);
+               if (t->state == TOUCH_NONE)
+                       continue;
+               t->point = topmost->point;
+               if (!t->dirty)
+                       t->dirty = topmost->dirty;
+       }
+ }
 +static inline bool
 +tp_need_motion_history_reset(struct tp_dispatch *tp)
 +{
 +      /* semi-mt finger postions may "jump" when nfingers changes */
 +      if (tp->semi_mt && tp->nfingers_down != tp->old_nfingers_down)
 +              return true;
 +
 +      /* if we're transitioning between slots and fake touches in either
 +       * direction, we may get a coordinate jump
 +       */
 +      if (tp->nfingers_down != tp->old_nfingers_down &&
 +               (tp->nfingers_down > tp->num_slots ||
 +               tp->old_nfingers_down > tp->num_slots))
 +              return true;
 +
 +      return false;
 +}
 +
  static void
  tp_process_state(struct tp_dispatch *tp, uint64_t time)
  {
        struct tp_touch *t;
-       struct tp_touch *first = tp_get_touch(tp, 0);
        unsigned int i;
        bool restart_filter = false;
 +      bool want_motion_reset;
  
        tp_process_fake_touches(tp, time);
        tp_unhover_touches(tp, time);
+       tp_position_fake_touches(tp);
  
 +      want_motion_reset = tp_need_motion_history_reset(tp);
 +
        for (i = 0; i < tp->ntouches; i++) {
                t = tp_get_touch(tp, i);
  
 -              /* semi-mt finger postions may "jump" when nfingers changes */
 -              if (tp->semi_mt && tp->nfingers_down != tp->old_nfingers_down)
 +              if (want_motion_reset) {
 +                      tp_motion_history_reset(t);
 +                      t->quirks.reset_motion_history = true;
 +              } else if (t->quirks.reset_motion_history) {
                        tp_motion_history_reset(t);
 +                      t->quirks.reset_motion_history = false;
 +              }
  
-               if (i >= tp->num_slots && t->state != TOUCH_NONE) {
-                       t->point = first->point;
-                       if (!t->dirty)
-                               t->dirty = first->dirty;
-               }
                if (!t->dirty)
                        continue;
  
Simple merge
diff --cc test/litest.c
Simple merge
index ccc3b88,0000000..896b34b
mode 100644,000000..100644
--- /dev/null
@@@ -1,1450 -1,0 +1,1552 @@@
-       libinput_dispatch(li);
 +/*
 + * Copyright © 2014 Red Hat, Inc.
 + *
 + * Permission is hereby granted, free of charge, to any person obtaining a
 + * copy of this software and associated documentation files (the "Software"),
 + * to deal in the Software without restriction, including without limitation
 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 + * and/or sell copies of the Software, and to permit persons to whom the
 + * Software is furnished to do so, subject to the following conditions:
 + *
 + * The above copyright notice and this permission notice (including the next
 + * paragraph) shall be included in all copies or substantial portions of the
 + * Software.
 + *
 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 + * DEALINGS IN THE SOFTWARE.
 + */
 +
 +#include <config.h>
 +
 +#include <check.h>
 +#include <errno.h>
 +#include <fcntl.h>
 +#include <libinput.h>
 +#include <unistd.h>
 +
 +#include "libinput-util.h"
 +#include "litest.h"
 +
 +static void
 +enable_clickfinger(struct litest_device *dev)
 +{
 +      enum libinput_config_status status, expected;
 +      struct libinput_device *device = dev->libinput_device;
 +
 +      status = libinput_device_config_click_set_method(device,
 +                               LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER);
 +      expected = LIBINPUT_CONFIG_STATUS_SUCCESS;
 +      litest_assert_int_eq(status, expected);
 +}
 +
 +static void
 +enable_buttonareas(struct litest_device *dev)
 +{
 +      enum libinput_config_status status, expected;
 +      struct libinput_device *device = dev->libinput_device;
 +
 +      status = libinput_device_config_click_set_method(device,
 +                               LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS);
 +      expected = LIBINPUT_CONFIG_STATUS_SUCCESS;
 +      litest_assert_int_eq(status, expected);
 +}
 +
 +START_TEST(touchpad_click_defaults_clickfinger)
 +{
 +      struct litest_device *dev = litest_current_device();
 +      struct libinput_device *device = dev->libinput_device;
 +      uint32_t methods, method;
 +      enum libinput_config_status status;
 +
 +      /* call this test for apple touchpads */
 +
 +      methods = libinput_device_config_click_get_methods(device);
 +      ck_assert(methods & LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS);
 +      ck_assert(methods & LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER);
 +
 +      method = libinput_device_config_click_get_method(device);
 +      ck_assert_int_eq(method, LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER);
 +      method = libinput_device_config_click_get_default_method(device);
 +      ck_assert_int_eq(method, LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER);
 +
 +      status = libinput_device_config_click_set_method(device,
 +                                                       LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS);
 +      ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
 +      status = libinput_device_config_click_set_method(device,
 +                                                       LIBINPUT_CONFIG_CLICK_METHOD_NONE);
 +      ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
 +}
 +END_TEST
 +
 +START_TEST(touchpad_click_defaults_btnarea)
 +{
 +      struct litest_device *dev = litest_current_device();
 +      struct libinput_device *device = dev->libinput_device;
 +      uint32_t methods, method;
 +      enum libinput_config_status status;
 +
 +      /* call this test for non-apple clickpads */
 +
 +      methods = libinput_device_config_click_get_methods(device);
 +      ck_assert(methods & LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER);
 +      ck_assert(methods & LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS);
 +
 +      method = libinput_device_config_click_get_method(device);
 +      ck_assert_int_eq(method,  LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS);
 +      method = libinput_device_config_click_get_default_method(device);
 +      ck_assert_int_eq(method,  LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS);
 +
 +      status = libinput_device_config_click_set_method(device,
 +                                                       LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER);
 +      ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
 +      status = libinput_device_config_click_set_method(device,
 +                                                       LIBINPUT_CONFIG_CLICK_METHOD_NONE);
 +      ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
 +}
 +END_TEST
 +
 +START_TEST(touchpad_click_defaults_none)
 +{
 +      struct litest_device *dev = litest_current_device();
 +      struct libinput_device *device = dev->libinput_device;
 +      uint32_t methods, method;
 +      enum libinput_config_status status;
 +
 +      /* call this test for non-clickpads */
 +
 +      methods = libinput_device_config_click_get_methods(device);
 +      ck_assert_int_eq(methods, 0);
 +
 +      method = libinput_device_config_click_get_method(device);
 +      ck_assert_int_eq(method, LIBINPUT_CONFIG_CLICK_METHOD_NONE);
 +      method = libinput_device_config_click_get_default_method(device);
 +      ck_assert_int_eq(method, LIBINPUT_CONFIG_CLICK_METHOD_NONE);
 +
 +      status = libinput_device_config_click_set_method(device,
 +                                                       LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER);
 +      ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_UNSUPPORTED);
 +      status = libinput_device_config_click_set_method(device,
 +                                                       LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS);
 +      ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_UNSUPPORTED);
 +}
 +END_TEST
 +
 +START_TEST(touchpad_1fg_clickfinger)
 +{
 +      struct litest_device *dev = litest_current_device();
 +      struct libinput *li = dev->libinput;
 +
 +      enable_clickfinger(dev);
 +
 +      litest_drain_events(li);
 +
 +      litest_touch_down(dev, 0, 50, 50);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 1);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 0);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_touch_up(dev, 0);
 +
 +      libinput_dispatch(li);
 +
 +      litest_assert_button_event(li, BTN_LEFT,
 +                                 LIBINPUT_BUTTON_STATE_PRESSED);
 +      litest_assert_button_event(li, BTN_LEFT,
 +                                 LIBINPUT_BUTTON_STATE_RELEASED);
 +}
 +END_TEST
 +
 +START_TEST(touchpad_1fg_clickfinger_no_touch)
 +{
 +      struct litest_device *dev = litest_current_device();
 +      struct libinput *li = dev->libinput;
 +
 +      enable_clickfinger(dev);
 +
 +      litest_drain_events(li);
 +
 +      litest_event(dev, EV_KEY, BTN_LEFT, 1);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 0);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +
 +      libinput_dispatch(li);
 +
 +      litest_assert_button_event(li, BTN_LEFT,
 +                                 LIBINPUT_BUTTON_STATE_PRESSED);
 +      litest_assert_button_event(li, BTN_LEFT,
 +                                 LIBINPUT_BUTTON_STATE_RELEASED);
 +}
 +END_TEST
 +
 +START_TEST(touchpad_2fg_clickfinger)
 +{
 +      struct litest_device *dev = litest_current_device();
 +      struct libinput *li = dev->libinput;
 +
 +      enable_clickfinger(dev);
 +
 +      litest_drain_events(li);
 +
 +      litest_touch_down(dev, 0, 50, 50);
 +      litest_touch_down(dev, 1, 70, 70);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 1);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 0);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_touch_up(dev, 0);
 +      litest_touch_up(dev, 1);
 +
 +      libinput_dispatch(li);
 +
 +      litest_assert_button_event(li, BTN_RIGHT,
 +                                 LIBINPUT_BUTTON_STATE_PRESSED);
 +      litest_assert_button_event(li, BTN_RIGHT,
 +                                 LIBINPUT_BUTTON_STATE_RELEASED);
 +}
 +END_TEST
 +
 +START_TEST(touchpad_3fg_clickfinger)
 +{
 +      struct litest_device *dev = litest_current_device();
 +      struct libinput *li = dev->libinput;
 +
 +      if (libevdev_get_num_slots(dev->evdev) < 3)
 +              return;
 +
 +      enable_clickfinger(dev);
 +
 +      litest_drain_events(li);
 +
 +      litest_touch_down(dev, 0, 50, 50);
 +      litest_touch_down(dev, 1, 60, 70);
 +      litest_touch_down(dev, 2, 70, 70);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 1);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 0);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_touch_up(dev, 0);
 +      litest_touch_up(dev, 1);
 +      litest_touch_up(dev, 2);
 +
 +      libinput_dispatch(li);
 +
 +      litest_assert_button_event(li,
 +                                 BTN_MIDDLE,
 +                                 LIBINPUT_BUTTON_STATE_PRESSED);
 +      litest_assert_button_event(li,
 +                                 BTN_MIDDLE,
 +                                 LIBINPUT_BUTTON_STATE_RELEASED);
 +}
 +END_TEST
 +
 +START_TEST(touchpad_3fg_clickfinger_btntool)
 +{
 +      struct litest_device *dev = litest_current_device();
 +      struct libinput *li = dev->libinput;
 +
 +      if (libevdev_get_num_slots(dev->evdev) >= 3 ||
 +          !libevdev_has_event_code(dev->evdev, EV_KEY, BTN_TOOL_TRIPLETAP))
 +              return;
 +
 +      enable_clickfinger(dev);
 +
 +      litest_drain_events(li);
 +
 +      litest_touch_down(dev, 0, 50, 50);
 +      litest_touch_down(dev, 1, 60, 70);
 +      litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 0);
 +      litest_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, 1);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 1);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 0);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 1);
 +      litest_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, 0);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_touch_up(dev, 0);
 +      litest_touch_up(dev, 1);
 +
 +      libinput_dispatch(li);
 +
 +      litest_assert_button_event(li,
 +                                 BTN_MIDDLE,
 +                                 LIBINPUT_BUTTON_STATE_PRESSED);
 +      litest_assert_button_event(li,
 +                                 BTN_MIDDLE,
 +                                 LIBINPUT_BUTTON_STATE_RELEASED);
 +}
 +END_TEST
 +
 +START_TEST(touchpad_4fg_clickfinger)
 +{
 +      struct litest_device *dev = litest_current_device();
 +      struct libinput *li = dev->libinput;
++      struct libinput_event *event;
 +
 +      if (libevdev_get_num_slots(dev->evdev) < 4)
 +              return;
 +
 +      enable_clickfinger(dev);
 +
 +      litest_drain_events(li);
 +
 +      litest_touch_down(dev, 0, 50, 50);
 +      litest_touch_down(dev, 1, 60, 70);
 +      litest_touch_down(dev, 2, 70, 70);
 +      litest_touch_down(dev, 3, 80, 70);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 1);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 0);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_touch_up(dev, 0);
 +      litest_touch_up(dev, 1);
 +      litest_touch_up(dev, 2);
 +      litest_touch_up(dev, 3);
 +
 +      libinput_dispatch(li);
 +
++      litest_wait_for_event(li);
++      event = libinput_get_event(li);
++      litest_is_button_event(event,
++                             BTN_MIDDLE,
++                             LIBINPUT_BUTTON_STATE_PRESSED);
++      libinput_event_destroy(event);
++      event = libinput_get_event(li);
++      litest_is_button_event(event,
++                             BTN_MIDDLE,
++                             LIBINPUT_BUTTON_STATE_RELEASED);
++      libinput_event_destroy(event);
++
 +      litest_assert_empty_queue(li);
 +}
 +END_TEST
 +
 +START_TEST(touchpad_4fg_clickfinger_btntool_2slots)
 +{
 +      struct litest_device *dev = litest_current_device();
 +      struct libinput *li = dev->libinput;
++      struct libinput_event *event;
 +
 +      if (libevdev_get_num_slots(dev->evdev) >= 3 ||
 +          !libevdev_has_event_code(dev->evdev, EV_KEY, BTN_TOOL_QUADTAP))
 +              return;
 +
 +      enable_clickfinger(dev);
 +
 +      litest_drain_events(li);
 +
 +      litest_touch_down(dev, 0, 50, 50);
 +      litest_touch_down(dev, 1, 60, 70);
 +      litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 0);
 +      litest_event(dev, EV_KEY, BTN_TOOL_QUADTAP, 1);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 1);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 0);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 1);
 +      litest_event(dev, EV_KEY, BTN_TOOL_QUADTAP, 0);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_touch_up(dev, 0);
 +      litest_touch_up(dev, 1);
 +
-       if (libevdev_get_num_slots(dev->evdev) != 3 ||
++      litest_wait_for_event(li);
++      event = libinput_get_event(li);
++      litest_is_button_event(event,
++                             BTN_MIDDLE,
++                             LIBINPUT_BUTTON_STATE_PRESSED);
++      libinput_event_destroy(event);
++      event = libinput_get_event(li);
++      litest_is_button_event(event,
++                             BTN_MIDDLE,
++                             LIBINPUT_BUTTON_STATE_RELEASED);
++      libinput_event_destroy(event);
 +
 +      litest_assert_empty_queue(li);
 +}
 +END_TEST
 +
 +START_TEST(touchpad_4fg_clickfinger_btntool_3slots)
 +{
 +      struct litest_device *dev = litest_current_device();
 +      struct libinput *li = dev->libinput;
++      struct libinput_event *event;
 +
++      if (libevdev_get_num_slots(dev->evdev) >= 4 ||
++          libevdev_get_num_slots(dev->evdev) < 3 ||
 +          !libevdev_has_event_code(dev->evdev, EV_KEY, BTN_TOOL_TRIPLETAP))
 +              return;
 +
 +      enable_clickfinger(dev);
 +
 +      litest_drain_events(li);
 +
 +      litest_touch_down(dev, 0, 50, 50);
 +      litest_touch_down(dev, 1, 60, 70);
 +      litest_touch_down(dev, 2, 70, 70);
 +      litest_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, 0);
 +      litest_event(dev, EV_KEY, BTN_TOOL_QUADTAP, 1);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 1);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 0);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, 1);
 +      litest_event(dev, EV_KEY, BTN_TOOL_QUADTAP, 0);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_touch_up(dev, 0);
 +      litest_touch_up(dev, 1);
 +      litest_touch_up(dev, 2);
 +
 +      libinput_dispatch(li);
 +
++      litest_wait_for_event(li);
++      event = libinput_get_event(li);
++      litest_is_button_event(event,
++                             BTN_MIDDLE,
++                             LIBINPUT_BUTTON_STATE_PRESSED);
++      libinput_event_destroy(event);
++      event = libinput_get_event(li);
++      litest_is_button_event(event,
++                             BTN_MIDDLE,
++                             LIBINPUT_BUTTON_STATE_RELEASED);
++      libinput_event_destroy(event);
++
 +      litest_assert_empty_queue(li);
 +}
 +END_TEST
 +
 +START_TEST(touchpad_2fg_clickfinger_distance)
 +{
 +      struct litest_device *dev = litest_current_device();
 +      struct libinput *li = dev->libinput;
 +      double w, h;
 +      bool small_touchpad = false;
 +      unsigned int expected_button;
 +
 +      if (libinput_device_get_size(dev->libinput_device, &w, &h) == 0 &&
 +          h < 50.0)
 +              small_touchpad = true;
 +
 +      enable_clickfinger(dev);
 +
 +      litest_drain_events(li);
 +
 +      litest_touch_down(dev, 0, 90, 50);
 +      litest_touch_down(dev, 1, 10, 50);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 1);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 0);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_touch_up(dev, 0);
 +      litest_touch_up(dev, 1);
 +
 +      litest_assert_button_event(li,
 +                                 BTN_LEFT,
 +                                 LIBINPUT_BUTTON_STATE_PRESSED);
 +      litest_assert_button_event(li,
 +                                 BTN_LEFT,
 +                                 LIBINPUT_BUTTON_STATE_RELEASED);
 +
 +      litest_assert_empty_queue(li);
 +
 +      litest_touch_down(dev, 0, 50, 5);
 +      litest_touch_down(dev, 1, 50, 95);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 1);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 0);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_touch_up(dev, 0);
 +      litest_touch_up(dev, 1);
 +
 +      /* if the touchpad is small enough, we expect all fingers to count
 +       * for clickfinger */
 +      if (small_touchpad)
 +              expected_button = BTN_RIGHT;
 +      else
 +              expected_button = BTN_LEFT;
 +
 +      litest_assert_button_event(li,
 +                                 expected_button,
 +                                 LIBINPUT_BUTTON_STATE_PRESSED);
 +      litest_assert_button_event(li,
 +                                 expected_button,
 +                                 LIBINPUT_BUTTON_STATE_RELEASED);
 +}
 +END_TEST
 +
 +START_TEST(touchpad_2fg_clickfinger_bottom)
 +{
 +      struct litest_device *dev = litest_current_device();
 +      struct libinput *li = dev->libinput;
 +
 +      /* this test is run for the T440s touchpad only, makes getting the
 +       * mm correct easier */
 +
 +      libinput_device_config_click_set_method(dev->libinput_device,
 +                                              LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER);
 +      litest_drain_events(li);
 +
 +      /* one above, one below the magic line, vert spread ca 27mm */
 +      litest_touch_down(dev, 0, 40, 60);
 +      litest_touch_down(dev, 1, 60, 100);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 1);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 0);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_touch_up(dev, 0);
 +      litest_touch_up(dev, 1);
 +
 +      litest_assert_button_event(li,
 +                                 BTN_LEFT,
 +                                 LIBINPUT_BUTTON_STATE_PRESSED);
 +      litest_assert_button_event(li,
 +                                 BTN_LEFT,
 +                                 LIBINPUT_BUTTON_STATE_RELEASED);
 +
 +      litest_assert_empty_queue(li);
 +
 +      /* both below the magic line */
 +      litest_touch_down(dev, 0, 40, 100);
 +      litest_touch_down(dev, 1, 60, 95);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 1);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 0);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_touch_up(dev, 0);
 +      litest_touch_up(dev, 1);
 +
 +      litest_assert_button_event(li,
 +                                 BTN_RIGHT,
 +                                 LIBINPUT_BUTTON_STATE_PRESSED);
 +      litest_assert_button_event(li,
 +                                 BTN_RIGHT,
 +                                 LIBINPUT_BUTTON_STATE_RELEASED);
 +
 +      /* one above, one below the magic line, vert spread 17mm */
 +      litest_touch_down(dev, 0, 50, 75);
 +      litest_touch_down(dev, 1, 55, 100);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 1);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 0);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_touch_up(dev, 0);
 +      litest_touch_up(dev, 1);
 +
 +      litest_assert_button_event(li,
 +                                 BTN_RIGHT,
 +                                 LIBINPUT_BUTTON_STATE_PRESSED);
 +      litest_assert_button_event(li,
 +                                 BTN_RIGHT,
 +                                 LIBINPUT_BUTTON_STATE_RELEASED);
 +}
 +END_TEST
 +
 +START_TEST(touchpad_clickfinger_to_area_method)
 +{
 +      struct litest_device *dev = litest_current_device();
 +      struct libinput *li = dev->libinput;
 +
 +      litest_drain_events(li);
 +
 +      enable_buttonareas(dev);
 +
 +      litest_touch_down(dev, 0, 95, 95);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 1);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 0);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_touch_up(dev, 0);
 +      libinput_dispatch(li);
 +
 +      litest_assert_button_event(li, BTN_RIGHT,
 +                                 LIBINPUT_BUTTON_STATE_PRESSED);
 +      litest_assert_button_event(li, BTN_RIGHT,
 +                                 LIBINPUT_BUTTON_STATE_RELEASED);
 +
 +      enable_clickfinger(dev);
 +
 +      litest_drain_events(li);
 +
 +      /* use bottom right corner to catch accidental softbutton right */
 +      litest_touch_down(dev, 0, 95, 95);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 1);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 0);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_touch_up(dev, 0);
 +      libinput_dispatch(li);
 +
 +      litest_assert_button_event(li, BTN_LEFT,
 +                                 LIBINPUT_BUTTON_STATE_PRESSED);
 +      litest_assert_button_event(li, BTN_LEFT,
 +                                 LIBINPUT_BUTTON_STATE_RELEASED);
 +
 +}
 +END_TEST
 +
 +START_TEST(touchpad_clickfinger_to_area_method_while_down)
 +{
 +      struct litest_device *dev = litest_current_device();
 +      struct libinput *li = dev->libinput;
 +
 +      litest_drain_events(li);
 +
 +      enable_buttonareas(dev);
 +
 +      litest_touch_down(dev, 0, 95, 95);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 1);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      libinput_dispatch(li);
 +      litest_assert_button_event(li, BTN_RIGHT,
 +                                 LIBINPUT_BUTTON_STATE_PRESSED);
 +
 +      enable_clickfinger(dev);
 +
 +      litest_event(dev, EV_KEY, BTN_LEFT, 0);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_touch_up(dev, 0);
 +      libinput_dispatch(li);
 +
 +      litest_assert_button_event(li, BTN_RIGHT,
 +                                 LIBINPUT_BUTTON_STATE_RELEASED);
 +
 +      litest_drain_events(li);
 +
 +      /* use bottom right corner to catch accidental softbutton right */
 +      litest_touch_down(dev, 0, 95, 95);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 1);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 0);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_touch_up(dev, 0);
 +      libinput_dispatch(li);
 +
 +      litest_assert_button_event(li, BTN_LEFT,
 +                                 LIBINPUT_BUTTON_STATE_PRESSED);
 +      litest_assert_button_event(li, BTN_LEFT,
 +                                 LIBINPUT_BUTTON_STATE_RELEASED);
 +
 +}
 +END_TEST
 +
 +START_TEST(touchpad_area_to_clickfinger_method)
 +{
 +      struct litest_device *dev = litest_current_device();
 +      struct libinput *li = dev->libinput;
 +
 +      enable_clickfinger(dev);
 +
 +      litest_drain_events(li);
 +
 +      /* use bottom right corner to catch accidental softbutton right */
 +      litest_touch_down(dev, 0, 95, 95);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 1);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 0);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_touch_up(dev, 0);
 +      libinput_dispatch(li);
 +
 +      litest_assert_button_event(li, BTN_LEFT,
 +                                 LIBINPUT_BUTTON_STATE_PRESSED);
 +      litest_assert_button_event(li, BTN_LEFT,
 +                                 LIBINPUT_BUTTON_STATE_RELEASED);
 +
 +      enable_buttonareas(dev);
 +
 +      litest_touch_down(dev, 0, 95, 95);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 1);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 0);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_touch_up(dev, 0);
 +      libinput_dispatch(li);
 +
 +      litest_assert_button_event(li, BTN_RIGHT,
 +                                 LIBINPUT_BUTTON_STATE_PRESSED);
 +      litest_assert_button_event(li, BTN_RIGHT,
 +                                 LIBINPUT_BUTTON_STATE_RELEASED);
 +
 +}
 +END_TEST
 +
 +START_TEST(touchpad_area_to_clickfinger_method_while_down)
 +{
 +      struct litest_device *dev = litest_current_device();
 +      struct libinput *li = dev->libinput;
 +
 +      enable_clickfinger(dev);
 +
 +      litest_drain_events(li);
 +
 +      /* use bottom right corner to catch accidental softbutton right */
 +      litest_touch_down(dev, 0, 95, 95);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 1);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_assert_button_event(li, BTN_LEFT,
 +                                 LIBINPUT_BUTTON_STATE_PRESSED);
 +
 +      enable_buttonareas(dev);
 +
 +      litest_event(dev, EV_KEY, BTN_LEFT, 0);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_touch_up(dev, 0);
 +      libinput_dispatch(li);
 +
 +      litest_assert_button_event(li, BTN_LEFT,
 +                                 LIBINPUT_BUTTON_STATE_RELEASED);
 +
 +      litest_touch_down(dev, 0, 95, 95);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 1);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 0);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_touch_up(dev, 0);
 +      libinput_dispatch(li);
 +
 +      litest_assert_button_event(li, BTN_RIGHT,
 +                                 LIBINPUT_BUTTON_STATE_PRESSED);
 +      litest_assert_button_event(li, BTN_RIGHT,
 +                                 LIBINPUT_BUTTON_STATE_RELEASED);
 +
 +}
 +END_TEST
 +
++START_TEST(touchpad_clickfinger_3fg_tool_position)
++{
++      struct litest_device *dev = litest_current_device();
++      struct libinput *li = dev->libinput;
++
++      enable_clickfinger(dev);
++      litest_drain_events(li);
++
++      /* one in thumb area, one in normal area. spread is wide so the two
++       * real fingers don't count together. we expect a 2-finger click */
++      litest_touch_down(dev, 0, 5, 99);
++      litest_touch_down(dev, 1, 90, 15);
++      litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 0);
++      litest_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, 1);
++      litest_event(dev, EV_SYN, SYN_REPORT, 0);
++      libinput_dispatch(li);
++
++      litest_event(dev, EV_KEY, BTN_LEFT, 1);
++      litest_event(dev, EV_SYN, SYN_REPORT, 0);
++      litest_event(dev, EV_KEY, BTN_LEFT, 0);
++      litest_event(dev, EV_SYN, SYN_REPORT, 0);
++      libinput_dispatch(li);
++
++      litest_assert_button_event(li, BTN_RIGHT,
++                                 LIBINPUT_BUTTON_STATE_PRESSED);
++      litest_assert_button_event(li, BTN_RIGHT,
++                                 LIBINPUT_BUTTON_STATE_RELEASED);
++}
++END_TEST
++
++START_TEST(touchpad_clickfinger_4fg_tool_position)
++{
++      struct litest_device *dev = litest_current_device();
++      struct libinput *li = dev->libinput;
++
++      enable_clickfinger(dev);
++      litest_drain_events(li);
++
++      litest_touch_down(dev, 0, 5, 99);
++      litest_touch_down(dev, 1, 90, 15);
++      litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 0);
++      litest_event(dev, EV_KEY, BTN_TOOL_QUADTAP, 1);
++      litest_event(dev, EV_SYN, SYN_REPORT, 0);
++      libinput_dispatch(li);
++
++      litest_event(dev, EV_KEY, BTN_LEFT, 1);
++      litest_event(dev, EV_SYN, SYN_REPORT, 0);
++      litest_event(dev, EV_KEY, BTN_LEFT, 0);
++      litest_event(dev, EV_SYN, SYN_REPORT, 0);
++      libinput_dispatch(li);
++
++      litest_assert_button_event(li,
++                                 BTN_MIDDLE,
++                                 LIBINPUT_BUTTON_STATE_PRESSED);
++      litest_assert_button_event(li,
++                                 BTN_MIDDLE,
++                                 LIBINPUT_BUTTON_STATE_RELEASED);
++}
++END_TEST
++
 +START_TEST(touchpad_btn_left)
 +{
 +      struct litest_device *dev = litest_current_device();
 +      struct libinput *li = dev->libinput;
 +
 +      litest_drain_events(li);
 +
 +      litest_event(dev, EV_KEY, BTN_LEFT, 1);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 0);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +
 +      libinput_dispatch(li);
 +
 +      litest_assert_button_event(li, BTN_LEFT,
 +                                 LIBINPUT_BUTTON_STATE_PRESSED);
 +      litest_assert_button_event(li, BTN_LEFT,
 +                                 LIBINPUT_BUTTON_STATE_RELEASED);
 +}
 +END_TEST
 +
 +START_TEST(clickpad_btn_left)
 +{
 +      struct litest_device *dev = litest_current_device();
 +      struct libinput *li = dev->libinput;
 +
 +      enable_buttonareas(dev);
 +
 +      litest_drain_events(li);
 +
 +      /* A clickpad always needs a finger down to tell where the
 +         click happens */
 +      litest_event(dev, EV_KEY, BTN_LEFT, 1);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 0);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +
 +      libinput_dispatch(li);
 +      ck_assert_int_eq(libinput_next_event_type(li), LIBINPUT_EVENT_NONE);
 +}
 +END_TEST
 +
 +START_TEST(clickpad_click_n_drag)
 +{
 +      struct litest_device *dev = litest_current_device();
 +      struct libinput *li = dev->libinput;
 +
 +      litest_drain_events(li);
 +
 +      litest_touch_down(dev, 0, 50, 50);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 1);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +
 +      libinput_dispatch(li);
 +      litest_assert_button_event(li, BTN_LEFT,
 +                                 LIBINPUT_BUTTON_STATE_PRESSED);
 +
 +      libinput_dispatch(li);
 +      ck_assert_int_eq(libinput_next_event_type(li), LIBINPUT_EVENT_NONE);
 +
 +      /* now put a second finger down */
 +      litest_touch_down(dev, 1, 70, 70);
 +      litest_touch_move_to(dev, 1, 70, 70, 80, 50, 5, 0);
 +      litest_touch_up(dev, 1);
 +
 +      litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
 +
 +      litest_event(dev, EV_KEY, BTN_LEFT, 0);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_touch_up(dev, 0);
 +
 +      litest_assert_button_event(li, BTN_LEFT,
 +                                 LIBINPUT_BUTTON_STATE_RELEASED);
 +}
 +END_TEST
 +
 +START_TEST(clickpad_finger_pin)
 +{
 +      struct litest_device *dev = litest_current_device();
 +      struct libinput *li = dev->libinput;
 +      struct libevdev *evdev = dev->evdev;
 +      const struct input_absinfo *abs;
 +      double w, h;
 +      double dist;
 +
 +      abs = libevdev_get_abs_info(evdev, ABS_MT_POSITION_X);
 +      ck_assert_notnull(abs);
 +      if (abs->resolution == 0)
 +              return;
 +
 +      if (libinput_device_get_size(dev->libinput_device, &w, &h) != 0)
 +              return;
 +
 +      dist = 100.0/max(w, h);
 +
 +      litest_drain_events(li);
 +
 +      /* make sure the movement generates pointer events when
 +         not pinned */
 +      litest_touch_down(dev, 0, 50, 50);
 +      litest_touch_move_to(dev, 0, 50, 50, 52, 52, 10, 1);
 +      litest_touch_move_to(dev, 0, 52, 52, 48, 48, 10, 1);
 +      litest_touch_move_to(dev, 0, 48, 48, 50, 50, 10, 1);
 +      litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
 +
 +      litest_button_click(dev, BTN_LEFT, true);
 +      litest_drain_events(li);
 +
 +      litest_touch_move_to(dev, 0, 50, 50, 50 + dist, 50 + dist, 10, 1);
 +      litest_touch_move_to(dev, 0, 50 + dist, 50 + dist, 50, 50, 10, 1);
 +      litest_touch_move_to(dev, 0, 50, 50, 50 - dist, 50 - dist, 10, 1);
 +
 +      litest_assert_empty_queue(li);
 +
 +      litest_button_click(dev, BTN_LEFT, false);
 +      litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_BUTTON);
 +
 +      /* still pinned after release */
 +      litest_touch_move_to(dev, 0, 50, 50, 50 + dist, 50 + dist, 10, 1);
 +      litest_touch_move_to(dev, 0, 50 + dist, 50 + dist, 50, 50, 10, 1);
 +      litest_touch_move_to(dev, 0, 50, 50, 50 - dist, 50 - dist, 10, 1);
 +
 +      litest_assert_empty_queue(li);
 +
 +      /* move to unpin */
 +      litest_touch_move_to(dev, 0, 50, 50, 70, 70, 10, 1);
 +      litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
 +}
 +END_TEST
 +
 +START_TEST(clickpad_softbutton_left)
 +{
 +      struct litest_device *dev = litest_current_device();
 +      struct libinput *li = dev->libinput;
 +
 +      litest_drain_events(li);
 +
 +      litest_touch_down(dev, 0, 10, 90);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 1);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +
 +      litest_assert_button_event(li,
 +                                 BTN_LEFT,
 +                                 LIBINPUT_BUTTON_STATE_PRESSED);
 +
 +      litest_event(dev, EV_KEY, BTN_LEFT, 0);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_touch_up(dev, 0);
 +
 +      litest_assert_button_event(li,
 +                                 BTN_LEFT,
 +                                 LIBINPUT_BUTTON_STATE_RELEASED);
 +
 +      libinput_dispatch(li);
 +
 +      litest_assert_empty_queue(li);
 +}
 +END_TEST
 +
 +START_TEST(clickpad_softbutton_right)
 +{
 +      struct litest_device *dev = litest_current_device();
 +      struct libinput *li = dev->libinput;
 +
 +      litest_drain_events(li);
 +
 +      litest_touch_down(dev, 0, 90, 90);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 1);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +
 +      litest_assert_button_event(li,
 +                                 BTN_RIGHT,
 +                          LIBINPUT_BUTTON_STATE_PRESSED);
 +
 +      litest_event(dev, EV_KEY, BTN_LEFT, 0);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_touch_up(dev, 0);
 +
 +      litest_assert_button_event(li,
 +                                 BTN_RIGHT,
 +                          LIBINPUT_BUTTON_STATE_RELEASED);
 +
 +      libinput_dispatch(li);
 +
 +      litest_assert_empty_queue(li);
 +}
 +END_TEST
 +
 +START_TEST(clickpad_softbutton_left_tap_n_drag)
 +{
 +      struct litest_device *dev = litest_current_device();
 +      struct libinput *li = dev->libinput;
 +
 +      litest_enable_tap(dev->libinput_device);
 +
 +      litest_drain_events(li);
 +
 +      /* Tap in left button area, then finger down, button click
 +              -> expect left button press/release and left button press
 +         Release button, finger up
 +              -> expect right button release
 +       */
 +      litest_touch_down(dev, 0, 20, 90);
 +      litest_touch_up(dev, 0);
 +      litest_touch_down(dev, 0, 20, 90);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 1);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +
 +      litest_assert_button_event(li,
 +                                 BTN_LEFT,
 +                          LIBINPUT_BUTTON_STATE_PRESSED);
 +      litest_assert_button_event(li,
 +                                 BTN_LEFT,
 +                          LIBINPUT_BUTTON_STATE_RELEASED);
 +      litest_assert_button_event(li,
 +                                 BTN_LEFT,
 +                          LIBINPUT_BUTTON_STATE_PRESSED);
 +      litest_assert_empty_queue(li);
 +
 +      litest_event(dev, EV_KEY, BTN_LEFT, 0);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_touch_up(dev, 0);
 +
 +      litest_assert_button_event(li,
 +                                 BTN_LEFT,
 +                          LIBINPUT_BUTTON_STATE_RELEASED);
 +      litest_assert_empty_queue(li);
 +}
 +END_TEST
 +
 +START_TEST(clickpad_softbutton_right_tap_n_drag)
 +{
 +      struct litest_device *dev = litest_current_device();
 +      struct libinput *li = dev->libinput;
 +
 +      litest_enable_tap(dev->libinput_device);
 +
 +      litest_drain_events(li);
 +
 +      /* Tap in right button area, then finger down, button click
 +              -> expect left button press/release and right button press
 +         Release button, finger up
 +              -> expect right button release
 +       */
 +      litest_touch_down(dev, 0, 90, 90);
 +      litest_touch_up(dev, 0);
 +      litest_touch_down(dev, 0, 90, 90);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 1);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +
 +      litest_assert_button_event(li,
 +                                 BTN_LEFT,
 +                                 LIBINPUT_BUTTON_STATE_PRESSED);
 +      litest_assert_button_event(li,
 +                                 BTN_LEFT,
 +                                 LIBINPUT_BUTTON_STATE_RELEASED);
 +      litest_assert_button_event(li,
 +                                 BTN_RIGHT,
 +                                 LIBINPUT_BUTTON_STATE_PRESSED);
 +      litest_assert_empty_queue(li);
 +
 +      litest_event(dev, EV_KEY, BTN_LEFT, 0);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_touch_up(dev, 0);
 +
 +      litest_assert_button_event(li,
 +                                 BTN_RIGHT,
 +                                 LIBINPUT_BUTTON_STATE_RELEASED);
 +      litest_assert_empty_queue(li);
 +}
 +END_TEST
 +
 +START_TEST(clickpad_softbutton_left_1st_fg_move)
 +{
 +      struct litest_device *dev = litest_current_device();
 +      struct libinput *li = dev->libinput;
 +      struct libinput_event *event;
 +      double x = 0, y = 0;
 +      int nevents = 0;
 +
 +      litest_drain_events(li);
 +
 +      /* One finger down in the left button area, button press
 +              -> expect a button event
 +         Move finger up out of the area, wait for timeout
 +         Move finger around diagonally down left
 +              -> expect motion events down left
 +         Release finger
 +              -> expect a button event */
 +
 +      /* finger down, press in left button */
 +      litest_touch_down(dev, 0, 20, 90);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 1);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +
 +      litest_assert_button_event(li,
 +                                 BTN_LEFT,
 +                                 LIBINPUT_BUTTON_STATE_PRESSED);
 +      litest_assert_empty_queue(li);
 +
 +      /* move out of the area, then wait for softbutton timer */
 +      litest_touch_move_to(dev, 0, 20, 90, 90, 20, 10, 0);
 +      libinput_dispatch(li);
 +      litest_timeout_softbuttons();
 +      libinput_dispatch(li);
 +      litest_drain_events(li);
 +
 +      /* move down left, expect motion */
 +      litest_touch_move_to(dev, 0, 90, 20, 20, 90, 10, 0);
 +
 +      libinput_dispatch(li);
 +      event = libinput_get_event(li);
 +      ck_assert(event != NULL);
 +      while (event) {
 +              struct libinput_event_pointer *p;
 +
 +              ck_assert_int_eq(libinput_event_get_type(event),
 +                               LIBINPUT_EVENT_POINTER_MOTION);
 +              p = libinput_event_get_pointer_event(event);
 +
 +              /* we moved up/right, now down/left so the pointer accel
 +                 code may lag behind with the dx/dy vectors. Hence, add up
 +                 the x/y movements and expect that on average we moved
 +                 left and down */
 +              x += libinput_event_pointer_get_dx(p);
 +              y += libinput_event_pointer_get_dy(p);
 +              nevents++;
 +
 +              libinput_event_destroy(event);
 +              libinput_dispatch(li);
 +              event = libinput_get_event(li);
 +      }
 +
 +      ck_assert(x/nevents < 0);
 +      ck_assert(y/nevents > 0);
 +
 +      litest_event(dev, EV_KEY, BTN_LEFT, 0);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_touch_up(dev, 0);
 +
 +      litest_assert_button_event(li,
 +                                 BTN_LEFT,
 +                                 LIBINPUT_BUTTON_STATE_RELEASED);
 +
 +      litest_assert_empty_queue(li);
 +}
 +END_TEST
 +
 +START_TEST(clickpad_softbutton_left_2nd_fg_move)
 +{
 +      struct litest_device *dev = litest_current_device();
 +      struct libinput *li = dev->libinput;
 +      struct libinput_event *event;
 +
 +      litest_drain_events(li);
 +
 +      /* One finger down in the left button area, button press
 +              -> expect a button event
 +         Put a second finger down in the area, move it right, release
 +              -> expect motion events right
 +         Put a second finger down in the area, move it down, release
 +              -> expect motion events down
 +         Release second finger, release first finger
 +              -> expect a button event */
 +      litest_touch_down(dev, 0, 20, 90);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 1);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +
 +      litest_assert_button_event(li,
 +                                 BTN_LEFT,
 +                                 LIBINPUT_BUTTON_STATE_PRESSED);
 +      litest_assert_empty_queue(li);
 +
 +      litest_touch_down(dev, 1, 20, 20);
 +      litest_touch_move_to(dev, 1, 20, 20, 80, 20, 10, 0);
 +
 +      libinput_dispatch(li);
 +      event = libinput_get_event(li);
 +      ck_assert(event != NULL);
 +      while (event) {
 +              struct libinput_event_pointer *p;
 +              double x, y;
 +
 +              ck_assert_int_eq(libinput_event_get_type(event),
 +                               LIBINPUT_EVENT_POINTER_MOTION);
 +              p = libinput_event_get_pointer_event(event);
 +
 +              x = libinput_event_pointer_get_dx(p);
 +              y = libinput_event_pointer_get_dy(p);
 +
 +              /* Ignore events only containing an unaccelerated motion
 +               * vector. */
 +              if (x != 0 || y != 0) {
 +                      ck_assert(x > 0);
 +                      ck_assert(y == 0);
 +              }
 +
 +              libinput_event_destroy(event);
 +              libinput_dispatch(li);
 +              event = libinput_get_event(li);
 +      }
 +      litest_touch_up(dev, 1);
 +
 +      /* second finger down */
 +      litest_touch_down(dev, 1, 20, 20);
 +      litest_touch_move_to(dev, 1, 20, 20, 20, 80, 10, 0);
 +
 +      libinput_dispatch(li);
 +      event = libinput_get_event(li);
 +      ck_assert(event != NULL);
 +      while (event) {
 +              struct libinput_event_pointer *p;
 +              double x, y;
 +
 +              ck_assert_int_eq(libinput_event_get_type(event),
 +                               LIBINPUT_EVENT_POINTER_MOTION);
 +              p = libinput_event_get_pointer_event(event);
 +
 +              x = libinput_event_pointer_get_dx(p);
 +              y = libinput_event_pointer_get_dy(p);
 +
 +              ck_assert(x == 0);
 +              ck_assert(y > 0);
 +
 +              libinput_event_destroy(event);
 +              libinput_dispatch(li);
 +              event = libinput_get_event(li);
 +      }
 +
 +      litest_touch_up(dev, 1);
 +
 +      litest_event(dev, EV_KEY, BTN_LEFT, 0);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_touch_up(dev, 0);
 +
 +      litest_assert_button_event(li,
 +                                 BTN_LEFT,
 +                                 LIBINPUT_BUTTON_STATE_RELEASED);
 +
 +      litest_assert_empty_queue(li);
 +}
 +END_TEST
 +
 +START_TEST(clickpad_softbutton_left_to_right)
 +{
 +      struct litest_device *dev = litest_current_device();
 +      struct libinput *li = dev->libinput;
 +
 +      litest_drain_events(li);
 +
 +      /* One finger down in left software button area,
 +         move to right button area immediately, click
 +              -> expect right button event
 +      */
 +
 +      litest_touch_down(dev, 0, 20, 90);
 +      litest_touch_move_to(dev, 0, 20, 90, 90, 90, 10, 0);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 1);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +
 +      litest_assert_button_event(li,
 +                                 BTN_RIGHT,
 +                                 LIBINPUT_BUTTON_STATE_PRESSED);
 +      litest_assert_empty_queue(li);
 +
 +      litest_event(dev, EV_KEY, BTN_LEFT, 0);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_touch_up(dev, 0);
 +
 +      litest_assert_button_event(li,
 +                                 BTN_RIGHT,
 +                                 LIBINPUT_BUTTON_STATE_RELEASED);
 +
 +      litest_assert_empty_queue(li);
 +}
 +END_TEST
 +
 +START_TEST(clickpad_softbutton_right_to_left)
 +{
 +      struct litest_device *dev = litest_current_device();
 +      struct libinput *li = dev->libinput;
 +
 +      litest_drain_events(li);
 +
 +      /* One finger down in right software button area,
 +         move to left button area immediately, click
 +              -> expect left button event
 +      */
 +
 +      litest_touch_down(dev, 0, 90, 90);
 +      litest_touch_move_to(dev, 0, 90, 90, 20, 90, 10, 0);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 1);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +
 +      litest_assert_button_event(li,
 +                                 BTN_LEFT,
 +                                 LIBINPUT_BUTTON_STATE_PRESSED);
 +      litest_assert_empty_queue(li);
 +
 +      litest_event(dev, EV_KEY, BTN_LEFT, 0);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_touch_up(dev, 0);
 +
 +      litest_assert_button_event(li,
 +                                 BTN_LEFT,
 +                                 LIBINPUT_BUTTON_STATE_RELEASED);
 +
 +      litest_assert_empty_queue(li);
 +}
 +END_TEST
 +
 +START_TEST(clickpad_topsoftbuttons_left)
 +{
 +      struct litest_device *dev = litest_current_device();
 +      struct libinput *li = dev->libinput;
 +
 +      litest_drain_events(li);
 +
 +      litest_touch_down(dev, 0, 10, 5);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 1);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +
 +      litest_assert_button_event(li,
 +                                 BTN_LEFT,
 +                                 LIBINPUT_BUTTON_STATE_PRESSED);
 +      litest_assert_empty_queue(li);
 +
 +      litest_event(dev, EV_KEY, BTN_LEFT, 0);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_touch_up(dev, 0);
 +
 +      litest_assert_button_event(li,
 +                                 BTN_LEFT,
 +                                 LIBINPUT_BUTTON_STATE_RELEASED);
 +
 +      litest_assert_empty_queue(li);
 +}
 +END_TEST
 +
 +START_TEST(clickpad_topsoftbuttons_right)
 +{
 +      struct litest_device *dev = litest_current_device();
 +      struct libinput *li = dev->libinput;
 +
 +      litest_drain_events(li);
 +
 +      litest_touch_down(dev, 0, 90, 5);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 1);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +
 +      litest_assert_button_event(li,
 +                                 BTN_RIGHT,
 +                                 LIBINPUT_BUTTON_STATE_PRESSED);
 +      litest_assert_empty_queue(li);
 +
 +      litest_event(dev, EV_KEY, BTN_LEFT, 0);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_touch_up(dev, 0);
 +
 +      litest_assert_button_event(li,
 +                                 BTN_RIGHT,
 +                                 LIBINPUT_BUTTON_STATE_RELEASED);
 +
 +      litest_assert_empty_queue(li);
 +}
 +END_TEST
 +
 +START_TEST(clickpad_topsoftbuttons_middle)
 +{
 +      struct litest_device *dev = litest_current_device();
 +      struct libinput *li = dev->libinput;
 +
 +      litest_drain_events(li);
 +
 +      litest_touch_down(dev, 0, 50, 5);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 1);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +
 +      litest_assert_button_event(li,
 +                                 BTN_MIDDLE,
 +                                 LIBINPUT_BUTTON_STATE_PRESSED);
 +      litest_assert_empty_queue(li);
 +
 +      litest_event(dev, EV_KEY, BTN_LEFT, 0);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_touch_up(dev, 0);
 +
 +      litest_assert_button_event(li,
 +                                 BTN_MIDDLE,
 +                                 LIBINPUT_BUTTON_STATE_RELEASED);
 +
 +      litest_assert_empty_queue(li);
 +}
 +END_TEST
 +
 +START_TEST(clickpad_topsoftbuttons_move_out_ignore)
 +{
 +      struct litest_device *dev = litest_current_device();
 +      struct libinput *li = dev->libinput;
 +
 +      /* Finger down in top button area, wait past enter timeout
 +         Move into main area, wait past leave timeout
 +         Click
 +           -> expect no events
 +       */
 +
 +      litest_drain_events(li);
 +
 +      litest_touch_down(dev, 0, 50, 5);
 +      libinput_dispatch(li);
 +      litest_timeout_softbuttons();
 +      libinput_dispatch(li);
 +      litest_assert_empty_queue(li);
 +
 +      litest_touch_move_to(dev, 0, 50, 5, 80, 90, 20, 0);
 +      libinput_dispatch(li);
 +      litest_timeout_softbuttons();
 +      libinput_dispatch(li);
 +
 +      litest_event(dev, EV_KEY, BTN_LEFT, 1);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 0);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +
 +      litest_touch_up(dev, 0);
 +
 +      litest_assert_empty_queue(li);
 +}
 +END_TEST
 +
 +START_TEST(clickpad_topsoftbuttons_clickfinger)
 +{
 +      struct litest_device *dev = litest_current_device();
 +      struct libinput *li = dev->libinput;
 +
 +      enable_clickfinger(dev);
 +
 +      litest_drain_events(li);
 +
 +      litest_touch_down(dev, 0, 90, 5);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 1);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 0);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_touch_up(dev, 0);
 +
 +      litest_assert_button_event(li,
 +                                 BTN_LEFT,
 +                                 LIBINPUT_BUTTON_STATE_PRESSED);
 +      litest_assert_button_event(li,
 +                                 BTN_LEFT,
 +                                 LIBINPUT_BUTTON_STATE_RELEASED);
 +
 +      litest_assert_empty_queue(li);
 +
 +      litest_touch_down(dev, 0, 90, 5);
 +      litest_touch_down(dev, 1, 80, 5);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 1);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 0);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_touch_up(dev, 0);
 +      litest_touch_up(dev, 1);
 +
 +      litest_assert_button_event(li,
 +                                 BTN_RIGHT,
 +                                 LIBINPUT_BUTTON_STATE_PRESSED);
 +      litest_assert_button_event(li,
 +                                 BTN_RIGHT,
 +                                 LIBINPUT_BUTTON_STATE_RELEASED);
 +}
 +END_TEST
 +
 +START_TEST(clickpad_topsoftbuttons_clickfinger_dev_disabled)
 +{
 +      struct litest_device *dev = litest_current_device();
 +      struct libinput *li = dev->libinput;
 +      struct litest_device *trackpoint = litest_add_device(li,
 +                                                           LITEST_TRACKPOINT);
 +
 +      libinput_device_config_send_events_set_mode(dev->libinput_device,
 +                                                  LIBINPUT_CONFIG_SEND_EVENTS_DISABLED);
 +      enable_clickfinger(dev);
 +      litest_drain_events(li);
 +
 +      litest_touch_down(dev, 0, 90, 5);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 1);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 0);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_touch_up(dev, 0);
 +
 +      litest_assert_button_event(li,
 +                                 BTN_RIGHT,
 +                                 LIBINPUT_BUTTON_STATE_PRESSED);
 +      litest_assert_button_event(li,
 +                                 BTN_RIGHT,
 +                                 LIBINPUT_BUTTON_STATE_RELEASED);
 +
 +      litest_assert_empty_queue(li);
 +
 +      litest_touch_down(dev, 0, 90, 5);
 +      litest_touch_down(dev, 1, 10, 5);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 1);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_event(dev, EV_KEY, BTN_LEFT, 0);
 +      litest_event(dev, EV_SYN, SYN_REPORT, 0);
 +      litest_touch_up(dev, 0);
 +      litest_touch_up(dev, 1);
 +
 +      litest_assert_button_event(li,
 +                                 BTN_MIDDLE,
 +                                 LIBINPUT_BUTTON_STATE_PRESSED);
 +      litest_assert_button_event(li,
 +                                 BTN_MIDDLE,
 +                                 LIBINPUT_BUTTON_STATE_RELEASED);
 +
 +      litest_delete_device(trackpoint);
 +}
 +END_TEST
 +
 +void
 +litest_setup_tests(void)
 +{
 +      litest_add("touchpad:clickfinger", touchpad_1fg_clickfinger, LITEST_CLICKPAD, LITEST_ANY);
 +      litest_add("touchpad:clickfinger", touchpad_1fg_clickfinger_no_touch, LITEST_CLICKPAD, LITEST_ANY);
 +      litest_add("touchpad:clickfinger", touchpad_2fg_clickfinger, LITEST_CLICKPAD, LITEST_ANY);
 +      litest_add("touchpad:clickfinger", touchpad_3fg_clickfinger, LITEST_CLICKPAD, LITEST_ANY);
 +      litest_add("touchpad:clickfinger", touchpad_3fg_clickfinger_btntool, LITEST_CLICKPAD, LITEST_ANY);
 +      litest_add("touchpad:clickfinger", touchpad_4fg_clickfinger, LITEST_CLICKPAD, LITEST_ANY);
 +      litest_add("touchpad:clickfinger", touchpad_4fg_clickfinger_btntool_2slots, LITEST_CLICKPAD, LITEST_ANY);
 +      litest_add("touchpad:clickfinger", touchpad_4fg_clickfinger_btntool_3slots, LITEST_CLICKPAD, LITEST_ANY);
 +      litest_add("touchpad:clickfinger", touchpad_2fg_clickfinger_distance, LITEST_CLICKPAD, LITEST_ANY);
 +      litest_add_for_device("touchpad:clickfinger", touchpad_2fg_clickfinger_bottom, LITEST_SYNAPTICS_TOPBUTTONPAD);
 +      litest_add("touchpad:clickfinger", touchpad_clickfinger_to_area_method, LITEST_CLICKPAD, LITEST_ANY);
 +      litest_add("touchpad:clickfinger",
 +                 touchpad_clickfinger_to_area_method_while_down, LITEST_CLICKPAD, LITEST_ANY);
 +      litest_add("touchpad:clickfinger", touchpad_area_to_clickfinger_method, LITEST_CLICKPAD, LITEST_ANY);
 +      litest_add("touchpad:clickfinger",
 +                 touchpad_area_to_clickfinger_method_while_down, LITEST_CLICKPAD, LITEST_ANY);
++      /* run those two for the T440 one only so we don't have to worry
++       * about small touchpads messing with thumb detection expectations */
++      litest_add_for_device("touchpad:clickfinger", touchpad_clickfinger_3fg_tool_position, LITEST_SYNAPTICS_TOPBUTTONPAD);
++      litest_add_for_device("touchpad:clickfinger", touchpad_clickfinger_4fg_tool_position, LITEST_SYNAPTICS_TOPBUTTONPAD);
 +
 +      litest_add("touchpad:click", touchpad_click_defaults_clickfinger, LITEST_APPLE_CLICKPAD, LITEST_ANY);
 +      litest_add("touchpad:click", touchpad_click_defaults_btnarea, LITEST_CLICKPAD, LITEST_APPLE_CLICKPAD);
 +      litest_add("touchpad:click", touchpad_click_defaults_none, LITEST_TOUCHPAD, LITEST_CLICKPAD);
 +
 +      litest_add("touchpad:click", touchpad_btn_left, LITEST_TOUCHPAD|LITEST_BUTTON, LITEST_CLICKPAD);
 +      litest_add("touchpad:click", clickpad_btn_left, LITEST_CLICKPAD, LITEST_ANY);
 +      litest_add("touchpad:click", clickpad_click_n_drag, LITEST_CLICKPAD, LITEST_SINGLE_TOUCH);
 +      litest_add("touchpad:click", clickpad_finger_pin, LITEST_CLICKPAD, LITEST_ANY);
 +
 +      litest_add("touchpad:softbutton", clickpad_softbutton_left, LITEST_CLICKPAD, LITEST_APPLE_CLICKPAD);
 +      litest_add("touchpad:softbutton", clickpad_softbutton_right, LITEST_CLICKPAD, LITEST_APPLE_CLICKPAD);
 +      litest_add("touchpad:softbutton", clickpad_softbutton_left_tap_n_drag, LITEST_CLICKPAD, LITEST_APPLE_CLICKPAD);
 +      litest_add("touchpad:softbutton", clickpad_softbutton_right_tap_n_drag, LITEST_CLICKPAD, LITEST_APPLE_CLICKPAD);
 +      litest_add("touchpad:softbutton", clickpad_softbutton_left_1st_fg_move, LITEST_CLICKPAD, LITEST_APPLE_CLICKPAD);
 +      litest_add("touchpad:softbutton", clickpad_softbutton_left_2nd_fg_move, LITEST_CLICKPAD, LITEST_APPLE_CLICKPAD);
 +      litest_add("touchpad:softbutton", clickpad_softbutton_left_to_right, LITEST_CLICKPAD, LITEST_APPLE_CLICKPAD);
 +      litest_add("touchpad:softbutton", clickpad_softbutton_right_to_left, LITEST_CLICKPAD, LITEST_APPLE_CLICKPAD);
 +
 +      litest_add("touchpad:topsoftbuttons", clickpad_topsoftbuttons_left, LITEST_TOPBUTTONPAD, LITEST_ANY);
 +      litest_add("touchpad:topsoftbuttons", clickpad_topsoftbuttons_right, LITEST_TOPBUTTONPAD, LITEST_ANY);
 +      litest_add("touchpad:topsoftbuttons", clickpad_topsoftbuttons_middle, LITEST_TOPBUTTONPAD, LITEST_ANY);
 +      litest_add("touchpad:topsoftbuttons", clickpad_topsoftbuttons_move_out_ignore, LITEST_TOPBUTTONPAD, LITEST_ANY);
 +      litest_add("touchpad:topsoftbuttons", clickpad_topsoftbuttons_clickfinger, LITEST_TOPBUTTONPAD, LITEST_ANY);
 +      litest_add("touchpad:topsoftbuttons", clickpad_topsoftbuttons_clickfinger_dev_disabled, LITEST_TOPBUTTONPAD, LITEST_ANY);
 +}
diff --cc test/touchpad.c
@@@ -3464,25 -4541,16 +3501,26 @@@ litest_setup_tests(void
        litest_add("touchpad:dwt", touchpad_dwt_click, LITEST_TOUCHPAD, LITEST_ANY);
        litest_add("touchpad:dwt", touchpad_dwt_edge_scroll, LITEST_TOUCHPAD, LITEST_CLICKPAD);
        litest_add("touchpad:dwt", touchpad_dwt_edge_scroll_interrupt, LITEST_TOUCHPAD, LITEST_CLICKPAD);
 +      litest_add("touchpad:dwt", touchpad_dwt_config_default_on, LITEST_TOUCHPAD, LITEST_ANY);
 +      litest_add("touchpad:dwt", touchpad_dwt_config_default_off, LITEST_ANY, LITEST_TOUCHPAD);
 +      litest_add("touchpad:dwt", touchpad_dwt_disabled, LITEST_TOUCHPAD, LITEST_ANY);
 +      litest_add("touchpad:dwt", touchpad_dwt_disable_during_touch, LITEST_TOUCHPAD, LITEST_ANY);
 +      litest_add("touchpad:dwt", touchpad_dwt_disable_before_touch, LITEST_TOUCHPAD, LITEST_ANY);
 +      litest_add("touchpad:dwt", touchpad_dwt_enable_during_touch, LITEST_TOUCHPAD, LITEST_ANY);
 +      litest_add("touchpad:dwt", touchpad_dwt_enable_before_touch, LITEST_TOUCHPAD, LITEST_ANY);
 +      litest_add("touchpad:dwt", touchpad_dwt_enable_during_tap, LITEST_TOUCHPAD, LITEST_ANY);
  
-       litest_add("touchpad:thumb", touchpad_thumb_begin_no_motion, LITEST_TOUCHPAD, LITEST_ANY);
-       litest_add("touchpad:thumb", touchpad_thumb_update_no_motion, LITEST_TOUCHPAD, LITEST_ANY);
+       litest_add("touchpad:thumb", touchpad_thumb_begin_no_motion, LITEST_CLICKPAD, LITEST_ANY);
+       litest_add("touchpad:thumb", touchpad_thumb_update_no_motion, LITEST_CLICKPAD, LITEST_ANY);
+       litest_add("touchpad:thumb", touchpad_thumb_moving, LITEST_CLICKPAD, LITEST_ANY);
        litest_add("touchpad:thumb", touchpad_thumb_clickfinger, LITEST_CLICKPAD, LITEST_ANY);
        litest_add("touchpad:thumb", touchpad_thumb_btnarea, LITEST_CLICKPAD, LITEST_ANY);
-       litest_add("touchpad:thumb", touchpad_thumb_edgescroll, LITEST_TOUCHPAD, LITEST_ANY);
-       litest_add("touchpad:thumb", touchpad_thumb_tap_begin, LITEST_TOUCHPAD, LITEST_ANY);
-       litest_add("touchpad:thumb", touchpad_thumb_tap_touch, LITEST_TOUCHPAD, LITEST_ANY);
-       litest_add("touchpad:thumb", touchpad_thumb_tap_hold, LITEST_TOUCHPAD, LITEST_ANY);
-       litest_add("touchpad:thumb", touchpad_thumb_tap_hold_2ndfg, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
-       litest_add("touchpad:thumb", touchpad_thumb_tap_hold_2ndfg_tap, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
+       litest_add("touchpad:thumb", touchpad_thumb_edgescroll, LITEST_CLICKPAD, LITEST_ANY);
+       litest_add("touchpad:thumb", touchpad_thumb_tap_begin, LITEST_CLICKPAD, LITEST_ANY);
+       litest_add("touchpad:thumb", touchpad_thumb_tap_touch, LITEST_CLICKPAD, LITEST_ANY);
+       litest_add("touchpad:thumb", touchpad_thumb_tap_hold, LITEST_CLICKPAD, LITEST_ANY);
+       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_for_device("touchpad:bugs", touchpad_tool_tripletap_touch_count, LITEST_SYNAPTICS_TOPBUTTONPAD);
  }