These devices set the LIBINPUT_DEVICE_CAP_STYLUS flag, and emit a lot more axis information then mice and touchpads. As such, tablet events are in a whole new group of events that is separate from everything else.
In this commit, only X and Y axes are reported in libinput. Based off the patch originally written by Carlos Garnacho Signed-off-by: Stephen Chandler Paul <[email protected]> --- src/Makefile.am | 2 + src/evdev-tablet.c | 170 +++++++++++++++++++++++++++++++++++++++++++++++++ src/evdev-tablet.h | 64 +++++++++++++++++++ src/evdev.c | 8 +++ src/evdev.h | 3 + src/libinput-private.h | 6 ++ src/libinput-util.h | 2 + src/libinput.c | 108 +++++++++++++++++++++++++++++++ src/libinput.h | 121 ++++++++++++++++++++++++++++++++++- 9 files changed, 483 insertions(+), 1 deletion(-) create mode 100644 src/evdev-tablet.c create mode 100644 src/evdev-tablet.h diff --git a/src/Makefile.am b/src/Makefile.am index bf56184..b880a69 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -11,6 +11,8 @@ libinput_la_SOURCES = \ libinput-util.h \ evdev.c \ evdev.h \ + evdev-tablet.c \ + evdev-tablet.h \ evdev-mt-touchpad.c \ evdev-mt-touchpad.h \ evdev-mt-touchpad-tap.c \ diff --git a/src/evdev-tablet.c b/src/evdev-tablet.c new file mode 100644 index 0000000..5c73bcb --- /dev/null +++ b/src/evdev-tablet.c @@ -0,0 +1,170 @@ +/* + * Copyright © 2014 Red Hat, Inc. + * Copyright © 2014 Stephen Chandler "Lyude" Paul + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the copyright holders not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. The copyright holders make + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "config.h" +#include "evdev-tablet.h" + +#include <assert.h> +#include <math.h> +#include <stdbool.h> +#include <string.h> + +#define tablet_set_status(tablet_,s_) (tablet_->status |= (s_)) +#define tablet_unset_status(tablet_,s_) (tablet_->status &= ~(s_)) +#define tablet_has_status(tablet_,s_) (!!(tablet_->status & s_)) + +static void +tablet_process_absolute(struct tablet_dispatch *tablet, + struct evdev_device *device, + struct input_event *e, + uint32_t time) +{ + enum libinput_tablet_axis axis; + + switch (e->code) { + case ABS_X: + case ABS_Y: + axis = evcode_to_axis(e->code); + if (axis == LIBINPUT_TABLET_AXIS_NONE) { + log_bug_libinput("Invalid ABS event code %#x\n", + e->code); + break; + } + + tablet->absinfo[axis] = libevdev_get_abs_info(device->evdev, + e->code); + + set_bit(tablet->changed_axes, axis); + tablet_set_status(tablet, TABLET_AXES_UPDATED); + break; + default: + log_info("Unhandled ABS event code %#x\n", e->code); + break; + } +} + +static void +tablet_notify_axes(struct tablet_dispatch *tablet, + struct evdev_device *device, + uint32_t time) +{ + struct libinput_device *base = &device->base; + bool axis_update_needed = false; + int a; + + for (a = 0; a < LIBINPUT_TABLET_AXIS_CNT; a++) { + if (!bit_is_set(tablet->changed_axes, a)) + continue; + + switch (a) { + case LIBINPUT_TABLET_AXIS_X: + case LIBINPUT_TABLET_AXIS_Y: + tablet->axes[a] = tablet->absinfo[a]->value; + break; + default: + log_bug_libinput("Invalid axis update: %d\n", a); + break; + } + + axis_update_needed = true; + } + + if (axis_update_needed) { + tablet_notify_axis(base, time, tablet->changed_axes, tablet->axes); + memset(tablet->changed_axes, 0, sizeof(tablet->changed_axes)); + } +} + +static void +tablet_flush(struct tablet_dispatch *tablet, + struct evdev_device *device, + uint32_t time) +{ + if (tablet_has_status(tablet, TABLET_AXES_UPDATED)) { + tablet_notify_axes(tablet, device, time); + tablet_unset_status(tablet, TABLET_AXES_UPDATED); + } +} + +static void +tablet_process(struct evdev_dispatch *dispatch, + struct evdev_device *device, + struct input_event *e, + uint64_t time) +{ + struct tablet_dispatch *tablet = + (struct tablet_dispatch *)dispatch; + + switch (e->type) { + case EV_ABS: + tablet_process_absolute(tablet, device, e, time); + break; + case EV_SYN: + tablet_flush(tablet, device, time); + break; + default: + log_error("Unexpected event type %#x\n", e->type); + break; + } +} + +static void +tablet_destroy(struct evdev_dispatch *dispatch) +{ + struct tablet_dispatch *tablet = + (struct tablet_dispatch*)dispatch; + + free(tablet); +} + +static struct evdev_dispatch_interface tablet_interface = { + tablet_process, + tablet_destroy +}; + +static int +tablet_init(struct tablet_dispatch *tablet, + struct evdev_device *device) +{ + tablet->base.interface = &tablet_interface; + tablet->device = device; + tablet->status = TABLET_NONE; + + return 0; +} + +struct evdev_dispatch * +evdev_tablet_create(struct evdev_device *device) +{ + struct tablet_dispatch *tablet; + + tablet = zalloc(sizeof *tablet); + if (!tablet) + return NULL; + + if (tablet_init(tablet, device) != 0) { + tablet_destroy(&tablet->base); + return NULL; + } + + return &tablet->base; +} diff --git a/src/evdev-tablet.h b/src/evdev-tablet.h new file mode 100644 index 0000000..d832c17 --- /dev/null +++ b/src/evdev-tablet.h @@ -0,0 +1,64 @@ +/* + * Copyright © 2014 Red Hat, Inc. + * Copyright © 2014 Stephen Chandler "Lyude" Paul + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the copyright holders not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. The copyright holders make + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +#ifndef EVDEV_TABLET_H +#define EVDEV_TABLET_H + +#include "evdev.h" + +enum tablet_status { + TABLET_NONE = 0, + TABLET_AXES_UPDATED = 1 << 0 +}; + +struct tablet_dispatch { + struct evdev_dispatch base; + struct evdev_device *device; + unsigned char status; + unsigned char changed_axes[NCHARS(LIBINPUT_TABLET_AXIS_CNT)]; + const struct input_absinfo *absinfo[LIBINPUT_TABLET_AXIS_CNT]; + double axes[LIBINPUT_TABLET_AXIS_CNT]; +}; + +static inline enum libinput_tablet_axis +evcode_to_axis(const uint32_t evcode) +{ + enum libinput_tablet_axis axis; + + switch (evcode) { + case ABS_X: + axis = LIBINPUT_TABLET_AXIS_X; + break; + case ABS_Y: + axis = LIBINPUT_TABLET_AXIS_Y; + break; + default: + axis = LIBINPUT_TABLET_AXIS_NONE; + break; + } + + return axis; +} + +#endif diff --git a/src/evdev.c b/src/evdev.c index 03f52e4..597977c 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -672,7 +672,15 @@ evdev_configure_device(struct evdev_device *device) device->dispatch = evdev_mt_touchpad_create(device); log_info("input device '%s', %s is a touchpad\n", device->devname, device->devnode); + } else if (!libevdev_has_event_code(device->evdev, EV_KEY, BTN_TOOL_FINGER) && + libevdev_has_event_code(device->evdev, EV_KEY, BTN_TOOL_PEN) && + has_abs) { + device->dispatch = evdev_tablet_create(device); + device->seat_caps |= EVDEV_DEVICE_TABLET; + log_info("input device '%s', %s is a tablet\n", + device->devname, device->devnode); } + for (i = KEY_ESC; i < KEY_MAX; i++) { if (i >= BTN_MISC && i < KEY_OK) continue; diff --git a/src/evdev.h b/src/evdev.h index bcb7e79..1164b7c 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -127,6 +127,9 @@ evdev_touchpad_create(struct evdev_device *device); struct evdev_dispatch * evdev_mt_touchpad_create(struct evdev_device *device); +struct evdev_dispatch * +evdev_tablet_create(struct evdev_device *device); + void evdev_device_proces_event(struct libinput_event *event); diff --git a/src/libinput-private.h b/src/libinput-private.h index f0bda1f..f6ba51c 100644 --- a/src/libinput-private.h +++ b/src/libinput-private.h @@ -195,6 +195,12 @@ touch_notify_touch_up(struct libinput_device *device, int32_t seat_slot); void +tablet_notify_axis(struct libinput_device *device, + uint32_t time, + unsigned char *changed_axes, + double *axes); + +void touch_notify_frame(struct libinput_device *device, uint32_t time); #endif /* LIBINPUT_PRIVATE_H */ diff --git a/src/libinput-util.h b/src/libinput-util.h index 4488fbf..a1d6616 100644 --- a/src/libinput-util.h +++ b/src/libinput-util.h @@ -76,6 +76,8 @@ int list_empty(const struct list *list); #define min(a, b) (((a) < (b)) ? (a) : (b)) #define max(a, b) (((a) > (b)) ? (a) : (b)) +#define NCHARS(x) ((size_t)(((x) + 7) / 8)) + #define LIBINPUT_EXPORT __attribute__ ((visibility("default"))) static inline void * diff --git a/src/libinput.c b/src/libinput.c index 5b10a10..fee500e 100644 --- a/src/libinput.c +++ b/src/libinput.c @@ -80,6 +80,13 @@ struct libinput_event_touch { double y; }; +struct libinput_event_tablet { + struct libinput_event base; + uint32_t time; + double *axes; + unsigned char changed_axes[NCHARS(LIBINPUT_TABLET_AXIS_CNT)]; +}; + static void libinput_default_log_func(enum libinput_log_priority priority, void *data, @@ -191,6 +198,7 @@ libinput_event_get_pointer_event(struct libinput_event *event) case LIBINPUT_EVENT_TOUCH_MOTION: case LIBINPUT_EVENT_TOUCH_CANCEL: case LIBINPUT_EVENT_TOUCH_FRAME: + case LIBINPUT_EVENT_TABLET_AXIS: break; } @@ -217,6 +225,7 @@ libinput_event_get_keyboard_event(struct libinput_event *event) case LIBINPUT_EVENT_TOUCH_MOTION: case LIBINPUT_EVENT_TOUCH_CANCEL: case LIBINPUT_EVENT_TOUCH_FRAME: + case LIBINPUT_EVENT_TABLET_AXIS: break; } @@ -243,6 +252,34 @@ libinput_event_get_touch_event(struct libinput_event *event) case LIBINPUT_EVENT_TOUCH_CANCEL: case LIBINPUT_EVENT_TOUCH_FRAME: return (struct libinput_event_touch *) event; + case LIBINPUT_EVENT_TABLET_AXIS: + break; + } + + return NULL; +} + +LIBINPUT_EXPORT struct libinput_event_tablet * +libinput_event_get_tablet_event(struct libinput_event *event) +{ + switch (event->type) { + case LIBINPUT_EVENT_NONE: + abort(); /* not used as actual event type */ + case LIBINPUT_EVENT_DEVICE_ADDED: + case LIBINPUT_EVENT_DEVICE_REMOVED: + case LIBINPUT_EVENT_KEYBOARD_KEY: + case LIBINPUT_EVENT_POINTER_MOTION: + case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE: + case LIBINPUT_EVENT_POINTER_BUTTON: + case LIBINPUT_EVENT_POINTER_AXIS: + case LIBINPUT_EVENT_TOUCH_DOWN: + case LIBINPUT_EVENT_TOUCH_UP: + case LIBINPUT_EVENT_TOUCH_MOTION: + case LIBINPUT_EVENT_TOUCH_CANCEL: + case LIBINPUT_EVENT_TOUCH_FRAME: + break; + case LIBINPUT_EVENT_TABLET_AXIS: + return (struct libinput_event_tablet *) event; } return NULL; @@ -267,6 +304,7 @@ libinput_event_get_device_notify_event(struct libinput_event *event) case LIBINPUT_EVENT_TOUCH_MOTION: case LIBINPUT_EVENT_TOUCH_CANCEL: case LIBINPUT_EVENT_TOUCH_FRAME: + case LIBINPUT_EVENT_TABLET_AXIS: break; } @@ -431,6 +469,51 @@ libinput_event_touch_get_y(struct libinput_event_touch *event) return event->y; } +LIBINPUT_EXPORT int +libinput_event_tablet_axis_has_changed(struct libinput_event_tablet *event, + enum libinput_tablet_axis axis) { + return (NCHARS(axis) <= sizeof(event->changed_axes)) ? + bit_is_set(event->changed_axes, axis) : 0; +} + +LIBINPUT_EXPORT double +libinput_event_tablet_get_axis_value(struct libinput_event_tablet *event, + enum libinput_tablet_axis axis) +{ + return (axis >= 0 && axis < LIBINPUT_TABLET_AXIS_CNT) ? + event->axes[axis] : 0; +} + +LIBINPUT_EXPORT double +libinput_event_tablet_get_x_transformed(struct libinput_event_tablet *event, + uint32_t width) +{ + struct evdev_device *device = + (struct evdev_device *) event->base.device; + + return evdev_device_transform_x(device, + event->axes[LIBINPUT_TABLET_AXIS_X], + width); +} + +LIBINPUT_EXPORT double +libinput_event_tablet_get_y_transformed(struct libinput_event_tablet *event, + uint32_t height) +{ + struct evdev_device *device = + (struct evdev_device *) event->base.device; + + return evdev_device_transform_y(device, + event->axes[LIBINPUT_TABLET_AXIS_Y], + height); +} + +LIBINPUT_EXPORT uint32_t +libinput_event_tablet_get_time(struct libinput_event_tablet *event) +{ + return event->time; +} + struct libinput_source * libinput_add_fd(struct libinput *libinput, int fd, @@ -1021,6 +1104,31 @@ touch_notify_frame(struct libinput_device *device, &touch_event->base); } +void +tablet_notify_axis(struct libinput_device *device, + uint32_t time, + unsigned char *changed_axes, + double *axes) +{ + struct libinput_event_tablet *axis_event; + + axis_event = zalloc(sizeof *axis_event); + if (!axis_event) + return; + + *axis_event = (struct libinput_event_tablet) { + .time = time, + .axes = axes, + }; + + memcpy(&axis_event->changed_axes, + changed_axes, + sizeof(axis_event->changed_axes)); + + post_device_event(device, + LIBINPUT_EVENT_TABLET_AXIS, + &axis_event->base); +} static void libinput_post_event(struct libinput *libinput, diff --git a/src/libinput.h b/src/libinput.h index d6f2588..18bb726 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -170,6 +170,19 @@ enum libinput_pointer_axis { }; /** + * @ingroup device + * + * Available axis types for a device. It must have the @ref + * LIBINPUT_DEVICE_CAP_TABLET capability. + */ +enum libinput_tablet_axis { + LIBINPUT_TABLET_AXIS_NONE = -1, + LIBINPUT_TABLET_AXIS_X = 0, + LIBINPUT_TABLET_AXIS_Y = 1, + LIBINPUT_TABLET_AXIS_CNT = LIBINPUT_TABLET_AXIS_Y + 1 +}; + +/** * @ingroup base * * Event type for events returned by libinput_get_event(). @@ -213,7 +226,9 @@ enum libinput_event_type { * Signals the end of a set of touchpoints at one device sample * time. This event has no coordinate information attached. */ - LIBINPUT_EVENT_TOUCH_FRAME + LIBINPUT_EVENT_TOUCH_FRAME, + + LIBINPUT_EVENT_TABLET_AXIS = 600 }; struct libinput; @@ -238,6 +253,15 @@ struct libinput_event_pointer; struct libinput_event_touch; /** + * @ingroup event_tablet + * @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. + */ +struct libinput_event_tablet; + +/** * @defgroup event Accessing and destruction of events */ @@ -330,6 +354,19 @@ libinput_event_get_touch_event(struct libinput_event *event); /** * @ingroup event * + * Return the tablet event that is this input event. If the event type does not + * match the tablet event types, this function returns NULL. + * + * The inverse of this function is libinput_event_tablet_get_base_event(). + * + * @return A touch event, or NULL for other events + */ +struct libinput_event_tablet * +libinput_event_get_tablet_event(struct libinput_event *event); + +/** + * @ingroup event + * * Return the device event that is this input event. If the event type does * not match the device event types, this function returns NULL. * @@ -756,6 +793,88 @@ struct libinput_event * libinput_event_touch_get_base_event(struct libinput_event_touch *event); /** + * @defgroup event_tablet Tablet events + * + * Events that come from tablet devices. + */ + +/** + * @ingroup event_tablet + * + * Checks if an axis was updated in this event or return 0 otherwise. + * For tablet events that are not of type LIBINPUT_EVENT_TABLET_AXIS, + * this function returns 0. + * + * @note It is an application bug to call this function for events other than + * LIBINPUT_EVENT_TABLET_AXIS. + * + * @param event The libinput tablet event + * @param axis The axis to check for updates + * @return 1 if the axis was updated or 0 otherwise + */ +int +libinput_event_tablet_axis_has_changed(struct libinput_event_tablet *event, + enum libinput_tablet_axis axis); + +/** + * @ingroup event_tablet + * + * Return the axis value of a given axis for a tablet. The interpretation of the + * value is dependent on the axis: + * - @ref LIBINPUT_TABLET_AXIS_X and @ref LIBINPUT_TABLET_AXIS_Y - the raw X and + * Y coordinates of the tablet tool. By default these are not transformed, + * however libinput provides libinput_event_tablet_get_x_transformed() and + * libinput_event_tablet_get_y_transformed() for transforming each respective + * axis value. + * + * For tablet events that are not of type @ref LIBINPUT_EVENT_TABLET_AXIS, this + * function returns 0. + * + * @param event The libinput tablet event + * @param axis The axis to retrieve the value of + * @return The current value of the the axis + */ +double +libinput_event_tablet_get_axis_value(struct libinput_event_tablet *event, + enum libinput_tablet_axis axis); + +/** + * @ingroup event_tablet + * + * Return the current absolute x coordinate of the tablet event, transformed to + * screen coordinates. + * + * @param event The libinput tablet event + * @param width The current output screen width + * @return the current absolute x coordinate transformed to a screen coordinate + */ +double +libinput_event_tablet_get_x_transformed(struct libinput_event_tablet *event, + uint32_t width); + +/** + * @ingroup event_tablet + * + * Return the current absolute y coordinate of the tablet event, transformed to + * screen coordinates. + * + * @param event The libinput tablet event + * @param height The current output screen height + * @return the current absolute y coordinate transformed to a screen coordinate + */ +double +libinput_event_tablet_get_y_transformed(struct libinput_event_tablet *event, + uint32_t height); +/** + * @ingroup event_tablet + * + * @param event The libinput tablet event + * @return The event time for this event + */ +uint32_t +libinput_event_tablet_get_time(struct libinput_event_tablet *event); + +/** * @defgroup base Initialization and manipulation of libinput contexts */ -- 1.8.5.5 _______________________________________________ wayland-devel mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/wayland-devel
