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

Peter Hutterer peter.hutterer at who-t.net
Wed Feb 11 23:33:52 PST 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.
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.

Currently implemented are two ring and two strip axes. The axis use depends a
lot on the device and is hard to predict. e.g. strips have apparently been
used for physical positioning (like a sliding actuator) whereas the wheel
usually only cares about deltas. The above set should cater for the common
use-cases.

Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
 src/evdev-mt-touchpad.c |   1 +
 src/evdev-tablet.c      |   1 +
 src/evdev.c             |  15 +++
 src/evdev.h             |  10 ++
 src/libinput-private.h  |   1 +
 src/libinput.c          | 163 +++++++++++++++++++++++++++++++
 src/libinput.h          | 252 +++++++++++++++++++++++++++++++++++++++++++++++-
 src/libinput.sym        |  12 +++
 test/litest.c           |   6 ++
 tools/event-debug.c     |  70 ++++++++++++++
 tools/event-gui.c       |   2 +
 11 files changed, 531 insertions(+), 2 deletions(-)

diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c
index ae37ab1..82d789b 100644
--- a/src/evdev-mt-touchpad.c
+++ b/src/evdev-mt-touchpad.c
@@ -1118,6 +1118,7 @@ static struct evdev_dispatch_interface tp_interface = {
 	tp_device_removed, /* device_suspended, treat as remove */
 	tp_device_added,   /* device_resumed, treat as add */
 	tp_tag_device,
+	NULL, /* transform_to_phys */
 };
 
 static void
diff --git a/src/evdev-tablet.c b/src/evdev-tablet.c
index 0d2fc1f..c997aaa 100644
--- a/src/evdev-tablet.c
+++ b/src/evdev-tablet.c
@@ -548,6 +548,7 @@ static struct evdev_dispatch_interface tablet_interface = {
 	NULL, /* device_suspended */
 	NULL, /* device_resumed */
 	NULL, /* tag_device */
+	NULL, /* transform_to_phys */
 };
 
 static int
diff --git a/src/evdev.c b/src/evdev.c
index c52b56c..f7fccdf 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -222,6 +222,18 @@ evdev_device_transform_y(struct evdev_device *device,
 	return scale_axis(device->abs.absinfo_y, y, height);
 }
 
+double
+evdev_device_buttonset_transform_to_phys(struct evdev_device *device,
+					 enum libinput_buttonset_axis axis,
+					 double value)
+{
+	struct evdev_dispatch *dispatch = device->dispatch;
+
+	return dispatch->interface->transform_to_phys(device,
+						      axis,
+						      value);
+}
+
 static void
 evdev_flush_pending_event(struct evdev_device *device, uint64_t time)
 {
@@ -793,6 +805,7 @@ struct evdev_dispatch_interface fallback_interface = {
 	NULL, /* device_suspended */
 	NULL, /* device_resumed */
 	fallback_tag_device,
+	NULL, /* transform_to_phys */
 };
 
 static uint32_t
@@ -1816,6 +1829,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;
 	}
diff --git a/src/evdev.h b/src/evdev.h
index b1d8f4d..918ee2f 100644
--- a/src/evdev.h
+++ b/src/evdev.h
@@ -49,6 +49,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 {
@@ -196,6 +197,10 @@ struct evdev_dispatch_interface {
 	/* Tag device with one of EVDEV_TAG */
 	void (*tag_device)(struct evdev_device *device,
 			   struct udev_device *udev_device);
+
+	double (*transform_to_phys)(struct evdev_device *device,
+				    enum libinput_buttonset_axis axis,
+				    double value);
 };
 
 struct evdev_dispatch {
@@ -276,6 +281,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,
+					 enum libinput_buttonset_axis axis,
+					 double value);
+
 int
 evdev_device_suspend(struct evdev_device *device);
 
diff --git a/src/libinput-private.h b/src/libinput-private.h
index a751990..b876779 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_TILT_Y
+#define LIBINPUT_BUTTONSET_AXIS_MAX LIBINPUT_BUTTONSET_AXIS_STRIP2
 
 struct libinput_source;
 
diff --git a/src/libinput.c b/src/libinput.c
index ae92561..732f9fe 100644
--- a/src/libinput.c
+++ b/src/libinput.c
@@ -90,6 +90,19 @@ struct libinput_event_tablet {
 	struct libinput_tool *tool;
 };
 
+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_AXIS_MAX + 1];
+	double deltas[LIBINPUT_BUTTONSET_AXIS_MAX + 1];
+	double deltas_discrete[LIBINPUT_BUTTONSET_AXIS_MAX + 1];
+	unsigned char changed_axes[NCHARS(LIBINPUT_BUTTONSET_AXIS_MAX + 1)];
+	enum libinput_buttonset_axis_source source;
+};
+
 static void
 libinput_default_log_func(struct libinput *libinput,
 			  enum libinput_log_priority priority,
@@ -197,6 +210,8 @@ libinput_event_get_pointer_event(struct libinput_event *event)
 	case LIBINPUT_EVENT_TABLET_PROXIMITY_IN:
 	case LIBINPUT_EVENT_TABLET_PROXIMITY_OUT:
 	case LIBINPUT_EVENT_TABLET_BUTTON:
+	case LIBINPUT_EVENT_BUTTONSET_AXIS:
+	case LIBINPUT_EVENT_BUTTONSET_BUTTON:
 		break;
 	}
 
@@ -227,6 +242,8 @@ libinput_event_get_keyboard_event(struct libinput_event *event)
 	case LIBINPUT_EVENT_TABLET_PROXIMITY_IN:
 	case LIBINPUT_EVENT_TABLET_PROXIMITY_OUT:
 	case LIBINPUT_EVENT_TABLET_BUTTON:
+	case LIBINPUT_EVENT_BUTTONSET_AXIS:
+	case LIBINPUT_EVENT_BUTTONSET_BUTTON:
 		break;
 	}
 
@@ -257,6 +274,8 @@ libinput_event_get_touch_event(struct libinput_event *event)
 	case LIBINPUT_EVENT_TABLET_PROXIMITY_IN:
 	case LIBINPUT_EVENT_TABLET_PROXIMITY_OUT:
 	case LIBINPUT_EVENT_TABLET_BUTTON:
+	case LIBINPUT_EVENT_BUTTONSET_AXIS:
+	case LIBINPUT_EVENT_BUTTONSET_BUTTON:
 		break;
 	}
 
@@ -287,6 +306,9 @@ libinput_event_get_tablet_event(struct libinput_event *event)
 	case LIBINPUT_EVENT_TABLET_PROXIMITY_OUT:
 	case LIBINPUT_EVENT_TABLET_BUTTON:
 		return (struct libinput_event_tablet *) event;
+	case LIBINPUT_EVENT_BUTTONSET_AXIS:
+	case LIBINPUT_EVENT_BUTTONSET_BUTTON:
+		break;
 	}
 
 	return NULL;
@@ -315,12 +337,45 @@ libinput_event_get_device_notify_event(struct libinput_event *event)
 	case LIBINPUT_EVENT_TABLET_PROXIMITY_IN:
 	case LIBINPUT_EVENT_TABLET_PROXIMITY_OUT:
 	case LIBINPUT_EVENT_TABLET_BUTTON:
+	case LIBINPUT_EVENT_BUTTONSET_AXIS:
+	case LIBINPUT_EVENT_BUTTONSET_BUTTON:
 		break;
 	}
 
 	return NULL;
 }
 
+LIBINPUT_EXPORT struct libinput_event_buttonset *
+libinput_event_get_buttonset_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:
+	case LIBINPUT_EVENT_TABLET_AXIS:
+	case LIBINPUT_EVENT_TABLET_PROXIMITY_IN:
+	case LIBINPUT_EVENT_TABLET_PROXIMITY_OUT:
+	case LIBINPUT_EVENT_TABLET_BUTTON:
+		break;
+	case LIBINPUT_EVENT_BUTTONSET_AXIS:
+	case LIBINPUT_EVENT_BUTTONSET_BUTTON:
+		return (struct libinput_event_buttonset *) event;
+	}
+
+	return NULL;
+}
+
 LIBINPUT_EXPORT uint32_t
 libinput_event_keyboard_get_time(struct libinput_event_keyboard *event)
 {
@@ -706,6 +761,114 @@ 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_has_axis(struct libinput_event_buttonset *event,
+				  enum libinput_buttonset_axis 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,
+					enum libinput_buttonset_axis 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,
+						    enum libinput_buttonset_axis 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,
+					enum libinput_buttonset_axis 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_discrete(struct libinput_event_buttonset *event,
+						 enum libinput_buttonset_axis 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,
+					 enum libinput_buttonset_axis axis)
+{
+	if (!libinput_event_buttonset_has_axis(event, 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,
diff --git a/src/libinput.h b/src/libinput.h
index a8146c0..d777730 100644
--- a/src/libinput.h
+++ b/src/libinput.h
@@ -55,7 +55,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
 };
 
 /**
@@ -148,6 +149,34 @@ enum libinput_tablet_axis {
 /**
  * @ingroup device
  *
+ * Available axis types for a buttonset device. It must have the @ref
+ * LIBINPUT_DEVICE_CAP_BUTTONSET capability.
+ */
+enum libinput_buttonset_axis {
+	LIBINPUT_BUTTONSET_AXIS_RING = 1,
+	LIBINPUT_BUTTONSET_AXIS_RING2 = 2,
+	LIBINPUT_BUTTONSET_AXIS_STRIP = 3,
+	LIBINPUT_BUTTONSET_AXIS_STRIP2 = 4,
+};
+
+/**
+ * @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.
  */
@@ -249,7 +278,10 @@ enum libinput_event_type {
 	 * LIBINPUT_EVENT_DEVICE_REMOVED.
 	 */
 	LIBINPUT_EVENT_TABLET_PROXIMITY_OUT,
-	LIBINPUT_EVENT_TABLET_BUTTON
+	LIBINPUT_EVENT_TABLET_BUTTON,
+
+	LIBINPUT_EVENT_BUTTONSET_AXIS = 700,
+	LIBINPUT_EVENT_BUTTONSET_BUTTON,
 };
 
 /**
@@ -350,6 +382,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
  */
 
@@ -474,6 +516,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 *
@@ -1230,6 +1285,199 @@ void
 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_has_axis(struct libinput_event_buttonset *event,
+				  enum libinput_buttonset_axis 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_RING and @ref
+ *   LIBINPUT_BUTTONSET_AXIS_RING2 - the absolute value of the wheel, 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 and @ref
+ *   LIBINPUT_BUTTONSET_AXIS_STRIP2 - 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.
+ *
+ * @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,
+					enum libinput_buttonset_axis 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,
+						    enum libinput_buttonset_axis 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.
+ * 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,
+				        enum libinput_buttonset_axis axis);
+
+/**
+ * @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,
+						 enum libinput_buttonset_axis 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,
+					 enum libinput_buttonset_axis 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
  */
diff --git a/src/libinput.sym b/src/libinput.sym
index d235e18..3ac32b0 100644
--- a/src/libinput.sym
+++ b/src/libinput.sym
@@ -154,4 +154,16 @@ LIBINPUT_0.11.0 {
 	libinput_device_group_ref;
 	libinput_device_group_set_user_data;
 	libinput_device_group_unref;
+
+	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_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_has_axis;
+	libinput_event_get_buttonset_event;
 } LIBINPUT_0.9.0;
diff --git a/test/litest.c b/test/litest.c
index 73228b4..51bfd24 100644
--- a/test/litest.c
+++ b/test/litest.c
@@ -1161,6 +1161,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 1ca53c4..9dbde99 100644
--- a/tools/event-debug.c
+++ b/tools/event-debug.c
@@ -118,6 +118,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	%s	", libinput_device_get_sysname(dev), type);
@@ -155,6 +161,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);
@@ -252,6 +261,61 @@ 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);
+	enum libinput_buttonset_axis axis = 0;
+	const char *axis_name;
+	double val, delta;
+
+	print_event_time(libinput_event_buttonset_get_time(b));
+
+	while (++axis <= LIBINPUT_BUTTONSET_AXIS_STRIP2) {
+		if (!libinput_event_buttonset_has_axis(b, axis))
+			continue;
+
+		val = libinput_event_buttonset_get_axis_value(b, axis);
+		delta = libinput_event_buttonset_get_axis_delta(b, axis);
+		switch(axis) {
+		case LIBINPUT_BUTTONSET_AXIS_RING:
+			axis_name = "ring";
+			break;
+		case LIBINPUT_BUTTONSET_AXIS_RING2:
+			axis_name = "ring2";
+			break;
+		case LIBINPUT_BUTTONSET_AXIS_STRIP:
+			axis_name = "strip";
+			break;
+		case LIBINPUT_BUTTONSET_AXIS_STRIP2:
+			axis_name = "strip2";
+			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);
@@ -451,6 +515,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 1857a2e..92ce27b 100644
--- a/tools/event-gui.c
+++ b/tools/event-gui.c
@@ -474,6 +474,8 @@ handle_event_libinput(GIOChannel *source, GIOCondition condition, gpointer data)
 		case LIBINPUT_EVENT_TABLET_PROXIMITY_IN:
 		case LIBINPUT_EVENT_TABLET_PROXIMITY_OUT:
 		case LIBINPUT_EVENT_TABLET_BUTTON:
+		case LIBINPUT_EVENT_BUTTONSET_AXIS:
+		case LIBINPUT_EVENT_BUTTONSET_BUTTON:
 			break;
 		}
 
-- 
2.1.0



More information about the wayland-devel mailing list