diff options
author | José Expósito <jose.exposito89@gmail.com> | 2021-09-27 09:02:57 +0200 |
---|---|---|
committer | José Expósito <jose.exposito89@gmail.com> | 2021-11-08 18:00:46 +0100 |
commit | 08245c778a8ff0e92b50266b9712174bbf4d9e32 (patch) | |
tree | 7632a1497fc65abd0fd3350edbdc92905a343cfd | |
parent | 5f0d191eba004277fb258bfde4065040e43853af (diff) | |
download | libinput-08245c778a8ff0e92b50266b9712174bbf4d9e32.tar.gz |
wheel: handle with a state machine
In order to be able to add more complex rules in the future, transform
the current wheel handling code into a state machine.
Signed-off-by: José Expósito <jose.exposito89@gmail.com>
-rw-r--r-- | src/evdev-fallback.h | 8 | ||||
-rw-r--r-- | src/evdev-wheel.c | 181 |
2 files changed, 176 insertions, 13 deletions
diff --git a/src/evdev-fallback.h b/src/evdev-fallback.h index 3b3e3188..2338f4a7 100644 --- a/src/evdev-fallback.h +++ b/src/evdev-fallback.h @@ -59,6 +59,12 @@ enum palm_state { PALM_WAS_PALM, /* this touch sequence was a palm but isn't now */ }; +enum wheel_state { + WHEEL_STATE_NONE, + WHEEL_STATE_PRESSED, + WHEEL_STATE_SCROLLING, +}; + struct mt_slot { bool dirty; enum mt_slot_state state; @@ -98,10 +104,10 @@ struct fallback_dispatch { struct device_coords rel; struct { + enum wheel_state state; struct device_coords lo_res; struct device_coords hi_res; bool emulate_hi_res_wheel; - bool is_inhibited; bool hi_res_event_received; } wheel; diff --git a/src/evdev-wheel.c b/src/evdev-wheel.c index 244e4eb0..acdbf861 100644 --- a/src/evdev-wheel.c +++ b/src/evdev-wheel.c @@ -30,6 +30,124 @@ #include "evdev-fallback.h" #include "util-input-event.h" +enum wheel_event { + WHEEL_EVENT_PRESS, + WHEEL_EVENT_RELEASE, + WHEEL_EVENT_SCROLL, +}; + +static inline const char * +wheel_state_to_str(enum wheel_state state) +{ + switch(state) { + CASE_RETURN_STRING(WHEEL_STATE_NONE); + CASE_RETURN_STRING(WHEEL_STATE_PRESSED); + CASE_RETURN_STRING(WHEEL_STATE_SCROLLING); + } + return NULL; +} + +static inline const char* +wheel_event_to_str(enum wheel_event event) +{ + switch(event) { + CASE_RETURN_STRING(WHEEL_EVENT_PRESS); + CASE_RETURN_STRING(WHEEL_EVENT_RELEASE); + CASE_RETURN_STRING(WHEEL_EVENT_SCROLL); + } + return NULL; +} + +static inline void +log_wheel_bug(struct fallback_dispatch *dispatch, enum wheel_event event) +{ + evdev_log_bug_libinput(dispatch->device, + "invalid wheel event %s in state %s\n", + wheel_event_to_str(event), + wheel_state_to_str(dispatch->wheel.state)); +} + +static void +wheel_handle_event_on_state_none(struct fallback_dispatch *dispatch, + enum wheel_event event, + uint64_t time) +{ + switch (event) { + case WHEEL_EVENT_PRESS: + dispatch->wheel.state = WHEEL_STATE_PRESSED; + break; + case WHEEL_EVENT_SCROLL: + dispatch->wheel.state = WHEEL_STATE_SCROLLING; + break; + case WHEEL_EVENT_RELEASE: + log_wheel_bug(dispatch, event); + break; + } +} + +static void +wheel_handle_event_on_state_pressed(struct fallback_dispatch *dispatch, + enum wheel_event event, + uint64_t time) +{ + switch (event) { + case WHEEL_EVENT_RELEASE: + dispatch->wheel.state = WHEEL_STATE_NONE; + break; + case WHEEL_EVENT_SCROLL: + /* Ignore scroll while the wheel is pressed */ + break; + case WHEEL_EVENT_PRESS: + log_wheel_bug(dispatch, event); + break; + } +} + +static void +wheel_handle_event_on_state_scrolling(struct fallback_dispatch *dispatch, + enum wheel_event event, + uint64_t time) +{ + switch (event) { + case WHEEL_EVENT_PRESS: + dispatch->wheel.state = WHEEL_STATE_PRESSED; + break; + case WHEEL_EVENT_SCROLL: + break; + case WHEEL_EVENT_RELEASE: + log_wheel_bug(dispatch, event); + break; + } +} + +static void +wheel_handle_event(struct fallback_dispatch *dispatch, + enum wheel_event event, + uint64_t time) +{ + enum wheel_state oldstate = dispatch->wheel.state; + + switch (oldstate) { + case WHEEL_STATE_NONE: + wheel_handle_event_on_state_none(dispatch, event, time); + break; + case WHEEL_STATE_PRESSED: + wheel_handle_event_on_state_pressed(dispatch, event, time); + break; + case WHEEL_STATE_SCROLLING: + wheel_handle_event_on_state_scrolling(dispatch, event, time); + break; + } + + if (oldstate != dispatch->wheel.state) { + evdev_log_debug(dispatch->device, + "wheel state %s → %s → %s\n", + wheel_state_to_str(oldstate), + wheel_event_to_str(event), + wheel_state_to_str(dispatch->wheel.state)); + } +} + static void wheel_flush_scroll(struct fallback_dispatch *dispatch, struct evdev_device *device, @@ -111,6 +229,33 @@ wheel_flush_scroll(struct fallback_dispatch *dispatch, } } +static void +wheel_handle_state_none(struct fallback_dispatch *dispatch, + struct evdev_device *device, + uint64_t time) +{ + +} + +static void +wheel_handle_state_pressed(struct fallback_dispatch *dispatch, + struct evdev_device *device, + uint64_t time) +{ + dispatch->wheel.hi_res.x = 0; + dispatch->wheel.hi_res.y = 0; + dispatch->wheel.lo_res.x = 0; + dispatch->wheel.lo_res.y = 0; +} + +static void +wheel_handle_state_scrolling(struct fallback_dispatch *dispatch, + struct evdev_device *device, + uint64_t time) +{ + wheel_flush_scroll(dispatch, device, time); +} + void fallback_wheel_process_relative(struct fallback_dispatch *dispatch, struct evdev_device *device, @@ -122,22 +267,26 @@ fallback_wheel_process_relative(struct fallback_dispatch *dispatch, if (dispatch->wheel.emulate_hi_res_wheel) dispatch->wheel.hi_res.y += e->value * 120; dispatch->pending_event |= EVDEV_WHEEL; + wheel_handle_event(dispatch, WHEEL_EVENT_SCROLL, time); 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; + wheel_handle_event(dispatch, WHEEL_EVENT_SCROLL, time); 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; + wheel_handle_event(dispatch, WHEEL_EVENT_SCROLL, time); 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; + wheel_handle_event(dispatch, WHEEL_EVENT_SCROLL, time); break; } } @@ -149,9 +298,6 @@ fallback_wheel_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. @@ -159,7 +305,14 @@ fallback_wheel_notify_physical_button(struct fallback_dispatch *dispatch, */ if (evdev_device_has_model_quirk(device, QUIRK_MODEL_LENOVO_TRACKPOINT_KEYBOARD_2)) - dispatch->wheel.is_inhibited = false; + return; + + if (button == BTN_MIDDLE) { + if (state == LIBINPUT_BUTTON_STATE_PRESSED) + wheel_handle_event(dispatch, WHEEL_EVENT_PRESS, time); + else + wheel_handle_event(dispatch, WHEEL_EVENT_RELEASE, time); + } } void @@ -182,21 +335,25 @@ fallback_wheel_handle_state(struct fallback_dispatch *dispatch, 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; + switch (dispatch->wheel.state) { + case WHEEL_STATE_NONE: + wheel_handle_state_none(dispatch, device, time); + break; + case WHEEL_STATE_PRESSED: + wheel_handle_state_pressed(dispatch, device, time); + break; + case WHEEL_STATE_SCROLLING: + wheel_handle_state_scrolling(dispatch, device, time); + break; } - - wheel_flush_scroll(dispatch, device, time); } void fallback_init_wheel(struct fallback_dispatch *dispatch, struct evdev_device *device) { + dispatch->wheel.state = WHEEL_STATE_NONE; + /* On kernel < 5.0 we need to emulate high-resolution wheel scroll events */ if ((libevdev_has_event_code(device->evdev, |