[PATCH v2 libinput 4/5] pad: implement wacom pad support
Jason Gerecke
killertofu at gmail.com
Thu Apr 14 22:33:53 UTC 2016
On 04/10/2016 09:15 PM, Peter Hutterer wrote:
> Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
> ---
> 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 *
>
More information about the wayland-devel
mailing list