Hi, On 06/13/2014 05:28 AM, Stephen Chandler Paul wrote: > 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);
This looks like this function is recursing into itself, it took me 3 times reading the code to see this is tablet_notify_axes vs tablet_notify_axis 1 letter difference in the name really is not enough, please rename one of the functions to make the name more unique. With that fixed this patch is: Reviewed-by: Hans de Goede <[email protected]> Regards, Hans > + 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 > */ > > _______________________________________________ wayland-devel mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/wayland-devel
