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

Peter Hutterer peter.hutterer at who-t.net
Mon Jan 18 20:46:34 PST 2016


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 can be queried for the respective value, which depends on
the type.

Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
This is a revamped version the buttonset interface. The main change is the
switch to more specific axis handling, similar to what we just did in the
tablet support branch:
Previously, you'd run libinput_event_buttonset_get_axis_value(event, axis)
and the value was axis-specific. Now you have to call the correct call for
the axis, e.g. libinput_event_buttonset_get_ring_position(event, axis). This
allows libinput to detect bugs quicker (e.g. if axis isn't a ring axis) and
it's more expressive and flexible.

The rest stays the same, a device has N axes, each of them has a type that
decides how to use the API.

Note: the axes supported here are quite a few to illustrate how things
should look like, but I think the buttonset version eventually merged should
just provide the ones we actually support, i.e. ring and strip for pads. The
rest can be added later, as we add support for specific devices.


 doc/Makefile.am        |   1 +
 doc/buttonsets.dox     |  53 ++++++
 src/libinput-private.h |   2 +
 src/libinput.c         | 410 +++++++++++++++++++++++++++++++++++++++
 src/libinput.h         | 508 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/libinput.sym       |  34 ++++
 test/litest.c          |   6 +
 tools/event-debug.c    |  66 +++++++
 tools/event-gui.c      |   3 +
 9 files changed, 1083 insertions(+)
 create mode 100644 doc/buttonsets.dox

diff --git a/doc/Makefile.am b/doc/Makefile.am
index 7a7c6cf..0ec9586 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -11,6 +11,7 @@ header_files = \
 	$(top_srcdir)/src/libinput.h \
 	$(top_srcdir)/README.txt \
 	$(srcdir)/absolute-axes.dox \
+	$(srcdir)/buttonsets.dox \
 	$(srcdir)/clickpad-softbuttons.dox \
 	$(srcdir)/device-configuration-via-udev.dox \
 	$(srcdir)/faqs.dox \
diff --git a/doc/buttonsets.dox b/doc/buttonsets.dox
new file mode 100644
index 0000000..5c25bc6
--- /dev/null
+++ b/doc/buttonsets.dox
@@ -0,0 +1,53 @@
+/**
+ at page buttonsets Buttonset devices
+
+Devices with the @ref LIBINPUT_DEVICE_CAP_BUTTONSET capability are so-called
+buttonsets, devices that have axes, buttons or keys but are are auxiliary
+devices that do not control the pointer or the keyboard.
+Examples for buttonset devices are the physical tablet ("pad") of Wacom
+graphics tablets, the Griffin PowerMate or the 3Dconnexion SpacePilot Pro.
+
+A buttonset device may have axes and even x and y axes but those axes are
+not used to control the pointer. Joysticks and gamepads are not buttonset
+devices, libinput currently does not support those.
+
+libinput expects additional knowledge about the device to live in the
+callers, it merely abstracts the interfaces and provides a coherent API to
+the callers. A caller should know about the device in advance and thus be
+able to interpret the various axes, buttons and keys correctly.
+
+ at section buttonset_buttons
+
+The set of buttons on a device is device-specific. libinput uses the Linux
+kernel's button names (BTN_* from linux/input.h) to identify buttons.
+Linux forces semantic naming on buttons (e.g. BTN_LEFT) but some devices
+have merely numbered buttons (e.g. the XKeys Pro). It is the caller's
+responsibility to detect such devices and interpret the button numbers
+correctly.
+
+libinput does not provide a function to enumerate all buttons on a device,
+instead the caller is expected to check for the buttons or keys it needs to
+handle. For example, a caller that cares about multimedia keys should check
+for the set of multimedia keys it handles rather than traversing the entire
+key space.
+
+ at section buttonset_axes Buttonset axes
+
+Axes on a buttonset are numbered sequentially, zero-indexed. The index is
+the main identifier of the axis, the order of axes is not guaranteed. A
+device may gain additional axes with future releases of libinput.
+
+Each axis has a type (see @ref libinput_buttonset_axis_type). libinput does
+not guarantee the order of the types, but it does guarantee a stable order of
+axes with the same type. If a device's axes i an j are of type @ref
+LIBINPUT_BUTTONSET_AXIS_RING, libinput guarantees that i < j even when the
+number or order of axes changes.  In other words, if the left ring was the
+first ring in the axis list, it will always be the first ring in the axis
+list.
+
+A buttonset device may have relative and absolute axes. Absolute axes are
+provided in physical distances where possible, relative events are always in
+normalized relative events. libinput uses the same default DPI as for mouse
+events, see @ref motion_normalization.
+
+*/
diff --git a/src/libinput-private.h b/src/libinput-private.h
index ff43d00..845dc00 100644
--- a/src/libinput-private.h
+++ b/src/libinput-private.h
@@ -33,6 +33,8 @@
 #include "libinput.h"
 #include "libinput-util.h"
 
+#define LIBINPUT_BUTTONSET_MAX_NUM_AXES 32
+
 struct libinput_source;
 
 /* A coordinate pair in device coordinates */
diff --git a/src/libinput.c b/src/libinput.c
index 5a2b66e..3aba899 100644
--- a/src/libinput.c
+++ b/src/libinput.c
@@ -42,6 +42,10 @@
 	if (!check_event_type(li_, __func__, type_, __VA_ARGS__, -1)) \
 		return retval_; \
 
+#define require_buttonset_axis(dev_, axis_, type_, retval_) \
+	if (!check_buttonset_axis_type(dev_, __func__, axis_, type_)) \
+		return retval_;
+
 static inline bool
 check_event_type(struct libinput *libinput,
 		 const char *function_name,
@@ -73,6 +77,32 @@ check_event_type(struct libinput *libinput,
 	return rc;
 }
 
+static inline bool
+check_buttonset_axis_type(struct libinput_device *device,
+			  const char *function_name,
+			  unsigned int axis,
+			  enum libinput_buttonset_axis_type type_wanted)
+{
+	enum libinput_buttonset_axis_type type;
+
+	if (axis >= libinput_device_buttonset_get_num_axes(device)) {
+		log_bug_client(device->seat->libinput,
+			       "Invalid axis number %d in %s()\n",
+			       axis, function_name);
+		return false;
+	}
+
+	type = libinput_device_buttonset_get_axis_type(device, axis);
+	if (type != type_wanted) {
+		log_bug_client(device->seat->libinput,
+			       "Invalid axis type %d (need %d for %s())\n",
+			       type, type_wanted, function_name);
+		return false;
+	} else {
+		return true;
+	}
+}
+
 struct libinput_source {
 	libinput_source_dispatch_t dispatch;
 	void *user_data;
@@ -138,6 +168,28 @@ struct libinput_event_tablet_tool {
 	enum libinput_tablet_tool_tip_state tip_state;
 };
 
+struct libinput_buttonset_axis {
+	enum libinput_buttonset_axis_type type;
+	enum libinput_buttonset_axis_source source;
+	union {
+		double mm;
+		double normalized;
+		double delta;
+		double degrees;
+		double position;
+	} value;
+};
+
+struct libinput_event_buttonset {
+	struct libinput_event base;
+	uint32_t button;
+	enum libinput_button_state state;
+	uint32_t seat_button_count;
+	uint32_t time;
+	struct libinput_buttonset_axis axes[LIBINPUT_BUTTONSET_MAX_NUM_AXES];
+	unsigned char changed_axes[NCHARS(LIBINPUT_BUTTONSET_MAX_NUM_AXES)];
+};
+
 static void
 libinput_default_log_func(struct libinput *libinput,
 			  enum libinput_log_priority priority,
@@ -330,6 +382,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)
 {
@@ -1447,6 +1511,316 @@ libinput_tablet_tool_unref(struct libinput_tablet_tool *tool)
 	return NULL;
 }
 
+LIBINPUT_EXPORT uint32_t
+libinput_event_buttonset_get_time(struct libinput_event_buttonset *event)
+{
+	require_event_type(libinput_event_get_context(&event->base),
+			   event->base.type,
+			   0,
+			   LIBINPUT_EVENT_BUTTONSET_AXIS,
+			   LIBINPUT_EVENT_BUTTONSET_BUTTON);
+
+	return us2ms(event->time);
+}
+
+LIBINPUT_EXPORT uint64_t
+libinput_event_buttonset_get_time_usec(struct libinput_event_buttonset *event)
+{
+	require_event_type(libinput_event_get_context(&event->base),
+			   event->base.type,
+			   0,
+			   LIBINPUT_EVENT_BUTTONSET_AXIS,
+			   LIBINPUT_EVENT_BUTTONSET_BUTTON);
+
+	return event->time;
+}
+
+LIBINPUT_EXPORT uint32_t
+libinput_event_buttonset_get_button(struct libinput_event_buttonset *event)
+{
+	require_event_type(libinput_event_get_context(&event->base),
+			   event->base.type,
+			   0,
+			   LIBINPUT_EVENT_BUTTONSET_BUTTON);
+
+	return event->button;
+}
+
+LIBINPUT_EXPORT enum libinput_button_state
+libinput_event_buttonset_get_button_state(struct libinput_event_buttonset *event)
+{
+	require_event_type(libinput_event_get_context(&event->base),
+			   event->base.type,
+			   0,
+			   LIBINPUT_EVENT_BUTTONSET_BUTTON);
+
+	return event->state;
+}
+
+LIBINPUT_EXPORT uint32_t
+libinput_event_buttonset_get_seat_button_count(struct libinput_event_buttonset *event)
+{
+	require_event_type(libinput_event_get_context(&event->base),
+			   event->base.type,
+			   0,
+			   LIBINPUT_EVENT_BUTTONSET_BUTTON);
+
+	return event->seat_button_count;
+}
+
+LIBINPUT_EXPORT int
+libinput_event_buttonset_axis_has_changed(struct libinput_event_buttonset *event,
+					  unsigned int axis)
+{
+	require_event_type(libinput_event_get_context(&event->base),
+			   event->base.type,
+			   0,
+			   LIBINPUT_EVENT_BUTTONSET_AXIS);
+
+	return (NCHARS(axis) <= sizeof(event->changed_axes)) ?
+		bit_is_set(event->changed_axes, axis) : 0;
+}
+
+LIBINPUT_EXPORT double
+libinput_event_buttonset_get_x(struct libinput_event_buttonset *event,
+			       unsigned int axis)
+{
+	require_event_type(libinput_event_get_context(&event->base),
+			   event->base.type,
+			   0.0,
+			   LIBINPUT_EVENT_BUTTONSET_AXIS);
+	require_buttonset_axis(event->base.device,
+			       axis,
+			       LIBINPUT_BUTTONSET_AXIS_X,
+			       0.0);
+
+	return event->axes[axis].value.mm;
+}
+
+LIBINPUT_EXPORT double
+libinput_event_buttonset_get_x_transformed(struct libinput_event_buttonset *event,
+					   unsigned int axis,
+					   uint32_t width)
+{
+	require_event_type(libinput_event_get_context(&event->base),
+			   event->base.type,
+			   0.0,
+			   LIBINPUT_EVENT_BUTTONSET_AXIS);
+	require_buttonset_axis(event->base.device,
+				    axis,
+				    LIBINPUT_BUTTONSET_AXIS_X,
+				    0.0);
+
+	return event->axes[axis].value.mm; /* FIXME */
+}
+
+LIBINPUT_EXPORT double
+libinput_event_buttonset_get_y(struct libinput_event_buttonset *event,
+			       unsigned int axis)
+{
+	require_event_type(libinput_event_get_context(&event->base),
+			   event->base.type,
+			   0.0,
+			   LIBINPUT_EVENT_BUTTONSET_AXIS);
+	require_buttonset_axis(event->base.device,
+				    axis,
+				    LIBINPUT_BUTTONSET_AXIS_Y,
+				    0.0);
+	return event->axes[axis].value.mm;
+}
+
+LIBINPUT_EXPORT double
+libinput_event_buttonset_get_y_transformed(struct libinput_event_buttonset *event,
+					   unsigned int axis,
+					   uint32_t height)
+{
+	require_event_type(libinput_event_get_context(&event->base),
+			   event->base.type,
+			   0.0,
+			   LIBINPUT_EVENT_BUTTONSET_AXIS);
+	require_buttonset_axis(event->base.device,
+				    axis,
+				    LIBINPUT_BUTTONSET_AXIS_Y,
+				    0.0);
+
+	return event->axes[axis].value.mm; /* FIXME */
+}
+
+LIBINPUT_EXPORT double
+libinput_event_buttonset_get_z(struct libinput_event_buttonset *event,
+			       unsigned int axis)
+{
+	require_event_type(libinput_event_get_context(&event->base),
+			   event->base.type,
+			   0.0,
+			   LIBINPUT_EVENT_BUTTONSET_AXIS);
+	require_buttonset_axis(event->base.device,
+				    axis,
+				    LIBINPUT_BUTTONSET_AXIS_Z,
+				    0.0);
+
+	return event->axes[axis].value.mm;
+}
+
+LIBINPUT_EXPORT double
+libinput_event_buttonset_get_dx(struct libinput_event_buttonset *event,
+				unsigned int axis)
+{
+	require_event_type(libinput_event_get_context(&event->base),
+			   event->base.type,
+			   0.0,
+			   LIBINPUT_EVENT_BUTTONSET_AXIS);
+	require_buttonset_axis(event->base.device,
+				    axis,
+				    LIBINPUT_BUTTONSET_AXIS_REL_X,
+				    0.0);
+
+	return event->axes[axis].value.delta;
+}
+
+LIBINPUT_EXPORT double
+libinput_event_buttonset_get_dy(struct libinput_event_buttonset *event,
+				unsigned int axis)
+{
+	require_event_type(libinput_event_get_context(&event->base),
+			   event->base.type,
+			   0.0,
+			   LIBINPUT_EVENT_BUTTONSET_AXIS);
+	require_buttonset_axis(event->base.device,
+				    axis,
+				    LIBINPUT_BUTTONSET_AXIS_REL_Y,
+				    0.0);
+
+	return event->axes[axis].value.delta;
+}
+
+LIBINPUT_EXPORT double
+libinput_event_buttonset_get_dz(struct libinput_event_buttonset *event,
+				unsigned int axis)
+{
+	require_event_type(libinput_event_get_context(&event->base),
+			   event->base.type,
+			   0.0,
+			   LIBINPUT_EVENT_BUTTONSET_AXIS);
+	require_buttonset_axis(event->base.device,
+				    axis,
+				    LIBINPUT_BUTTONSET_AXIS_REL_Z,
+				    0.0);
+
+	return event->axes[axis].value.delta;
+}
+
+LIBINPUT_EXPORT double
+libinput_event_buttonset_get_rotation_x(struct libinput_event_buttonset *event,
+					unsigned int axis)
+{
+	require_event_type(libinput_event_get_context(&event->base),
+			   event->base.type,
+			   0.0,
+			   LIBINPUT_EVENT_BUTTONSET_AXIS);
+	require_buttonset_axis(event->base.device,
+				    axis,
+				    LIBINPUT_BUTTONSET_AXIS_ROTATION_X,
+				    0.0);
+
+	return event->axes[axis].value.degrees;
+}
+
+LIBINPUT_EXPORT double
+libinput_event_buttonset_get_rotation_y(struct libinput_event_buttonset *event,
+					unsigned int axis)
+{
+	require_event_type(libinput_event_get_context(&event->base),
+			   event->base.type,
+			   0.0,
+			   LIBINPUT_EVENT_BUTTONSET_AXIS);
+	require_buttonset_axis(event->base.device,
+				    axis,
+				    LIBINPUT_BUTTONSET_AXIS_ROTATION_Y,
+				    0.0);
+
+	return event->axes[axis].value.degrees;
+}
+
+LIBINPUT_EXPORT double
+libinput_event_buttonset_get_rotation_z(struct libinput_event_buttonset *event,
+					unsigned int axis)
+{
+	require_event_type(libinput_event_get_context(&event->base),
+			   event->base.type,
+			   0.0,
+			   LIBINPUT_EVENT_BUTTONSET_AXIS);
+	require_buttonset_axis(event->base.device,
+				    axis,
+				    LIBINPUT_BUTTONSET_AXIS_ROTATION_Z,
+				    0.0);
+
+	return event->axes[axis].value.degrees;
+}
+
+LIBINPUT_EXPORT double
+libinput_event_buttonset_get_ring_position(struct libinput_event_buttonset *event,
+					   unsigned int axis)
+{
+	require_event_type(libinput_event_get_context(&event->base),
+			   event->base.type,
+			   0.0,
+			   LIBINPUT_EVENT_BUTTONSET_AXIS);
+	require_buttonset_axis(event->base.device,
+				    axis,
+				    LIBINPUT_BUTTONSET_AXIS_RING,
+				    0.0);
+
+	return event->axes[axis].value.position;
+}
+
+LIBINPUT_EXPORT enum libinput_buttonset_axis_source
+libinput_event_buttonset_get_ring_source(struct libinput_event_buttonset *event,
+					 unsigned int axis)
+{
+	require_event_type(libinput_event_get_context(&event->base),
+			   event->base.type,
+			   0.0,
+			   LIBINPUT_EVENT_BUTTONSET_AXIS);
+	require_buttonset_axis(event->base.device,
+				    axis,
+				    LIBINPUT_BUTTONSET_AXIS_RING,
+				    0.0);
+
+	return event->axes[axis].source;
+}
+
+LIBINPUT_EXPORT double
+libinput_event_buttonset_get_strip_position(struct libinput_event_buttonset *event,
+					    unsigned int axis)
+{
+	require_event_type(libinput_event_get_context(&event->base),
+			   event->base.type,
+			   0.0,
+			   LIBINPUT_EVENT_BUTTONSET_AXIS);
+	require_buttonset_axis(event->base.device,
+			       axis,
+			       LIBINPUT_BUTTONSET_AXIS_STRIP,
+			       0.0);
+
+	return event->axes[axis].value.position;
+}
+
+LIBINPUT_EXPORT enum libinput_buttonset_axis_source
+libinput_event_buttonset_get_strip_source(struct libinput_event_buttonset *event,
+					 unsigned int axis)
+{
+	require_event_type(libinput_event_get_context(&event->base),
+			   event->base.type,
+			   0.0,
+			   LIBINPUT_EVENT_BUTTONSET_AXIS);
+	require_buttonset_axis(event->base.device,
+			       axis,
+			       LIBINPUT_BUTTONSET_AXIS_STRIP,
+			       0.0);
+	return event->axes[axis].source;
+}
+
 struct libinput_source *
 libinput_add_fd(struct libinput *libinput,
 		int fd,
@@ -1927,6 +2301,9 @@ device_has_cap(struct libinput_device *device,
 	case LIBINPUT_DEVICE_CAP_TABLET_TOOL:
 		capability = "CAP_TABLET";
 		break;
+	case LIBINPUT_DEVICE_CAP_BUTTONSET:
+		capability = "CAP_BUTTONSET";
+		break;
 	}
 
 	log_bug_libinput(device->seat->libinput,
@@ -2423,6 +2800,8 @@ event_type_to_str(enum libinput_event_type type)
 	CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_PINCH_BEGIN);
 	CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_PINCH_UPDATE);
 	CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_PINCH_END);
+	CASE_RETURN_STRING(LIBINPUT_EVENT_BUTTONSET_AXIS);
+	CASE_RETURN_STRING(LIBINPUT_EVENT_BUTTONSET_BUTTON);
 	case LIBINPUT_EVENT_NONE:
 		abort();
 	}
@@ -2650,6 +3029,25 @@ libinput_device_keyboard_has_key(struct libinput_device *device, uint32_t code)
 					     code);
 }
 
+LIBINPUT_EXPORT int
+libinput_device_buttonset_has_button(struct libinput_device *device, uint32_t code)
+{
+	return 0; /* FIXME */
+}
+
+LIBINPUT_EXPORT enum libinput_buttonset_axis_type
+libinput_device_buttonset_get_axis_type(struct libinput_device *device,
+					unsigned int axis)
+{
+	return 0; /* FIXME */
+}
+
+LIBINPUT_EXPORT unsigned int
+libinput_device_buttonset_get_num_axes(struct libinput_device *device)
+{
+	return 0; /* FIXME */
+}
+
 LIBINPUT_EXPORT struct libinput_event *
 libinput_event_device_notify_get_base_event(struct libinput_event_device_notify *event)
 {
@@ -2722,6 +3120,18 @@ libinput_event_tablet_tool_get_base_event(struct libinput_event_tablet_tool *eve
 	return &event->base;
 }
 
+LIBINPUT_EXPORT struct libinput_event *
+libinput_event_buttonset_get_base_event(struct libinput_event_buttonset *event)
+{
+	require_event_type(libinput_event_get_context(&event->base),
+			   event->base.type,
+			   NULL,
+			   LIBINPUT_EVENT_BUTTONSET_BUTTON,
+			   LIBINPUT_EVENT_BUTTONSET_AXIS);
+
+	return &event->base;
+}
+
 LIBINPUT_EXPORT struct libinput_device_group *
 libinput_device_group_ref(struct libinput_device_group *group)
 {
diff --git a/src/libinput.h b/src/libinput.h
index 1cf690b..f7b771d 100644
--- a/src/libinput.h
+++ b/src/libinput.h
@@ -59,6 +59,7 @@ enum libinput_device_capability {
 	LIBINPUT_DEVICE_CAP_POINTER = 1,
 	LIBINPUT_DEVICE_CAP_TOUCH = 2,
 	LIBINPUT_DEVICE_CAP_TABLET_TOOL = 3,
+	LIBINPUT_DEVICE_CAP_BUTTONSET = 4,
 	LIBINPUT_DEVICE_CAP_GESTURE = 5,
 };
 
@@ -138,6 +139,50 @@ enum libinput_pointer_axis_source {
  * @ingroup device
  * @struct libinput_tablet_tool
  *
+ * 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_X = 1, /**< Absolute X axis */
+	LIBINPUT_BUTTONSET_AXIS_Y, /**< Absolute Y axis */
+	LIBINPUT_BUTTONSET_AXIS_Z, /**< Absolute Z axis */
+	LIBINPUT_BUTTONSET_AXIS_REL_X, /**< Relative X axis */
+	LIBINPUT_BUTTONSET_AXIS_REL_Y, /**< Relative Y axis */
+	LIBINPUT_BUTTONSET_AXIS_REL_Z, /**< Relative Z axis */
+	LIBINPUT_BUTTONSET_AXIS_ROTATION_X,
+	LIBINPUT_BUTTONSET_AXIS_ROTATION_Y,
+	LIBINPUT_BUTTONSET_AXIS_ROTATION_Z,
+	/**
+	 * A ring-like axis with absolute axis values, e.g. the ring on the
+	 * Wacom Intuos4.
+	 */
+	LIBINPUT_BUTTONSET_AXIS_RING,
+	/**
+	 * A strip-like axis with absolute axis values, e.g. the strip on
+	 * the Wacom Intuos3.
+	 */
+	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 a device with the @ref
  * LIBINPUT_DEVICE_CAP_TABLET_TOOL capability.
  *
@@ -339,6 +384,9 @@ enum libinput_event_type {
 	 */
 	LIBINPUT_EVENT_TABLET_TOOL_BUTTON,
 
+	LIBINPUT_EVENT_BUTTONSET_AXIS = 700,
+	LIBINPUT_EVENT_BUTTONSET_BUTTON,
+
 	LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN = 800,
 	LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE,
 	LIBINPUT_EVENT_GESTURE_SWIPE_END,
@@ -444,6 +492,17 @@ struct libinput_event_touch;
 struct libinput_event_tablet_tool;
 
 /**
+ * @ingroup event_buttonset
+ * @struct libinput_event_buttonset
+ *
+ * Event representing a button press/release or axis update on device with
+ * the @ref LIBINPUT_DEVICE_CAP_BUTTONSET capability. 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
  */
 
@@ -579,6 +638,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 *
@@ -2048,6 +2120,380 @@ libinput_tablet_tool_set_user_data(struct libinput_tablet_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.
+ *
+ * Note that buttonset devices may have x/y axes. It is up to the caller to
+ * decide whether those devices should control the pointer.
+ * While libinput provides some information about the device and a unified
+ * API to handle axes and events, the caller is expected to gather
+ * additional information from external sources. For example, for
+ * information on the button layout and other behaviors on Wacom tablet
+ * pads, the caller should use libwacom.
+ */
+
+/**
+ * @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);
+
+/**
+ * @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
+ *
+ * @return The event time for this event
+ */
+uint64_t
+libinput_event_buttonset_get_time_usec(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
+ *
+ * Get the x coordinate in mm for the given axis from the left edge of the
+ * device in its current logical rotation. The axis must be of type
+ * @ref LIBINPUT_BUTTONSET_AXIS_X.
+ *
+ * @param event The event
+ * @param axis An index for an axis of type @ref LIBINPUT_BUTTONSET_AXIS_X
+ * @return The x coordinate in mm, or 0 if the axis is not of type @ref
+ * LIBINPUT_BUTTONSET_AXIS_X.
+ */
+double
+libinput_event_buttonset_get_x(struct libinput_event_buttonset *event,
+			       unsigned int axis);
+
+/**
+ * @ingroup event_buttonset
+ *
+ * Return the x coordinate of the buttonset event, transformed to
+ * screen coordinates. The axis must be of type @ref
+ * LIBINPUT_BUTTONSET_AXIS_X.
+ *
+ * @param event The event
+ * @param axis An index for an axis of type @ref LIBINPUT_BUTTONSET_AXIS_X
+ * @param width The screen width
+ * @return The x coordinate transformed to screen coordinates, or 0 if the
+ * axis is not of type @ref LIBINPUT_BUTTONSET_AXIS_X.
+ */
+double
+libinput_event_buttonset_get_x_transformed(struct libinput_event_buttonset *event,
+					   unsigned int axis,
+					   uint32_t width);
+/**
+ * @ingroup event_buttonset
+ *
+ * Get the y coordinate in mm for the given axis from the top edge of the
+ * device in its current logical rotation. The axis must be of type
+ * @ref LIBINPUT_BUTTONSET_AXIS_Y.
+ *
+ * @param event The event
+ * @param axis An index for an axis of type @ref LIBINPUT_BUTTONSET_AXIS_Y
+ * @return The y coordinate in mm, or 0 if the axis is not of type @ref
+ * LIBINPUT_BUTTONSET_AXIS_Y.
+ */
+double
+libinput_event_buttonset_get_y(struct libinput_event_buttonset *event,
+			       unsigned int axis);
+
+/**
+ * @ingroup event_buttonset
+ *
+ * Return the y coordinate of the buttonset event, transformed to
+ * screen coordinates. The axis must be of type @ref
+ * LIBINPUT_BUTTONSET_AXIS_Y.
+ *
+ * @param event The event
+ * @param axis An index for an axis of type @ref LIBINPUT_BUTTONSET_AXIS_Y
+ * @param height The screen height
+ * @return The x coordinate transformed to screen coordinates, or 0 if the
+ * axis is not of type @ref LIBINPUT_BUTTONSET_AXIS_Y.
+ */
+double
+libinput_event_buttonset_get_y_transformed(struct libinput_event_buttonset *event,
+					   unsigned int axis,
+					   uint32_t height);
+/**
+ * @ingroup event_buttonset
+ *
+ * Get the z coordinate in mm for the given axis from the top edge of the
+ * device in its current logical rotation. The axis must be of type
+ * @ref LIBINPUT_BUTTONSET_AXIS_Z.
+ *
+ * @param event The event
+ * @param axis An index for an axis of type @ref LIBINPUT_BUTTONSET_AXIS_Z
+ * @return The z coordinate in mm, or 0 if the axis is not of type @ref
+ * LIBINPUT_BUTTONSET_AXIS_Z.
+ */
+double
+libinput_event_buttonset_get_z(struct libinput_event_buttonset *event,
+			       unsigned int axis);
+
+/**
+ * @ingroup event_buttonset
+ *
+ * Get the delta coordinates for a relative x axis of type
+ * @ref LIBINPUT_BUTTONSET_AXIS_REL_X.
+ *
+ * The interpretation of a delta is device-specific. Buttonset devices are
+ * not usually supposed to control the cursor position, a caller should not
+ * assume that delta coordinates are directly applicable to pointer
+ * movement.
+ *
+ * @param event The event
+ * @param axis An index for an axis of type @ref
+ * LIBINPUT_BUTTONSET_AXIS_REL_X
+ * @return The delta x coordinate, or 0 if the axis is not of type @ref
+ * LIBINPUT_BUTTONSET_AXIS_REL_X.
+ */
+double
+libinput_event_buttonset_get_dx(struct libinput_event_buttonset *event,
+				unsigned int axis);
+
+/**
+ * @ingroup event_buttonset
+ *
+ * Get the delta coordinates for a relative x axis of type
+ * @ref LIBINPUT_BUTTONSET_AXIS_REL_Y.
+ *
+ * The interpretation of a delta is device-specific. Buttonset devices are
+ * not usually supposed to control the cursor position, a caller should not
+ * assume that delta coordinates are directly applicable to pointer
+ * movement.
+ *
+ * @param event The event
+ * @param axis An index for an axis of type @ref
+ * LIBINPUT_BUTTONSET_AXIS_REL_Y
+ * @return The delta y coordinate, or 0 if the axis is not of type @ref
+ * LIBINPUT_BUTTONSET_AXIS_REL_Y.
+ */
+double
+libinput_event_buttonset_get_dy(struct libinput_event_buttonset *event,
+				unsigned int axis);
+
+/**
+ * @ingroup event_buttonset
+ *
+ * Get the delta coordinates for a relative x axis of type
+ * @ref LIBINPUT_BUTTONSET_AXIS_REL_Z.
+ *
+ * @param event The event
+ * @param axis An index for an axis of type @ref
+ * LIBINPUT_BUTTONSET_AXIS_REL_Z
+ * @return The delta z coordinate, or 0 if the axis is not of type @ref
+ * LIBINPUT_BUTTONSET_AXIS_REL_Z.
+ */
+double
+libinput_event_buttonset_get_dz(struct libinput_event_buttonset *event,
+				unsigned int axis);
+
+/**
+ * @ingroup event_buttonset
+ *
+ * Get the rotational position in degrees off the logical neutral position
+ * in the current logical orientation for an axis of type @ref
+ * LIBINPUT_BUTTONSET_AXIS_ROTATION_X.
+ *
+ * @param event The event
+ * @param axis An index for an axis of type @ref
+ * LIBINPUT_BUTTONSET_AXIS_ROTATION_X
+ * @return The rotational x value in degrees, or 0 if the axis is not of type @ref
+ * LIBINPUT_BUTTONSET_AXIS_REL_Z.
+ */
+double
+libinput_event_buttonset_get_rotation_x(struct libinput_event_buttonset *event,
+					unsigned int axis);
+/**
+ * @ingroup event_buttonset
+ *
+ * Get the rotational position in degrees off the logical neutral position
+ * in the current logical orientation for an axis of type @ref
+ * LIBINPUT_BUTTONSET_AXIS_ROTATION_Y.
+ *
+ * @param event The event
+ * @param axis An index for an axis of type @ref
+ * LIBINPUT_BUTTONSET_AXIS_ROTATION_Y
+ * @return The rotational y value in degrees, or 0 if the axis is not of type @ref
+ * LIBINPUT_BUTTONSET_AXIS_REL_Y.
+ */
+double
+libinput_event_buttonset_get_rotation_y(struct libinput_event_buttonset *event,
+					unsigned int axis);
+/**
+ * @ingroup event_buttonset
+ *
+ * Get the rotational position in degrees off the logical neutral position
+ * in the current logical orientation for an axis of type @ref
+ * LIBINPUT_BUTTONSET_AXIS_ROTATION_Z.
+ *
+ * @param event The event
+ * @param axis An index for an axis of type @ref
+ * LIBINPUT_BUTTONSET_AXIS_ROTATION_Z
+ * @return The rotational z value in degrees, or 0 if the axis is not of type @ref
+ * LIBINPUT_BUTTONSET_AXIS_REL_Z.
+ */
+double
+libinput_event_buttonset_get_rotation_z(struct libinput_event_buttonset *event,
+					unsigned int axis);
+
+/**
+ * @ingroup event_buttonset
+ *
+ * Get the absolute position for an axis of type @ref
+ * LIBINPUT_BUTTONSET_AXIS_RING in degrees clockwise in the
+ * device's current logical rotation.
+ *
+ * If the libinput_event_buttonset_get_ring_source() returns @ref
+ * LIBINPUT_BUTTONSET_AXIS_SOURCE_FINGER for this event and this axis,
+ * libinput will send an event with a value of -1 when the finger is
+ * lifted.
+ *
+ * @param event The event
+ * @param axis An index for an axis of type @ref
+ * LIBINPUT_BUTTONSET_AXIS_RING
+ * @return The ring's position in degrees, or 0 if the axis is not of type @ref
+ * LIBINPUT_BUTTONSET_AXIS_RING.
+ */
+double
+libinput_event_buttonset_get_ring_position(struct libinput_event_buttonset *event,
+					   unsigned int axis);
+/**
+ * @ingroup event_buttonset
+ *
+ * Return the source for an axis of type @ref LIBINPUT_BUTTONSET_AXIS_RING.
+ *
+ * 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_ring_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.
+ *
+ */
+enum libinput_buttonset_axis_source
+libinput_event_buttonset_get_ring_source(struct libinput_event_buttonset *event,
+					 unsigned int axis);
+
+/**
+ * @ingroup event_buttonset
+ *
+ * Get the absolute position for an axis of type @ref
+ * LIBINPUT_BUTTONSET_AXIS_STRIP normalized to the axis range [0, 1], where
+ * 0 is the strip's top or left-most point in the device's current logical
+ * rotation.
+ *
+ * If the libinput_event_buttonset_get_strip_source() returns @ref
+ * LIBINPUT_BUTTONSET_AXIS_SOURCE_FINGER for this event and this axis,
+ * libinput will send an event with a value of -1 when the finger is
+ * lifted.
+ *
+ * @param event The event
+ * @param axis An index for an axis of type @ref
+ * LIBINPUT_BUTTONSET_AXIS_STRIP
+ * @return The normalized position on the strip, or 0 if the axis is not of type @ref
+ * LIBINPUT_BUTTONSET_AXIS_STRIP.
+ */
+double
+libinput_event_buttonset_get_strip_position(struct libinput_event_buttonset *event,
+					    unsigned int axis);
+
+/**
+ * @ingroup event_buttonset
+ *
+ * Return the source for an axis of type @ref LIBINPUT_BUTTONSET_AXIS_STRIP.
+ *
+ * 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_strip_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.
+ */
+enum libinput_buttonset_axis_source
+libinput_event_buttonset_get_strip_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);
+
+/**
  * @defgroup base Initialization and manipulation of libinput contexts
  */
 
@@ -2874,6 +3320,68 @@ libinput_device_keyboard_has_key(struct libinput_device *device,
 				 uint32_t code);
 
 /**
+ * Check if a @ref LIBINPUT_DEVICE_CAP_BUTTONSET device has a button with
+ * the given 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.
+ *
+ * @see @ref buttonset_buttons
+ */
+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: axis numbers are not stable, see @ref buttonset_axes for details.
+ *
+ * @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 0 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
diff --git a/src/libinput.sym b/src/libinput.sym
index 22a8dd8..07073b2 100644
--- a/src/libinput.sym
+++ b/src/libinput.sym
@@ -231,3 +231,37 @@ LIBINPUT_TABLET_SUPPORT {
 	libinput_tablet_tool_set_user_data;
 	libinput_tablet_tool_unref;
 } LIBINPUT_1.1;
+
+BUTTONSET_INTERFACE {
+	libinput_device_buttonset_has_button;
+	libinput_device_buttonset_get_axis_type;
+	libinput_device_buttonset_get_num_axes;
+	libinput_event_buttonset_get_base_event;
+	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_get_time_usec;
+	libinput_event_buttonset_axis_has_changed;
+	libinput_event_get_buttonset_event;
+	libinput_event_buttonset_get_x;
+	libinput_event_buttonset_get_x_transformed;
+	libinput_event_buttonset_get_y;
+	libinput_event_buttonset_get_y_transformed;
+	libinput_event_buttonset_get_z;
+	libinput_event_buttonset_get_dx;
+	libinput_event_buttonset_get_dy;
+	libinput_event_buttonset_get_dz;
+	libinput_event_buttonset_get_rotation_x;
+	libinput_event_buttonset_get_rotation_y;
+	libinput_event_buttonset_get_rotation_z;
+	libinput_event_buttonset_get_ring_position;
+	libinput_event_buttonset_get_ring_source;
+	libinput_event_buttonset_get_strip_position;
+	libinput_event_buttonset_get_strip_source;
+	libinput_event_buttonset_get_dx;
+	libinput_event_buttonset_get_dy;
+	libinput_event_buttonset_get_dz;
+	libinput_event_buttonset_get_ring_position;
+	libinput_event_buttonset_get_strip_position;
+} LIBINPUT_TABLET_SUPPORT;
diff --git a/test/litest.c b/test/litest.c
index 3da187c..0d93ab4 100644
--- a/test/litest.c
+++ b/test/litest.c
@@ -1934,6 +1934,12 @@ litest_event_type_str(struct libinput_event *event)
 	case LIBINPUT_EVENT_TABLET_TOOL_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 648111e..359b437 100644
--- a/tools/event-debug.c
+++ b/tools/event-debug.c
@@ -121,6 +121,12 @@ print_event_header(struct libinput_event *ev)
 	case LIBINPUT_EVENT_TABLET_TOOL_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);
@@ -172,6 +178,9 @@ print_device_notify(struct libinput_event *ev)
 	if (libinput_device_has_capability(dev,
 					   LIBINPUT_DEVICE_CAP_TABLET_TOOL))
 		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);
@@ -315,6 +324,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;
+	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;
+
+		switch(libinput_device_buttonset_get_axis_type(device, axis)) {
+		case LIBINPUT_BUTTONSET_AXIS_RING:
+			axis_name = "ring";
+			val = libinput_event_buttonset_get_ring_position(b, axis);
+			break;
+		case LIBINPUT_BUTTONSET_AXIS_STRIP:
+			axis_name = "strip";
+			val = libinput_event_buttonset_get_strip_position(b, axis);
+			break;
+		default:
+			axis_name = "UNKNOWN";
+			break;
+		}
+		printf("\t%s: %.2f", axis_name, val);
+	}
+
+	printf("\n");
+}
+
+static void
 print_pointer_axis_event(struct libinput_event *ev)
 {
 	struct libinput_event_pointer *p = libinput_event_get_pointer_event(ev);
@@ -647,6 +707,12 @@ handle_and_print_events(struct libinput *li)
 		case LIBINPUT_EVENT_TABLET_TOOL_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 fa0e1a0..e258d69 100644
--- a/tools/event-gui.c
+++ b/tools/event-gui.c
@@ -710,6 +710,9 @@ handle_event_libinput(GIOChannel *source, GIOCondition condition, gpointer data)
 		case LIBINPUT_EVENT_TABLET_TOOL_BUTTON:
 			handle_event_tablet(ev, w);
 			break;
+		case LIBINPUT_EVENT_BUTTONSET_AXIS:
+		case LIBINPUT_EVENT_BUTTONSET_BUTTON:
+			break;
 		}
 
 		libinput_event_destroy(ev);
-- 
2.5.0



More information about the wayland-devel mailing list