Signed-off-by: Peter Hutterer <peter.hutte...@who-t.net> --- src/Makefile.am | 1 + src/evdev-tablet-pad.c | 536 +++++++++++++++++++++++++++++++++++++++++++++++++ src/evdev-tablet-pad.h | 66 ++++++ src/evdev.c | 28 +-- src/evdev.h | 14 ++ src/libinput.c | 7 +- 6 files changed, 637 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..810b241 --- /dev/null +++ b/src/evdev-tablet-pad.c @@ -0,0 +1,536 @@ +/* + * 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 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; + + absinfo = libevdev_get_abs_info(device->evdev, code); + assert(absinfo); + + return normalize_ring(absinfo) * 360; +} + +static inline double +pad_handle_strip(struct pad_dispatch *pad, + struct evdev_device *device, + unsigned int code) +{ + const struct input_absinfo *absinfo; + + absinfo = libevdev_get_abs_info(device->evdev, code); + assert(absinfo); + + if (absinfo->value == 0) + return 0.0; + + return normalize_strip(absinfo); +} + +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 num_button; + unsigned int i; + + for (i = 0; i < sizeof(buttons->bits); i++) { + unsigned char buttons_slice = buttons->bits[i]; + + num_button = i * 8; + while (buttons_slice) { + int enabled; + + num_button++; + enabled = (buttons_slice & 1); + buttons_slice >>= 1; + + if (!enabled) + continue; + + tablet_pad_notify_button(base, + time, + num_button - 1, + 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_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); + } + + 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 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; + + 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_has_button(struct evdev_device *device, uint32_t code) +{ + if (!(device->seat_caps & EVDEV_DEVICE_TABLET_PAD)) + return -1; + + return libevdev_has_event_code(device->evdev, EV_KEY, code); +} + +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..a769b47 --- /dev/null +++ b/src/evdev-tablet-pad.h @@ -0,0 +1,66 @@ +/* + * 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; + + 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 51768fe..a50b0a3 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -61,7 +61,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), }; @@ -78,7 +78,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}, @@ -2026,7 +2026,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, @@ -2044,14 +2044,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", @@ -2087,7 +2079,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, @@ -2516,6 +2518,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 482712b..79afc20 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), }; @@ -316,6 +317,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); @@ -366,6 +370,16 @@ 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_has_button(struct evdev_device *device, + uint32_t code); + +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 5f1cc1a..6a209ec 100644 --- a/src/libinput.c +++ b/src/libinput.c @@ -2799,19 +2799,20 @@ LIBINPUT_EXPORT int libinput_device_tablet_pad_has_button(struct libinput_device *device, uint32_t code) { - return 0; + return evdev_device_tablet_pad_has_button((struct evdev_device *)device, + code); } 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 * -- 2.5.0 _______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/wayland-devel