On 04/10/2016 09:15 PM, Peter Hutterer wrote:
> Signed-off-by: Peter Hutterer <[email protected]>
> ---
> Adjustments for the new API in 2/5
> 
>  src/Makefile.am        |   1 +
>  src/evdev-tablet-pad.c | 614 
> +++++++++++++++++++++++++++++++++++++++++++++++++
>  src/evdev-tablet-pad.h |  69 ++++++
>  src/evdev.c            |  28 ++-
>  src/evdev.h            |  13 ++
>  src/libinput.c         |   6 +-
>  6 files changed, 716 insertions(+), 15 deletions(-)
>  create mode 100644 src/evdev-tablet-pad.c
>  create mode 100644 src/evdev-tablet-pad.h
> 
> diff --git a/src/Makefile.am b/src/Makefile.am
> index 343e75c..a3df6c8 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -20,6 +20,7 @@ libinput_la_SOURCES =                       \
>       evdev-mt-touchpad-gestures.c    \
>       evdev-tablet.c                  \
>       evdev-tablet.h                  \
> +     evdev-tablet-pad.c              \
>       filter.c                        \
>       filter.h                        \
>       filter-private.h                \
> diff --git a/src/evdev-tablet-pad.c b/src/evdev-tablet-pad.c
> new file mode 100644
> index 0000000..8c64830
> --- /dev/null
> +++ b/src/evdev-tablet-pad.c
> @@ -0,0 +1,614 @@
> +/*
> + * Copyright © 2016 Red Hat, Inc.
> + *
> + * Permission to use, copy, modify, distribute, and sell this software and
> + * its documentation for any purpose is hereby granted without fee, provided
> + * that the above copyright notice appear in all copies and that both that
> + * copyright notice and this permission notice appear in supporting
> + * documentation, and that the name of the copyright holders not be used in
> + * advertising or publicity pertaining to distribution of the software
> + * without specific, written prior permission.  The copyright holders make
> + * no representations about the suitability of this software for any
> + * purpose.  It is provided "as is" without express or implied warranty.
> + *
> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
> + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
> + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
> + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
> + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
> + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
> + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include "config.h"
> +#include "evdev-tablet-pad.h"
> +
> +#include <assert.h>
> +#include <stdbool.h>
> +#include <string.h>
> +
> +#define pad_set_status(pad_,s_) (pad_)->status |= (s_)
> +#define pad_unset_status(pad_,s_) (pad_)->status &= ~(s_)
> +#define pad_has_status(pad_,s_) (!!((pad_)->status & (s_)))
> +
> +static void
> +pad_get_buttons_pressed(struct pad_dispatch *pad,
> +                     struct button_state *buttons)
> +{
> +     struct button_state *state = &pad->button_state;
> +     struct button_state *prev_state = &pad->prev_button_state;
> +     unsigned int i;
> +
> +     for (i = 0; i < sizeof(buttons->bits); i++)
> +             buttons->bits[i] = state->bits[i] & ~(prev_state->bits[i]);
> +}
> +
> +static void
> +pad_get_buttons_released(struct pad_dispatch *pad,
> +                      struct button_state *buttons)
> +{
> +     struct button_state *state = &pad->button_state;
> +     struct button_state *prev_state = &pad->prev_button_state;
> +     unsigned int i;
> +
> +     for (i = 0; i < sizeof(buttons->bits); i++)
> +             buttons->bits[i] = prev_state->bits[i] & ~(state->bits[i]);
> +}
> +
> +static inline bool
> +pad_button_is_down(const struct pad_dispatch *pad,
> +                uint32_t button)
> +{
> +     return bit_is_set(pad->button_state.bits, button);
> +}
> +
> +static inline bool
> +pad_any_button_down(const struct pad_dispatch *pad)
> +{
> +     const struct button_state *state = &pad->button_state;
> +     unsigned int i;
> +
> +     for (i = 0; i < sizeof(state->bits); i++)
> +             if (state->bits[i] != 0)
> +                     return true;
> +
> +     return false;
> +}
> +
> +static inline void
> +pad_button_set_down(struct pad_dispatch *pad,
> +                 uint32_t button,
> +                 bool is_down)
> +{
> +     struct button_state *state = &pad->button_state;
> +
> +     if (is_down) {
> +             set_bit(state->bits, button);
> +             pad_set_status(pad, PAD_BUTTONS_PRESSED);
> +     } else {
> +             clear_bit(state->bits, button);
> +             pad_set_status(pad, PAD_BUTTONS_RELEASED);
> +     }
> +}
> +
> +static void
> +pad_process_absolute(struct pad_dispatch *pad,
> +                  struct evdev_device *device,
> +                  struct input_event *e,
> +                  uint64_t time)
> +{
> +     switch (e->code) {
> +     case ABS_WHEEL:
> +             pad->changed_axes |= PAD_AXIS_RING1;
> +             pad_set_status(pad, PAD_AXES_UPDATED);
> +             break;
> +     case ABS_THROTTLE:
> +             pad->changed_axes |= PAD_AXIS_RING2;
> +             pad_set_status(pad, PAD_AXES_UPDATED);
> +             break;
> +     case ABS_RX:
> +             pad->changed_axes |= PAD_AXIS_STRIP1;
> +             pad_set_status(pad, PAD_AXES_UPDATED);
> +             break;
> +     case ABS_RY:
> +             pad->changed_axes |= PAD_AXIS_STRIP2;
> +             pad_set_status(pad, PAD_AXES_UPDATED);
> +             break;
> +     case ABS_MISC:
> +             /* The wacom driver always sends a 0 axis event on finger
> +                up, but we also get an ABS_MISC 15 on touch down and
> +                ABS_MISC 0 on touch up, on top of the actual event. This
> +                is kernel behavior for xf86-input-wacom backwards
> +                compatibility after the 3.17 wacom HID move.
> +
> +                We use that event to tell when we truly went a full
> +                rotation around the wheel vs. a finger release.
> +
> +                FIXME: On the Intuos5 and later the kernel merges all
> +                states into that event, so if any finger is down on any
> +                button, the wheel release won't trigger the ABS_MISC 0
> +                but still send a 0 event. We can't currently detect this.
> +              */
> +             pad->have_abs_misc_terminator = true;
> +             break;
> +     default:
> +             log_info(device->base.seat->libinput,
> +                      "Unhandled EV_ABS event code %#x\n", e->code);
> +             break;
> +     }
> +}
> +
> +static inline double
> +normalize_ring(const struct input_absinfo *absinfo)
> +{
> +     /* libinput has 0 as the ring's northernmost point in the device's
> +        current logical rotation, increasing clockwise to 1. Wacom has
> +        0 on the left-most wheel position.
> +      */
> +     double range = absinfo->maximum - absinfo->minimum + 1;
> +     double value = (absinfo->value - absinfo->minimum) / range - 0.25;
> +
> +     if (value < 0.0)
> +             value += 1.0;
> +
> +     return value;
> +}
> +
> +static inline double
> +normalize_strip(const struct input_absinfo *absinfo)
> +{
> +     /* strip axes don't use a proper value, they just shift the bit left
> +      * for each position. 0 isn't a real value either, it's only sent on
> +      * finger release */
> +     double min = 0,
> +            max = log2(absinfo->maximum);
> +     double range = max - min;
> +     double value = (log2(absinfo->value) - min) / range;
> +
> +     return value;
> +}
> +
> +static inline double
> +pad_handle_ring(struct pad_dispatch *pad,
> +             struct evdev_device *device,
> +             unsigned int code)
> +{
> +     const struct input_absinfo *absinfo;
> +     double degrees;
> +
> +     absinfo = libevdev_get_abs_info(device->evdev, code);
> +     assert(absinfo);
> +
> +     degrees = normalize_ring(absinfo) * 360;
> +
> +     if (device->left_handed.enabled)
> +             degrees = fmod(degrees + 180, 360);
> +
> +     return degrees;
> +}
> +
> +static inline double
> +pad_handle_strip(struct pad_dispatch *pad,
> +              struct evdev_device *device,
> +              unsigned int code)
> +{
> +     const struct input_absinfo *absinfo;
> +     double pos;
> +
> +     absinfo = libevdev_get_abs_info(device->evdev, code);
> +     assert(absinfo);
> +
> +     if (absinfo->value == 0)
> +             return 0.0;
> +
> +     pos = normalize_strip(absinfo);
> +
> +     if (device->left_handed.enabled)
> +             pos = 1.0 - pos;
> +
> +     return pos;
> +}
> +
> +static void
> +pad_check_notify_axes(struct pad_dispatch *pad,
> +                   struct evdev_device *device,
> +                   uint64_t time)
> +{
> +     struct libinput_device *base = &device->base;
> +     double value;
> +     bool send_finger_up = false;
> +
> +     /* Suppress the reset to 0 on finger up. See the
> +        comment in pad_process_absolute */
> +     if (pad->have_abs_misc_terminator &&
> +         libevdev_get_event_value(device->evdev, EV_ABS, ABS_MISC) == 0)
> +             send_finger_up = true;
> +
> +     if (pad->changed_axes & PAD_AXIS_RING1) {
> +             value = pad_handle_ring(pad, device, ABS_WHEEL);
> +             if (send_finger_up)
> +                     value = -1.0;
> +
> +             tablet_pad_notify_ring(base,
> +                                    time,
> +                                    0,
> +                                    value,
> +                                    LIBINPUT_TABLET_PAD_RING_SOURCE_FINGER);
> +     }
> +
> +     if (pad->changed_axes & PAD_AXIS_RING2) {
> +             value = pad_handle_ring(pad, device, ABS_THROTTLE);
> +             if (send_finger_up)
> +                     value = -1.0;
> +
> +             tablet_pad_notify_ring(base,
> +                                    time,
> +                                    1,
> +                                    value,
> +                                    LIBINPUT_TABLET_PAD_RING_SOURCE_FINGER);
> +     }
> +
> +     if (pad->changed_axes & PAD_AXIS_STRIP1) {
> +             value = pad_handle_strip(pad, device, ABS_RX);
> +             if (send_finger_up)
> +                     value = -1.0;
> +
> +             tablet_pad_notify_strip(base,
> +                                     time,
> +                                     0,
> +                                     value,
> +                                     
> LIBINPUT_TABLET_PAD_STRIP_SOURCE_FINGER);
> +     }
> +
> +     if (pad->changed_axes & PAD_AXIS_STRIP2) {
> +             value = pad_handle_strip(pad, device, ABS_RY);
> +             if (send_finger_up)
> +                     value = -1.0;
> +
> +             tablet_pad_notify_strip(base,
> +                                     time,
> +                                     1,
> +                                     value,
> +                                     
> LIBINPUT_TABLET_PAD_STRIP_SOURCE_FINGER);
> +     }
> +
> +     pad->changed_axes = PAD_AXIS_NONE;
> +     pad->have_abs_misc_terminator = false;
> +}
> +
> +static void
> +pad_process_key(struct pad_dispatch *pad,
> +             struct evdev_device *device,
> +             struct input_event *e,
> +             uint64_t time)
> +{
> +     uint32_t button = e->code;
> +     uint32_t is_press = e->value != 0;
> +
> +     pad_button_set_down(pad, button, is_press);
> +}
> +
> +static void
> +pad_notify_button_mask(struct pad_dispatch *pad,
> +                    struct evdev_device *device,
> +                    uint64_t time,
> +                    const struct button_state *buttons,
> +                    enum libinput_button_state state)
> +{
> +     struct libinput_device *base = &device->base;
> +     int32_t code;
> +     unsigned int i;
> +
> +     for (i = 0; i < sizeof(buttons->bits); i++) {
> +             unsigned char buttons_slice = buttons->bits[i];
> +
> +             code = i * 8;
> +             while (buttons_slice) {
> +                     int enabled;
> +                     char map;
> +
> +                     code++;
> +                     enabled = (buttons_slice & 1);
> +                     buttons_slice >>= 1;
> +
> +                     if (!enabled)
> +                             continue;
> +
> +                     map = pad->button_map[code - 1];
> +                     if (map != -1)
> +                             tablet_pad_notify_button(base, time, map, 
> state);
> +             }
> +     }
> +}
> +
> +static void
> +pad_notify_buttons(struct pad_dispatch *pad,
> +                struct evdev_device *device,
> +                uint64_t time,
> +                enum libinput_button_state state)
> +{
> +     struct button_state buttons;
> +
> +     if (state == LIBINPUT_BUTTON_STATE_PRESSED)
> +             pad_get_buttons_pressed(pad, &buttons);
> +     else
> +             pad_get_buttons_released(pad, &buttons);
> +
> +     pad_notify_button_mask(pad, device, time, &buttons, state);
> +}
> +
> +static void
> +pad_change_to_left_handed(struct evdev_device *device)
> +{
> +     struct pad_dispatch *pad = (struct pad_dispatch*)device->dispatch;
> +
> +     if (device->left_handed.enabled == device->left_handed.want_enabled)
> +             return;
> +
> +     if (pad_any_button_down(pad))
> +             return;
> +
> +     device->left_handed.enabled = device->left_handed.want_enabled;
> +}
> +
> +static void
> +pad_flush(struct pad_dispatch *pad,
> +       struct evdev_device *device,
> +       uint64_t time)
> +{
> +     if (pad_has_status(pad, PAD_AXES_UPDATED)) {
> +             pad_check_notify_axes(pad, device, time);
> +             pad_unset_status(pad, PAD_AXES_UPDATED);
> +     }
> +
> +     if (pad_has_status(pad, PAD_BUTTONS_RELEASED)) {
> +             pad_notify_buttons(pad,
> +                                device,
> +                                time,
> +                                LIBINPUT_BUTTON_STATE_RELEASED);
> +             pad_unset_status(pad, PAD_BUTTONS_RELEASED);
> +
> +             pad_change_to_left_handed(device);
> +     }
> +
> +     if (pad_has_status(pad, PAD_BUTTONS_PRESSED)) {
> +             pad_notify_buttons(pad,
> +                                device,
> +                                time,
> +                                LIBINPUT_BUTTON_STATE_PRESSED);
> +             pad_unset_status(pad, PAD_BUTTONS_PRESSED);
> +     }
> +
> +     /* Update state */
> +     memcpy(&pad->prev_button_state,
> +            &pad->button_state,
> +            sizeof(pad->button_state));
> +}
> +
> +static void
> +pad_process(struct evdev_dispatch *dispatch,
> +         struct evdev_device *device,
> +         struct input_event *e,
> +         uint64_t time)
> +{
> +     struct pad_dispatch *pad = (struct pad_dispatch *)dispatch;
> +
> +     switch (e->type) {
> +     case EV_ABS:
> +             pad_process_absolute(pad, device, e, time);
> +             break;
> +     case EV_KEY:
> +             pad_process_key(pad, device, e, time);
> +             break;
> +     case EV_SYN:
> +             pad_flush(pad, device, time);
> +             break;
> +     default:
> +             log_error(device->base.seat->libinput,
> +                       "Unexpected event type %s (%#x)\n",
> +                       libevdev_event_type_get_name(e->type),
> +                       e->type);
> +             break;
> +     }
> +}
> +
> +static void
> +pad_suspend(struct evdev_dispatch *dispatch,
> +         struct evdev_device *device)
> +{
> +     struct pad_dispatch *pad = (struct pad_dispatch *)dispatch;
> +     struct libinput *libinput = device->base.seat->libinput;
> +     unsigned int code;
> +
> +     for (code = KEY_ESC; code < KEY_CNT; code++) {
> +             if (pad_button_is_down(pad, code))
> +                     pad_button_set_down(pad, code, false);
> +     }
> +
> +     pad_flush(pad, device, libinput_now(libinput));
> +}
> +
> +static void
> +pad_destroy(struct evdev_dispatch *dispatch)
> +{
> +     struct pad_dispatch *pad = (struct pad_dispatch*)dispatch;
> +
> +     free(pad);
> +}
> +
> +static struct evdev_dispatch_interface pad_interface = {
> +     pad_process,
> +     pad_suspend, /* suspend */
> +     NULL, /* remove */
> +     pad_destroy,
> +     NULL, /* device_added */
> +     NULL, /* device_removed */
> +     NULL, /* device_suspended */
> +     NULL, /* device_resumed */
> +     NULL, /* post_added */
> +};
> +
> +static void
> +pad_init_buttons(struct pad_dispatch *pad,
> +              struct evdev_device *device)
> +{
> +     unsigned int code;
> +     size_t i;
> +     int map = 0;
> +
> +     for (i = 0; i < ARRAY_LENGTH(pad->button_map); i++)
> +             pad->button_map[i] = -1;
> +
> +     for (code = BTN_0; code < BTN_MOUSE; code++) {
> +             if (libevdev_has_event_code(device->evdev, EV_KEY, code))
> +                     pad->button_map[code] = map++;
> +     }
> +
> +     for (code = BTN_A; code < BTN_DIGI; code++) {
> +             if (libevdev_has_event_code(device->evdev, EV_KEY, code))
> +                     pad->button_map[code] = map++;
> +     }
> +
> +     pad->nbuttons = map;
> +}
> +

For the sake of the compatibility with future devices, I'd recommend
more strictly following the button ranges used by the kernel:
http://lxr.free-electrons.com/source/drivers/hid/wacom_wac.c#L2712

Also, note that you're missing coverage of BTN_BASE and BTN_BASE2.

Jason
---
Now instead of four in the eights place /
you’ve got three, ‘Cause you added one /
(That is to say, eight) to the two, /
But you can’t take seven from three, /
So you look at the sixty-fours....

> +static void
> +pad_init_left_handed(struct evdev_device *device)
> +{
> +     if (evdev_tablet_has_left_handed(device))
> +             evdev_init_left_handed(device,
> +                                    pad_change_to_left_handed);
> +}
> +
> +static int
> +pad_init(struct pad_dispatch *pad, struct evdev_device *device)
> +{
> +     pad->base.interface = &pad_interface;
> +     pad->device = device;
> +     pad->status = PAD_NONE;
> +     pad->changed_axes = PAD_AXIS_NONE;
> +
> +     pad_init_buttons(pad, device);
> +     pad_init_left_handed(device);
> +
> +     return 0;
> +}
> +
> +static uint32_t
> +pad_sendevents_get_modes(struct libinput_device *device)
> +{
> +     return LIBINPUT_CONFIG_SEND_EVENTS_DISABLED;
> +}
> +
> +static enum libinput_config_status
> +pad_sendevents_set_mode(struct libinput_device *device,
> +                     enum libinput_config_send_events_mode mode)
> +{
> +     struct evdev_device *evdev = (struct evdev_device*)device;
> +     struct pad_dispatch *pad = (struct pad_dispatch*)evdev->dispatch;
> +
> +     if (mode == pad->sendevents.current_mode)
> +             return LIBINPUT_CONFIG_STATUS_SUCCESS;
> +
> +     switch(mode) {
> +     case LIBINPUT_CONFIG_SEND_EVENTS_ENABLED:
> +             break;
> +     case LIBINPUT_CONFIG_SEND_EVENTS_DISABLED:
> +             pad_suspend(evdev->dispatch, evdev);
> +             break;
> +     default:
> +             return LIBINPUT_CONFIG_STATUS_UNSUPPORTED;
> +     }
> +
> +     pad->sendevents.current_mode = mode;
> +
> +     return LIBINPUT_CONFIG_STATUS_SUCCESS;
> +}
> +
> +static enum libinput_config_send_events_mode
> +pad_sendevents_get_mode(struct libinput_device *device)
> +{
> +     struct evdev_device *evdev = (struct evdev_device*)device;
> +     struct pad_dispatch *dispatch = (struct pad_dispatch*)evdev->dispatch;
> +
> +     return dispatch->sendevents.current_mode;
> +}
> +
> +static enum libinput_config_send_events_mode
> +pad_sendevents_get_default_mode(struct libinput_device *device)
> +{
> +     return LIBINPUT_CONFIG_SEND_EVENTS_ENABLED;
> +}
> +
> +struct evdev_dispatch *
> +evdev_tablet_pad_create(struct evdev_device *device)
> +{
> +     struct pad_dispatch *pad;
> +
> +     pad = zalloc(sizeof *pad);
> +     if (!pad)
> +             return NULL;
> +
> +     if (pad_init(pad, device) != 0) {
> +             pad_destroy(&pad->base);
> +             return NULL;
> +     }
> +
> +     device->base.config.sendevents = &pad->sendevents.config;
> +     pad->sendevents.current_mode = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED;
> +     pad->sendevents.config.get_modes = pad_sendevents_get_modes;
> +     pad->sendevents.config.set_mode = pad_sendevents_set_mode;
> +     pad->sendevents.config.get_mode = pad_sendevents_get_mode;
> +     pad->sendevents.config.get_default_mode = 
> pad_sendevents_get_default_mode;
> +
> +     return &pad->base;
> +}
> +
> +int
> +evdev_device_tablet_pad_get_num_buttons(struct evdev_device *device)
> +{
> +     struct pad_dispatch *pad = (struct pad_dispatch*)device->dispatch;
> +
> +     if (!(device->seat_caps & EVDEV_DEVICE_TABLET_PAD))
> +             return -1;
> +
> +     return pad->nbuttons;
> +}
> +
> +int
> +evdev_device_tablet_pad_get_num_rings(struct evdev_device *device)
> +{
> +     int nrings = 0;
> +
> +     if (!(device->seat_caps & EVDEV_DEVICE_TABLET_PAD))
> +             return -1;
> +
> +     if (libevdev_has_event_code(device->evdev, EV_ABS, ABS_WHEEL)) {
> +             nrings++;
> +             if (libevdev_has_event_code(device->evdev,
> +                                         EV_ABS,
> +                                         ABS_THROTTLE))
> +                     nrings++;
> +     }
> +
> +     return nrings;
> +}
> +
> +int
> +evdev_device_tablet_pad_get_num_strips(struct evdev_device *device)
> +{
> +     int nstrips = 0;
> +
> +     if (!(device->seat_caps & EVDEV_DEVICE_TABLET_PAD))
> +             return -1;
> +
> +     if (libevdev_has_event_code(device->evdev, EV_ABS, ABS_RX)) {
> +             nstrips++;
> +             if (libevdev_has_event_code(device->evdev,
> +                                         EV_ABS,
> +                                         ABS_RY))
> +                     nstrips++;
> +     }
> +
> +     return nstrips;
> +}
> diff --git a/src/evdev-tablet-pad.h b/src/evdev-tablet-pad.h
> new file mode 100644
> index 0000000..828ded8
> --- /dev/null
> +++ b/src/evdev-tablet-pad.h
> @@ -0,0 +1,69 @@
> +/*
> + * Copyright © 2015 Red Hat, Inc.
> + *
> + * Permission to use, copy, modify, distribute, and sell this software and
> + * its documentation for any purpose is hereby granted without fee, provided
> + * that the above copyright notice appear in all copies and that both that
> + * copyright notice and this permission notice appear in supporting
> + * documentation, and that the name of the copyright holders not be used in
> + * advertising or publicity pertaining to distribution of the software
> + * without specific, written prior permission.  The copyright holders make
> + * no representations about the suitability of this software for any
> + * purpose.  It is provided "as is" without express or implied warranty.
> + *
> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
> + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
> + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
> + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
> + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
> + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
> + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#ifndef EVDEV_BUTTONSET_WACOM_H
> +#define EVDEV_BUTTONSET_WACOM_H
> +
> +#include "evdev.h"
> +
> +#define LIBINPUT_BUTTONSET_AXIS_NONE 0
> +
> +enum pad_status {
> +     PAD_NONE = 0,
> +     PAD_AXES_UPDATED = 1 << 0,
> +     PAD_BUTTONS_PRESSED = 1 << 1,
> +     PAD_BUTTONS_RELEASED = 1 << 2,
> +};
> +
> +enum pad_axes {
> +     PAD_AXIS_NONE = 0,
> +     PAD_AXIS_RING1 = 1 << 0,
> +     PAD_AXIS_RING2 = 1 << 1,
> +     PAD_AXIS_STRIP1 = 1 << 2,
> +     PAD_AXIS_STRIP2 = 1 << 3,
> +};
> +
> +struct button_state {
> +     unsigned char bits[NCHARS(KEY_CNT)];
> +};
> +
> +struct pad_dispatch {
> +     struct evdev_dispatch base;
> +     struct evdev_device *device;
> +     unsigned char status;
> +     uint32_t changed_axes;
> +
> +     struct button_state button_state;
> +     struct button_state prev_button_state;
> +
> +     char button_map[KEY_CNT];
> +     unsigned int nbuttons;
> +
> +     bool have_abs_misc_terminator;
> +
> +     struct {
> +             struct libinput_device_config_send_events config;
> +             enum libinput_config_send_events_mode current_mode;
> +     } sendevents;
> +};
> +
> +#endif
> diff --git a/src/evdev.c b/src/evdev.c
> index a5511c5..0ec3823 100644
> --- a/src/evdev.c
> +++ b/src/evdev.c
> @@ -65,7 +65,7 @@ enum evdev_device_udev_tags {
>          EVDEV_UDEV_TAG_TABLET = (1 << 5),
>          EVDEV_UDEV_TAG_JOYSTICK = (1 << 6),
>          EVDEV_UDEV_TAG_ACCELEROMETER = (1 << 7),
> -        EVDEV_UDEV_TAG_BUTTONSET = (1 << 8),
> +        EVDEV_UDEV_TAG_TABLET_PAD = (1 << 8),
>          EVDEV_UDEV_TAG_POINTINGSTICK = (1 << 9),
>  };
>  
> @@ -82,7 +82,7 @@ static const struct evdev_udev_tag_match 
> evdev_udev_tag_matches[] = {
>       {"ID_INPUT_TOUCHPAD",           EVDEV_UDEV_TAG_TOUCHPAD},
>       {"ID_INPUT_TOUCHSCREEN",        EVDEV_UDEV_TAG_TOUCHSCREEN},
>       {"ID_INPUT_TABLET",             EVDEV_UDEV_TAG_TABLET},
> -     {"ID_INPUT_TABLET_PAD",         EVDEV_UDEV_TAG_BUTTONSET},
> +     {"ID_INPUT_TABLET_PAD",         EVDEV_UDEV_TAG_TABLET_PAD},
>       {"ID_INPUT_JOYSTICK",           EVDEV_UDEV_TAG_JOYSTICK},
>       {"ID_INPUT_ACCELEROMETER",      EVDEV_UDEV_TAG_ACCELEROMETER},
>       {"ID_INPUT_POINTINGSTICK",      EVDEV_UDEV_TAG_POINTINGSTICK},
> @@ -2031,7 +2031,7 @@ evdev_configure_device(struct evdev_device *device)
>                udev_tags & EVDEV_UDEV_TAG_POINTINGSTICK ? " Pointingstick" : 
> "",
>                udev_tags & EVDEV_UDEV_TAG_JOYSTICK ? " Joystick" : "",
>                udev_tags & EVDEV_UDEV_TAG_ACCELEROMETER ? " Accelerometer" : 
> "",
> -              udev_tags & EVDEV_UDEV_TAG_BUTTONSET ? " Buttonset" : "");
> +              udev_tags & EVDEV_UDEV_TAG_TABLET_PAD ? " TabletPad" : "");
>  
>       if (udev_tags & EVDEV_UDEV_TAG_ACCELEROMETER) {
>               log_info(libinput,
> @@ -2049,14 +2049,6 @@ evdev_configure_device(struct evdev_device *device)
>               return -1;
>       }
>  
> -     /* libwacom assigns tablet _and_ tablet_pad to the pad devices */
> -     if (udev_tags & EVDEV_UDEV_TAG_BUTTONSET) {
> -             log_info(libinput,
> -                      "input device '%s', %s is a buttonset, ignoring\n",
> -                      device->devname, devnode);
> -             return -1;
> -     }
> -
>       if (evdev_reject_device(device) == -1) {
>               log_info(libinput,
>                        "input device '%s', %s was rejected.\n",
> @@ -2092,7 +2084,17 @@ evdev_configure_device(struct evdev_device *device)
>       tablet_tags = EVDEV_UDEV_TAG_TABLET |
>                     EVDEV_UDEV_TAG_TOUCHPAD |
>                     EVDEV_UDEV_TAG_TOUCHSCREEN;
> -     if ((udev_tags & tablet_tags) == EVDEV_UDEV_TAG_TABLET) {
> +
> +     /* libwacom assigns tablet _and_ tablet_pad to the pad devices */
> +     if (udev_tags & EVDEV_UDEV_TAG_TABLET_PAD) {
> +             device->dispatch = evdev_tablet_pad_create(device);
> +             device->seat_caps |= EVDEV_DEVICE_TABLET_PAD;
> +             log_info(libinput,
> +                      "input device '%s', %s is a tablet pad\n",
> +                      device->devname, devnode);
> +             return device->dispatch == NULL ? -1 : 0;
> +
> +     } else if ((udev_tags & tablet_tags) == EVDEV_UDEV_TAG_TABLET) {
>               device->dispatch = evdev_tablet_create(device);
>               device->seat_caps |= EVDEV_DEVICE_TABLET;
>               log_info(libinput,
> @@ -2521,6 +2523,8 @@ evdev_device_has_capability(struct evdev_device *device,
>               return !!(device->seat_caps & EVDEV_DEVICE_GESTURE);
>       case LIBINPUT_DEVICE_CAP_TABLET_TOOL:
>               return !!(device->seat_caps & EVDEV_DEVICE_TABLET);
> +     case LIBINPUT_DEVICE_CAP_TABLET_PAD:
> +             return !!(device->seat_caps & EVDEV_DEVICE_TABLET_PAD);
>       default:
>               return 0;
>       }
> diff --git a/src/evdev.h b/src/evdev.h
> index f5e7bed..d76c3dd 100644
> --- a/src/evdev.h
> +++ b/src/evdev.h
> @@ -61,6 +61,7 @@ enum evdev_device_seat_capability {
>       EVDEV_DEVICE_KEYBOARD = (1 << 1),
>       EVDEV_DEVICE_TOUCH = (1 << 2),
>       EVDEV_DEVICE_TABLET = (1 << 3),
> +     EVDEV_DEVICE_TABLET_PAD = (1 << 4),
>       EVDEV_DEVICE_GESTURE = (1 << 5),
>  };
>  
> @@ -317,6 +318,9 @@ evdev_mt_touchpad_create(struct evdev_device *device);
>  struct evdev_dispatch *
>  evdev_tablet_create(struct evdev_device *device);
>  
> +struct evdev_dispatch *
> +evdev_tablet_pad_create(struct evdev_device *device);
> +
>  void
>  evdev_tag_touchpad(struct evdev_device *device,
>                  struct udev_device *udev_device);
> @@ -367,6 +371,15 @@ evdev_device_has_button(struct evdev_device *device, 
> uint32_t code);
>  int
>  evdev_device_has_key(struct evdev_device *device, uint32_t code);
>  
> +int
> +evdev_device_tablet_pad_get_num_buttons(struct evdev_device *device);
> +
> +int
> +evdev_device_tablet_pad_get_num_rings(struct evdev_device *device);
> +
> +int
> +evdev_device_tablet_pad_get_num_strips(struct evdev_device *device);
> +
>  double
>  evdev_device_transform_x(struct evdev_device *device,
>                        double x,
> diff --git a/src/libinput.c b/src/libinput.c
> index 53da963..22fef0a 100644
> --- a/src/libinput.c
> +++ b/src/libinput.c
> @@ -2794,19 +2794,19 @@ libinput_device_keyboard_has_key(struct 
> libinput_device *device, uint32_t code)
>  LIBINPUT_EXPORT int
>  libinput_device_tablet_pad_get_num_buttons(struct libinput_device *device)
>  {
> -     return 0;
> +     return evdev_device_tablet_pad_get_num_buttons((struct evdev_device 
> *)device);
>  }
>  
>  LIBINPUT_EXPORT int
>  libinput_device_tablet_pad_get_num_rings(struct libinput_device *device)
>  {
> -     return 0;
> +     return evdev_device_tablet_pad_get_num_rings((struct evdev_device 
> *)device);
>  }
>  
>  LIBINPUT_EXPORT int
>  libinput_device_tablet_pad_get_num_strips(struct libinput_device *device)
>  {
> -     return 0;
> +     return evdev_device_tablet_pad_get_num_strips((struct evdev_device 
> *)device);
>  }
>  
>  LIBINPUT_EXPORT struct libinput_event *
> 
_______________________________________________
wayland-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to