From e5212e2080ea4196b0f81a888a6603db975d8e0b Mon Sep 17 00:00:00 2001 From: Stephen Chandler Paul Date: Tue, 10 Jun 2014 16:48:19 -0400 Subject: [PATCH] Emit LIBINPUT_TABLET_EVENT_TOOL_UPDATE events on tool changes Signed-off-by: Stephen Chandler Paul Reviewed-by: Peter Hutterer Reviewed-by: Hans de Goede --- src/evdev-tablet.c | 99 ++++++++++++++++++++++++++++++++++++++++++ src/evdev-tablet.h | 6 ++- src/libinput-private.h | 7 +++ src/libinput.c | 39 +++++++++++++++++ src/libinput.h | 35 ++++++++++++++- 5 files changed, 183 insertions(+), 3 deletions(-) diff --git a/src/evdev-tablet.c b/src/evdev-tablet.c index a12b6709..da86b057 100644 --- a/src/evdev-tablet.c +++ b/src/evdev-tablet.c @@ -58,6 +58,19 @@ tablet_process_absolute(struct tablet_dispatch *tablet, } } +static void +tablet_update_tool(struct tablet_dispatch *tablet, + enum libinput_tool_type tool, + bool enabled) +{ + assert(tool != LIBINPUT_TOOL_NONE); + + if (enabled && tool != tablet->current_tool_type) { + tablet->current_tool_type = tool; + tablet_set_status(tablet, TABLET_TOOL_UPDATED); + } +} + static void tablet_check_notify_axes(struct tablet_dispatch *tablet, struct evdev_device *device, @@ -95,11 +108,90 @@ tablet_check_notify_axes(struct tablet_dispatch *tablet, } } +static void +tablet_process_key(struct tablet_dispatch *tablet, + struct evdev_device *device, + struct input_event *e, + uint32_t time) +{ + switch (e->code) { + case BTN_TOOL_PEN: + case BTN_TOOL_RUBBER: + case BTN_TOOL_BRUSH: + case BTN_TOOL_PENCIL: + case BTN_TOOL_AIRBRUSH: + case BTN_TOOL_FINGER: + case BTN_TOOL_MOUSE: + case BTN_TOOL_LENS: + /* These codes have an equivalent libinput_tool value */ + tablet_update_tool(tablet, e->code, e->value); + break; + default: + break; + } +} + +static void +tablet_process_misc(struct tablet_dispatch *tablet, + struct evdev_device *device, + struct input_event *e, + uint32_t time) +{ + switch (e->code) { + case MSC_SERIAL: + if (e->value != (signed)tablet->current_tool_serial && + e->value != -1) { + tablet->current_tool_serial = e->value; + tablet_set_status(tablet, TABLET_TOOL_UPDATED); + } + break; + default: + log_info("Unhandled MSC event code %#x\n", e->code); + break; + } +} + +static void +tablet_notify_tool(struct tablet_dispatch *tablet, + struct evdev_device *device, + uint32_t time) +{ + struct libinput_device *base = &device->base; + struct libinput_tool *tool; + struct libinput_tool *new_tool = NULL; + + /* Check if we already have the tool in our list of tools */ + list_for_each(tool, &base->seat->libinput->tool_list, link) { + if (tablet->current_tool_type == tool->type && + tablet->current_tool_serial == tool->serial) { + new_tool = tool; + break; + } + } + + /* If we didn't already have the tool in our list of tools, add it */ + if (new_tool == NULL) { + new_tool = zalloc(sizeof *new_tool); + *new_tool = (struct libinput_tool) { + .type = tablet->current_tool_type, + .serial = tablet->current_tool_serial, + .refcount = 1, + }; + + list_insert(&base->seat->libinput->tool_list, &new_tool->link); + } + + tablet_notify_tool_update(base, time, new_tool); +} + static void tablet_flush(struct tablet_dispatch *tablet, struct evdev_device *device, uint32_t time) { + if (tablet_has_status(tablet, TABLET_TOOL_UPDATED)) + tablet_notify_tool(tablet, device, time); + if (tablet_has_status(tablet, TABLET_AXES_UPDATED)) { tablet_check_notify_axes(tablet, device, time); tablet_unset_status(tablet, TABLET_AXES_UPDATED); @@ -119,6 +211,12 @@ tablet_process(struct evdev_dispatch *dispatch, case EV_ABS: tablet_process_absolute(tablet, device, e, time); break; + case EV_KEY: + tablet_process_key(tablet, device, e, time); + break; + case EV_MSC: + tablet_process_misc(tablet, device, e, time); + break; case EV_SYN: tablet_flush(tablet, device, time); break; @@ -151,6 +249,7 @@ tablet_init(struct tablet_dispatch *tablet, tablet->base.interface = &tablet_interface; tablet->device = device; tablet->status = TABLET_NONE; + tablet->current_tool_type = LIBINPUT_TOOL_NONE; /* Mark any axes the tablet has as changed */ for (a = 0; a < LIBINPUT_TABLET_AXIS_CNT; a++) { diff --git a/src/evdev-tablet.h b/src/evdev-tablet.h index 551bcafd..28b7a63e 100644 --- a/src/evdev-tablet.h +++ b/src/evdev-tablet.h @@ -29,7 +29,8 @@ enum tablet_status { TABLET_NONE = 0, - TABLET_AXES_UPDATED = 1 << 0 + TABLET_AXES_UPDATED = 1 << 0, + TABLET_TOOL_UPDATED = 1 << 1 }; struct tablet_dispatch { @@ -38,6 +39,9 @@ struct tablet_dispatch { unsigned char status; unsigned char changed_axes[NCHARS(LIBINPUT_TABLET_AXIS_CNT)]; double axes[LIBINPUT_TABLET_AXIS_CNT]; + + enum libinput_tool_type current_tool_type; + uint32_t current_tool_serial; }; static inline enum libinput_tablet_axis diff --git a/src/libinput-private.h b/src/libinput-private.h index 83906f5b..532ce298 100644 --- a/src/libinput-private.h +++ b/src/libinput-private.h @@ -54,6 +54,8 @@ struct libinput { size_t events_in; size_t events_out; + struct list tool_list; + const struct libinput_interface *interface; const struct libinput_interface_backend *interface_backend; void *user_data; @@ -207,6 +209,11 @@ tablet_notify_axis(struct libinput_device *device, unsigned char *changed_axes, double *axes); +void +tablet_notify_tool_update(struct libinput_device *device, + uint32_t time, + struct libinput_tool *tool); + void touch_notify_frame(struct libinput_device *device, uint32_t time); diff --git a/src/libinput.c b/src/libinput.c index 5e6ba93c..c7505c02 100644 --- a/src/libinput.c +++ b/src/libinput.c @@ -85,6 +85,7 @@ struct libinput_event_tablet { uint32_t time; double *axes; unsigned char changed_axes[NCHARS(LIBINPUT_TABLET_AXIS_CNT)]; + struct libinput_tool *tool; }; static void @@ -199,6 +200,7 @@ libinput_event_get_pointer_event(struct libinput_event *event) case LIBINPUT_EVENT_TOUCH_CANCEL: case LIBINPUT_EVENT_TOUCH_FRAME: case LIBINPUT_EVENT_TABLET_AXIS: + case LIBINPUT_EVENT_TABLET_TOOL_UPDATE: break; } @@ -226,6 +228,7 @@ libinput_event_get_keyboard_event(struct libinput_event *event) case LIBINPUT_EVENT_TOUCH_CANCEL: case LIBINPUT_EVENT_TOUCH_FRAME: case LIBINPUT_EVENT_TABLET_AXIS: + case LIBINPUT_EVENT_TABLET_TOOL_UPDATE: break; } @@ -253,6 +256,7 @@ libinput_event_get_touch_event(struct libinput_event *event) case LIBINPUT_EVENT_TOUCH_FRAME: return (struct libinput_event_touch *) event; case LIBINPUT_EVENT_TABLET_AXIS: + case LIBINPUT_EVENT_TABLET_TOOL_UPDATE: break; } @@ -279,6 +283,7 @@ libinput_event_get_tablet_event(struct libinput_event *event) case LIBINPUT_EVENT_TOUCH_FRAME: break; case LIBINPUT_EVENT_TABLET_AXIS: + case LIBINPUT_EVENT_TABLET_TOOL_UPDATE: return (struct libinput_event_tablet *) event; } @@ -305,6 +310,7 @@ libinput_event_get_device_notify_event(struct libinput_event *event) case LIBINPUT_EVENT_TOUCH_CANCEL: case LIBINPUT_EVENT_TOUCH_FRAME: case LIBINPUT_EVENT_TABLET_AXIS: + case LIBINPUT_EVENT_TABLET_TOOL_UPDATE: break; } @@ -509,6 +515,12 @@ libinput_event_tablet_get_y_transformed(struct libinput_event_tablet *event, height); } +LIBINPUT_EXPORT struct libinput_tool * +libinput_event_tablet_get_tool(struct libinput_event_tablet *event) +{ + return event->tool; +} + LIBINPUT_EXPORT uint32_t libinput_event_tablet_get_time(struct libinput_event_tablet *event) { @@ -605,6 +617,7 @@ libinput_init(struct libinput *libinput, libinput->user_data = user_data; list_init(&libinput->source_destroy_list); list_init(&libinput->seat_list); + list_init(&libinput->tool_list); if (libinput_timer_subsys_init(libinput) != 0) { free(libinput->events); @@ -637,6 +650,7 @@ libinput_destroy(struct libinput *libinput) struct libinput_event *event; struct libinput_device *device, *next_device; struct libinput_seat *seat, *next_seat; + struct libinput_tool *tool, *next_tool; if (libinput == NULL) return; @@ -659,6 +673,10 @@ libinput_destroy(struct libinput *libinput) libinput_seat_destroy(seat); } + list_for_each_safe(tool, next_tool, &libinput->tool_list, link) { + libinput_tool_unref(tool); + } + libinput_timer_subsys_destroy(libinput); libinput_drop_destroyed_sources(libinput); close(libinput->epoll_fd); @@ -1160,6 +1178,27 @@ tablet_notify_axis(struct libinput_device *device, &axis_event->base); } +void +tablet_notify_tool_update(struct libinput_device *device, + uint32_t time, + struct libinput_tool *tool) +{ + struct libinput_event_tablet *tool_update_event; + + tool_update_event = zalloc(sizeof *tool_update_event); + if (!tool_update_event) + return; + + *tool_update_event = (struct libinput_event_tablet) { + .time = time, + .tool = tool, + }; + + post_device_event(device, + LIBINPUT_EVENT_TABLET_TOOL_UPDATE, + &tool_update_event->base); +} + static void libinput_post_event(struct libinput *libinput, struct libinput_event *event) diff --git a/src/libinput.h b/src/libinput.h index 0bd24c2e..2f272e7a 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -254,7 +254,12 @@ enum libinput_event_type { */ LIBINPUT_EVENT_TOUCH_FRAME, - LIBINPUT_EVENT_TABLET_AXIS = 600 + LIBINPUT_EVENT_TABLET_AXIS = 600, + /** + * Signals that a device with the @ref LIBINPUT_DEVICE_CAP_TABLET + * capability has changed its tool. + */ + LIBINPUT_EVENT_TABLET_TOOL_UPDATE }; struct libinput; @@ -283,7 +288,8 @@ struct libinput_event_touch; * @struct libinput_event_tablet * * Tablet event representing an axis update, button press, or tool update. Valid - * event types for this event are @ref LIBINPUT_EVENT_TABLET_AXIS. + * event types for this event are @ref LIBINPUT_EVENT_TABLET_AXIS, and + * @ref LIBINPUT_EVENT_TABLET_TOOL_UPDATE. */ struct libinput_event_tablet; @@ -891,6 +897,31 @@ libinput_event_tablet_get_x_transformed(struct libinput_event_tablet *event, double libinput_event_tablet_get_y_transformed(struct libinput_event_tablet *event, uint32_t height); + +/** + * @ingroup event_tablet + * + * Return the new tool in use for this event. + * For tablet events that are not of type @ref + * LIBINPUT_EVENT_TABLET_TOOL_UPDATE, this function returns NULL. By default, + * the lifetime of each tool is bound to the lifetime of the event, so the tool + * will be destroyed when the event is destroyed. However, the lifetime of the + * tool may be extended by using libinput_tool_ref() to increment the reference + * count of the tool. Whenever libinput detects that the tool is in proximity of + * any tablet that's connected, it will return the same libinput_tool object. + * + * @note It is an application bug to call this function for events other than + * @ref LIBINPUT_EVENT_TABLET_TOOL_UPDATE. + * + * @note On tablets where the serial number of tools is not reported, each tool + * cannot be guaranteed to be unique. + * + * @param event The libinput tablet event + * @return The new tool triggering this event + */ +struct libinput_tool * +libinput_event_tablet_get_tool(struct libinput_event_tablet *event); + /** * @ingroup event_tablet *