mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2026-05-06 18:27:59 +02:00
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>
This commit is contained in:
parent
c2c526a7c5
commit
8e17a9ab5c
6 changed files with 722 additions and 15 deletions
|
|
@ -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 \
|
||||
|
|
|
|||
620
src/evdev-tablet-pad.c
Normal file
620
src/evdev-tablet-pad.c
Normal file
|
|
@ -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;
|
||||
}
|
||||
69
src/evdev-tablet-pad.h
Normal file
69
src/evdev-tablet-pad.h
Normal file
|
|
@ -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
|
||||
28
src/evdev.c
28
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;
|
||||
}
|
||||
|
|
|
|||
13
src/evdev.h
13
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,
|
||||
|
|
|
|||
|
|
@ -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 *
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue