tablet: disable smoothing for AES devices

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>
This commit is contained in:
Peter Hutterer 2020-10-08 09:47:36 +10:00
parent cd37dcfa66
commit a506d092b8
3 changed files with 134 additions and 1 deletions

View 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;

View 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)];

View 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);
}