[PATCH v2 libinput 2/5] Add the LIBINPUT_DEVICE_CAP_TABLET_PAD capability and matching interface

Peter Hutterer peter.hutterer at who-t.net
Mon Apr 11 04:15:29 UTC 2016


This interface handles the buttons on the physical tablet itself, including
the touch ring and the strip.

A notable difference to other libinput interfaces here is that we do not use
linux/input.h event codes for buttons. Instead, the buttons are merely
numbered sequentially, starting at button 1. This means:
* the API is different, instead of get_button() we have get_button_number() to
  drive the point home
* there is no seat button count. pads are inherently different devices and
  compositors should treat them as such. The seat button count makes sense
  when you want to know how many devices have BTN_LEFT down, but it makes no
  sense for buttons where all the semantics are handled by the compositor
  anyway.

Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
Changes to v1:
- squashed left-handed patch (previously separate) into this one
- change from linux/input.h-style button numbering to simple sequential
  numbers
- dropped the seat button count bits

 doc/tablet-support.dox |  31 ++++-
 src/libinput-private.h |  18 +++
 src/libinput.c         | 257 ++++++++++++++++++++++++++++++++++++++++
 src/libinput.h         | 313 ++++++++++++++++++++++++++++++++++++++++++++++++-
 src/libinput.sym       |  19 +++
 test/litest.c          |   9 ++
 tools/event-debug.c    |  81 +++++++++++++
 tools/event-gui.c      |   4 +
 8 files changed, 729 insertions(+), 3 deletions(-)

diff --git a/doc/tablet-support.dox b/doc/tablet-support.dox
index 35b9230..8bfdf58 100644
--- a/doc/tablet-support.dox
+++ b/doc/tablet-support.dox
@@ -8,7 +8,7 @@ Apple iPad.
 
 @image html tablet.svg "Illustration of a graphics tablet"
 
- at section tablet-tools Tablet buttons vs. tablet tools
+ at section tablet-tools Pad buttons vs. tablet tools
 
 Most tablets provide two types of devices. The pysical tablet often provides
 a number of buttons and a touch ring or strip. Interaction on the drawing
@@ -17,6 +17,12 @@ The libinput interface exposed by devices with the @ref
 LIBINPUT_DEVICE_CAP_TABLET_TOOL capability applies only to events generated
 by tools.
 
+Buttons, rings or strips on the physical tablet hardware (the "pad") are
+exposed by devices with the @ref LIBINPUT_DEVICE_CAP_TABLET_PAD capability.
+Pad events do not require a tool to be in proximity. Note that both
+capabilities may exist on the same device though usually they are split
+across multiple kernel devices.
+
 Touch events on the tablet integrated into a screen itself are exposed
 through the @ref LIBINPUT_DEVICE_CAP_TOUCH capability. Touch events on a
 standalone tablet are exposed through the @ref LIBINPUT_DEVICE_CAP_POINTER
@@ -25,7 +31,7 @@ node for the touch device, resulting in a separate libinput device.
 See libinput_device_get_device_group() for information on how to associate
 the touch part with other devices exposed by the same physical hardware.
 
- at section tablet-tip Tool tip events vs. button events
+ at section tablet-tip Tool tip events vs. tool button events
 
 The primary use of a tablet tool is to draw on the surface of the tablet.
 When the tool tip comes into contact with the surface, libinput sends an
@@ -113,6 +119,8 @@ tablets however extends further than the user may lift the mouse, i.e. the
 tool may not be lifted out of physical proximity. For such tools, libinput 
 provides software-emulated proximity. 
 
+Events from the pad do not require proximity, they may be sent any time.
+
 @section tablet-pressure-offset Pressure offset on worn-out tools
 
 When a tool is used for an extended period it can wear down physically. A
@@ -209,4 +217,23 @@ libinput_event_tablet_tool_get_y_transformed() the resulting value may be
 less than 0 or larger than the upper range provided. It is up to the caller
 to test for this and handle or ignore these events accordingly.
 
+ at section tablet-pad-buttons Tablet pad button numbers
+
+Tablet Pad buttons are numbered sequentially, starting with button 0. Thus
+button numbers returned by libinput_event_tablet_pad_get_button_number()
+have no semantic meaning, a notable difference to the button codes returned
+by other libinput interfaces (e.g. libinput_event_tablet_tool_get_button()).
+
+The Linux kernel requires all input events to have semantic event codes,
+but generic buttons like those on a pad cannot easily be assigned semantic
+codes. The kernel supports generic codes in the form of BTN_0 through to
+BTN_9 and additional unnamed space up until code 0x10f. Additional generic
+buttons are available as BTN_A in the range dedicated for gamepads and
+joysticks. Thus, tablet with a large number of buttons have to map across
+two semantic ranges, have to use unnamed kernel button codes or risk leaking
+into an unrelated range. libinput transparently maps the kernel event codes
+into a sequential button range on the pad. Callers should use external
+sources like libwacom to associate button numbers to their position on the
+tablet.
+
 */
diff --git a/src/libinput-private.h b/src/libinput-private.h
index 8d2492a..539e69a 100644
--- a/src/libinput-private.h
+++ b/src/libinput-private.h
@@ -544,6 +544,24 @@ tablet_notify_button(struct libinput_device *device,
 		     int32_t button,
 		     enum libinput_button_state state);
 
+void
+tablet_pad_notify_button(struct libinput_device *device,
+			 uint64_t time,
+			 int32_t button,
+			 enum libinput_button_state state);
+void
+tablet_pad_notify_ring(struct libinput_device *device,
+		       uint64_t time,
+		       unsigned int number,
+		       double value,
+		       enum libinput_tablet_pad_ring_axis_source source);
+void
+tablet_pad_notify_strip(struct libinput_device *device,
+			uint64_t time,
+			unsigned int number,
+			double value,
+			enum libinput_tablet_pad_strip_axis_source source);
+
 static inline uint64_t
 libinput_now(struct libinput *libinput)
 {
diff --git a/src/libinput.c b/src/libinput.c
index b6e660a..53da963 100644
--- a/src/libinput.c
+++ b/src/libinput.c
@@ -138,6 +138,23 @@ struct libinput_event_tablet_tool {
 	enum libinput_tablet_tool_tip_state tip_state;
 };
 
+struct libinput_event_tablet_pad {
+	struct libinput_event base;
+	uint32_t button;
+	enum libinput_button_state state;
+	uint64_t time;
+	struct {
+		enum libinput_tablet_pad_ring_axis_source source;
+		double position;
+		int number;
+	} ring;
+	struct {
+		enum libinput_tablet_pad_strip_axis_source source;
+		double position;
+		int number;
+	} strip;
+};
+
 static void
 libinput_default_log_func(struct libinput *libinput,
 			  enum libinput_log_priority priority,
@@ -318,6 +335,19 @@ libinput_event_get_tablet_tool_event(struct libinput_event *event)
 	return (struct libinput_event_tablet_tool *) event;
 }
 
+LIBINPUT_EXPORT struct libinput_event_tablet_pad *
+libinput_event_get_tablet_pad_event(struct libinput_event *event)
+{
+	require_event_type(libinput_event_get_context(event),
+			   event->type,
+			   NULL,
+			   LIBINPUT_EVENT_TABLET_PAD_RING,
+			   LIBINPUT_EVENT_TABLET_PAD_STRIP,
+			   LIBINPUT_EVENT_TABLET_PAD_BUTTON);
+
+	return (struct libinput_event_tablet_pad *) event;
+}
+
 LIBINPUT_EXPORT struct libinput_event_device_notify *
 libinput_event_get_device_notify_event(struct libinput_event *event)
 {
@@ -1956,6 +1986,9 @@ device_has_cap(struct libinput_device *device,
 	case LIBINPUT_DEVICE_CAP_TABLET_TOOL:
 		capability = "CAP_TABLET_TOOL";
 		break;
+	case LIBINPUT_DEVICE_CAP_TABLET_PAD:
+		capability = "CAP_TABLET_PAD";
+		break;
 	}
 
 	log_bug_libinput(device->seat->libinput,
@@ -2343,6 +2376,82 @@ tablet_notify_button(struct libinput_device *device,
 			  &button_event->base);
 }
 
+void
+tablet_pad_notify_button(struct libinput_device *device,
+			 uint64_t time,
+			 int32_t button,
+			 enum libinput_button_state state)
+{
+	struct libinput_event_tablet_pad *button_event;
+
+	button_event = zalloc(sizeof *button_event);
+	if (!button_event)
+		return;
+
+	*button_event = (struct libinput_event_tablet_pad) {
+		.time = time,
+		.button = button,
+		.state = state,
+	};
+
+	post_device_event(device,
+			  time,
+			  LIBINPUT_EVENT_TABLET_PAD_BUTTON,
+			  &button_event->base);
+}
+
+void
+tablet_pad_notify_ring(struct libinput_device *device,
+		       uint64_t time,
+		       unsigned int number,
+		       double value,
+		       enum libinput_tablet_pad_ring_axis_source source)
+{
+	struct libinput_event_tablet_pad *ring_event;
+
+	ring_event = zalloc(sizeof *ring_event);
+	if (!ring_event)
+		return;
+
+	*ring_event = (struct libinput_event_tablet_pad) {
+		.time = time,
+		.ring.number = number,
+		.ring.position = value,
+		.ring.source = source,
+	};
+
+	post_device_event(device,
+			  time,
+			  LIBINPUT_EVENT_TABLET_PAD_RING,
+			  &ring_event->base);
+}
+
+void
+tablet_pad_notify_strip(struct libinput_device *device,
+			uint64_t time,
+			unsigned int number,
+			double value,
+			enum libinput_tablet_pad_strip_axis_source source)
+{
+	struct libinput_event_tablet_pad *strip_event;
+
+	strip_event = zalloc(sizeof *strip_event);
+	if (!strip_event)
+		return;
+
+	*strip_event = (struct libinput_event_tablet_pad) {
+		.time = time,
+		.strip.number = number,
+		.strip.position = value,
+		.strip.source = source,
+	};
+
+	post_device_event(device,
+			  time,
+			  LIBINPUT_EVENT_TABLET_PAD_STRIP,
+			  &strip_event->base);
+}
+
 static void
 gesture_notify(struct libinput_device *device,
 	       uint64_t time,
@@ -2448,6 +2557,9 @@ event_type_to_str(enum libinput_event_type type)
 	CASE_RETURN_STRING(LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
 	CASE_RETURN_STRING(LIBINPUT_EVENT_TABLET_TOOL_TIP);
 	CASE_RETURN_STRING(LIBINPUT_EVENT_TABLET_TOOL_BUTTON);
+	CASE_RETURN_STRING(LIBINPUT_EVENT_TABLET_PAD_BUTTON);
+	CASE_RETURN_STRING(LIBINPUT_EVENT_TABLET_PAD_RING);
+	CASE_RETURN_STRING(LIBINPUT_EVENT_TABLET_PAD_STRIP);
 	CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN);
 	CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE);
 	CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_SWIPE_END);
@@ -2679,6 +2791,24 @@ libinput_device_keyboard_has_key(struct libinput_device *device, uint32_t code)
 	return evdev_device_has_key((struct evdev_device *)device, code);
 }
 
+LIBINPUT_EXPORT int
+libinput_device_tablet_pad_get_num_buttons(struct libinput_device *device)
+{
+	return 0;
+}
+
+LIBINPUT_EXPORT int
+libinput_device_tablet_pad_get_num_rings(struct libinput_device *device)
+{
+	return 0;
+}
+
+LIBINPUT_EXPORT int
+libinput_device_tablet_pad_get_num_strips(struct libinput_device *device)
+{
+	return 0;
+}
+
 LIBINPUT_EXPORT struct libinput_event *
 libinput_event_device_notify_get_base_event(struct libinput_event_device_notify *event)
 {
@@ -2751,6 +2881,133 @@ libinput_event_tablet_tool_get_base_event(struct libinput_event_tablet_tool *eve
 	return &event->base;
 }
 
+LIBINPUT_EXPORT double
+libinput_event_tablet_pad_get_ring_position(struct libinput_event_tablet_pad *event)
+{
+	require_event_type(libinput_event_get_context(&event->base),
+			   event->base.type,
+			   0.0,
+			   LIBINPUT_EVENT_TABLET_PAD_RING);
+
+	return event->ring.position;
+}
+
+LIBINPUT_EXPORT unsigned int
+libinput_event_tablet_pad_get_ring_number(struct libinput_event_tablet_pad *event)
+{
+	require_event_type(libinput_event_get_context(&event->base),
+			   event->base.type,
+			   0,
+			   LIBINPUT_EVENT_TABLET_PAD_RING);
+
+	return event->ring.number;
+}
+
+LIBINPUT_EXPORT enum libinput_tablet_pad_ring_axis_source
+libinput_event_tablet_pad_get_ring_source(struct libinput_event_tablet_pad *event)
+{
+	require_event_type(libinput_event_get_context(&event->base),
+			   event->base.type,
+			   LIBINPUT_TABLET_PAD_RING_SOURCE_UNKNOWN,
+			   LIBINPUT_EVENT_TABLET_PAD_RING);
+
+	return event->ring.source;
+}
+
+LIBINPUT_EXPORT double
+libinput_event_tablet_pad_get_strip_position(struct libinput_event_tablet_pad *event)
+{
+	require_event_type(libinput_event_get_context(&event->base),
+			   event->base.type,
+			   0.0,
+			   LIBINPUT_EVENT_TABLET_PAD_STRIP);
+
+	return event->strip.position;
+}
+
+LIBINPUT_EXPORT unsigned int
+libinput_event_tablet_pad_get_strip_number(struct libinput_event_tablet_pad *event)
+{
+	require_event_type(libinput_event_get_context(&event->base),
+			   event->base.type,
+			   0,
+			   LIBINPUT_EVENT_TABLET_PAD_STRIP);
+
+	return event->strip.number;
+}
+
+LIBINPUT_EXPORT enum libinput_tablet_pad_strip_axis_source
+libinput_event_tablet_pad_get_strip_source(struct libinput_event_tablet_pad *event)
+{
+	require_event_type(libinput_event_get_context(&event->base),
+			   event->base.type,
+			   LIBINPUT_TABLET_PAD_STRIP_SOURCE_UNKNOWN,
+			   LIBINPUT_EVENT_TABLET_PAD_STRIP);
+
+	return event->strip.source;
+}
+
+LIBINPUT_EXPORT uint32_t
+libinput_event_tablet_pad_get_button_number(struct libinput_event_tablet_pad *event)
+{
+	require_event_type(libinput_event_get_context(&event->base),
+			   event->base.type,
+			   0,
+			   LIBINPUT_EVENT_TABLET_PAD_BUTTON);
+
+	return event->button;
+}
+
+LIBINPUT_EXPORT enum libinput_button_state
+libinput_event_tablet_pad_get_button_state(struct libinput_event_tablet_pad *event)
+{
+	require_event_type(libinput_event_get_context(&event->base),
+			   event->base.type,
+			   0,
+			   LIBINPUT_EVENT_TABLET_PAD_BUTTON);
+
+	return event->state;
+}
+
+LIBINPUT_EXPORT uint32_t
+libinput_event_tablet_pad_get_time(struct libinput_event_tablet_pad *event)
+{
+	require_event_type(libinput_event_get_context(&event->base),
+			   event->base.type,
+			   0,
+			   LIBINPUT_EVENT_TABLET_PAD_RING,
+			   LIBINPUT_EVENT_TABLET_PAD_STRIP,
+			   LIBINPUT_EVENT_TABLET_PAD_BUTTON);
+
+	return us2ms(event->time);
+}
+
+LIBINPUT_EXPORT uint64_t
+libinput_event_tablet_pad_get_time_usec(struct libinput_event_tablet_pad *event)
+{
+	require_event_type(libinput_event_get_context(&event->base),
+			   event->base.type,
+			   0,
+			   LIBINPUT_EVENT_TABLET_PAD_RING,
+			   LIBINPUT_EVENT_TABLET_PAD_STRIP,
+			   LIBINPUT_EVENT_TABLET_PAD_BUTTON);
+
+	return event->time;
+}
+
+LIBINPUT_EXPORT struct libinput_event *
+libinput_event_tablet_pad_get_base_event(struct libinput_event_tablet_pad *event)
+{
+	require_event_type(libinput_event_get_context(&event->base),
+			   event->base.type,
+			   NULL,
+			   LIBINPUT_EVENT_TABLET_PAD_RING,
+			   LIBINPUT_EVENT_TABLET_PAD_STRIP,
+			   LIBINPUT_EVENT_TABLET_PAD_BUTTON);
+
+	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 3449611..da8f4e3 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_TABLET_PAD = 4,
 	LIBINPUT_DEVICE_CAP_GESTURE = 5,
 };
 
@@ -135,6 +136,36 @@ enum libinput_pointer_axis_source {
 };
 
 /**
+ * @ingroup event_tablet
+ *
+ * The source for a @ref LIBINPUT_EVENT_TABLET_PAD_RING event. See
+ * libinput_event_tablet_pad_get_ring_source() for details.
+ */
+enum libinput_tablet_pad_ring_axis_source {
+	LIBINPUT_TABLET_PAD_RING_SOURCE_UNKNOWN = 1,
+	/**
+	 * The event is caused by the movement of one or more fingers on
+	 * the ring.
+	 */
+	LIBINPUT_TABLET_PAD_RING_SOURCE_FINGER,
+};
+
+/**
+ * @ingroup event_tablet
+ *
+ * The source for a @ref LIBINPUT_EVENT_TABLET_PAD_STRIP event. See
+ * libinput_event_tablet_pad_get_strip_source() for details.
+ */
+enum libinput_tablet_pad_strip_axis_source {
+	LIBINPUT_TABLET_PAD_STRIP_SOURCE_UNKNOWN = 1,
+	/**
+	 * The event is caused by the movement of one or more fingers on
+	 * the strip.
+	 */
+	LIBINPUT_TABLET_PAD_STRIP_SOURCE_FINGER,
+};
+
+/**
  * @ingroup device
  * @struct libinput_tablet_tool
  *
@@ -336,9 +367,34 @@ enum libinput_event_type {
 	 * same logical hardware event, the order of the @ref
 	 * LIBINPUT_EVENT_TABLET_TOOL_BUTTON and @ref
 	 * LIBINPUT_EVENT_TABLET_TOOL_AXIS event is device-specific.
+	 *
+	 * This event is not to be confused with the button events emitted
+	 * by the tablet pad. See @ref LIBINPUT_EVENT_TABLET_PAD_BUTTON.
+	 *
+	 * @see LIBINPUT_EVENT_TABLET_BUTTON
 	 */
 	LIBINPUT_EVENT_TABLET_TOOL_BUTTON,
 
+	/**
+	 * A button pressed on a device with the @ref
+	 * LIBINPUT_DEVICE_CAP_TABLET_PAD capability.
+	 *
+	 * This event is not to be confused with the button events emitted
+	 * by tools on a tablet. See @ref LIBINPUT_EVENT_TABLET_TOOL_BUTTON.
+	 */
+	LIBINPUT_EVENT_TABLET_PAD_BUTTON = 700,
+	/**
+	 * A status change on a tablet ring with the
+	 * LIBINPUT_DEVICE_CAP_TABLET_PAD capability.
+	 */
+	LIBINPUT_EVENT_TABLET_PAD_RING,
+
+	/**
+	 * A status change on a strip on a device with the @ref
+	 * LIBINPUT_DEVICE_CAP_TABLET_PAD capability.
+	 */
+	LIBINPUT_EVENT_TABLET_PAD_STRIP,
+
 	LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN = 800,
 	LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE,
 	LIBINPUT_EVENT_GESTURE_SWIPE_END,
@@ -446,6 +502,17 @@ struct libinput_event_touch;
 struct libinput_event_tablet_tool;
 
 /**
+ * @ingroup event_tablet
+ * @struct libinput_event_tablet_pad
+ *
+ * Tablet pad event representing an button press, or ring/strip update on
+ * the tablet pad itself. Valid event types for this event are @ref
+ * LIBINPUT_EVENT_TABLET_PAD_BUTTON, @ref LIBINPUT_EVENT_TABLET_PAD_RING and
+ * @ref LIBINPUT_EVENT_TABLET_PAD_STRIP.
+ */
+struct libinput_event_tablet_pad;
+
+/**
  * @defgroup event Accessing and destruction of events
  */
 
@@ -569,6 +636,19 @@ libinput_event_get_tablet_tool_event(struct libinput_event *event);
 /**
  * @ingroup event
  *
+ * Return the tablet pad event that is this input event. If the event type does not
+ * match the tablet pad event types, this function returns NULL.
+ *
+ * The inverse of this function is libinput_event_tablet_pad_get_base_event().
+ *
+ * @return A tablet pad event, or NULL for other events
+ */
+struct libinput_event_tablet_pad *
+libinput_event_get_tablet_pad_event(struct libinput_event *event);
+
+/**
+ * @ingroup event
+ *
  * Return the device event that is this input event. If the event type does
  * not match the device event types, this function returns NULL.
  *
@@ -1357,7 +1437,17 @@ libinput_event_gesture_get_angle_delta(struct libinput_event_gesture *event);
 /**
  * @defgroup event_tablet Tablet events
  *
- * Events that come from tools on tablet devices.
+ * Events that come from tools on or the pad of tablet devices.
+ *
+ * Events from tablet devices are exposed by two interfaces, tools and pads.
+ * Tool events originate (usually) from a stylus-like device, pad events
+ * reflect any events originating fom the physical tablet itself.
+ *
+ * Note that many tablets support touch events. These are exposed through
+ * the @ref LIBINPUT_DEVICE_CAP_POINTER interface (for external touchpad-like
+ * devices such as the Wacom Intuos series) or @ref
+ * LIBINPUT_DEVICE_CAP_TOUCH interface (for built-in touchscreen-like
+ * devices such as the Wacom Cintiq series).
  */
 
 /**
@@ -2106,6 +2196,182 @@ libinput_tablet_tool_set_user_data(struct libinput_tablet_tool *tool,
 				   void *user_data);
 
 /**
+ * @ingroup event_tablet
+ *
+ * @return The generic libinput_event of this event
+ */
+struct libinput_event *
+libinput_event_tablet_pad_get_base_event(struct libinput_event_tablet_pad *event);
+
+/**
+ * @ingroup event_tablet
+ *
+ * Returns the current position of the ring, in degrees counterclockwise
+ * from the northern-most point of the ring in the tablet's current logical
+ * orientation.
+ *
+ * If the source is @ref LIBINPUT_TABLET_PAD_RING_SOURCE_FINGER,
+ * libinput sends a terminating event with a ring value of -1 when the
+ * finger is lifted from the ring. A caller may use this information to e.g.
+ * determine if kinetic scrolling should be triggered.
+ *
+ * @note It is an application bug to call this function for events other than
+ * @ref LIBINPUT_EVENT_TABLET_PAD_RING.  For other events, this function
+ * returns 0.
+ *
+ * @param event The libinput tablet pad event
+ * @return The current value of the the axis
+ * @retval -1 The finger was lifted
+ */
+double
+libinput_event_tablet_pad_get_ring_position(struct libinput_event_tablet_pad *event);
+
+/**
+ * @ingroup event_tablet
+ *
+ * Returns the number of the ring that has changed state, with 0 being the
+ * first ring. On tablets with only one ring, this function always returns
+ * 0.
+ *
+ * @note It is an application bug to call this function for events other than
+ * @ref LIBINPUT_EVENT_TABLET_PAD_RING.  For other events, this function
+ * returns 0.
+ *
+ * @param event The libinput tablet pad event
+ * @return The index of the ring that changed state
+ */
+unsigned int
+libinput_event_tablet_pad_get_ring_number(struct libinput_event_tablet_pad *event);
+
+/**
+ * @ingroup event_tablet
+ *
+ * Returns the source of the interaction with the ring. If the source is
+ * @ref LIBINPUT_TABLET_PAD_RING_SOURCE_FINGER, libinput sends a ring
+ * position value of -1 to terminate the current interaction.
+ *
+ * @note It is an application bug to call this function for events other than
+ * @ref LIBINPUT_EVENT_TABLET_PAD_RING.  For other events, this function
+ * returns 0.
+ *
+ * @param event The libinput tablet pad event
+ * @return The source of the ring interaction
+ */
+enum libinput_tablet_pad_ring_axis_source
+libinput_event_tablet_pad_get_ring_source(struct libinput_event_tablet_pad *event);
+
+/**
+ * @ingroup event_tablet
+ *
+ * Returns the current position of the strip, normalized to the range
+ * [0, 1], with 0 being the top/left-most point in the tablet's current
+ * logical orientation.
+ *
+ * If the source is @ref LIBINPUT_TABLET_PAD_STRIP_SOURCE_FINGER,
+ * libinput sends a terminating event with a ring value of -1 when the
+ * finger is lifted from the ring. A caller may use this information to e.g.
+ * determine if kinetic scrolling should be triggered.
+ *
+ * @note It is an application bug to call this function for events other than
+ * @ref LIBINPUT_EVENT_TABLET_PAD_STRIP.  For other events, this function
+ * returns 0.
+ *
+ * @param event The libinput tablet pad event
+ * @return The current value of the the axis
+ * @retval -1 The finger was lifted
+ */
+double
+libinput_event_tablet_pad_get_strip_position(struct libinput_event_tablet_pad *event);
+
+/**
+ * @ingroup event_tablet
+ *
+ * Returns the number of the strip that has changed state, with 0 being the
+ * first strip. On tablets with only one strip, this function always returns
+ * 0.
+ *
+ * @note It is an application bug to call this function for events other than
+ * @ref LIBINPUT_EVENT_TABLET_PAD_STRIP.  For other events, this function
+ * returns 0.
+ *
+ * @param event The libinput tablet pad event
+ * @return The index of the strip that changed state
+ */
+unsigned int
+libinput_event_tablet_pad_get_strip_number(struct libinput_event_tablet_pad *event);
+
+/**
+ * @ingroup event_tablet
+ *
+ * Returns the source of the interaction with the strip. If the source is
+ * @ref LIBINPUT_TABLET_PAD_STRIP_SOURCE_FINGER, libinput sends a strip
+ * position value of -1 to terminate the current interaction.
+ *
+ * @note It is an application bug to call this function for events other than
+ * @ref LIBINPUT_EVENT_TABLET_PAD_STRIP.  For other events, this function
+ * returns 0.
+ *
+ * @param event The libinput tablet pad event
+ * @return The source of the strip interaction
+ */
+enum libinput_tablet_pad_strip_axis_source
+libinput_event_tablet_pad_get_strip_source(struct libinput_event_tablet_pad *event);
+
+/**
+ * @ingroup event_tablet
+ *
+ * Return the button number that triggered this event, starting at 0.
+ * For events that are not of type @ref LIBINPUT_EVENT_TABLET_PAD_BUTTON,
+ * this function returns 0.
+ *
+ * Note that the number returned is a generic sequential button number and
+ * not a semantics button code as defined in linux/input.h.
+ * See @ref tablet-pad-buttons for more details.
+ *
+ * @note It is an application bug to call this function for events other than
+ * @ref LIBINPUT_EVENT_TABLET_PAD_BUTTON. For other events, this function
+ * returns 0.
+ *
+ * @param event The libinput tablet pad event
+ * @return the button triggering this event
+ */
+uint32_t
+libinput_event_tablet_pad_get_button_number(struct libinput_event_tablet_pad *event);
+
+/**
+ * @ingroup event_tablet
+ *
+ * Return the button state of the event.
+ *
+ * @note It is an application bug to call this function for events other than
+ * @ref LIBINPUT_EVENT_TABLET_PAD_BUTTON. For other events, this function
+ * returns 0.
+ *
+ * @param event The libinput tablet pad event
+ * @return the button state triggering this event
+ */
+enum libinput_button_state
+libinput_event_tablet_pad_get_button_state(struct libinput_event_tablet_pad *event);
+
+/**
+ * @ingroup event_tablet
+ *
+ * @param event The libinput tablet pad event
+ * @return The event time for this event
+ */
+uint32_t
+libinput_event_tablet_pad_get_time(struct libinput_event_tablet_pad *event);
+
+/**
+ * @ingroup event_tablet
+ *
+ * @param event The libinput tablet pad event
+ * @return The event time for this event in microseconds
+ */
+uint64_t
+libinput_event_tablet_pad_get_time_usec(struct libinput_event_tablet_pad *event);
+
+/**
  * @defgroup base Initialization and manipulation of libinput contexts
  */
 
@@ -2934,6 +3200,51 @@ libinput_device_keyboard_has_key(struct libinput_device *device,
 /**
  * @ingroup device
  *
+ * Return the number of buttons on a device with the
+ * @ref LIBINPUT_DEVICE_CAP_TABLET_PAD capability.
+ * Buttons on a pad device are numbered sequentially, see @ref
+ * tablet-pad-buttons for details.
+ *
+ * @param device A current input device
+ *
+ * @return The number of buttons supported by the device.
+ */
+int
+libinput_device_tablet_pad_get_num_buttons(struct libinput_device *device);
+
+/**
+ * @ingroup device
+ *
+ * Return the number of rings a device with the @ref
+ * LIBINPUT_DEVICE_CAP_TABLET_PAD capability provides.
+ *
+ * @param device A current input device
+ *
+ * @return The number of rings or 0 if the device has no rings.
+ *
+ * @see libinput_event_tablet_pad_get_ring_number
+ */
+int
+libinput_device_tablet_pad_get_num_rings(struct libinput_device *device);
+
+/**
+ * @ingroup device
+ *
+ * Return the number of strips a device with the @ref
+ * LIBINPUT_DEVICE_CAP_TABLET_PAD capability provides.
+ *
+ * @param device A current input device
+ *
+ * @return The number of strips or 0 if the device has no strips.
+ *
+ * @see libinput_event_tablet_pad_get_strip_number
+ */
+int
+libinput_device_tablet_pad_get_num_strips(struct libinput_device *device);
+
+/**
+ * @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 a211388..0fe8998 100644
--- a/src/libinput.sym
+++ b/src/libinput.sym
@@ -234,3 +234,22 @@ LIBINPUT_1.2 {
 	libinput_tablet_tool_set_user_data;
 	libinput_tablet_tool_unref;
 } LIBINPUT_1.1;
+
+TABLET_PAD {
+	libinput_device_tablet_pad_get_num_buttons;
+	libinput_device_tablet_pad_get_num_rings;
+	libinput_device_tablet_pad_get_num_strips;
+	libinput_event_get_tablet_pad_event;
+	libinput_event_tablet_pad_get_base_event;
+	libinput_event_tablet_pad_get_button_number;
+	libinput_event_tablet_pad_get_button_state;
+	libinput_event_tablet_pad_get_ring_position;
+	libinput_event_tablet_pad_get_ring_number;
+	libinput_event_tablet_pad_get_ring_source;
+	libinput_event_tablet_pad_get_strip_position;
+	libinput_event_tablet_pad_get_strip_number;
+	libinput_event_tablet_pad_get_strip_source;
+	libinput_event_tablet_pad_get_time;
+	libinput_event_tablet_pad_get_time_usec;
+
+} LIBINPUT_1.2;
diff --git a/test/litest.c b/test/litest.c
index 67ff937..70b4bd3 100644
--- a/test/litest.c
+++ b/test/litest.c
@@ -1963,6 +1963,15 @@ litest_event_type_str(struct libinput_event *event)
 	case LIBINPUT_EVENT_TABLET_TOOL_BUTTON:
 		str = "TABLET TOOL BUTTON";
 		break;
+	case LIBINPUT_EVENT_TABLET_PAD_BUTTON:
+		str = "TABLET PAD BUTTON";
+		break;
+	case LIBINPUT_EVENT_TABLET_PAD_RING:
+		str = "TABLET PAD RING";
+		break;
+	case LIBINPUT_EVENT_TABLET_PAD_STRIP:
+		str = "TABLET PAD STRIP";
+		break;
 	}
 	return str;
 }
diff --git a/tools/event-debug.c b/tools/event-debug.c
index 079029b..aa64e7d 100644
--- a/tools/event-debug.c
+++ b/tools/event-debug.c
@@ -121,6 +121,15 @@ print_event_header(struct libinput_event *ev)
 	case LIBINPUT_EVENT_TABLET_TOOL_BUTTON:
 		type = "TABLET_TOOL_BUTTON";
 		break;
+	case LIBINPUT_EVENT_TABLET_PAD_BUTTON:
+		type = "TABLET_PAD_BUTTON";
+		break;
+	case LIBINPUT_EVENT_TABLET_PAD_RING:
+		type = "TABLET_PAD_RING";
+		break;
+	case LIBINPUT_EVENT_TABLET_PAD_STRIP:
+		type = "TABLET_PAD_STRIP";
+		break;
 	}
 
 	printf("%-7s	%-16s ", libinput_device_get_sysname(dev), type);
@@ -172,6 +181,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_TABLET_PAD))
+		printf("P");
 
 	if (libinput_device_get_size(dev, &w, &h) == 0)
 		printf("\tsize %.2f/%.2fmm", w, h);
@@ -574,6 +586,66 @@ print_gesture_event_with_coords(struct libinput_event *ev)
 	}
 }
 
+static void
+print_tablet_pad_button_event(struct libinput_event *ev)
+{
+	struct libinput_event_tablet_pad *p = libinput_event_get_tablet_pad_event(ev);
+	enum libinput_button_state state;
+
+	print_event_time(libinput_event_tablet_pad_get_time(p));
+
+	state = libinput_event_tablet_pad_get_button_state(p);
+	printf("%3d %s\n",
+	       libinput_event_tablet_pad_get_button_number(p),
+	       state == LIBINPUT_BUTTON_STATE_PRESSED ? "pressed" : "released");
+}
+
+static void
+print_tablet_pad_ring_event(struct libinput_event *ev)
+{
+	struct libinput_event_tablet_pad *p = libinput_event_get_tablet_pad_event(ev);
+	const char *source = "<invalid>";
+
+	print_event_time(libinput_event_tablet_pad_get_time(p));
+
+	switch (libinput_event_tablet_pad_get_ring_source(p)) {
+	case LIBINPUT_TABLET_PAD_RING_SOURCE_FINGER:
+		source = "finger";
+		break;
+	case LIBINPUT_TABLET_PAD_RING_SOURCE_UNKNOWN:
+		source = "unknown";
+		break;
+	}
+
+	printf("ring %d position %.2f (source %s)\n",
+	       libinput_event_tablet_pad_get_ring_number(p),
+	       libinput_event_tablet_pad_get_ring_position(p),
+	       source);
+}
+
+static void
+print_tablet_pad_strip_event(struct libinput_event *ev)
+{
+	struct libinput_event_tablet_pad *p = libinput_event_get_tablet_pad_event(ev);
+	const char *source = "<invalid>";
+
+	print_event_time(libinput_event_tablet_pad_get_time(p));
+
+	switch (libinput_event_tablet_pad_get_strip_source(p)) {
+	case LIBINPUT_TABLET_PAD_STRIP_SOURCE_FINGER:
+		source = "finger";
+		break;
+	case LIBINPUT_TABLET_PAD_STRIP_SOURCE_UNKNOWN:
+		source = "unknown";
+		break;
+	}
+
+	printf("strip %d position %.2f (source %s)\n",
+	       libinput_event_tablet_pad_get_strip_number(p),
+	       libinput_event_tablet_pad_get_strip_position(p),
+	       source);
+}
+
 static int
 handle_and_print_events(struct libinput *li)
 {
@@ -653,6 +725,15 @@ handle_and_print_events(struct libinput *li)
 		case LIBINPUT_EVENT_TABLET_TOOL_BUTTON:
 			print_tablet_button_event(ev);
 			break;
+		case LIBINPUT_EVENT_TABLET_PAD_BUTTON:
+			print_tablet_pad_button_event(ev);
+			break;
+		case LIBINPUT_EVENT_TABLET_PAD_RING:
+			print_tablet_pad_ring_event(ev);
+			break;
+		case LIBINPUT_EVENT_TABLET_PAD_STRIP:
+			print_tablet_pad_strip_event(ev);
+			break;
 		}
 
 		libinput_event_destroy(ev);
diff --git a/tools/event-gui.c b/tools/event-gui.c
index 9d541a3..791a1ea 100644
--- a/tools/event-gui.c
+++ b/tools/event-gui.c
@@ -798,6 +798,10 @@ handle_event_libinput(GIOChannel *source, GIOCondition condition, gpointer data)
 		case LIBINPUT_EVENT_TABLET_TOOL_BUTTON:
 			handle_event_tablet(ev, w);
 			break;
+		case LIBINPUT_EVENT_TABLET_PAD_BUTTON:
+		case LIBINPUT_EVENT_TABLET_PAD_RING:
+		case LIBINPUT_EVENT_TABLET_PAD_STRIP:
+			break;
 		}
 
 		libinput_event_destroy(ev);
-- 
2.5.5



More information about the wayland-devel mailing list