mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2025-12-25 05:50:05 +01:00
tablet: add API for relative dials
Some tablets such as those in the XP-PEN PRO series use "dials" which are actually scrollwheels and emit EV_REL events. These should not be emulated as rings (which are absolute) so we must expose them as a new tablet event. Adds LIBINPUT_EVENT_TABLET_PAD_DIAL that work largely identical as our high-resolution wheel events (i.e. the values are in multiples or fractions of of 120). Currently supports two dials. This is a lot of copy/paste from the ring axes because the interface is virtually identical. The main difference is that dials give us a v120 value in the same manner as our scroll axes. Notes: - REL_DIAL is mutually exclusive with REL_WHEEL, we assume the kernel doesn't (at this point) give us devices with both. If this changes for devices with three dials (wheel + hwheel + dial) we need to add code for that. - REL_DIAL does not have a high-resolution axis and we assume that any device with REL_WHEEL_HI_RES will also have REL_HWHEEL_HI_RES (if the second wheel exists). - With dials being REL_DIAL or REL_WHEEL there is no possibility of detecting a finger release (the kernel does not route EV_RELs with a value of zero). Unless this is implemented via a side-channel - and it doesn't look like any hardware that supports dials does that - we cannot forward any information here. So unlike absolute rings we cannot provide a source information here. Closes #600 Co-authored-by: Peter Hutterer <peter.hutterer@who-t.net> Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/967>
This commit is contained in:
parent
d487ca36a4
commit
beca998122
19 changed files with 735 additions and 12 deletions
|
|
@ -757,6 +757,7 @@ if get_option('tests')
|
|||
'test/litest-device-generic-singletouch.c',
|
||||
'test/litest-device-gpio-keys.c',
|
||||
'test/litest-device-huion-pentablet.c',
|
||||
'test/litest-device-huion-q620m-dial.c',
|
||||
'test/litest-device-hp-wmi-hotkeys.c',
|
||||
'test/litest-device-ignored-mouse.c',
|
||||
'test/litest-device-keyboard.c',
|
||||
|
|
@ -792,7 +793,9 @@ if get_option('tests')
|
|||
'test/litest-device-synaptics-t440.c',
|
||||
'test/litest-device-synaptics-x1-carbon-3rd.c',
|
||||
'test/litest-device-synaptics-phantomclicks.c',
|
||||
'test/litest-device-tablet-doubledial.c',
|
||||
'test/litest-device-tablet-mode-switch.c',
|
||||
'test/litest-device-tablet-rel-dial.c',
|
||||
'test/litest-device-thinkpad-extrabuttons.c',
|
||||
'test/litest-device-trackpoint.c',
|
||||
'test/litest-device-touch-screen.c',
|
||||
|
|
|
|||
|
|
@ -517,6 +517,7 @@ pad_init_leds_from_libwacom(struct pad_dispatch *pad,
|
|||
|
||||
pad_init_mode_rings(pad, wacom);
|
||||
pad_init_mode_strips(pad, wacom);
|
||||
/* Note: libwacom doesn't do dials yet */
|
||||
|
||||
out:
|
||||
if (wacom)
|
||||
|
|
@ -546,6 +547,7 @@ pad_init_fallback_group(struct pad_dispatch *pad)
|
|||
group->base.button_mask = -1;
|
||||
group->base.strip_mask = -1;
|
||||
group->base.ring_mask = -1;
|
||||
group->base.dial_mask = -1;
|
||||
group->base.toggle_button_mask = 0;
|
||||
|
||||
list_insert(&pad->modes.mode_group_list, &group->base.link);
|
||||
|
|
|
|||
|
|
@ -97,6 +97,50 @@ pad_button_set_down(struct pad_dispatch *pad,
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pad_process_relative(struct pad_dispatch *pad,
|
||||
struct evdev_device *device,
|
||||
struct input_event *e,
|
||||
uint64_t time)
|
||||
{
|
||||
switch (e->code) {
|
||||
case REL_DIAL:
|
||||
pad->dials.dial1 = e->value * 120;
|
||||
pad->changed_axes |= PAD_AXIS_DIAL1;
|
||||
pad_set_status(pad, PAD_AXES_UPDATED);
|
||||
break;
|
||||
case REL_WHEEL:
|
||||
if (!pad->dials.has_hires_dial) {
|
||||
pad->dials.dial1 = e->value * 120;
|
||||
pad->changed_axes |= PAD_AXIS_DIAL1;
|
||||
pad_set_status(pad, PAD_AXES_UPDATED);
|
||||
}
|
||||
break;
|
||||
case REL_HWHEEL:
|
||||
if (!pad->dials.has_hires_dial) {
|
||||
pad->dials.dial2 = e->value * 120;
|
||||
pad->changed_axes |= PAD_AXIS_DIAL2;
|
||||
pad_set_status(pad, PAD_AXES_UPDATED);
|
||||
}
|
||||
break;
|
||||
case REL_WHEEL_HI_RES:
|
||||
pad->dials.dial1 = e->value;
|
||||
pad->changed_axes |= PAD_AXIS_DIAL1;
|
||||
pad_set_status(pad, PAD_AXES_UPDATED);
|
||||
break;
|
||||
case REL_HWHEEL_HI_RES:
|
||||
pad->dials.dial2 = e->value * 120;
|
||||
pad->changed_axes |= PAD_AXIS_DIAL2;
|
||||
pad_set_status(pad, PAD_AXES_UPDATED);
|
||||
break;
|
||||
default:
|
||||
evdev_log_info(device,
|
||||
"Unhandled EV_REL event code %#x\n",
|
||||
e->code);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pad_process_absolute(struct pad_dispatch *pad,
|
||||
struct evdev_device *device,
|
||||
|
|
@ -216,6 +260,22 @@ pad_handle_strip(struct pad_dispatch *pad,
|
|||
return pos;
|
||||
}
|
||||
|
||||
static inline struct libinput_tablet_pad_mode_group *
|
||||
pad_dial_get_mode_group(struct pad_dispatch *pad,
|
||||
unsigned int dial)
|
||||
{
|
||||
struct libinput_tablet_pad_mode_group *group;
|
||||
|
||||
list_for_each(group, &pad->modes.mode_group_list, link) {
|
||||
if (libinput_tablet_pad_mode_group_has_dial(group, dial))
|
||||
return group;
|
||||
}
|
||||
|
||||
assert(!"Unable to find dial mode group");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct libinput_tablet_pad_mode_group *
|
||||
pad_ring_get_mode_group(struct pad_dispatch *pad,
|
||||
unsigned int ring)
|
||||
|
|
@ -264,6 +324,26 @@ pad_check_notify_axes(struct pad_dispatch *pad,
|
|||
libevdev_get_event_value(device->evdev, EV_ABS, ABS_MISC) == 0)
|
||||
send_finger_up = true;
|
||||
|
||||
/* Unlike the ring axis we don't get an event when we release
|
||||
* so we can't set a source */
|
||||
if (pad->changed_axes & PAD_AXIS_DIAL1) {
|
||||
group = pad_dial_get_mode_group(pad, 0);
|
||||
tablet_pad_notify_dial(base,
|
||||
time,
|
||||
0,
|
||||
pad->dials.dial1,
|
||||
group);
|
||||
}
|
||||
|
||||
if (pad->changed_axes & PAD_AXIS_DIAL2) {
|
||||
group = pad_dial_get_mode_group(pad, 1);
|
||||
tablet_pad_notify_dial(base,
|
||||
time,
|
||||
1,
|
||||
pad->dials.dial2,
|
||||
group);
|
||||
}
|
||||
|
||||
if (pad->changed_axes & PAD_AXIS_RING1) {
|
||||
value = pad_handle_ring(pad, device, ABS_WHEEL);
|
||||
if (send_finger_up)
|
||||
|
|
@ -473,6 +553,8 @@ pad_flush(struct pad_dispatch *pad,
|
|||
memcpy(&pad->prev_button_state,
|
||||
&pad->button_state,
|
||||
sizeof(pad->button_state));
|
||||
pad->dials.dial1 = 0;
|
||||
pad->dials.dial2 = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -484,6 +566,9 @@ pad_process(struct evdev_dispatch *dispatch,
|
|||
struct pad_dispatch *pad = pad_dispatch(dispatch);
|
||||
|
||||
switch (e->type) {
|
||||
case EV_REL:
|
||||
pad_process_relative(pad, device, e, time);
|
||||
break;
|
||||
case EV_ABS:
|
||||
pad_process_absolute(pad, device, e, time);
|
||||
break;
|
||||
|
|
@ -686,6 +771,16 @@ pad_init(struct pad_dispatch *pad, struct evdev_device *device)
|
|||
pad->status = PAD_NONE;
|
||||
pad->changed_axes = PAD_AXIS_NONE;
|
||||
|
||||
/* We expect the kernel to either give us both axes as hires or neither.
|
||||
* Getting one is a kernel bug we don't need to care about */
|
||||
pad->dials.has_hires_dial = libevdev_has_event_code(device->evdev, EV_REL, REL_WHEEL_HI_RES) ||
|
||||
libevdev_has_event_code(device->evdev, EV_REL, REL_HWHEEL_HI_RES);
|
||||
|
||||
if (libevdev_has_event_code(device->evdev, EV_REL, REL_WHEEL) &&
|
||||
libevdev_has_event_code(device->evdev, EV_REL, REL_DIAL)) {
|
||||
log_bug_libinput(pad_libinput_context(pad), "Unsupported combination REL_DIAL and REL_WHEEL\n");
|
||||
}
|
||||
|
||||
pad_init_buttons(pad, device);
|
||||
pad_init_left_handed(device);
|
||||
if (pad_init_leds(pad, device) != 0)
|
||||
|
|
@ -782,6 +877,26 @@ evdev_device_tablet_pad_get_num_buttons(struct evdev_device *device)
|
|||
return pad->nbuttons;
|
||||
}
|
||||
|
||||
int
|
||||
evdev_device_tablet_pad_get_num_dials(struct evdev_device *device)
|
||||
{
|
||||
int ndials = 0;
|
||||
|
||||
if (!(device->seat_caps & EVDEV_DEVICE_TABLET_PAD))
|
||||
return -1;
|
||||
|
||||
if (libevdev_has_event_code(device->evdev, EV_REL, REL_WHEEL) ||
|
||||
libevdev_has_event_code(device->evdev, EV_REL, REL_DIAL)) {
|
||||
ndials++;
|
||||
if (libevdev_has_event_code(device->evdev,
|
||||
EV_REL,
|
||||
REL_HWHEEL))
|
||||
ndials++;
|
||||
}
|
||||
|
||||
return ndials;
|
||||
}
|
||||
|
||||
int
|
||||
evdev_device_tablet_pad_get_num_rings(struct evdev_device *device)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@ enum pad_axes {
|
|||
PAD_AXIS_RING2 = bit(1),
|
||||
PAD_AXIS_STRIP1 = bit(2),
|
||||
PAD_AXIS_STRIP2 = bit(3),
|
||||
PAD_AXIS_DIAL1 = bit(4),
|
||||
PAD_AXIS_DIAL2 = bit(5),
|
||||
};
|
||||
|
||||
struct button_state {
|
||||
|
|
@ -73,6 +75,12 @@ struct pad_dispatch {
|
|||
|
||||
bool have_abs_misc_terminator;
|
||||
|
||||
struct {
|
||||
bool has_hires_dial;
|
||||
double dial1;
|
||||
double dial2;
|
||||
} dials;
|
||||
|
||||
struct {
|
||||
struct libinput_device_config_send_events config;
|
||||
enum libinput_config_send_events_mode current_mode;
|
||||
|
|
|
|||
|
|
@ -518,6 +518,9 @@ evdev_device_tablet_pad_has_key(struct evdev_device *device,
|
|||
int
|
||||
evdev_device_tablet_pad_get_num_buttons(struct evdev_device *device);
|
||||
|
||||
int
|
||||
evdev_device_tablet_pad_get_num_dials(struct evdev_device *device);
|
||||
|
||||
int
|
||||
evdev_device_tablet_pad_get_num_rings(struct evdev_device *device);
|
||||
|
||||
|
|
|
|||
|
|
@ -503,6 +503,7 @@ struct libinput_tablet_pad_mode_group {
|
|||
uint32_t button_mask;
|
||||
uint32_t ring_mask;
|
||||
uint32_t strip_mask;
|
||||
uint32_t dial_mask;
|
||||
|
||||
uint32_t toggle_button_mask;
|
||||
|
||||
|
|
@ -797,6 +798,13 @@ tablet_pad_notify_button(struct libinput_device *device,
|
|||
enum libinput_button_state state,
|
||||
struct libinput_tablet_pad_mode_group *group);
|
||||
void
|
||||
tablet_pad_notify_dial(struct libinput_device *device,
|
||||
uint64_t time,
|
||||
unsigned int number,
|
||||
double value,
|
||||
struct libinput_tablet_pad_mode_group *group);
|
||||
|
||||
void
|
||||
tablet_pad_notify_ring(struct libinput_device *device,
|
||||
uint64_t time,
|
||||
unsigned int number,
|
||||
|
|
|
|||
|
|
@ -104,6 +104,7 @@ event_type_to_str(enum libinput_event_type type)
|
|||
CASE_RETURN_STRING(LIBINPUT_EVENT_TABLET_PAD_RING);
|
||||
CASE_RETURN_STRING(LIBINPUT_EVENT_TABLET_PAD_STRIP);
|
||||
CASE_RETURN_STRING(LIBINPUT_EVENT_TABLET_PAD_KEY);
|
||||
CASE_RETURN_STRING(LIBINPUT_EVENT_TABLET_PAD_DIAL);
|
||||
CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN);
|
||||
CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE);
|
||||
CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_SWIPE_END);
|
||||
|
|
@ -232,6 +233,10 @@ struct libinput_event_tablet_pad {
|
|||
uint32_t code;
|
||||
enum libinput_key_state state;
|
||||
} key;
|
||||
struct {
|
||||
double v120;
|
||||
int number;
|
||||
} dial;
|
||||
struct {
|
||||
enum libinput_tablet_pad_ring_axis_source source;
|
||||
double position;
|
||||
|
|
@ -443,6 +448,7 @@ libinput_event_get_tablet_pad_event(struct libinput_event *event)
|
|||
event->type,
|
||||
NULL,
|
||||
LIBINPUT_EVENT_TABLET_PAD_RING,
|
||||
LIBINPUT_EVENT_TABLET_PAD_DIAL,
|
||||
LIBINPUT_EVENT_TABLET_PAD_STRIP,
|
||||
LIBINPUT_EVENT_TABLET_PAD_BUTTON,
|
||||
LIBINPUT_EVENT_TABLET_PAD_KEY);
|
||||
|
|
@ -2024,6 +2030,7 @@ libinput_event_destroy(struct libinput_event *event)
|
|||
libinput_event_get_tablet_tool_event(event));
|
||||
break;
|
||||
case LIBINPUT_EVENT_TABLET_PAD_RING:
|
||||
case LIBINPUT_EVENT_TABLET_PAD_DIAL:
|
||||
case LIBINPUT_EVENT_TABLET_PAD_STRIP:
|
||||
case LIBINPUT_EVENT_TABLET_PAD_BUTTON:
|
||||
case LIBINPUT_EVENT_TABLET_PAD_KEY:
|
||||
|
|
@ -2909,6 +2916,34 @@ tablet_pad_notify_button(struct libinput_device *device,
|
|||
&button_event->base);
|
||||
}
|
||||
|
||||
void
|
||||
tablet_pad_notify_dial(struct libinput_device *device,
|
||||
uint64_t time,
|
||||
unsigned int number,
|
||||
double value,
|
||||
struct libinput_tablet_pad_mode_group *group)
|
||||
{
|
||||
struct libinput_event_tablet_pad *dial_event;
|
||||
unsigned int mode;
|
||||
|
||||
dial_event = zalloc(sizeof *dial_event);
|
||||
|
||||
mode = libinput_tablet_pad_mode_group_get_mode(group);
|
||||
|
||||
*dial_event = (struct libinput_event_tablet_pad) {
|
||||
.time = time,
|
||||
.dial.number = number,
|
||||
.dial.v120 = value,
|
||||
.mode_group = libinput_tablet_pad_mode_group_ref(group),
|
||||
.mode = mode,
|
||||
};
|
||||
|
||||
post_device_event(device,
|
||||
time,
|
||||
LIBINPUT_EVENT_TABLET_PAD_DIAL,
|
||||
&dial_event->base);
|
||||
}
|
||||
|
||||
void
|
||||
tablet_pad_notify_ring(struct libinput_device *device,
|
||||
uint64_t time,
|
||||
|
|
@ -3375,6 +3410,12 @@ libinput_device_tablet_pad_get_num_buttons(struct libinput_device *device)
|
|||
return evdev_device_tablet_pad_get_num_buttons((struct evdev_device *)device);
|
||||
}
|
||||
|
||||
LIBINPUT_EXPORT int
|
||||
libinput_device_tablet_pad_get_num_dials(struct libinput_device *device)
|
||||
{
|
||||
return evdev_device_tablet_pad_get_num_dials((struct evdev_device *)device);
|
||||
}
|
||||
|
||||
LIBINPUT_EXPORT int
|
||||
libinput_device_tablet_pad_get_num_rings(struct libinput_device *device)
|
||||
{
|
||||
|
|
@ -3431,6 +3472,17 @@ libinput_tablet_pad_mode_group_has_button(struct libinput_tablet_pad_mode_group
|
|||
return !!(group->button_mask & bit(button));
|
||||
}
|
||||
|
||||
LIBINPUT_EXPORT int
|
||||
libinput_tablet_pad_mode_group_has_dial(struct libinput_tablet_pad_mode_group *group,
|
||||
unsigned int dial)
|
||||
{
|
||||
if ((int)dial >=
|
||||
libinput_device_tablet_pad_get_num_dials(group->device))
|
||||
return 0;
|
||||
|
||||
return !!(group->dial_mask & bit(dial));
|
||||
}
|
||||
|
||||
LIBINPUT_EXPORT int
|
||||
libinput_tablet_pad_mode_group_has_ring(struct libinput_tablet_pad_mode_group *group,
|
||||
unsigned int ring)
|
||||
|
|
@ -3589,6 +3641,28 @@ libinput_event_tablet_tool_get_base_event(struct libinput_event_tablet_tool *eve
|
|||
return &event->base;
|
||||
}
|
||||
|
||||
LIBINPUT_EXPORT double
|
||||
libinput_event_tablet_pad_get_dial_delta_v120(struct libinput_event_tablet_pad *event)
|
||||
{
|
||||
require_event_type(libinput_event_get_context(&event->base),
|
||||
event->base.type,
|
||||
0.0,
|
||||
LIBINPUT_EVENT_TABLET_PAD_DIAL);
|
||||
|
||||
return event->dial.v120;
|
||||
}
|
||||
|
||||
LIBINPUT_EXPORT unsigned int
|
||||
libinput_event_tablet_pad_get_dial_number(struct libinput_event_tablet_pad *event)
|
||||
{
|
||||
require_event_type(libinput_event_get_context(&event->base),
|
||||
event->base.type,
|
||||
0,
|
||||
LIBINPUT_EVENT_TABLET_PAD_DIAL);
|
||||
|
||||
return event->dial.number;
|
||||
}
|
||||
|
||||
LIBINPUT_EXPORT double
|
||||
libinput_event_tablet_pad_get_ring_position(struct libinput_event_tablet_pad *event)
|
||||
{
|
||||
|
|
@ -3706,6 +3780,7 @@ libinput_event_tablet_pad_get_mode(struct libinput_event_tablet_pad *event)
|
|||
event->base.type,
|
||||
0,
|
||||
LIBINPUT_EVENT_TABLET_PAD_RING,
|
||||
LIBINPUT_EVENT_TABLET_PAD_DIAL,
|
||||
LIBINPUT_EVENT_TABLET_PAD_STRIP,
|
||||
LIBINPUT_EVENT_TABLET_PAD_BUTTON);
|
||||
|
||||
|
|
@ -3719,6 +3794,7 @@ libinput_event_tablet_pad_get_mode_group(struct libinput_event_tablet_pad *event
|
|||
event->base.type,
|
||||
NULL,
|
||||
LIBINPUT_EVENT_TABLET_PAD_RING,
|
||||
LIBINPUT_EVENT_TABLET_PAD_DIAL,
|
||||
LIBINPUT_EVENT_TABLET_PAD_STRIP,
|
||||
LIBINPUT_EVENT_TABLET_PAD_BUTTON);
|
||||
|
||||
|
|
@ -3732,6 +3808,7 @@ libinput_event_tablet_pad_get_time(struct libinput_event_tablet_pad *event)
|
|||
event->base.type,
|
||||
0,
|
||||
LIBINPUT_EVENT_TABLET_PAD_RING,
|
||||
LIBINPUT_EVENT_TABLET_PAD_DIAL,
|
||||
LIBINPUT_EVENT_TABLET_PAD_STRIP,
|
||||
LIBINPUT_EVENT_TABLET_PAD_BUTTON,
|
||||
LIBINPUT_EVENT_TABLET_PAD_KEY);
|
||||
|
|
@ -3746,6 +3823,7 @@ libinput_event_tablet_pad_get_time_usec(struct libinput_event_tablet_pad *event)
|
|||
event->base.type,
|
||||
0,
|
||||
LIBINPUT_EVENT_TABLET_PAD_RING,
|
||||
LIBINPUT_EVENT_TABLET_PAD_DIAL,
|
||||
LIBINPUT_EVENT_TABLET_PAD_STRIP,
|
||||
LIBINPUT_EVENT_TABLET_PAD_BUTTON,
|
||||
LIBINPUT_EVENT_TABLET_PAD_KEY);
|
||||
|
|
@ -3760,6 +3838,7 @@ libinput_event_tablet_pad_get_base_event(struct libinput_event_tablet_pad *event
|
|||
event->base.type,
|
||||
NULL,
|
||||
LIBINPUT_EVENT_TABLET_PAD_RING,
|
||||
LIBINPUT_EVENT_TABLET_PAD_DIAL,
|
||||
LIBINPUT_EVENT_TABLET_PAD_STRIP,
|
||||
LIBINPUT_EVENT_TABLET_PAD_BUTTON,
|
||||
LIBINPUT_EVENT_TABLET_PAD_KEY);
|
||||
|
|
|
|||
|
|
@ -164,7 +164,8 @@ struct libinput_event_tablet_tool;
|
|||
*
|
||||
* Tablet pad event representing a button press, or ring/strip update on
|
||||
* the tablet pad itself. Valid event types for this event are @ref
|
||||
* LIBINPUT_EVENT_TABLET_PAD_BUTTON, @ref LIBINPUT_EVENT_TABLET_PAD_RING and
|
||||
* LIBINPUT_EVENT_TABLET_PAD_BUTTON, @ref LIBINPUT_EVENT_TABLET_PAD_DIAL,
|
||||
* @ref LIBINPUT_EVENT_TABLET_PAD_RING and
|
||||
* @ref LIBINPUT_EVENT_TABLET_PAD_STRIP.
|
||||
*
|
||||
* @since 1.3
|
||||
|
|
@ -429,7 +430,8 @@ struct libinput_tablet_pad_mode_group;
|
|||
* the Wacom Cintiq 22HD provide two mode groups. If multiple mode groups
|
||||
* are available, a caller should use
|
||||
* libinput_tablet_pad_mode_group_has_button(),
|
||||
* libinput_tablet_pad_mode_group_has_ring() and
|
||||
* libinput_tablet_pad_mode_group_has_ring(),
|
||||
* libinput_tablet_pad_mode_group_has_dial() and
|
||||
* libinput_tablet_pad_mode_group_has_strip() to associate each button,
|
||||
* ring and strip with the correct mode group.
|
||||
*
|
||||
|
|
@ -539,6 +541,22 @@ int
|
|||
libinput_tablet_pad_mode_group_has_button(struct libinput_tablet_pad_mode_group *group,
|
||||
unsigned int button);
|
||||
|
||||
/**
|
||||
* @ingroup tablet_pad_modes
|
||||
*
|
||||
* Devices without mode switching capabilities return true for every dial.
|
||||
*
|
||||
* @param group A previously obtained mode group
|
||||
* @param dial A dial index, starting at 0
|
||||
* @return true if the given dial index is part of this mode group or
|
||||
* false otherwise
|
||||
*
|
||||
* @since 1.26
|
||||
*/
|
||||
int
|
||||
libinput_tablet_pad_mode_group_has_dial(struct libinput_tablet_pad_mode_group *group,
|
||||
unsigned int dial);
|
||||
|
||||
/**
|
||||
* @ingroup tablet_pad_modes
|
||||
*
|
||||
|
|
@ -968,6 +986,14 @@ enum libinput_event_type {
|
|||
*/
|
||||
LIBINPUT_EVENT_TABLET_PAD_KEY,
|
||||
|
||||
/**
|
||||
* A status change on a tablet dial with the @ref
|
||||
* LIBINPUT_DEVICE_CAP_TABLET_PAD capability.
|
||||
*
|
||||
* @since 1.26
|
||||
*/
|
||||
LIBINPUT_EVENT_TABLET_PAD_DIAL,
|
||||
|
||||
LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN = 800,
|
||||
LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE,
|
||||
LIBINPUT_EVENT_GESTURE_SWIPE_END,
|
||||
|
|
@ -3314,6 +3340,44 @@ libinput_event_tablet_pad_get_key(struct libinput_event_tablet_pad *event);
|
|||
enum libinput_key_state
|
||||
libinput_event_tablet_pad_get_key_state(struct libinput_event_tablet_pad *event);
|
||||
|
||||
/**
|
||||
* @ingroup event_tablet_pad
|
||||
*
|
||||
* Returns the delta change of the dial, in multiples or fractions of 120, with
|
||||
* each multiple of 120 indicating one logical wheel event.
|
||||
* See libinput_event_pointer_get_scroll_value_v120() for more details.
|
||||
*
|
||||
* @note It is an application bug to call this function for events other than
|
||||
* @ref LIBINPUT_EVENT_TABLET_PAD_DIAL. For other events, this function
|
||||
* returns 0.
|
||||
*
|
||||
* @param event The libinput tablet pad event
|
||||
* @return The delta of the the axis
|
||||
*
|
||||
* @since 1.26
|
||||
*/
|
||||
double
|
||||
libinput_event_tablet_pad_get_dial_delta_v120(struct libinput_event_tablet_pad *event);
|
||||
|
||||
/**
|
||||
* @ingroup event_tablet_pad
|
||||
*
|
||||
* Returns the number of the dial that has changed state, with 0 being the
|
||||
* first dial. On tablets with only one dial, this function always returns
|
||||
* 0.
|
||||
*
|
||||
* @note It is an application bug to call this function for events other than
|
||||
* @ref LIBINPUT_EVENT_TABLET_PAD_DIAL. For other events, this function
|
||||
* returns 0.
|
||||
*
|
||||
* @param event The libinput tablet pad event
|
||||
* @return The index of the dial that changed state
|
||||
*
|
||||
* @since 1.26
|
||||
*/
|
||||
unsigned int
|
||||
libinput_event_tablet_pad_get_dial_number(struct libinput_event_tablet_pad *event);
|
||||
|
||||
/**
|
||||
* @ingroup event_tablet_pad
|
||||
*
|
||||
|
|
@ -4377,6 +4441,23 @@ libinput_device_switch_has_switch(struct libinput_device *device,
|
|||
int
|
||||
libinput_device_tablet_pad_get_num_buttons(struct libinput_device *device);
|
||||
|
||||
/**
|
||||
* @ingroup device
|
||||
*
|
||||
* Return the number of dials a device with the @ref
|
||||
* LIBINPUT_DEVICE_CAP_TABLET_PAD capability provides.
|
||||
*
|
||||
* @param device A current input device
|
||||
*
|
||||
* @return The number of dials or 0 if the device has no dials. -1 on error.
|
||||
*
|
||||
* @see libinput_event_tablet_pad_get_dial_number
|
||||
*
|
||||
* @since 1.26
|
||||
*/
|
||||
int
|
||||
libinput_device_tablet_pad_get_num_dials(struct libinput_device *device);
|
||||
|
||||
/**
|
||||
* @ingroup device
|
||||
*
|
||||
|
|
|
|||
|
|
@ -335,6 +335,10 @@ LIBINPUT_1.23 {
|
|||
} LIBINPUT_1.21;
|
||||
|
||||
LIBINPUT_1.26 {
|
||||
libinput_device_tablet_pad_get_num_dials;
|
||||
libinput_event_tablet_pad_get_dial_delta_v120;
|
||||
libinput_event_tablet_pad_get_dial_number;
|
||||
libinput_tablet_pad_mode_group_has_dial;
|
||||
libinput_tablet_tool_config_pressure_range_is_available;
|
||||
libinput_tablet_tool_config_pressure_range_set;
|
||||
libinput_tablet_tool_config_pressure_range_get_minimum;
|
||||
|
|
|
|||
76
test/litest-device-huion-q620m-dial.c
Normal file
76
test/litest-device-huion-q620m-dial.c
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright © 2024 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 "litest.h"
|
||||
#include "litest-int.h"
|
||||
|
||||
static struct input_event down[] = {
|
||||
{ .type = -1, .code = -1 },
|
||||
};
|
||||
|
||||
static struct input_event move[] = {
|
||||
{ .type = -1, .code = -1 },
|
||||
};
|
||||
|
||||
static struct litest_device_interface interface = {
|
||||
.touch_down_events = down,
|
||||
.touch_move_events = move,
|
||||
};
|
||||
|
||||
static struct input_absinfo absinfo[] = {
|
||||
{ ABS_X, 0, 1, 0, 0, 0 },
|
||||
{ ABS_Y, 0, 1, 0, 0, 0 },
|
||||
{ ABS_MISC, 0, 255, 0, 0, 0 },
|
||||
{ .value = -1 },
|
||||
};
|
||||
|
||||
static struct input_id input_id = {
|
||||
.bustype = 0x3,
|
||||
.vendor = 0x256c,
|
||||
.product = 0x006d,
|
||||
};
|
||||
|
||||
static int events[] = {
|
||||
EV_KEY, BTN_0,
|
||||
EV_REL, REL_WHEEL,
|
||||
EV_REL, REL_WHEEL_HI_RES,
|
||||
-1, -1,
|
||||
};
|
||||
|
||||
/* Device from https://gitlab.freedesktop.org/libinput/libinput/-/issues/600 */
|
||||
TEST_DEVICE("huion-q620m-dial-pad",
|
||||
.type = LITEST_HUION_Q620M_DIAL,
|
||||
.features = LITEST_TABLET_PAD | LITEST_DIAL,
|
||||
.interface = &interface,
|
||||
|
||||
.name = "HUION Huion Tablet_Q620M Dial",
|
||||
.id = &input_id,
|
||||
.events = events,
|
||||
.absinfo = absinfo,
|
||||
.udev_properties = {
|
||||
{ "ID_INPUT_TABLET_PAD", "1" },
|
||||
{ NULL },
|
||||
},
|
||||
)
|
||||
81
test/litest-device-tablet-doubledial.c
Normal file
81
test/litest-device-tablet-doubledial.c
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Copyright © 2024 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 "litest.h"
|
||||
#include "litest-int.h"
|
||||
|
||||
static struct input_event down[] = {
|
||||
{ .type = -1, .code = -1 },
|
||||
};
|
||||
|
||||
static struct input_event move[] = {
|
||||
{ .type = -1, .code = -1 },
|
||||
};
|
||||
|
||||
static struct litest_device_interface interface = {
|
||||
.touch_down_events = down,
|
||||
.touch_move_events = move,
|
||||
};
|
||||
|
||||
static struct input_absinfo absinfo[] = {
|
||||
{ ABS_X, 0, 1, 0, 0, 0 },
|
||||
{ ABS_Y, 0, 1, 0, 0, 0 },
|
||||
{ ABS_MISC, 0, 0, 0, 0, 0 },
|
||||
{ .value = -1 },
|
||||
};
|
||||
|
||||
static struct input_id input_id = {
|
||||
.bustype = 0x3,
|
||||
.vendor = 0x123,
|
||||
.product = 0x678,
|
||||
};
|
||||
|
||||
static int events[] = {
|
||||
EV_KEY, BTN_0,
|
||||
EV_KEY, BTN_1,
|
||||
EV_KEY, BTN_2,
|
||||
EV_KEY, BTN_3,
|
||||
EV_KEY, BTN_STYLUS,
|
||||
EV_REL, REL_WHEEL,
|
||||
EV_REL, REL_WHEEL_HI_RES,
|
||||
EV_REL, REL_HWHEEL,
|
||||
EV_REL, REL_HWHEEL_HI_RES,
|
||||
-1, -1,
|
||||
};
|
||||
|
||||
TEST_DEVICE("tablet-doubledial-pad",
|
||||
.type = LITEST_TABLET_DOUBLEDIAL_PAD,
|
||||
.features = LITEST_TABLET_PAD | LITEST_DIAL,
|
||||
.interface = &interface,
|
||||
|
||||
.name = "Generic Double Dial Pad",
|
||||
.id = &input_id,
|
||||
.events = events,
|
||||
.absinfo = absinfo,
|
||||
.udev_properties = {
|
||||
{ "ID_INPUT_TABLET_PAD", "1" },
|
||||
{ NULL },
|
||||
},
|
||||
)
|
||||
78
test/litest-device-tablet-rel-dial.c
Normal file
78
test/litest-device-tablet-rel-dial.c
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Copyright © 2024 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 "litest.h"
|
||||
#include "litest-int.h"
|
||||
|
||||
static struct input_event down[] = {
|
||||
{ .type = -1, .code = -1 },
|
||||
};
|
||||
|
||||
static struct input_event move[] = {
|
||||
{ .type = -1, .code = -1 },
|
||||
};
|
||||
|
||||
static struct litest_device_interface interface = {
|
||||
.touch_down_events = down,
|
||||
.touch_move_events = move,
|
||||
};
|
||||
|
||||
static struct input_absinfo absinfo[] = {
|
||||
{ ABS_X, 0, 1, 0, 0, 0 },
|
||||
{ ABS_Y, 0, 1, 0, 0, 0 },
|
||||
{ ABS_MISC, 0, 0, 0, 0, 0 },
|
||||
{ .value = -1 },
|
||||
};
|
||||
|
||||
static struct input_id input_id = {
|
||||
.bustype = 0x3,
|
||||
.vendor = 0x123,
|
||||
.product = 0x456,
|
||||
};
|
||||
|
||||
static int events[] = {
|
||||
EV_KEY, BTN_0,
|
||||
EV_KEY, BTN_1,
|
||||
EV_KEY, BTN_2,
|
||||
EV_KEY, BTN_3,
|
||||
EV_KEY, BTN_STYLUS,
|
||||
EV_REL, REL_DIAL,
|
||||
-1, -1,
|
||||
};
|
||||
|
||||
TEST_DEVICE("tablet-rel-dial-pad",
|
||||
.type = LITEST_TABLET_REL_DIAL_PAD,
|
||||
.features = LITEST_TABLET_PAD | LITEST_DIAL,
|
||||
.interface = &interface,
|
||||
|
||||
.name = "Generic Rel DialPad",
|
||||
.id = &input_id,
|
||||
.events = events,
|
||||
.absinfo = absinfo,
|
||||
.udev_properties = {
|
||||
{ "ID_INPUT_TABLET_PAD", "1" },
|
||||
{ NULL },
|
||||
},
|
||||
)
|
||||
|
|
@ -137,6 +137,14 @@ struct litest_device_interface {
|
|||
struct input_event *pad_ring_change_events;
|
||||
struct input_event *pad_ring_end_events;
|
||||
|
||||
/**
|
||||
* Pad events, LITEST_AUTO_ASSIGN is allowed on event values
|
||||
* for ABS_WHEEL
|
||||
*/
|
||||
struct input_event *pad_dial_start_events;
|
||||
struct input_event *pad_dial_change_events;
|
||||
struct input_event *pad_dial_end_events;
|
||||
|
||||
/**
|
||||
* Pad events, LITEST_AUTO_ASSIGN is allowed on event values
|
||||
* for ABS_RX
|
||||
|
|
|
|||
|
|
@ -2901,10 +2901,23 @@ auto_assign_pad_value(struct litest_device *dev,
|
|||
{
|
||||
const struct input_absinfo *abs;
|
||||
|
||||
if (ev->value != LITEST_AUTO_ASSIGN ||
|
||||
ev->type != EV_ABS)
|
||||
if (ev->value != LITEST_AUTO_ASSIGN)
|
||||
return value;
|
||||
|
||||
if (ev->type == EV_REL) {
|
||||
switch (ev->code) {
|
||||
case REL_WHEEL:
|
||||
case REL_HWHEEL:
|
||||
case REL_DIAL:
|
||||
assert (fmod(value, 120.0) == 0.0); /* Fractions not supported yet */
|
||||
return value/120.0;
|
||||
default:
|
||||
return value;
|
||||
}
|
||||
} else if (ev->type != EV_ABS) {
|
||||
return value;
|
||||
}
|
||||
|
||||
abs = libevdev_get_abs_info(dev->evdev, ev->code);
|
||||
litest_assert_notnull(abs);
|
||||
|
||||
|
|
@ -3213,6 +3226,9 @@ litest_event_type_str(enum libinput_event_type type)
|
|||
case LIBINPUT_EVENT_TABLET_PAD_KEY:
|
||||
str = "TABLET PAD KEY";
|
||||
break;
|
||||
case LIBINPUT_EVENT_TABLET_PAD_DIAL:
|
||||
str = "TABLET PAD DIAL";
|
||||
break;
|
||||
case LIBINPUT_EVENT_SWITCH_TOGGLE:
|
||||
str = "SWITCH TOGGLE";
|
||||
break;
|
||||
|
|
@ -3314,6 +3330,12 @@ litest_print_event(struct libinput_event *event)
|
|||
libinput_event_tablet_pad_get_ring_position(pad),
|
||||
libinput_event_tablet_pad_get_ring_source(pad));
|
||||
break;
|
||||
case LIBINPUT_EVENT_TABLET_PAD_DIAL:
|
||||
pad = libinput_event_get_tablet_pad_event(event);
|
||||
fprintf(stderr, "dial %d delta %.2f",
|
||||
libinput_event_tablet_pad_get_dial_number(pad),
|
||||
libinput_event_tablet_pad_get_dial_delta_v120(pad));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -3920,6 +3942,23 @@ litest_is_pad_button_event(struct libinput_event *event,
|
|||
return p;
|
||||
}
|
||||
|
||||
struct libinput_event_tablet_pad *
|
||||
litest_is_pad_dial_event(struct libinput_event *event,
|
||||
unsigned int number)
|
||||
{
|
||||
struct libinput_event_tablet_pad *p;
|
||||
enum libinput_event_type type = LIBINPUT_EVENT_TABLET_PAD_DIAL;
|
||||
|
||||
litest_assert_ptr_notnull(event);
|
||||
litest_assert_event_type(event, type);
|
||||
p = libinput_event_get_tablet_pad_event(event);
|
||||
|
||||
litest_assert_int_eq(libinput_event_tablet_pad_get_dial_number(p),
|
||||
number);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
struct libinput_event_tablet_pad *
|
||||
litest_is_pad_ring_event(struct libinput_event *event,
|
||||
unsigned int number,
|
||||
|
|
|
|||
|
|
@ -315,6 +315,9 @@ enum litest_device_type {
|
|||
/* Tablets */
|
||||
LITEST_ELAN_TABLET,
|
||||
LITEST_HUION_TABLET,
|
||||
LITEST_HUION_Q620M_DIAL,
|
||||
LITEST_TABLET_DOUBLEDIAL_PAD,
|
||||
LITEST_TABLET_REL_DIAL_PAD,
|
||||
LITEST_QEMU_TABLET,
|
||||
LITEST_UCLOGIC_TABLET,
|
||||
LITEST_WACOM_BAMBOO,
|
||||
|
|
@ -380,6 +383,7 @@ enum litest_device_type {
|
|||
#define LITEST_TOTEM bit(31)
|
||||
#define LITEST_FORCED_PROXOUT bit(32)
|
||||
#define LITEST_PRECALIBRATED bit(33)
|
||||
#define LITEST_DIAL bit(34)
|
||||
|
||||
/* this is a semi-mt device, so we keep track of the touches that the tests
|
||||
* send and modify them so that the first touch is always slot 0 and sends
|
||||
|
|
@ -812,6 +816,9 @@ litest_is_pad_button_event(struct libinput_event *event,
|
|||
unsigned int button,
|
||||
enum libinput_button_state state);
|
||||
struct libinput_event_tablet_pad *
|
||||
litest_is_pad_dial_event(struct libinput_event *event,
|
||||
unsigned int number);
|
||||
struct libinput_event_tablet_pad *
|
||||
litest_is_pad_ring_event(struct libinput_event *event,
|
||||
unsigned int number,
|
||||
enum libinput_tablet_pad_ring_axis_source source);
|
||||
|
|
|
|||
|
|
@ -486,6 +486,82 @@ START_TEST(pad_ring_finger_up)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(pad_has_dial)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput_device *device = dev->libinput_device;
|
||||
int ndials;
|
||||
int expected_ndials = 1;
|
||||
|
||||
if (libevdev_has_event_code(dev->evdev, EV_REL, REL_HWHEEL))
|
||||
expected_ndials = 2;
|
||||
|
||||
ndials = libinput_device_tablet_pad_get_num_dials(device);
|
||||
ck_assert_int_ge(ndials, expected_ndials);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(pad_dial_low_res)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
unsigned int code = 0;
|
||||
|
||||
if (libevdev_has_event_code(dev->evdev, EV_REL, REL_WHEEL))
|
||||
code = REL_WHEEL;
|
||||
if (libevdev_has_event_code(dev->evdev, EV_REL, REL_DIAL))
|
||||
code = REL_DIAL;
|
||||
|
||||
litest_drain_events(li);
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
int direction = -1 + 2 * i % 2;
|
||||
litest_event(dev, EV_REL, code, direction);
|
||||
if (code == REL_WHEEL)
|
||||
litest_event(dev, EV_REL, REL_WHEEL_HI_RES, direction * 120);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
libinput_dispatch(li);
|
||||
|
||||
struct libinput_event *ev = libinput_get_event(li);
|
||||
struct libinput_event_tablet_pad *pev = litest_is_pad_dial_event(ev, 0);
|
||||
|
||||
double v120 = libinput_event_tablet_pad_get_dial_delta_v120(pev);
|
||||
ck_assert_double_ge(v120, 120.0 * direction);
|
||||
libinput_event_destroy(ev);
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(pad_dial_hi_res)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
const int increment = 30;
|
||||
int accumulated = 0;
|
||||
|
||||
if (!libevdev_has_event_code(dev->evdev, EV_REL, REL_WHEEL_HI_RES))
|
||||
return;
|
||||
|
||||
litest_drain_events(li);
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
litest_event(dev, EV_REL, REL_WHEEL_HI_RES, increment);
|
||||
accumulated += increment;
|
||||
if (accumulated % 120 == 0)
|
||||
litest_event(dev, EV_REL, REL_WHEEL, 1);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
libinput_dispatch(li);
|
||||
|
||||
struct libinput_event *ev = libinput_get_event(li);
|
||||
struct libinput_event_tablet_pad *pev = litest_is_pad_dial_event(ev, 0);
|
||||
|
||||
double v120 = libinput_event_tablet_pad_get_dial_delta_v120(pev);
|
||||
ck_assert_double_ge(v120, increment);
|
||||
libinput_event_destroy(ev);
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(pad_has_strip)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
|
|
@ -994,10 +1070,12 @@ TEST_COLLECTION(tablet_pad)
|
|||
litest_add(pad_time, LITEST_TABLET_PAD, LITEST_ANY);
|
||||
|
||||
litest_add(pad_num_buttons, LITEST_TABLET_PAD, LITEST_ANY);
|
||||
litest_add(pad_num_buttons_libwacom, LITEST_TABLET_PAD, LITEST_ANY);
|
||||
/* None of our dial devices have libwacom entries */
|
||||
litest_add(pad_num_buttons_libwacom, LITEST_TABLET_PAD, LITEST_DIAL);
|
||||
litest_add(pad_button_intuos, LITEST_TABLET_PAD, LITEST_ANY);
|
||||
litest_add(pad_button_bamboo, LITEST_TABLET_PAD, LITEST_ANY);
|
||||
litest_add(pad_button_libwacom, LITEST_TABLET_PAD, LITEST_ANY);
|
||||
/* None of our dial devices have libwacom entries */
|
||||
litest_add(pad_button_libwacom, LITEST_TABLET_PAD, LITEST_DIAL);
|
||||
litest_add(pad_button_mode_groups, LITEST_TABLET_PAD, LITEST_ANY);
|
||||
|
||||
litest_add(pad_has_ring, LITEST_RING, LITEST_ANY);
|
||||
|
|
@ -1008,6 +1086,10 @@ TEST_COLLECTION(tablet_pad)
|
|||
litest_add(pad_strip, LITEST_STRIP, LITEST_ANY);
|
||||
litest_add(pad_strip_finger_up, LITEST_STRIP, LITEST_ANY);
|
||||
|
||||
litest_add(pad_has_dial, LITEST_DIAL, LITEST_ANY);
|
||||
litest_add(pad_dial_low_res, LITEST_DIAL, LITEST_ANY);
|
||||
litest_add(pad_dial_hi_res, LITEST_DIAL, LITEST_ANY);
|
||||
|
||||
litest_add_for_device(pad_left_handed_default, LITEST_WACOM_INTUOS5_PAD);
|
||||
litest_add_for_device(pad_no_left_handed, LITEST_WACOM_INTUOS3_PAD);
|
||||
litest_add_for_device(pad_left_handed_ring, LITEST_WACOM_INTUOS5_PAD);
|
||||
|
|
|
|||
|
|
@ -158,6 +158,9 @@ print_event_header(struct libinput_event *ev)
|
|||
case LIBINPUT_EVENT_TABLET_PAD_KEY:
|
||||
type = "TABLET_PAD_KEY";
|
||||
break;
|
||||
case LIBINPUT_EVENT_TABLET_PAD_DIAL:
|
||||
type = "TABLET_PAD_DIAL";
|
||||
break;
|
||||
case LIBINPUT_EVENT_SWITCH_TOGGLE:
|
||||
type = "SWITCH_TOGGLE";
|
||||
break;
|
||||
|
|
@ -819,6 +822,21 @@ print_tablet_pad_key_event(struct libinput_event *ev)
|
|||
state == LIBINPUT_KEY_STATE_PRESSED ? "pressed" : "released");
|
||||
}
|
||||
|
||||
static void
|
||||
print_tablet_pad_dial_event(struct libinput_event *ev)
|
||||
{
|
||||
struct libinput_event_tablet_pad *p = libinput_event_get_tablet_pad_event(ev);
|
||||
unsigned int mode;
|
||||
|
||||
print_event_time(libinput_event_tablet_pad_get_time(p));
|
||||
|
||||
mode = libinput_event_tablet_pad_get_mode(p);
|
||||
printq("dial %d delta %.2f (mode %d)\n",
|
||||
libinput_event_tablet_pad_get_dial_number(p),
|
||||
libinput_event_tablet_pad_get_dial_delta_v120(p),
|
||||
mode);
|
||||
}
|
||||
|
||||
static void
|
||||
print_switch_event(struct libinput_event *ev)
|
||||
{
|
||||
|
|
@ -943,6 +961,9 @@ handle_and_print_events(struct libinput *li)
|
|||
case LIBINPUT_EVENT_TABLET_PAD_KEY:
|
||||
print_tablet_pad_key_event(ev);
|
||||
break;
|
||||
case LIBINPUT_EVENT_TABLET_PAD_DIAL:
|
||||
print_tablet_pad_dial_event(ev);
|
||||
break;
|
||||
case LIBINPUT_EVENT_SWITCH_TOGGLE:
|
||||
print_switch_event(ev);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -190,6 +190,10 @@ struct window {
|
|||
double position;
|
||||
int number;
|
||||
} strip;
|
||||
struct {
|
||||
double position;
|
||||
int number;
|
||||
} dial;
|
||||
} pad;
|
||||
|
||||
struct {
|
||||
|
|
@ -720,12 +724,12 @@ draw_pad(struct window *w, cairo_t *cr)
|
|||
ry = w->height/2 + 100;
|
||||
|
||||
cairo_save(cr);
|
||||
/* outer ring */
|
||||
/* outer ring (for ring) */
|
||||
cairo_set_source_rgb(cr, .7, .7, .0);
|
||||
cairo_arc(cr, rx, ry, 50, 0, 2 * M_PI);
|
||||
cairo_fill(cr);
|
||||
|
||||
/* inner ring */
|
||||
/* inner ring (for dial) */
|
||||
cairo_set_source_rgb(cr, 1., 1., 1.);
|
||||
cairo_arc(cr, rx, ry, 30, 0, 2 * M_PI);
|
||||
cairo_fill(cr);
|
||||
|
|
@ -743,7 +747,20 @@ draw_pad(struct window *w, cairo_t *cr)
|
|||
snprintf(number, sizeof(number), "%d", w->pad.ring.number);
|
||||
cairo_set_source_rgb(cr, .0, .0, .0);
|
||||
draw_text(cr, number, rx, ry);
|
||||
}
|
||||
|
||||
if (w->pad.dial.position != -1) {
|
||||
const int degrees_per_click = 15.0;
|
||||
double degrees = fmod(w->pad.dial.position/120 * degrees_per_click, 360);
|
||||
pos = (degrees + 270) * M_PI/180.0;
|
||||
cairo_set_source_rgb(cr, .0, .0, .0);
|
||||
cairo_set_line_width(cr, 20);
|
||||
cairo_arc(cr, rx, ry, 20, pos - M_PI/12 , pos + M_PI/12);
|
||||
cairo_stroke(cr);
|
||||
|
||||
snprintf(number, sizeof(number), "%d", w->pad.dial.number);
|
||||
cairo_set_source_rgb(cr, .0, .0, .0);
|
||||
draw_text(cr, number, rx, ry);
|
||||
}
|
||||
|
||||
cairo_restore(cr);
|
||||
|
|
@ -1160,6 +1177,7 @@ window_init(struct window *w)
|
|||
|
||||
w->pad.ring.position = -1;
|
||||
w->pad.strip.position = -1;
|
||||
w->pad.dial.position = -1;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -1726,7 +1744,7 @@ handle_event_tablet_pad(struct libinput_event *ev, struct window *w)
|
|||
"Pad 0", "Pad 1", "Pad 2", "Pad 3", "Pad 4", "Pad 5",
|
||||
"Pad 6", "Pad 7", "Pad 8", "Pad 9", "Pad >= 10"
|
||||
};
|
||||
double position;
|
||||
double position, delta;
|
||||
double number;
|
||||
|
||||
switch (libinput_event_get_type(ev)) {
|
||||
|
|
@ -1748,6 +1766,14 @@ handle_event_tablet_pad(struct libinput_event *ev, struct window *w)
|
|||
w->pad.strip.number = number;
|
||||
w->pad.strip.position = position;
|
||||
break;
|
||||
case LIBINPUT_EVENT_TABLET_PAD_DIAL:
|
||||
delta = libinput_event_tablet_pad_get_dial_delta_v120(p);
|
||||
number = libinput_event_tablet_pad_get_dial_number(p);
|
||||
if (w->pad.dial.number != number)
|
||||
w->pad.dial.position = -delta;
|
||||
w->pad.dial.number = number;
|
||||
w->pad.dial.position += delta;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
|
@ -1825,6 +1851,7 @@ handle_event_libinput(GIOChannel *source, GIOCondition condition, gpointer data)
|
|||
case LIBINPUT_EVENT_TABLET_PAD_BUTTON:
|
||||
case LIBINPUT_EVENT_TABLET_PAD_RING:
|
||||
case LIBINPUT_EVENT_TABLET_PAD_STRIP:
|
||||
case LIBINPUT_EVENT_TABLET_PAD_DIAL:
|
||||
handle_event_tablet_pad(ev, w);
|
||||
break;
|
||||
case LIBINPUT_EVENT_TABLET_PAD_KEY:
|
||||
|
|
|
|||
|
|
@ -91,9 +91,10 @@ displayed on press.
|
|||
.TP 8
|
||||
.B Tablet pads
|
||||
Button events are displayed in the bottom-most button oblong, with the name
|
||||
of the button displayed on press. Ring and strip events are displayed in the
|
||||
yellow 'IO' symbol, with the position and the number of the ring/strip
|
||||
filled in when events are available.
|
||||
of the button displayed on press. Dials, ring and strip events are displayed in
|
||||
the yellow 'IO' symbol, with the position of the ring or strip or the
|
||||
delta of the dial filled in when events are available. The number of the dial,
|
||||
ring or strip is displayed when an event is available.
|
||||
.TP 8
|
||||
.B Kernel events
|
||||
Left of the center is a blue ring to debug kernel relative events (REL_X and
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue