[RFC v2 libinput 1/2] Add a "buttonset" interface for button-only devices

Peter Hutterer peter.hutterer at who-t.net
Tue Mar 17 23:58:04 PDT 2015


A generic interface for devices that provide buttons and axes, but don't
control the pointer. This caters for the Pad part of Wacom graphics tablets
but could eventually also deal with remote controls, 3D mice and other
devices.

This patch adds a new interface "buttonset" with a new capability and two
events AXIS and BUTTON. The interface is largely modelled after the
tablet interface, but with different axes and a few different behaviors.
Notably, axes are numbered, with an axis type. The button events do the
obvious, axis events provide 5 hooks:

libinput_event_buttonset_get_axis_value() -> axis value in physical dimensions
libinput_event_buttonset_get_axis_value_transformed()
libinput_event_buttonset_get_axis_delta() -> axis delta in physical dimensions
libinput_event_buttonset_get_axis_delta_transformed()
libinput_event_buttonset_get_axis_delta_discrete() -> axis delta in clicks

The latter is similar after the scroll click counts.

Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
 src/evdev-mt-touchpad.c |   3 +
 src/evdev-tablet.c      |   3 +
 src/evdev.c             |  48 +++++++
 src/evdev.h             |  29 ++++
 src/libinput-private.h  |   1 +
 src/libinput.c          | 173 +++++++++++++++++++++++
 src/libinput.h          | 359 +++++++++++++++++++++++++++++++++++++++++++++++-
 src/libinput.sym        |  18 +++
 test/litest.c           |   6 +
 tools/event-debug.c     |  66 +++++++++
 tools/event-gui.c       |   2 +
 11 files changed, 706 insertions(+), 2 deletions(-)

diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c
index 1650a35..58520b8 100644
--- a/src/evdev-mt-touchpad.c
+++ b/src/evdev-mt-touchpad.c
@@ -899,6 +899,9 @@ static struct evdev_dispatch_interface tp_interface = {
 	tp_device_added,   /* device_resumed, treat as add */
 	tp_tag_device,
 	NULL,              /* post_added */
+	NULL,              /* buttonset_to_phys */
+	NULL,		   /* buttonset_get_num_axes */
+	NULL,		   /* buttonset_get_axis_type */
 };
 
 static void
diff --git a/src/evdev-tablet.c b/src/evdev-tablet.c
index 3e3924c..dc1c05b 100644
--- a/src/evdev-tablet.c
+++ b/src/evdev-tablet.c
@@ -1030,6 +1030,9 @@ static struct evdev_dispatch_interface tablet_interface = {
 	NULL, /* device_resumed */
 	NULL, /* tag_device */
 	tablet_check_initial_proximity,
+	NULL, /* buttonset_to_phys */
+	NULL, /* buttonset_get_num_axes */
+	NULL, /* buttonset_get_axis_type */
 };
 
 static int
diff --git a/src/evdev.c b/src/evdev.c
index 0c85230..4beacaa 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -234,6 +234,16 @@ normalize_delta(struct evdev_device *device,
 	normalized->y = delta->y * (double)device->dpi / DEFAULT_MOUSE_DPI;
 }
 
+double
+evdev_device_buttonset_transform_to_phys(struct evdev_device *device,
+					 unsigned int axis,
+					 double value)
+{
+	struct evdev_dispatch *dispatch = device->dispatch;
+
+	return dispatch->interface->buttonset_to_phys(device, axis, value);
+}
+
 static void
 evdev_flush_pending_event(struct evdev_device *device, uint64_t time)
 {
@@ -814,6 +824,9 @@ struct evdev_dispatch_interface fallback_interface = {
 	NULL, /* device_resumed */
 	fallback_tag_device,
 	NULL, /* post_added */
+	NULL, /* buttonset_to_phys */
+	NULL, /* buttonset_get_num_axes */
+	NULL, /* buttonset_get_axis_type */
 };
 
 static uint32_t
@@ -1978,6 +1991,8 @@ evdev_device_has_capability(struct evdev_device *device,
 		return !!(device->seat_caps & EVDEV_DEVICE_TOUCH);
 	case LIBINPUT_DEVICE_CAP_TABLET:
 		return !!(device->seat_caps & EVDEV_DEVICE_TABLET);
+	case LIBINPUT_DEVICE_CAP_BUTTONSET:
+		return !!(device->seat_caps & EVDEV_DEVICE_BUTTONSET);
 	default:
 		return 0;
 	}
@@ -2012,6 +2027,39 @@ evdev_device_has_button(struct evdev_device *device, uint32_t code)
 	return libevdev_has_event_code(device->evdev, EV_KEY, code);
 }
 
+int
+evdev_device_buttonset_has_button(struct evdev_device *device,
+				  uint32_t code)
+{
+	if (!(device->seat_caps & EVDEV_DEVICE_BUTTONSET))
+		return -1;
+
+	return libevdev_has_event_code(device->evdev, EV_KEY, code);
+}
+
+unsigned int
+evdev_device_buttonset_get_num_axes(struct evdev_device *device)
+{
+	struct evdev_dispatch *dispatch = device->dispatch;
+
+	if (!(device->seat_caps & EVDEV_DEVICE_BUTTONSET))
+		return 0;
+
+	return dispatch->interface->buttonset_get_num_axes(device);
+}
+
+enum libinput_buttonset_axis_type
+evdev_device_buttonset_get_axis_type(struct evdev_device *device,
+				     unsigned int axis)
+{
+	struct evdev_dispatch *dispatch = device->dispatch;
+
+	if (!(device->seat_caps & EVDEV_DEVICE_BUTTONSET))
+		return LIBINPUT_BUTTONSET_AXIS_NONE;
+
+	return dispatch->interface->buttonset_get_axis_type(device, axis);
+}
+
 static inline bool
 evdev_is_scrolling(const struct evdev_device *device,
 		   enum libinput_pointer_axis axis)
diff --git a/src/evdev.h b/src/evdev.h
index c49186b..a8d2d38 100644
--- a/src/evdev.h
+++ b/src/evdev.h
@@ -55,6 +55,7 @@ enum evdev_device_seat_capability {
 	EVDEV_DEVICE_KEYBOARD = (1 << 1),
 	EVDEV_DEVICE_TOUCH = (1 << 2),
 	EVDEV_DEVICE_TABLET = (1 << 3),
+	EVDEV_DEVICE_BUTTONSET = (1 << 4),
 };
 
 enum evdev_device_tags {
@@ -204,6 +205,19 @@ struct evdev_dispatch_interface {
 	 * was sent */
 	void (*post_added)(struct evdev_device *device,
 			   struct evdev_dispatch *dispatch);
+
+        /* Transform axis value to physical dimension */
+	double (*buttonset_to_phys)(struct evdev_device *device,
+				    unsigned int axis,
+				    double value);
+
+	/* Return the number of axes on the buttonset device */
+	unsigned int (*buttonset_get_num_axes)(struct evdev_device *device);
+
+	/* Return the axis type of the given axes on the buttonset device */
+	enum libinput_buttonset_axis_type (*buttonset_get_axis_type)(
+					     struct evdev_device *device,
+					     unsigned int axis);
 };
 
 struct evdev_dispatch {
@@ -283,6 +297,16 @@ evdev_device_get_size(struct evdev_device *device,
 int
 evdev_device_has_button(struct evdev_device *device, uint32_t code);
 
+int
+evdev_device_buttonset_has_button(struct evdev_device *device,
+				  uint32_t code);
+
+enum libinput_buttonset_axis_type
+evdev_device_buttonset_get_axis_type(struct evdev_device *device,
+				     unsigned int axis);
+unsigned int
+evdev_device_buttonset_get_num_axes(struct evdev_device *device);
+
 double
 evdev_device_transform_x(struct evdev_device *device,
 			 double x,
@@ -292,6 +316,11 @@ double
 evdev_device_transform_y(struct evdev_device *device,
 			 double y,
 			 uint32_t height);
+double
+evdev_device_buttonset_transform_to_phys(struct evdev_device *device,
+					 unsigned int axis,
+					 double value);
+
 int
 evdev_device_suspend(struct evdev_device *device);
 
diff --git a/src/libinput-private.h b/src/libinput-private.h
index d1da276..5ce8fdd 100644
--- a/src/libinput-private.h
+++ b/src/libinput-private.h
@@ -31,6 +31,7 @@
 #include "libinput-util.h"
 
 #define LIBINPUT_TABLET_AXIS_MAX LIBINPUT_TABLET_AXIS_REL_WHEEL
+#define LIBINPUT_BUTTONSET_MAX_NUM_AXES 32
 
 struct libinput_source;
 
diff --git a/src/libinput.c b/src/libinput.c
index 144e950..d52ca0d 100644
--- a/src/libinput.c
+++ b/src/libinput.c
@@ -126,6 +126,19 @@ struct libinput_event_tablet {
 	enum libinput_tool_proximity_state proximity_state;
 };
 
+struct libinput_event_buttonset {
+	struct libinput_event base;
+	uint32_t button;
+	enum libinput_button_state state;
+	uint32_t seat_button_count;
+	uint32_t time;
+	double axes[LIBINPUT_BUTTONSET_MAX_NUM_AXES];
+	double deltas[LIBINPUT_BUTTONSET_MAX_NUM_AXES];
+	double deltas_discrete[LIBINPUT_BUTTONSET_MAX_NUM_AXES];
+	unsigned char changed_axes[NCHARS(LIBINPUT_BUTTONSET_MAX_NUM_AXES)];
+	enum libinput_buttonset_axis_source source;
+};
+
 static void
 libinput_default_log_func(struct libinput *libinput,
 			  enum libinput_log_priority priority,
@@ -272,6 +285,18 @@ libinput_event_get_device_notify_event(struct libinput_event *event)
 	return (struct libinput_event_device_notify *) event;
 }
 
+LIBINPUT_EXPORT struct libinput_event_buttonset *
+libinput_event_get_buttonset_event(struct libinput_event *event)
+{
+	require_event_type(libinput_event_get_context(event),
+			   event->type,
+			   NULL,
+			   LIBINPUT_EVENT_BUTTONSET_AXIS,
+			   LIBINPUT_EVENT_BUTTONSET_BUTTON);
+
+	return (struct libinput_event_buttonset *) event;
+}
+
 LIBINPUT_EXPORT uint32_t
 libinput_event_keyboard_get_time(struct libinput_event_keyboard *event)
 {
@@ -890,6 +915,132 @@ libinput_tool_unref(struct libinput_tool *tool)
 	return NULL;
 }
 
+LIBINPUT_EXPORT uint32_t
+libinput_event_buttonset_get_time(struct libinput_event_buttonset *event)
+{
+	return event->time;
+}
+
+LIBINPUT_EXPORT uint32_t
+libinput_event_buttonset_get_button(struct libinput_event_buttonset *event)
+{
+	return event->button;
+}
+
+LIBINPUT_EXPORT enum libinput_button_state
+libinput_event_buttonset_get_button_state(struct libinput_event_buttonset *event)
+{
+	return event->state;
+}
+
+LIBINPUT_EXPORT uint32_t
+libinput_event_buttonset_get_seat_button_count(struct libinput_event_buttonset *event)
+{
+	return event->seat_button_count;
+}
+
+LIBINPUT_EXPORT int
+libinput_event_buttonset_axis_has_changed(struct libinput_event_buttonset *event,
+					  unsigned int axis)
+{
+	return (NCHARS(axis) <= sizeof(event->changed_axes)) ?
+		bit_is_set(event->changed_axes, axis) : 0;
+}
+
+LIBINPUT_EXPORT double
+libinput_event_buttonset_get_axis_value(struct libinput_event_buttonset *event,
+					unsigned int axis)
+{
+	struct evdev_device *device =
+		(struct evdev_device *) event->base.device;
+
+	if (event->base.type != LIBINPUT_EVENT_BUTTONSET_AXIS)
+		return 0;
+
+	if (axis >= ARRAY_LENGTH(event->axes))
+		return 0;
+
+	return evdev_device_buttonset_transform_to_phys(device,
+							axis,
+							event->axes[axis]);
+}
+
+LIBINPUT_EXPORT double
+libinput_event_buttonset_get_axis_value_transformed(struct libinput_event_buttonset *event,
+						    unsigned int axis,
+						    uint32_t max)
+{
+	if (event->base.type != LIBINPUT_EVENT_BUTTONSET_AXIS)
+		return 0;
+
+	if (axis >= ARRAY_LENGTH(event->axes))
+		return 0;
+
+	return event->axes[axis] * max;
+}
+
+LIBINPUT_EXPORT double
+libinput_event_buttonset_get_axis_delta(struct libinput_event_buttonset *event,
+					unsigned int axis)
+{
+	struct evdev_device *device =
+		(struct evdev_device *) event->base.device;
+
+	if (event->base.type != LIBINPUT_EVENT_BUTTONSET_AXIS)
+		return 0;
+
+	if (axis >= ARRAY_LENGTH(event->deltas))
+		return 0;
+
+	return evdev_device_buttonset_transform_to_phys(device,
+							axis,
+							event->deltas[axis]);
+}
+
+LIBINPUT_EXPORT double
+libinput_event_buttonset_get_axis_delta_transformed(struct libinput_event_buttonset *event,
+						    unsigned int axis,
+						    uint32_t max)
+{
+	struct evdev_device *device =
+		(struct evdev_device *) event->base.device;
+
+	if (event->base.type != LIBINPUT_EVENT_BUTTONSET_AXIS)
+		return 0;
+
+	if (axis >= ARRAY_LENGTH(event->deltas))
+		return 0;
+
+	/* FIXME */
+	return 0;
+}
+
+LIBINPUT_EXPORT double
+libinput_event_buttonset_get_axis_delta_discrete(struct libinput_event_buttonset *event,
+						 unsigned int axis)
+{
+	if (event->base.type != LIBINPUT_EVENT_BUTTONSET_AXIS)
+		return 0;
+
+	if (axis >= ARRAY_LENGTH(event->deltas))
+		return 0;
+
+	return event->deltas_discrete[axis];
+}
+
+LIBINPUT_EXPORT enum libinput_buttonset_axis_source
+libinput_event_buttonset_get_axis_source(struct libinput_event_buttonset *event,
+					 unsigned int axis)
+{
+	if (event->base.type != LIBINPUT_EVENT_BUTTONSET_AXIS)
+		return 0;
+
+	if (axis >= ARRAY_LENGTH(event->axes))
+		return 0;
+
+	return event->source;
+}
+
 struct libinput_source *
 libinput_add_fd(struct libinput *libinput,
 		int fd,
@@ -1855,6 +2006,28 @@ libinput_device_pointer_has_button(struct libinput_device *device, uint32_t code
 	return evdev_device_has_button((struct evdev_device *)device, code);
 }
 
+LIBINPUT_EXPORT int
+libinput_device_buttonset_has_button(struct libinput_device *device, uint32_t code)
+{
+	return evdev_device_has_button((struct evdev_device *)device, code);
+}
+
+LIBINPUT_EXPORT enum libinput_buttonset_axis_type
+libinput_device_buttonset_get_axis_type(struct libinput_device *device,
+					unsigned int axis)
+{
+	return evdev_device_buttonset_get_axis_type(
+					    (struct evdev_device *)device,
+					    axis);
+}
+
+LIBINPUT_EXPORT unsigned int
+libinput_device_buttonset_get_num_axes(struct libinput_device *device)
+{
+	return evdev_device_buttonset_get_num_axes(
+					   (struct evdev_device *)device);
+}
+
 LIBINPUT_EXPORT struct libinput_event *
 libinput_event_device_notify_get_base_event(struct libinput_event_device_notify *event)
 {
diff --git a/src/libinput.h b/src/libinput.h
index a795e3f..70e67c2 100644
--- a/src/libinput.h
+++ b/src/libinput.h
@@ -54,7 +54,8 @@ enum libinput_device_capability {
 	LIBINPUT_DEVICE_CAP_KEYBOARD = 0,
 	LIBINPUT_DEVICE_CAP_POINTER = 1,
 	LIBINPUT_DEVICE_CAP_TOUCH = 2,
-	LIBINPUT_DEVICE_CAP_TABLET = 3
+	LIBINPUT_DEVICE_CAP_TABLET = 3,
+	LIBINPUT_DEVICE_CAP_BUTTONSET = 4
 };
 
 /**
@@ -150,6 +151,43 @@ enum libinput_tablet_axis {
 /**
  * @ingroup device
  *
+ * Available axis types for a buttonset device. It must have the @ref
+ * LIBINPUT_DEVICE_CAP_BUTTONSET capability. A device may have more than one
+ * axis of the same type, e.g. a Wacom Cintiq 24HD has two ring axes.
+ */
+enum libinput_buttonset_axis_type {
+	LIBINPUT_BUTTONSET_AXIS_NONE,
+	LIBINPUT_BUTTONSET_AXIS_X,
+	LIBINPUT_BUTTONSET_AXIS_Y,
+	LIBINPUT_BUTTONSET_AXIS_Z,
+	LIBINPUT_BUTTONSET_AXIS_REL_X,
+	LIBINPUT_BUTTONSET_AXIS_REL_Y,
+	LIBINPUT_BUTTONSET_AXIS_REL_Z,
+	LIBINPUT_BUTTONSET_AXIS_ROTATION_X,
+	LIBINPUT_BUTTONSET_AXIS_ROTATION_Y,
+	LIBINPUT_BUTTONSET_AXIS_ROTATION_Z,
+	LIBINPUT_BUTTONSET_AXIS_RING,
+	LIBINPUT_BUTTONSET_AXIS_STRIP,
+};
+
+/**
+ * @ingroup device
+ *
+ * The source for a libinput_buttonset_axis event. See
+ * libinput_event_buttonset_get_axis_source() for details.
+ */
+enum libinput_buttonset_axis_source {
+	LIBINPUT_BUTTONSET_AXIS_SOURCE_UNKNOWN = 1,
+	/**
+	 * The event is caused by the movement of one or more fingers on a
+	 * device.
+	 */
+	LIBINPUT_BUTTONSET_AXIS_SOURCE_FINGER,
+};
+
+/**
+ * @ingroup device
+ *
  * An object representing a tool being used by the device. It must have the @ref
  * LIBINPUT_DEVICE_CAP_TABLET capability.
  */
@@ -269,7 +307,10 @@ enum libinput_event_type {
 	 * initial proximity out event.
 	 */
 	LIBINPUT_EVENT_TABLET_PROXIMITY,
-	LIBINPUT_EVENT_TABLET_BUTTON
+	LIBINPUT_EVENT_TABLET_BUTTON,
+
+	LIBINPUT_EVENT_BUTTONSET_AXIS = 700,
+	LIBINPUT_EVENT_BUTTONSET_BUTTON,
 };
 
 /**
@@ -369,6 +410,16 @@ struct libinput_event_touch;
 struct libinput_event_tablet;
 
 /**
+ * @ingroup event_buttonset
+ * @struct libinput_event_buttonset
+ *
+ * Event representing a button press/release or axis update on a buttonset
+ * device. Valid event types for this event are @ref
+ * LIBINPUT_EVENT_BUTTONSET_AXIS and @ref LIBINPUT_EVENT_BUTTONSET_BUTTON.
+ */
+struct libinput_event_buttonset;
+
+/**
  * @defgroup event Accessing and destruction of events
  */
 
@@ -493,6 +544,19 @@ libinput_event_get_device_notify_event(struct libinput_event *event);
 /**
  * @ingroup event
  *
+ * Return the buttonset event that is this input event. If the event type
+ * does not match the buttonset event types, this function returns NULL.
+ *
+ * The inverse of this function is libinput_event_buttonset_get_base_event().
+ *
+ * @return A buttonset event, or NULL for other events
+ */
+struct libinput_event_buttonset *
+libinput_event_get_buttonset_event(struct libinput_event *event);
+
+/**
+ * @ingroup event
+ *
  * @return The generic libinput_event of this event
  */
 struct libinput_event *
@@ -1394,6 +1458,236 @@ libinput_tool_set_user_data(struct libinput_tool *tool,
 			    void *user_data);
 
 /**
+ * @defgroup event_buttonset Events from button devices
+ *
+ * Events that come from button devices. Such devices provide one or more
+ * custom buttons (other than left, middle, right) and usually do not
+ * control the pointer. Axes other than x/y axes may be present on the
+ * device.
+ */
+
+/**
+ * @ingroup event_buttonset
+ *
+ * @return The event time for this event
+ */
+uint32_t
+libinput_event_buttonset_get_time(struct libinput_event_buttonset *event);
+
+/**
+ * @ingroup event_buttonset
+ *
+ * Checks if an axis was updated in this event or return 0 otherwise.
+ * For buttonset events that are not of type @ref LIBINPUT_EVENT_BUTTONSET_AXIS,
+ * this function returns 0.
+ *
+ * @note It is an application bug to call this function for events other than
+ * @ref LIBINPUT_EVENT_BUTTONSET_AXIS.
+ *
+ * @param event The libinput buttonset event
+ * @param axis The axis to check for updates
+ * @return 1 if the axis was updated or 0 otherwise
+ */
+int
+libinput_event_buttonset_axis_has_changed(struct libinput_event_buttonset *event,
+					  unsigned int axis);
+
+/**
+ * @ingroup event_buttonset
+ *
+ * Return the axis value of a given axis for a buttonset. The interpretation
+ * of the value is dependent on the axis:
+ * - @ref LIBINPUT_BUTTONSET_AXIS_X, @ref LIBINPUT_BUTTONSET_AXIS_Y, @ref
+ *   LIBINPUT_BUTTONSET_AXIS_Z - the current value, in mm, of the x, y, or
+ *   z axis on this device in it's current logical rotation.
+ * - @ref LIBINPUT_BUTTONSET_AXIS_REL_X, @ref LIBINPUT_BUTTONSET_AXIS_REL_Y,
+ *   @ref LIBINPUT_BUTTONSET_AXIS_REL_Z - always returns zero. Use
+ *   libinput_event_buttonset_get_axis_delta() instead.
+ * - @ref LIBINPUT_BUTTONSET_AXIS_ROTATION_X, @ref
+ *   LIBINPUT_BUTTONSET_AXIS_ROTATION_Y, @ref
+ *   LIBINPUT_BUTTONSET_AXIS_ROTATION_Z - the device's rotation in degrees.
+ *   z axis on this device in it's current logical rotation.
+ * - @ref LIBINPUT_BUTTONSET_AXIS_RING - the absolute value of a ring,
+ *   in degrees clockwise, 0 is the ring's northernmost point in the
+ *   device's current logical rotation.
+ *   If the axis source is @ref LIBINPUT_BUTTONSET_AXIS_SOURCE_FINGER,
+ *   libinput will send an event with a value of -1 when the finger is
+ *   lifted.
+ * - @ref LIBINPUT_BUTTONSET_AXIS_STRIP - normalized to a range [0, 1]
+ *   where 0 is the strips top/left-most point in the device's current
+ *   logical rotation.
+ *   If the axis source is @ref LIBINPUT_BUTTONSET_AXIS_SOURCE_FINGER,
+ *   libinput will send an event with a value of -1 when the finger is
+ *   lifted.
+ *
+ * @note This function may be called for a specific axis even if
+ * libinput_event_buttonset_axis_has_changed() returns 0 for that axis.
+ * libinput always includes all device axes in the event.
+ *
+ * @param event The libinput buttonset event
+ * @param axis The axis to retrieve the value of
+ * @return The current value of the the axis
+ * @retval -1 The finger was lifted from a ring or strip axis.
+ */
+double
+libinput_event_buttonset_get_axis_value(struct libinput_event_buttonset *event,
+					unsigned int axis);
+
+/**
+ * @ingroup event_buttonset
+ *
+ * Return the axis value of the given axis, transformed into the range
+ * [0, max].
+ *
+ * For a detailed explanation of the value, see
+ * libinput_event_buttonset_get_axis_value().
+ *
+ * @param event The libinput buttonset event
+ * @param axis The axis to retrieve the value of
+ * @param max The upper value of the range to convert to (inclusive)
+ * @return The current value of the the axis, transformed into [0, max]
+ */
+double
+libinput_event_buttonset_get_axis_value_transformed(struct libinput_event_buttonset *event,
+						    unsigned int axis,
+						    uint32_t max);
+/**
+ * @ingroup event_buttonset
+ *
+ * Return the axis delta of a given axis for a buttonset in physical
+ * dimensions, relative to the previous event. The interpretation
+ * of the value is dependent on the axis:
+ * - @ref LIBINPUT_BUTTONSET_AXIS_REL_X, @ref LIBINPUT_BUTTONSET_AXIS_REL_Y,
+ *   @ref LIBINPUT_BUTTONSET_AXIS_REL_Z - relative movement, normalized to
+ *   that of a 1000dpi mouse.
+ * For all other axes, see libinput_event_buttonset_get_axis_value() for
+ * details on the various axes.
+ *
+ * @param event The libinput buttonset event
+ * @param axis The axis to retrieve the value of
+ * @return The axis delta to the last last event in discrete steps
+ */
+double
+libinput_event_buttonset_get_axis_delta(struct libinput_event_buttonset *event,
+				        unsigned int axis);
+
+/**
+ * @ingroup event_buttonset
+ *
+ * Return the axis delta of a given axis for a buttonset, transformed into
+ * the range [0, max]. The interpretation * of the value is dependent on the
+ * axis:
+ * - @ref LIBINPUT_BUTTONSET_AXIS_REL_X, @ref LIBINPUT_BUTTONSET_AXIS_REL_Y,
+ *   @ref LIBINPUT_BUTTONSET_AXIS_REL_Z - the return value is always 0
+ *
+ * For all other axes, see libinput_event_buttonset_get_axis_value() for
+ * details on the various axes.
+ *
+ * @param event The libinput buttonset event
+ * @param axis The axis to retrieve the value of
+ * @param max The upper value of the range to convert to (inclusive)
+ * @return The axis delta to the last last event, transformed into [0, max]
+ */
+double
+libinput_event_buttonset_get_axis_delta_transformed(
+				    struct libinput_event_buttonset *event,
+				    unsigned int axis,
+				    uint32_t max);
+/**
+ * @ingroup event_buttonset
+ * Return the axis delta of a given axis for a buttonset in discrete steps,
+ * relative to the previous event.
+ * How an axis value translates into a discrete steps depends on the device.
+ *
+ * @param event The libinput buttonset event
+ * @param axis The axis to retrieve the value of
+ * @return The axis delta to the last last event in discrete steps
+ */
+double
+libinput_event_buttonset_get_axis_delta_discrete(struct libinput_event_buttonset *event,
+						 unsigned int axis);
+
+/**
+ * @ingroup event_buttonset
+ *
+ * Return the source for a given buttonset axis.
+ *
+ * If the source is @ref LIBINPUT_BUTTONSET_AXIS_SOURCE_FINGER, libinput
+ * guarantees that a sequence is terminated with an out-of-range value (see
+ * libinput_event_buttonset_get_axis_value() for details).
+ * A caller may use this information to decide on whether kinetic motion
+ * should be triggered on this event sequence.
+ *
+ * If the source is @ref LIBINPUT_BUTTONSET_AXIS_SOURCE_UNKNOWN, libinput
+ * does not send a terminating value to indicate release.
+ *
+ * For buttonset events that are not of type @ref LIBINPUT_EVENT_BUTTONSET_AXIS,
+ * this function returns 0. For axes not present in this event, this
+ * function returns 0.
+ *
+ * @note It is an application bug to call this function for events other than
+ * @ref LIBINPUT_EVENT_BUTTONSET_AXIS or for axes not present in this event.
+ *
+ * @return the source for this buttonset axis event
+ */
+enum libinput_buttonset_axis_source
+libinput_event_buttonset_get_axis_source(struct libinput_event_buttonset *event,
+					 unsigned int axis);
+
+/**
+ * @ingroup event_buttonset
+ *
+ * Return the button that triggered this event.
+ * For buttonset events that are not of type @ref LIBINPUT_EVENT_BUTTONSET_BUTTON, this
+ * function returns 0.
+ *
+ * @note It is an application bug to call this function for events other than
+ * @ref LIBINPUT_EVENT_BUTTONSET_BUTTON.
+ *
+ * @param event The libinput buttonset event
+ * @return the button triggering this event
+ */
+uint32_t
+libinput_event_buttonset_get_button(struct libinput_event_buttonset *event);
+
+/**
+ * @ingroup event_buttonset
+ *
+ * Return the button state of the event.
+ *
+ * @note It is an application bug to call this function for events other than
+ * @ref LIBINPUT_EVENT_BUTTONSET_BUTTON.
+ *
+ * @param event The libinput buttonset event
+ * @return the button state triggering this event
+ */
+enum libinput_button_state
+libinput_event_buttonset_get_button_state(struct libinput_event_buttonset *event);
+
+/**
+ * @ingroup event_buttonset
+ *
+ * For the button of a @ref LIBINPUT_EVENT_BUTTONSET_BUTTON event, return the total
+ * number of buttons pressed on all devices on the associated seat after the
+ * the event was triggered.
+ *
+ " @note It is an application bug to call this function for events other than
+ * @ref LIBINPUT_EVENT_BUTTONSET_BUTTON. For other events, this function returns 0.
+ *
+ * @return the seat wide pressed button count for the key of this event
+ */
+uint32_t
+libinput_event_buttonset_get_seat_button_count(struct libinput_event_buttonset *event);
+
+/**
+ * @ingroup event_buttonset
+ *
+ * @return The generic libinput_event of this event
+ */
+struct libinput_event *
+libinput_event_buttonset_get_base_event(struct libinput_event_buttonset *event);
+
+/**
  * @defgroup base Initialization and manipulation of libinput contexts
  */
 
@@ -2186,6 +2480,67 @@ libinput_device_pointer_has_button(struct libinput_device *device, uint32_t code
 /**
  * @ingroup device
  *
+ * Check if a @ref LIBINPUT_DEVICE_CAP_BUTTONSET device has a button with
+ * the passed in code (see linux/input.h).
+ *
+ * @param device A current input device
+ * @param code button code to check for
+ *
+ * @return 1 if the device supports this button code, 0 if it does not, -1
+ * on error.
+ */
+int
+libinput_device_buttonset_has_button(struct libinput_device *device,
+				     uint32_t code);
+
+/**
+ * @ingroup device
+ *
+ * Return the number of axes on this @ref LIBINPUT_DEVICE_CAP_BUTTONSET
+ * device.
+ *
+ * If the device does not have the @ref LIBINPUT_DEVICE_CAP_BUTTONSET
+ * capability, this function returns zero.
+ *
+ * @note It is an application bug to call this function on a device
+ * without the @ref LIBINPUT_DEVICE_CAP_BUTTONSET capability.
+ *
+ * @param device A current input device
+ *
+ * @return The number of axes on this device or zero.
+ */
+unsigned int
+libinput_device_buttonset_get_num_axes(struct libinput_device *device);
+
+/**
+ * @ingroup device
+ *
+ * Return the axis type for the given axis on this @ref
+ * LIBINPUT_DEVICE_CAP_BUTTONSET device.
+ *
+ * If the device does not have the @ref LIBINPUT_DEVICE_CAP_BUTTONSET
+ * capability or the axis does not exist on this device, this function
+ * returns zero.
+ *
+ * @note It is an application bug to call this function on a device
+ * without the @ref LIBINPUT_DEVICE_CAP_BUTTONSET capability or for an axis
+ * that does not exist.
+ *
+ * @param device A current input device
+ * @param axis The axis to retrieve the type of
+ *
+ * @return The axis type for the given axis or
+ * @ref LIBINPUT_BUTTONSET_AXIS_NONE if the axis does not exist
+ *
+ * @see libinput_device_buttonset_get_num_axes
+ */
+enum libinput_buttonset_axis_type
+libinput_device_buttonset_get_axis_type(struct libinput_device *device,
+					unsigned int axis);
+
+/**
+ * @ingroup device
+ *
  * Increase the refcount of the device group. A device group will be freed
  * whenever the refcount reaches 0. This may happen during
  * libinput_dispatch() if all devices of this group were removed from the
diff --git a/src/libinput.sym b/src/libinput.sym
index deab3c2..287976e 100644
--- a/src/libinput.sym
+++ b/src/libinput.sym
@@ -155,3 +155,21 @@ LIBINPUT_TABLET_SUPPORT {
 	libinput_tool_set_user_data;
 	libinput_tool_unref;
 } LIBINPUT_0.12.0;
+
+BUTTONSET_INTERFACE {
+	libinput_device_buttonset_has_button;
+	libinput_device_buttonset_get_axis_type;
+	libinput_device_buttonset_get_num_axes;
+	libinput_event_buttonset_get_axis_delta;
+	libinput_event_buttonset_get_axis_delta_discrete;
+	libinput_event_buttonset_get_axis_delta_transformed;
+	libinput_event_buttonset_get_axis_source;
+	libinput_event_buttonset_get_axis_value;
+	libinput_event_buttonset_get_axis_value_transformed;
+	libinput_event_buttonset_get_button;
+	libinput_event_buttonset_get_button_state;
+	libinput_event_buttonset_get_seat_button_count;
+	libinput_event_buttonset_get_time;
+	libinput_event_buttonset_axis_has_changed;
+	libinput_event_get_buttonset_event;
+} LIBINPUT_TABLET_SUPPORT;
diff --git a/test/litest.c b/test/litest.c
index 9ac7d3c..21306ac 100644
--- a/test/litest.c
+++ b/test/litest.c
@@ -1203,6 +1203,12 @@ litest_event_type_str(struct libinput_event *event)
 	case LIBINPUT_EVENT_TABLET_BUTTON:
 		str = "TABLET BUTTON";
 		break;
+	case LIBINPUT_EVENT_BUTTONSET_AXIS:
+		str = "BUTTONSET AXIS";
+		break;
+	case LIBINPUT_EVENT_BUTTONSET_BUTTON:
+		str = "BUTTONSET BUTTON";
+		break;
 	}
 	return str;
 }
diff --git a/tools/event-debug.c b/tools/event-debug.c
index d2ac415..d055cf9 100644
--- a/tools/event-debug.c
+++ b/tools/event-debug.c
@@ -115,6 +115,12 @@ print_event_header(struct libinput_event *ev)
 	case LIBINPUT_EVENT_TABLET_BUTTON:
 		type = "TABLET_BUTTON";
 		break;
+	case LIBINPUT_EVENT_BUTTONSET_AXIS:
+		type = "BUTTONSET_AXIS";
+		break;
+	case LIBINPUT_EVENT_BUTTONSET_BUTTON:
+		type = "BUTTONSET_BUTTON";
+		break;
 	}
 
 	printf("%-7s	%-16s ", libinput_device_get_sysname(dev), type);
@@ -163,6 +169,9 @@ print_device_notify(struct libinput_event *ev)
 	if (libinput_device_has_capability(dev,
 					   LIBINPUT_DEVICE_CAP_TABLET))
 		printf("T");
+	if (libinput_device_has_capability(dev,
+					   LIBINPUT_DEVICE_CAP_BUTTONSET))
+		printf("b");
 
 	if (libinput_device_get_size(dev, &w, &h) == 0)
 		printf("\tsize %.2f/%.2fmm", w, h);
@@ -269,6 +278,57 @@ print_tablet_button_event(struct libinput_event *ev)
 }
 
 static void
+print_buttonset_button_event(struct libinput_event *ev)
+{
+	struct libinput_event_buttonset *b = libinput_event_get_buttonset_event(ev);
+	enum libinput_button_state state;
+
+	print_event_time(libinput_event_buttonset_get_time(b));
+
+	state = libinput_event_buttonset_get_button_state(b);
+	printf("%3d %s, seat count: %u\n",
+	       libinput_event_buttonset_get_button(b),
+	       state == LIBINPUT_BUTTON_STATE_PRESSED ? "pressed" : "released",
+	       libinput_event_buttonset_get_seat_button_count(b));
+}
+
+static void
+print_buttonset_axis_event(struct libinput_event *ev)
+{
+	struct libinput_event_buttonset *b = libinput_event_get_buttonset_event(ev);
+	const char *axis_name;
+	double val, delta;
+	unsigned int axis;
+	struct libinput_device *device = libinput_event_get_device(ev);
+
+	print_event_time(libinput_event_buttonset_get_time(b));
+
+	for (axis = 0;
+	     axis < libinput_device_buttonset_get_num_axes(device);
+	     axis++) {
+		if (!libinput_event_buttonset_axis_has_changed(b, axis))
+			continue;
+
+		val = libinput_event_buttonset_get_axis_value(b, axis);
+		delta = libinput_event_buttonset_get_axis_delta(b, axis);
+		switch(libinput_device_buttonset_get_axis_type(device, axis)) {
+		case LIBINPUT_BUTTONSET_AXIS_RING:
+			axis_name = "ring";
+			break;
+		case LIBINPUT_BUTTONSET_AXIS_STRIP:
+			axis_name = "strip";
+			break;
+		default:
+			axis_name = "UNKNOWN";
+			break;
+		}
+		printf("\t%s: %.2f (%+.2f)", axis_name, val, delta);
+	}
+
+	printf("\n");
+}
+
+static void
 print_pointer_axis_event(struct libinput_event *ev)
 {
 	struct libinput_event_pointer *p = libinput_event_get_pointer_event(ev);
@@ -578,6 +638,12 @@ handle_and_print_events(struct libinput *li)
 		case LIBINPUT_EVENT_TABLET_BUTTON:
 			print_tablet_button_event(ev);
 			break;
+		case LIBINPUT_EVENT_BUTTONSET_BUTTON:
+			print_buttonset_button_event(ev);
+			break;
+		case LIBINPUT_EVENT_BUTTONSET_AXIS:
+			print_buttonset_axis_event(ev);
+			break;
 		}
 
 		libinput_event_destroy(ev);
diff --git a/tools/event-gui.c b/tools/event-gui.c
index f544b6f..9b66db6 100644
--- a/tools/event-gui.c
+++ b/tools/event-gui.c
@@ -472,6 +472,8 @@ handle_event_libinput(GIOChannel *source, GIOCondition condition, gpointer data)
 		case LIBINPUT_EVENT_TABLET_AXIS:
 		case LIBINPUT_EVENT_TABLET_PROXIMITY:
 		case LIBINPUT_EVENT_TABLET_BUTTON:
+		case LIBINPUT_EVENT_BUTTONSET_AXIS:
+		case LIBINPUT_EVENT_BUTTONSET_BUTTON:
 			break;
 		}
 
-- 
2.3.2



More information about the wayland-devel mailing list