wheel: centralize wheel handling

Move the logic to handle wheels to its own file.
Refactor, no functional changes.

Signed-off-by: José Expósito <jose.exposito89@gmail.com>
This commit is contained in:
José Expósito 2021-09-26 18:15:51 +02:00
parent 5e44861e0e
commit 4e52f03580
4 changed files with 244 additions and 160 deletions

View file

@ -368,6 +368,7 @@ src_libinput = src_libfilter + [
'src/evdev-tablet-pad.c',
'src/evdev-tablet-pad.h',
'src/evdev-tablet-pad-leds.c',
'src/evdev-wheel.c',
'src/path-seat.c',
'src/udev-seat.c',
'src/udev-seat.h',

View file

@ -68,18 +68,8 @@ fallback_notify_physical_button(struct fallback_dispatch *dispatch,
int button,
enum libinput_button_state state)
{
if (button == BTN_MIDDLE)
dispatch->wheel.is_inhibited = (state == LIBINPUT_BUTTON_STATE_PRESSED);
/* Lenovo TrackPoint Keyboard II sends its own scroll events when its
* trackpoint is moved while the middle button is pressed.
* Do not inhibit the scroll events.
* https://gitlab.freedesktop.org/libinput/libinput/-/issues/651
*/
if (evdev_device_has_model_quirk(device,
QUIRK_MODEL_LENOVO_TRACKPOINT_KEYBOARD_2))
dispatch->wheel.is_inhibited = false;
fallback_wheel_notify_physical_button(dispatch, device, time,
button, state);
evdev_pointer_notify_physical_button(device, time, button, state);
}
@ -102,10 +92,10 @@ fallback_interface_get_switch_state(struct evdev_dispatch *evdev_dispatch,
LIBINPUT_SWITCH_STATE_OFF;
}
static inline void
normalize_delta(struct evdev_device *device,
const struct device_coords *delta,
struct normalized_coords *normalized)
void
fallback_normalize_delta(struct evdev_device *device,
const struct device_coords *delta,
struct normalized_coords *normalized)
{
normalized->x = delta->x * DEFAULT_MOUSE_DPI / (double)device->dpi;
normalized->y = delta->y * DEFAULT_MOUSE_DPI / (double)device->dpi;
@ -195,7 +185,7 @@ fallback_flush_relative_motion(struct fallback_dispatch *dispatch,
fallback_rotate_relative(dispatch, device);
normalize_delta(device, &dispatch->rel, &unaccel);
fallback_normalize_delta(device, &dispatch->rel, &unaccel);
raw.x = dispatch->rel.x;
raw.y = dispatch->rel.y;
dispatch->rel.x = 0;
@ -223,110 +213,6 @@ fallback_flush_relative_motion(struct fallback_dispatch *dispatch,
pointer_notify_motion(base, time, &accel, &raw);
}
static void
fallback_flush_wheels(struct fallback_dispatch *dispatch,
struct evdev_device *device,
uint64_t time)
{
struct normalized_coords wheel_degrees = { 0.0, 0.0 };
struct discrete_coords discrete = { 0.0, 0.0 };
struct wheel_v120 v120 = { 0.0, 0.0 };
if (!(device->seat_caps & EVDEV_DEVICE_POINTER))
return;
if (!dispatch->wheel.emulate_hi_res_wheel &&
!dispatch->wheel.hi_res_event_received &&
(dispatch->wheel.lo_res.x != 0 || dispatch->wheel.lo_res.y != 0)) {
evdev_log_bug_kernel(device,
"device supports high-resolution scroll but only low-resolution events have been received.\n"
"See %s/incorrectly-enabled-hires.html for details\n",
HTTP_DOC_LINK);
dispatch->wheel.emulate_hi_res_wheel = true;
dispatch->wheel.hi_res.x = dispatch->wheel.lo_res.x * 120;
dispatch->wheel.hi_res.y = dispatch->wheel.lo_res.y * 120;
}
if (dispatch->wheel.is_inhibited) {
dispatch->wheel.hi_res.x = 0;
dispatch->wheel.hi_res.y = 0;
dispatch->wheel.lo_res.x = 0;
dispatch->wheel.lo_res.y = 0;
return;
}
if (device->model_flags & EVDEV_MODEL_LENOVO_SCROLLPOINT) {
struct normalized_coords unaccel = { 0.0, 0.0 };
dispatch->wheel.hi_res.y *= -1;
normalize_delta(device, &dispatch->wheel.hi_res, &unaccel);
evdev_post_scroll(device,
time,
LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS,
&unaccel);
dispatch->wheel.hi_res.x = 0;
dispatch->wheel.hi_res.y = 0;
return;
}
if (dispatch->wheel.hi_res.y != 0) {
int value = dispatch->wheel.hi_res.y;
v120.y = -1 * value;
wheel_degrees.y = -1 * value/120.0 * device->scroll.wheel_click_angle.y;
evdev_notify_axis_wheel(
device,
time,
bit(LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL),
&wheel_degrees,
&v120);
dispatch->wheel.hi_res.y = 0;
}
if (dispatch->wheel.lo_res.y != 0) {
int value = dispatch->wheel.lo_res.y;
wheel_degrees.y = -1 * value * device->scroll.wheel_click_angle.y;
discrete.y = -1 * value;
evdev_notify_axis_legacy_wheel(
device,
time,
bit(LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL),
&wheel_degrees,
&discrete);
dispatch->wheel.lo_res.y = 0;
}
if (dispatch->wheel.hi_res.x != 0) {
int value = dispatch->wheel.hi_res.x;
v120.x = value;
wheel_degrees.x = value/120.0 * device->scroll.wheel_click_angle.x;
evdev_notify_axis_wheel(
device,
time,
bit(LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL),
&wheel_degrees,
&v120);
dispatch->wheel.hi_res.x = 0;
}
if (dispatch->wheel.lo_res.x != 0) {
int value = dispatch->wheel.lo_res.x;
wheel_degrees.x = value * device->scroll.wheel_click_angle.x;
discrete.x = value;
evdev_notify_axis_legacy_wheel(
device,
time,
bit(LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL),
&wheel_degrees,
&discrete);
dispatch->wheel.lo_res.x = 0;
}
}
static void
fallback_flush_absolute_motion(struct fallback_dispatch *dispatch,
struct evdev_device *device,
@ -895,29 +781,9 @@ fallback_process_relative(struct fallback_dispatch *dispatch,
dispatch->rel.y += e->value;
dispatch->pending_event |= EVDEV_RELATIVE_MOTION;
break;
case REL_WHEEL:
dispatch->wheel.lo_res.y += e->value;
if (dispatch->wheel.emulate_hi_res_wheel)
dispatch->wheel.hi_res.y += e->value * 120;
dispatch->pending_event |= EVDEV_WHEEL;
break;
case REL_HWHEEL:
dispatch->wheel.lo_res.x += e->value;
if (dispatch->wheel.emulate_hi_res_wheel)
dispatch->wheel.hi_res.x += e->value * 120;
dispatch->pending_event |= EVDEV_WHEEL;
break;
case REL_WHEEL_HI_RES:
dispatch->wheel.hi_res.y += e->value;
dispatch->wheel.hi_res_event_received = true;
dispatch->pending_event |= EVDEV_WHEEL;
break;
case REL_HWHEEL_HI_RES:
dispatch->wheel.hi_res.x += e->value;
dispatch->wheel.hi_res_event_received = true;
dispatch->pending_event |= EVDEV_WHEEL;
break;
}
fallback_wheel_process_relative(dispatch, device, e, time);
}
static inline void
@ -1079,7 +945,7 @@ fallback_handle_state(struct fallback_dispatch *dispatch,
if (need_touch_frame)
touch_notify_frame(&device->base, time);
fallback_flush_wheels(dispatch, device, time);
fallback_wheel_handle_state(dispatch, device, time);
/* Buttons and keys */
if (dispatch->pending_event & EVDEV_KEY) {
@ -1827,22 +1693,7 @@ fallback_dispatch_create(struct libinput_device *libinput_device)
want_config);
}
/* On kernel < 5.0 we need to emulate high-resolution
wheel scroll events */
if ((libevdev_has_event_code(device->evdev,
EV_REL,
REL_WHEEL) &&
!libevdev_has_event_code(device->evdev,
EV_REL,
REL_WHEEL_HI_RES)) ||
(libevdev_has_event_code(device->evdev,
EV_REL,
REL_HWHEEL) &&
!libevdev_has_event_code(device->evdev,
EV_REL,
REL_HWHEEL_HI_RES)))
dispatch->wheel.emulate_hi_res_wheel = true;
fallback_init_wheel(dispatch, device);
fallback_init_debounce(dispatch);
fallback_init_arbitration(dispatch, device);

View file

@ -254,5 +254,30 @@ fallback_notify_physical_button(struct fallback_dispatch *dispatch,
uint64_t time,
int button,
enum libinput_button_state state);
void
fallback_normalize_delta(struct evdev_device *device,
const struct device_coords *delta,
struct normalized_coords *normalized);
void
fallback_init_wheel(struct fallback_dispatch *dispatch,
struct evdev_device *device);
void
fallback_wheel_notify_physical_button(struct fallback_dispatch *dispatch,
struct evdev_device *device,
uint64_t time,
int button,
enum libinput_button_state state);
void
fallback_wheel_process_relative(struct fallback_dispatch *dispatch,
struct evdev_device *device,
struct input_event *e, uint64_t time);
void
fallback_wheel_handle_state(struct fallback_dispatch *dispatch,
struct evdev_device *device,
uint64_t time);
#endif

207
src/evdev-wheel.c Normal file
View file

@ -0,0 +1,207 @@
/*
* Copyright © 2010 Intel Corporation
* Copyright © 2013 Jonas Ådahl
* Copyright © 2013-2017 Red Hat, Inc.
* Copyright © 2017 James Ye <jye836@gmail.com>
* Copyright © 2021 José Expósito
*
* 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-fallback.h"
#include "util-input-event.h"
void
fallback_wheel_process_relative(struct fallback_dispatch *dispatch,
struct evdev_device *device,
struct input_event *e, uint64_t time)
{
switch (e->code) {
case REL_WHEEL:
dispatch->wheel.lo_res.y += e->value;
if (dispatch->wheel.emulate_hi_res_wheel)
dispatch->wheel.hi_res.y += e->value * 120;
dispatch->pending_event |= EVDEV_WHEEL;
break;
case REL_HWHEEL:
dispatch->wheel.lo_res.x += e->value;
if (dispatch->wheel.emulate_hi_res_wheel)
dispatch->wheel.hi_res.x += e->value * 120;
dispatch->pending_event |= EVDEV_WHEEL;
break;
case REL_WHEEL_HI_RES:
dispatch->wheel.hi_res.y += e->value;
dispatch->wheel.hi_res_event_received = true;
dispatch->pending_event |= EVDEV_WHEEL;
break;
case REL_HWHEEL_HI_RES:
dispatch->wheel.hi_res.x += e->value;
dispatch->wheel.hi_res_event_received = true;
dispatch->pending_event |= EVDEV_WHEEL;
break;
}
}
void
fallback_wheel_notify_physical_button(struct fallback_dispatch *dispatch,
struct evdev_device *device,
uint64_t time,
int button,
enum libinput_button_state state)
{
if (button == BTN_MIDDLE)
dispatch->wheel.is_inhibited = (state == LIBINPUT_BUTTON_STATE_PRESSED);
/* Lenovo TrackPoint Keyboard II sends its own scroll events when its
* trackpoint is moved while the middle button is pressed.
* Do not inhibit the scroll events.
* https://gitlab.freedesktop.org/libinput/libinput/-/issues/651
*/
if (evdev_device_has_model_quirk(device,
QUIRK_MODEL_LENOVO_TRACKPOINT_KEYBOARD_2))
dispatch->wheel.is_inhibited = false;
}
void
fallback_wheel_handle_state(struct fallback_dispatch *dispatch,
struct evdev_device *device,
uint64_t time)
{
struct normalized_coords wheel_degrees = { 0.0, 0.0 };
struct discrete_coords discrete = { 0.0, 0.0 };
struct wheel_v120 v120 = { 0.0, 0.0 };
if (!(device->seat_caps & EVDEV_DEVICE_POINTER))
return;
if (!dispatch->wheel.emulate_hi_res_wheel &&
!dispatch->wheel.hi_res_event_received &&
(dispatch->wheel.lo_res.x != 0 || dispatch->wheel.lo_res.y != 0)) {
evdev_log_bug_kernel(device,
"device supports high-resolution scroll but only low-resolution events have been received.\n"
"See %s/incorrectly-enabled-hires.html for details\n",
HTTP_DOC_LINK);
dispatch->wheel.emulate_hi_res_wheel = true;
dispatch->wheel.hi_res.x = dispatch->wheel.lo_res.x * 120;
dispatch->wheel.hi_res.y = dispatch->wheel.lo_res.y * 120;
}
if (dispatch->wheel.is_inhibited) {
dispatch->wheel.hi_res.x = 0;
dispatch->wheel.hi_res.y = 0;
dispatch->wheel.lo_res.x = 0;
dispatch->wheel.lo_res.y = 0;
return;
}
if (device->model_flags & EVDEV_MODEL_LENOVO_SCROLLPOINT) {
struct normalized_coords unaccel = { 0.0, 0.0 };
dispatch->wheel.hi_res.y *= -1;
fallback_normalize_delta(device, &dispatch->wheel.hi_res, &unaccel);
evdev_post_scroll(device,
time,
LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS,
&unaccel);
dispatch->wheel.hi_res.x = 0;
dispatch->wheel.hi_res.y = 0;
return;
}
if (dispatch->wheel.hi_res.y != 0) {
int value = dispatch->wheel.hi_res.y;
v120.y = -1 * value;
wheel_degrees.y = -1 * value/120.0 * device->scroll.wheel_click_angle.y;
evdev_notify_axis_wheel(
device,
time,
bit(LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL),
&wheel_degrees,
&v120);
dispatch->wheel.hi_res.y = 0;
}
if (dispatch->wheel.lo_res.y != 0) {
int value = dispatch->wheel.lo_res.y;
wheel_degrees.y = -1 * value * device->scroll.wheel_click_angle.y;
discrete.y = -1 * value;
evdev_notify_axis_legacy_wheel(
device,
time,
bit(LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL),
&wheel_degrees,
&discrete);
dispatch->wheel.lo_res.y = 0;
}
if (dispatch->wheel.hi_res.x != 0) {
int value = dispatch->wheel.hi_res.x;
v120.x = value;
wheel_degrees.x = value/120.0 * device->scroll.wheel_click_angle.x;
evdev_notify_axis_wheel(
device,
time,
bit(LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL),
&wheel_degrees,
&v120);
dispatch->wheel.hi_res.x = 0;
}
if (dispatch->wheel.lo_res.x != 0) {
int value = dispatch->wheel.lo_res.x;
wheel_degrees.x = value * device->scroll.wheel_click_angle.x;
discrete.x = value;
evdev_notify_axis_legacy_wheel(
device,
time,
bit(LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL),
&wheel_degrees,
&discrete);
dispatch->wheel.lo_res.x = 0;
}
}
void
fallback_init_wheel(struct fallback_dispatch *dispatch,
struct evdev_device *device)
{
/* On kernel < 5.0 we need to emulate high-resolution
wheel scroll events */
if ((libevdev_has_event_code(device->evdev,
EV_REL,
REL_WHEEL) &&
!libevdev_has_event_code(device->evdev,
EV_REL,
REL_WHEEL_HI_RES)) ||
(libevdev_has_event_code(device->evdev,
EV_REL,
REL_HWHEEL) &&
!libevdev_has_event_code(device->evdev,
EV_REL,
REL_HWHEEL_HI_RES)))
dispatch->wheel.emulate_hi_res_wheel = true;
}