tablet: log a bug when a tablet switches between tools directly

We expect the kernel to transition properly for us, e.g. BTN_TOOL_PEN goes to
0, BTN_TOOL_ERASER goes to 1. Two cases have surfaced recently where this
doesn't happen and debugging this takes time - so let's warn about it to make
it obvious.

Example 1: https://github.com/linuxwacom/libwacom/issues/70
Example 2: https://gitlab.freedesktop.org/libinput/libinput/issues/259

This is just a warning, nothing more. We should just handle that case
accordingly but that requires more effort.

Fixes #260

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
Peter Hutterer 2019-04-01 15:29:37 +10:00
parent 4912e7ed4a
commit ca1a75a961
3 changed files with 53 additions and 0 deletions

View file

@ -278,6 +278,11 @@ tablet_update_tool(struct tablet_dispatch *tablet,
assert(tool != LIBINPUT_TOOL_NONE);
if (enabled) {
if (tablet->current_tool.is_active)
evdev_log_bug_kernel(device,
"Tool directly switched from %d to %d",
tablet->current_tool.type,
tool);
tablet->current_tool.type = tool;
tablet_set_status(tablet, TABLET_TOOL_ENTERING_PROXIMITY);
tablet_unset_status(tablet, TABLET_TOOL_OUT_OF_PROXIMITY);
@ -285,6 +290,8 @@ tablet_update_tool(struct tablet_dispatch *tablet,
else if (!tablet_has_status(tablet, TABLET_TOOL_OUT_OF_PROXIMITY)) {
tablet_set_status(tablet, TABLET_TOOL_LEAVING_PROXIMITY);
}
tablet->current_tool.is_active = enabled;
}
static inline double
@ -2158,6 +2165,7 @@ tablet_init(struct tablet_dispatch *tablet,
tablet->device = device;
tablet->status = TABLET_NONE;
tablet->current_tool.type = LIBINPUT_TOOL_NONE;
tablet->current_tool.is_active = false;
list_init(&tablet->tool_list);
if (tablet_reject_device(device))

View file

@ -78,6 +78,8 @@ struct tablet_dispatch {
enum libinput_tablet_tool_type type;
uint32_t id;
uint32_t serial;
bool is_active; /* evdev protocol state */
} current_tool;
uint32_t cursor_proximity_threshold;

View file

@ -2684,6 +2684,48 @@ START_TEST(tool_in_prox_before_start)
}
END_TEST
static void tool_switch_warning(struct libinput *libinput,
enum libinput_log_priority priority,
const char *format,
va_list args)
{
int *warning_triggered = (int*)libinput_get_user_data(libinput);
if (priority == LIBINPUT_LOG_PRIORITY_ERROR &&
strstr(format, "Tool directly switched"))
(*warning_triggered)++;
}
START_TEST(tool_direct_switch)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
struct axis_replacement axes[] = {
{ ABS_DISTANCE, 10 },
{ ABS_PRESSURE, 0 },
{ -1, -1 }
};
int warning_triggered = 0;
if (!libevdev_has_event_code(dev->evdev, EV_KEY, BTN_TOOL_RUBBER))
return;
libinput_set_user_data(li, &warning_triggered);
libinput_log_set_handler(li, tool_switch_warning);
litest_tablet_proximity_in(dev, 10, 10, axes);
litest_drain_events(li);
litest_event(dev, EV_KEY, BTN_TOOL_RUBBER, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
libinput_dispatch(li);
ck_assert_int_eq(warning_triggered, 1);
litest_restore_log_handler(li);
}
END_TEST
START_TEST(mouse_tool)
{
struct litest_device *dev = litest_current_device();
@ -4952,6 +4994,7 @@ TEST_COLLECTION(tablet)
litest_add_no_device("tablet:tool", tool_capabilities);
litest_add("tablet:tool", tool_type, LITEST_TABLET, LITEST_ANY);
litest_add("tablet:tool", tool_in_prox_before_start, LITEST_TABLET, LITEST_ANY);
litest_add("tablet:tool", tool_direct_switch, LITEST_TABLET, LITEST_ANY);
litest_add("tablet:tool_serial", tool_unique, LITEST_TABLET | LITEST_TOOL_SERIAL, LITEST_ANY);
litest_add("tablet:tool_serial", tool_serial, LITEST_TABLET | LITEST_TOOL_SERIAL, LITEST_ANY);
litest_add("tablet:tool_serial", tool_id, LITEST_TABLET | LITEST_TOOL_SERIAL, LITEST_ANY);