mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2026-02-05 08:40:26 +01:00
This enables us to specify the location that needs to be arbitrated, rather than just disabling the whole device altogether. This patch just adds the hooks, no implementation. This is internal API only, one backend can specify an area in mm which gets converted to device coordinates in the target device and arbitrated there. Right now, everything simply passes NULL. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
759 lines
18 KiB
C
759 lines
18 KiB
C
/*
|
|
* Copyright © 2016 Red Hat, Inc.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice (including the next
|
|
* paragraph) shall be included in all copies or substantial portions of the
|
|
* Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
* DEALINGS IN THE 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,
|
|
.touch_arbitration_toggle = NULL,
|
|
.touch_arbitration_update_rect = 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;
|
|
}
|