tablet: disable smoothing for AES devices
authorPeter Hutterer <peter.hutterer@who-t.net>
Wed, 7 Oct 2020 23:47:36 +0000 (09:47 +1000)
committerPeter Hutterer <peter.hutterer@who-t.net>
Wed, 25 Nov 2020 03:54:47 +0000 (03:54 +0000)
Data in
https://gitlab.freedesktop.org/libinput/libinput/-/issues/225#note_379034
suggests that AES devices have lower noise than the older EMR
devices, so let's try disabling it for those devices.

We can't directly get the AES devices in libinput unless we want to add a
whole bunch of quirks for the various vid/pid combinations. But we can get
that info from libwacom, primarily because we know that libwacom will list all
known AES pens for any device. So we can check for one that we know of (0x11)
and if it's in the list, the tablet is an AES tablet.

Setting the history size to 1 means we never do any actual smoothing.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
src/evdev-tablet.c
src/evdev-tablet.h
test/test-tablet.c

index d4e3890..02753d3 100644 (file)
@@ -89,7 +89,7 @@ tablet_force_button_presses(struct tablet_dispatch *tablet)
 static inline size_t
 tablet_history_size(const struct tablet_dispatch *tablet)
 {
-       return ARRAY_LENGTH(tablet->history.samples);
+       return tablet->history.size;
 }
 
 static inline void
@@ -2344,6 +2344,55 @@ tablet_init_left_handed(struct evdev_device *device)
                                       tablet_change_to_left_handed);
 }
 
+static void
+tablet_init_smoothing(struct evdev_device *device,
+                     struct tablet_dispatch *tablet)
+{
+       size_t history_size = ARRAY_LENGTH(tablet->history.samples);
+#if HAVE_LIBWACOM
+       const char *devnode;
+       WacomDeviceDatabase *db;
+       WacomDevice *libwacom_device = NULL;
+       const int *stylus_ids;
+       int nstyli;
+       bool is_aes = false;
+       int vid = evdev_device_get_id_vendor(device);
+
+       /* Wacom-specific check for whether smoothing is required:
+        * libwacom keeps all the AES pens in a single group, so any device
+        * that supports AES pens will list all AES pens. 0x11 is one of the
+        * lenovo pens so we use that as the flag of whether the tablet
+        * is an AES tablet
+        */
+       if (vid != VENDOR_ID_WACOM)
+               goto out;
+
+       db = tablet_libinput_context(tablet)->libwacom.db;
+       if (!db)
+               goto out;
+
+       devnode = udev_device_get_devnode(device->udev_device);
+       libwacom_device = libwacom_new_from_path(db, devnode, WFALLBACK_NONE, NULL);
+       if (!libwacom_device)
+               goto out;
+
+       stylus_ids = libwacom_get_supported_styli(libwacom_device, &nstyli);
+       for (int i = 0; i < nstyli; i++) {
+               if (stylus_ids[i] == 0x11) {
+                       is_aes = true;
+                       break;
+               }
+       }
+
+       if (is_aes)
+               history_size = 1;
+
+       libwacom_destroy(libwacom_device);
+out:
+#endif
+       tablet->history.size = history_size;
+}
+
 static bool
 tablet_reject_device(struct evdev_device *device)
 {
@@ -2408,6 +2457,7 @@ tablet_init(struct tablet_dispatch *tablet,
 
        evdev_init_sendevents(device, &tablet->base);
        tablet_init_left_handed(device);
+       tablet_init_smoothing(device, tablet);
 
        for (axis = LIBINPUT_TABLET_TOOL_AXIS_X;
             axis <= LIBINPUT_TABLET_TOOL_AXIS_MAX;
index 34d5b99..48469a2 100644 (file)
@@ -64,6 +64,7 @@ struct tablet_dispatch {
                unsigned int index;
                unsigned int count;
                struct tablet_axes samples[TABLET_HISTORY_LENGTH];
+               size_t size;
        } history;
 
        unsigned char axis_caps[NCHARS(LIBINPUT_TABLET_TOOL_AXIS_MAX + 1)];
index 73c0074..211ccfb 100644 (file)
@@ -5988,6 +5988,86 @@ START_TEST(huion_static_btn_tool_pen_disable_quirk_on_prox_out)
 }
 END_TEST
 
+START_TEST(tablet_smoothing)
+{
+#if HAVE_LIBWACOM
+       struct litest_device *dev = litest_current_device();
+       struct libinput *li = dev->libinput;
+       double x, y;
+       struct point {
+               double x, y;
+       } coordinates[100];
+       size_t npoints = 0;
+       size_t idx = 0;
+       struct axis_replacement axes[] = {
+               { ABS_DISTANCE, 10 },
+               { ABS_PRESSURE, 0 },
+               { -1, -1 }
+       };
+
+       litest_drain_events(li);
+
+       litest_tablet_proximity_in(dev, 10, 10, axes);
+       libinput_dispatch(li);
+       litest_drain_events(li);
+
+       /* Move in a straight line, collect the resulting points */
+       for (x = 11, y = 11; x < 50; x++, y++) {
+               struct libinput_event *event;
+               struct libinput_event_tablet_tool *tev;
+               struct point *p = &coordinates[npoints++];
+
+               litest_assert(npoints <= ARRAY_LENGTH(coordinates));
+
+               litest_tablet_motion(dev, x, y, axes);
+               libinput_dispatch(li);
+
+               event = libinput_get_event(li);
+               tev = litest_is_tablet_event(event,
+                                            LIBINPUT_EVENT_TABLET_TOOL_AXIS);
+               p->x = libinput_event_tablet_tool_get_x(tev);
+               p->y = libinput_event_tablet_tool_get_y(tev);
+
+               libinput_event_destroy(event);
+       }
+
+       litest_tablet_proximity_out(dev);
+       litest_tablet_proximity_in(dev, 10, 10, axes);
+       libinput_dispatch(li);
+       litest_drain_events(li);
+
+       /* Move in a wobbly line, collect every second point */
+       for (x = 11, y = 11; x < 50; x++, y++) {
+               struct libinput_event *event;
+               struct libinput_event_tablet_tool *tev;
+               double ex, ey;
+               struct point *p = &coordinates[idx++];
+
+               litest_assert(idx <= npoints);
+
+               /* point off position */
+               litest_tablet_motion(dev, x - 2, y + 1, axes);
+               libinput_dispatch(li);
+               event = libinput_get_event(li);
+               litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_AXIS);
+               libinput_event_destroy(event);
+
+               /* same position as before */
+               litest_tablet_motion(dev, x, y, axes);
+               libinput_dispatch(li);
+               event = libinput_get_event(li);
+               tev = litest_is_tablet_event(event,
+                                            LIBINPUT_EVENT_TABLET_TOOL_AXIS);
+               ex = libinput_event_tablet_tool_get_x(tev);
+               ey = libinput_event_tablet_tool_get_y(tev);
+
+               ck_assert_double_eq(ex, p->x);
+               ck_assert_double_eq(ey, p->y);
+       }
+#endif
+}
+END_TEST
+
 TEST_COLLECTION(tablet)
 {
        struct range with_timeout = { 0, 2 };
@@ -6112,4 +6192,6 @@ TEST_COLLECTION(tablet)
        litest_add_for_device("tablet:quirks", huion_static_btn_tool_pen, LITEST_HUION_TABLET);
        litest_add_for_device("tablet:quirks", huion_static_btn_tool_pen_no_timeout_during_usage, LITEST_HUION_TABLET);
        litest_add_ranged_for_device("tablet:quirks", huion_static_btn_tool_pen_disable_quirk_on_prox_out, LITEST_HUION_TABLET, &with_timeout);
+
+       litest_add_for_device("tablet:smoothing", tablet_smoothing, LITEST_WACOM_HID4800_PEN);
 }