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

Benjamin Tissoires benjamin.tissoires at gmail.com
Wed Jan 20 11:58:09 PST 2016


Hi Peter,

On Tue, Jan 19, 2016 at 5:46 AM, Peter Hutterer
<peter.hutterer at who-t.net> wrote:
> 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.
>

A few comments on the API, and on the terminology used (mostly in the .h file).

>
>  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,
> +};

Given the latest API and the quirks needed for Wacom pads support, I
wonder if those names are not too generic.
I believe X|Y|Z|REL_X|REL_Y|REL_Z|ROT_X|ROT_Y|ROT_Z are primary meant
for 3D mice and/or tools like the SpacePilot).
On the other hand, we have STRIP, which, by its documentation later
on, seems to be the exact same thing as a Y axis.

Comparing STRIP and Y makes me wonder whether we do not already
implies that STRIP will only be used by Pads on Wacom devices, while
the rest of the world will use Y.
The other explanation would be that STRIP has an actual input source
(a finger), and is only meant for capacitive touch strip. In this
case, why do we need to specify whether we have an input source.

I wonder, if we should not use a clear unambiguous name (which would
contain TABLET or 3D_MOUSEin it), and be really precise in the
definitions we are using.
This also means that the buttonset will end up being just a bag of
special usages, but I am not sure we will be able to avoid the quirks
here and there if we keep having generic axis.

Regarding the RING axis, the same thing applies. A more generic term
would be rotary encoder, with overrolling (0.8 + 0.3 = 0.1) or not.
The fact that the ring is an actual ring does not help if one decides
to use a different design.

> +
> +/**
> + * @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

I am not sure what "axis from the top edge of thedevice in its current
logical rotation" means.
I think we should be very cautious in describing those axis, or some
will give ascending Z, and other descending ones.

I recently had the issue with the HID protocol. See "4.2 Axis Usages"
in http://www.usb.org/developers/hidpage/Hut1_12v2.pdf (the HID usage
table).
" Z – A linear translation in the Z direction. Report values should
increase as the control’s position is moved from high to low (Z). "
This makes sense given the righthand rule taking into account x (left
to right) and y (top to bottom).

Maybe we should state that Z is generally negative from the surface to
the point tracked instead of positive, to follow the righthand rule.
Or we should explicitely say that we break this rule.

> + * @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

device specific, but should increase along the X axis and decrease on
the opposite side (same comment for REL_Y and REL_Z).

> + * 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

we should mention whether the angle is direct or not here (see the HUT
for a better formulation: "angular position report values follow the
righthand rule").

> + * LIBINPUT_BUTTONSET_AXIS_REL_Z.

REL_Z? shouldn't it be ROTATION_X?

> + */
> +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.

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.

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.

Could be interesting to have this also for buttons. Wacom Intuos Pros
report the capacitive information for each button, and it would be
interesting to send those to the userspace. Currently the kernel
strips those events but we should be able to change that if we have
the requirements and uses.

Thinking about the PS3 controller (ok, buttonset is not for gamepads,
but still), I wonder if this is actually just wrong (sending out of
range values when the finger is lifted).
For each button on the PS3 controller, we have 2 different
informations: whether the user pressed it or not (the "click"), and if
not, an absolute value of the pressure used against each button.

Here, we also have 2 sensors combined into one physical tool of
interaction: a capacitive sensor which gives the finger on/off
information, and the buttons, rotary position, etc...

Could we imagine a way where we have the buttonset which is a set of
composite objects (I think the term could be actuator, or instrument).
Each composite object has one or more valuator/button/whatever so that
the client of libinput knows what is the topology of the device.
Agree, this might be overkill, but I really dislike the "out of bound
value means the finger is up" because in the kernel, we will mostly
send this information on a different channel than the out of bound
value (maybe not).

I think I'll stop here. Thanks for reading :)

Cheers,
Benjamin

> + *
> + * @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