mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2026-01-03 10:20:14 +01:00
Some of wacom's tablets, notably the Bamboo series, have a non-predictable scheme of mapping the buttons to numeric button numbers in libwacom. Since we promise sequential button numbers, we need to have those identical to libwacom, otherwise it's impossible to map the two together. Most tablets have a predictable mapping, so this does not affect the majority of devices. For the old-style bamboos, this swaps the buttons around with the buttons being ordered vertically top-to-bottom in libwacom. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Acked-by: Jason Gerecke <jason.gerecke@wacom.com>
757 lines
18 KiB
C
757 lines
18 KiB
C
/*
|
|
* 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>
|
|
|
|
#if HAVE_LIBWACOM
|
|
#include <libwacom/libwacom.h>
|
|
#endif
|
|
|
|
#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:
|
|
evdev_log_info(device,
|
|
"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 inline struct libinput_tablet_pad_mode_group *
|
|
pad_ring_get_mode_group(struct pad_dispatch *pad,
|
|
unsigned int ring)
|
|
{
|
|
struct libinput_tablet_pad_mode_group *group;
|
|
|
|
list_for_each(group, &pad->modes.mode_group_list, link) {
|
|
if (libinput_tablet_pad_mode_group_has_ring(group, ring))
|
|
return group;
|
|
}
|
|
|
|
assert(!"Unable to find ring mode group");
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static inline struct libinput_tablet_pad_mode_group *
|
|
pad_strip_get_mode_group(struct pad_dispatch *pad,
|
|
unsigned int strip)
|
|
{
|
|
struct libinput_tablet_pad_mode_group *group;
|
|
|
|
list_for_each(group, &pad->modes.mode_group_list, link) {
|
|
if (libinput_tablet_pad_mode_group_has_strip(group, strip))
|
|
return group;
|
|
}
|
|
|
|
assert(!"Unable to find strip mode group");
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
pad_check_notify_axes(struct pad_dispatch *pad,
|
|
struct evdev_device *device,
|
|
uint64_t time)
|
|
{
|
|
struct libinput_device *base = &device->base;
|
|
struct libinput_tablet_pad_mode_group *group;
|
|
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;
|
|
|
|
group = pad_ring_get_mode_group(pad, 0);
|
|
tablet_pad_notify_ring(base,
|
|
time,
|
|
0,
|
|
value,
|
|
LIBINPUT_TABLET_PAD_RING_SOURCE_FINGER,
|
|
group);
|
|
}
|
|
|
|
if (pad->changed_axes & PAD_AXIS_RING2) {
|
|
value = pad_handle_ring(pad, device, ABS_THROTTLE);
|
|
if (send_finger_up)
|
|
value = -1.0;
|
|
|
|
group = pad_ring_get_mode_group(pad, 1);
|
|
tablet_pad_notify_ring(base,
|
|
time,
|
|
1,
|
|
value,
|
|
LIBINPUT_TABLET_PAD_RING_SOURCE_FINGER,
|
|
group);
|
|
}
|
|
|
|
if (pad->changed_axes & PAD_AXIS_STRIP1) {
|
|
value = pad_handle_strip(pad, device, ABS_RX);
|
|
if (send_finger_up)
|
|
value = -1.0;
|
|
|
|
group = pad_strip_get_mode_group(pad, 0);
|
|
tablet_pad_notify_strip(base,
|
|
time,
|
|
0,
|
|
value,
|
|
LIBINPUT_TABLET_PAD_STRIP_SOURCE_FINGER,
|
|
group);
|
|
}
|
|
|
|
if (pad->changed_axes & PAD_AXIS_STRIP2) {
|
|
value = pad_handle_strip(pad, device, ABS_RY);
|
|
if (send_finger_up)
|
|
value = -1.0;
|
|
|
|
group = pad_strip_get_mode_group(pad, 1);
|
|
tablet_pad_notify_strip(base,
|
|
time,
|
|
1,
|
|
value,
|
|
LIBINPUT_TABLET_PAD_STRIP_SOURCE_FINGER,
|
|
group);
|
|
}
|
|
|
|
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 inline struct libinput_tablet_pad_mode_group *
|
|
pad_button_get_mode_group(struct pad_dispatch *pad,
|
|
unsigned int button)
|
|
{
|
|
struct libinput_tablet_pad_mode_group *group;
|
|
|
|
list_for_each(group, &pad->modes.mode_group_list, link) {
|
|
if (libinput_tablet_pad_mode_group_has_button(group, button))
|
|
return group;
|
|
}
|
|
|
|
assert(!"Unable to find button mode group\n");
|
|
|
|
return NULL;
|
|
}
|
|
|
|
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;
|
|
struct libinput_tablet_pad_mode_group *group;
|
|
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) {
|
|
group = pad_button_get_mode_group(pad, map);
|
|
pad_button_update_mode(group, map, state);
|
|
tablet_pad_notify_button(base, time, map, state, group);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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 = 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;
|
|
case EV_MSC:
|
|
/* The EKR sends the serial as MSC_SERIAL, ignore this for
|
|
* now */
|
|
break;
|
|
default:
|
|
evdev_log_error(device,
|
|
"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 = pad_dispatch(dispatch);
|
|
struct libinput *libinput = pad_libinput_context(pad);
|
|
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 = pad_dispatch(dispatch);
|
|
|
|
pad_destroy_leds(pad);
|
|
free(pad);
|
|
}
|
|
|
|
static struct evdev_dispatch_interface pad_interface = {
|
|
.process = pad_process,
|
|
.suspend = pad_suspend,
|
|
.remove = NULL,
|
|
.destroy = pad_destroy,
|
|
.device_added = NULL,
|
|
.device_removed = NULL,
|
|
.device_suspended = NULL,
|
|
.device_resumed = NULL,
|
|
.post_added = NULL,
|
|
.toggle_touch = NULL,
|
|
.get_switch_state = NULL,
|
|
};
|
|
|
|
static bool
|
|
pad_init_buttons_from_libwacom(struct pad_dispatch *pad,
|
|
struct evdev_device *device)
|
|
{
|
|
bool rc = false;
|
|
#if HAVE_LIBWACOM_GET_BUTTON_EVDEV_CODE
|
|
WacomDeviceDatabase *db = NULL;
|
|
WacomDevice *tablet = NULL;
|
|
int num_buttons;
|
|
int map = 0;
|
|
|
|
db = libwacom_database_new();
|
|
if (!db) {
|
|
evdev_log_info(device,
|
|
"Failed to initialize libwacom context.\n");
|
|
goto out;
|
|
}
|
|
|
|
tablet = libwacom_new_from_usbid(db,
|
|
evdev_device_get_id_vendor(device),
|
|
evdev_device_get_id_product(device),
|
|
NULL);
|
|
if (!tablet)
|
|
goto out;
|
|
|
|
num_buttons = libwacom_get_num_buttons(tablet);
|
|
for (int i = 0; i < num_buttons; i++) {
|
|
unsigned int code;
|
|
|
|
code = libwacom_get_button_evdev_code(tablet, 'A' + i);
|
|
if (code == 0)
|
|
continue;
|
|
|
|
pad->button_map[code] = map++;
|
|
}
|
|
|
|
pad->nbuttons = map;
|
|
|
|
rc = true;
|
|
out:
|
|
if (tablet)
|
|
libwacom_destroy(tablet);
|
|
if (db)
|
|
libwacom_database_destroy(db);
|
|
#endif
|
|
return rc;
|
|
}
|
|
|
|
static void
|
|
pad_init_buttons_from_kernel(struct pad_dispatch *pad,
|
|
struct evdev_device *device)
|
|
{
|
|
unsigned int code;
|
|
int map = 0;
|
|
|
|
/* 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_BASE; code < BTN_BASE + 2; 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_LEFT; code < BTN_LEFT + 7; code++) {
|
|
if (libevdev_has_event_code(device->evdev, EV_KEY, code))
|
|
pad->button_map[code] = map++;
|
|
}
|
|
|
|
pad->nbuttons = map;
|
|
}
|
|
|
|
static void
|
|
pad_init_buttons(struct pad_dispatch *pad,
|
|
struct evdev_device *device)
|
|
{
|
|
size_t i;
|
|
|
|
for (i = 0; i < ARRAY_LENGTH(pad->button_map); i++)
|
|
pad->button_map[i] = -1;
|
|
|
|
if (!pad_init_buttons_from_libwacom(pad, device))
|
|
pad_init_buttons_from_kernel(pad, device);
|
|
|
|
}
|
|
|
|
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.dispatch_type = DISPATCH_TABLET_PAD;
|
|
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);
|
|
if (pad_init_leds(pad, device) != 0)
|
|
return 1;
|
|
|
|
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 = 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 = 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_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;
|
|
}
|