[PATCH libinput 02/23] evdev: Add basic support for tablet devices
Stephen Chandler Paul
thatslyude at gmail.com
Thu Jun 12 20:28:23 PDT 2014
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 <thatslyude at gmail.com>
---
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
More information about the wayland-devel
mailing list