summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPeter Hutterer <peter.hutterer@who-t.net>2016-02-05 15:16:38 +1000
committerPeter Hutterer <peter.hutterer@who-t.net>2016-04-18 09:12:02 +1000
commit8e17a9ab5c293306ff0bc0b63551e6a79fd497b1 (patch)
tree02f5f4c0bfaa97f458142a1a908de4a86eadf871 /src
parentc2c526a7c5287cf2c0beeff0cfbce66c51d79ce8 (diff)
pad: implement wacom pad support
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Jason Gerecke <jason.gerecke@wacom.com> Reviewed-by: Carlos Garnacho <carlosg@gnome.org>
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am1
-rw-r--r--src/evdev-tablet-pad.c620
-rw-r--r--src/evdev-tablet-pad.h69
-rw-r--r--src/evdev.c28
-rw-r--r--src/evdev.h13
-rw-r--r--src/libinput.c6
6 files changed, 722 insertions, 15 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 343e75c7..a3df6c8f 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 00000000..ad6ead84
--- /dev/null
+++ b/src/evdev-tablet-pad.c
@@ -0,0 +1,620 @@
+/*
+ * 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;
+
+ /* we match wacom_report_numbered_buttons() from the kernel */
+ for (code = BTN_0; code < BTN_0 + 10; code++) {
+ if (libevdev_has_event_code(device->evdev, EV_KEY, code))
+ pad->button_map[code] = map++;
+ }
+
+ for (code = BTN_A; code < BTN_A + 6; code++) {
+ if (libevdev_has_event_code(device->evdev, EV_KEY, code))
+ pad->button_map[code] = map++;
+ }
+
+ for (code = BTN_BASE; code < BTN_BASE + 2; code++) {
+ if (libevdev_has_event_code(device->evdev, EV_KEY, code))
+ pad->button_map[code] = map++;
+ }
+
+ pad->nbuttons = map;
+}
+
+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 00000000..828ded8f
--- /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 330ca6b9..7a28bf21 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},
@@ -2049,7 +2049,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,
@@ -2067,14 +2067,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",
@@ -2110,7 +2102,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,
@@ -2539,6 +2541,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 56f07dba..3ed077b4 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),
};
@@ -319,6 +320,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);
@@ -369,6 +373,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 bd97fb0e..bcd0dcd0 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 *