[PATCH libinput] tablet: don't send tip up/button release/prox out events for unknown tools
Peter Hutterer
peter.hutterer at who-t.net
Thu Aug 18 05:20:05 UTC 2016
If the kernel does not send the MSC_SERIAL information with every event, we
end up creating a tool with a serial of 0. When the MSC_SERIAL comes in
later for this tool libinput will think it's a new tool. On proximity out of
that new tool we send the required release events even though we never sent
the proximity in/button down/tip down events.
Simply ditch those events and log a bug message instead. This causes the
first tool with serial 0 to remain in proximity/down state forever but it's a
made-up situation anyway, let's deal with that when we have devices other
than our own test devices triggering this.
Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
src/evdev-tablet.c | 58 +++++++++++++++++++++++++++-------------
src/libinput-private.h | 2 ++
test/tablet.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 114 insertions(+), 18 deletions(-)
diff --git a/src/evdev-tablet.c b/src/evdev-tablet.c
index 8f24555..bc85655 100644
--- a/src/evdev-tablet.c
+++ b/src/evdev-tablet.c
@@ -1198,6 +1198,24 @@ tablet_mark_all_axes_changed(struct tablet_dispatch *tablet,
sizeof(tablet->changed_axes));
}
+static inline bool
+tool_was_in_proximity(struct tablet_dispatch *tablet,
+ struct libinput_tablet_tool *tool)
+{
+ if (!tool->in_proximity) {
+ struct libinput *libinput = tablet_libinput_context(tablet);
+ log_bug_kernel(libinput,
+ "%s: prox out for tool type %d tool_id %#x serial %#x, "
+ "but no prox in recorded\n",
+ tablet->device->devname,
+ tool->type,
+ tool->serial,
+ tool->tool_id);
+ }
+
+ return tool->in_proximity;
+}
+
static void
tablet_update_proximity_state(struct tablet_dispatch *tablet,
struct evdev_device *device,
@@ -1295,6 +1313,7 @@ tablet_send_axis_proximity_tip_down_events(struct tablet_dispatch *tablet,
LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN,
tablet->changed_axes,
&axes);
+ tool->in_proximity = true;
tablet_unset_status(tablet, TABLET_TOOL_ENTERING_PROXIMITY);
tablet_unset_status(tablet, TABLET_AXES_UPDATED);
}
@@ -1310,12 +1329,13 @@ tablet_send_axis_proximity_tip_down_events(struct tablet_dispatch *tablet,
tablet_unset_status(tablet, TABLET_TOOL_ENTERING_CONTACT);
tablet_set_status(tablet, TABLET_TOOL_IN_CONTACT);
} else if (tablet_has_status(tablet, TABLET_TOOL_LEAVING_CONTACT)) {
- tablet_notify_tip(&device->base,
- time,
- tool,
- LIBINPUT_TABLET_TOOL_TIP_UP,
- tablet->changed_axes,
- &tablet->axes);
+ if (tool_was_in_proximity(tablet, tool))
+ tablet_notify_tip(&device->base,
+ time,
+ tool,
+ LIBINPUT_TABLET_TOOL_TIP_UP,
+ tablet->changed_axes,
+ &tablet->axes);
tablet_unset_status(tablet, TABLET_AXES_UPDATED);
tablet_unset_status(tablet, TABLET_TOOL_LEAVING_CONTACT);
tablet_unset_status(tablet, TABLET_TOOL_IN_CONTACT);
@@ -1388,11 +1408,12 @@ tablet_flush(struct tablet_dispatch *tablet,
time);
if (tablet_has_status(tablet, TABLET_BUTTONS_RELEASED)) {
- tablet_notify_buttons(tablet,
- device,
- time,
- tool,
- LIBINPUT_BUTTON_STATE_RELEASED);
+ if (tool_was_in_proximity(tablet, tool))
+ tablet_notify_buttons(tablet,
+ device,
+ time,
+ tool,
+ LIBINPUT_BUTTON_STATE_RELEASED);
tablet_unset_status(tablet, TABLET_BUTTONS_RELEASED);
}
@@ -1407,13 +1428,14 @@ tablet_flush(struct tablet_dispatch *tablet,
if (tablet_has_status(tablet, TABLET_TOOL_LEAVING_PROXIMITY)) {
memset(tablet->changed_axes, 0, sizeof(tablet->changed_axes));
- tablet_notify_proximity(&device->base,
- time,
- tool,
- LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT,
- tablet->changed_axes,
- &tablet->axes);
-
+ if (tool_was_in_proximity(tablet, tool))
+ tablet_notify_proximity(&device->base,
+ time,
+ tool,
+ LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT,
+ tablet->changed_axes,
+ &tablet->axes);
+ tool->in_proximity = false;
tablet_set_status(tablet, TABLET_TOOL_OUT_OF_PROXIMITY);
tablet_unset_status(tablet, TABLET_TOOL_LEAVING_PROXIMITY);
diff --git a/src/libinput-private.h b/src/libinput-private.h
index 479da75..a59bc30 100644
--- a/src/libinput-private.h
+++ b/src/libinput-private.h
@@ -338,6 +338,8 @@ struct libinput_tablet_tool {
struct threshold pressure_threshold;
int pressure_offset; /* in device coordinates */
bool has_pressure_offset;
+
+ bool in_proximity;
};
struct libinput_tablet_pad_mode_group {
diff --git a/test/tablet.c b/test/tablet.c
index c6886b0..3802852 100644
--- a/test/tablet.c
+++ b/test/tablet.c
@@ -2272,6 +2272,77 @@ START_TEST(tool_in_prox_before_start)
}
END_TEST
+START_TEST(tool_in_prox_before_start_no_serial)
+{
+ struct libinput *li;
+ struct litest_device *dev = litest_current_device();
+ struct libinput_event *event;
+ struct libinput_event_tablet_tool *tev;
+ struct libinput_tablet_tool *tool;
+ struct axis_replacement axes[] = {
+ { ABS_DISTANCE, 10 },
+ { ABS_PRESSURE, 0 },
+ { ABS_TILT_X, 0 },
+ { ABS_TILT_Y, 0 },
+ { -1, -1 }
+ };
+ const char *devnode;
+ unsigned int serial;
+
+ /* Move into proximity before we have a context */
+ litest_tablet_proximity_in(dev, 10, 10, axes);
+
+ /* for simplicity, we create a new litest context */
+ devnode = libevdev_uinput_get_devnode(dev->uinput);
+ li = litest_create_context();
+ libinput_path_add_device(li, devnode);
+
+ litest_wait_for_event_of_type(li,
+ LIBINPUT_EVENT_DEVICE_ADDED,
+ -1);
+ event = libinput_get_event(li);
+ libinput_event_destroy(event);
+
+ litest_assert_empty_queue(li);
+
+ /* send an event without MSC_SERIAL so we won't know the serial
+ number. This should never happen on a real device unless the
+ kernel is buggy */
+ litest_event(dev, EV_KEY, BTN_STYLUS, 1);
+ litest_event(dev, EV_SYN, SYN_REPORT, 0);
+ libinput_dispatch(li);
+
+ event = libinput_get_event(li);
+ tev = litest_is_tablet_event(event,
+ LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
+ tool = libinput_event_tablet_tool_get_tool(tev);
+ serial = libinput_tablet_tool_get_serial(tool);
+ libinput_event_destroy(event);
+
+ event = libinput_get_event(li);
+ tev = litest_is_tablet_event(event,
+ LIBINPUT_EVENT_TABLET_TOOL_BUTTON);
+ tool = libinput_event_tablet_tool_get_tool(tev);
+ ck_assert_int_eq(serial,
+ libinput_tablet_tool_get_serial(tool));
+ libinput_event_destroy(event);
+
+ litest_tablet_proximity_out(dev);
+
+ litest_disable_log_handler(li);
+ libinput_dispatch(li);
+ litest_restore_log_handler(li);
+
+ /* The proximity out added the MSC_SERIAL, but the original tool
+ * (without the serial) never left proximity so we don't expect
+ * button release events or a proximity out here
+ */
+ litest_assert_empty_queue(li);
+
+ libinput_unref(li);
+}
+END_TEST
+
START_TEST(mouse_tool)
{
struct litest_device *dev = litest_current_device();
@@ -3676,6 +3747,7 @@ litest_setup_tests_tablet(void)
litest_add("tablet:tool", tool_ref, LITEST_TABLET | LITEST_TOOL_SERIAL, LITEST_ANY);
litest_add_no_device("tablet:tool", tool_capabilities);
litest_add("tablet:tool", tool_in_prox_before_start, LITEST_TABLET, LITEST_ANY);
+ litest_add("tablet:tool", tool_in_prox_before_start_no_serial, LITEST_TABLET|LITEST_TOOL_SERIAL, 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", serial_changes_tool, LITEST_TABLET | LITEST_TOOL_SERIAL, LITEST_ANY);
--
2.7.4
More information about the wayland-devel
mailing list