diff --git a/src/evdev-tablet.c b/src/evdev-tablet.c index d4e3890a..02753d39 100644 --- a/src/evdev-tablet.c +++ b/src/evdev-tablet.c @@ -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; diff --git a/src/evdev-tablet.h b/src/evdev-tablet.h index 34d5b991..48469a2b 100644 --- a/src/evdev-tablet.h +++ b/src/evdev-tablet.h @@ -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)]; diff --git a/test/test-tablet.c b/test/test-tablet.c index 73c0074d..211ccfb1 100644 --- a/test/test-tablet.c +++ b/test/test-tablet.c @@ -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); }