From 0ae8e69ca8f868c00977bf02971c3d881b42d225 Mon Sep 17 00:00:00 2001 From: Louis Goyard Date: Tue, 12 Mar 2024 00:08:21 +0900 Subject: [PATCH] tablet: add tablet tool main functions --- src/evdev-tablet.c | 160 +++++++++++++++++++++++++++++++++++++++++++++ src/evdev-tablet.h | 1 + 2 files changed, 161 insertions(+) diff --git a/src/evdev-tablet.c b/src/evdev-tablet.c index 75ca81ea..be10ce6d 100644 --- a/src/evdev-tablet.c +++ b/src/evdev-tablet.c @@ -1324,6 +1324,159 @@ tablet_get_current_tool(struct tablet_dispatch *tablet) tablet->current_tool.serial); } +static void +evdev_tablet_stop_scroll(struct evdev_device *device, + struct libinput_tablet_tool* tool, + uint64_t time, + enum libinput_tablet_tool_axis_source source) +{ + const struct normalized_coords zero = { 0.0, 0.0 }; + + /* terminate scrolling with a zero scroll event */ + if (device->scroll.direction != 0) { + switch (source) { + case LIBINPUT_TABLET_TOOL_AXIS_SOURCE_CONTINUOUS: + evdev_notify_axis_tablet_tool_continous(device, + time, + tool, + device->scroll.direction, + &zero); + break; + default: + evdev_log_bug_libinput(device, + "Stopping invalid scroll source %d\n", + source); + break; + } + } + + device->scroll.buildup.x = 0; + device->scroll.buildup.y = 0; + device->scroll.direction = 0; +} + +#define DEFAULT_BUTTON_SCROLL_TIMEOUT ms2us(200) +static inline void +tablet_notify_button_scroll(struct evdev_device *device, + struct tablet_dispatch *tablet, + uint64_t time, + bool is_press) +{ + if (is_press) { + device->scroll.button_scroll_state = BUTTONSCROLL_BUTTON_DOWN; + + enum timer_flags flags = TIMER_FLAG_NONE; + libinput_timer_set_flags(&device->scroll.timer, + time + DEFAULT_BUTTON_SCROLL_TIMEOUT, + flags); + device->scroll.button_down_time = time; + evdev_log_debug(device, "btnscroll: down\n"); + } else { + struct libinput_tablet_tool *tool; + tool = tablet_get_current_tool(tablet); + if (!tool) + return; /* OOM */ + + libinput_timer_cancel(&device->scroll.timer); + switch(device->scroll.button_scroll_state) { + case BUTTONSCROLL_IDLE: + evdev_log_bug_libinput(device, + "invalid state IDLE for button up\n"); + break; + case BUTTONSCROLL_BUTTON_DOWN: + case BUTTONSCROLL_READY: + evdev_log_debug(device, "btnscroll: cancel\n"); + + enum libinput_tablet_tool_tip_state tip_state; + if (tablet_has_status(tablet, TABLET_TOOL_IN_CONTACT)) + tip_state = LIBINPUT_TABLET_TOOL_TIP_DOWN; + else + tip_state = LIBINPUT_TABLET_TOOL_TIP_UP; + + /* If the button is released quickly enough or + * without scroll events, emit the + * button press/release events. */ + tablet_notify_button(&device->base, + device->scroll.button_down_time, + tool, + tip_state, + &tablet->axes, + device->scroll.button, + LIBINPUT_BUTTON_STATE_PRESSED); + tablet_notify_button(&device->base, + time, + tool, + tip_state, + &tablet->axes, + device->scroll.button, + LIBINPUT_BUTTON_STATE_RELEASED); + break; + case BUTTONSCROLL_SCROLLING: + evdev_log_debug(device, "btnscroll: up\n"); + evdev_tablet_stop_scroll(device, tool, time, + LIBINPUT_TABLET_TOOL_AXIS_SOURCE_CONTINUOUS); + break; + } + + device->scroll.button_scroll_state = BUTTONSCROLL_IDLE; + } +} +#undef DEFAULT_BUTTON_SCROLL_TIMEOUT + +#define __SIGN(x) ((x > 0) - (x < 0)) +#define TABLET_TOOL_SCROLL_MINIMUM 2 +#define TABLET_TOOL_SCROLL_REDUCER 8 +static inline bool +post_button_scroll(struct evdev_device *device, + struct tablet_dispatch *tablet, + uint64_t time) +{ + if (device->scroll.method != LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN) + return false; + + switch(device->scroll.button_scroll_state) { + case BUTTONSCROLL_IDLE: + return false; + case BUTTONSCROLL_BUTTON_DOWN: + /* if the button is down but scroll is not active, we're within the + timeout where we swallow motion events but don't post + scroll buttons */ + evdev_log_debug(device, "btnscroll: discarding\n"); + return true; + case BUTTONSCROLL_READY: + device->scroll.button_scroll_state = BUTTONSCROLL_SCROLLING; + _fallthrough_; + case BUTTONSCROLL_SCROLLING: + { + struct normalized_coords normalized = { tablet->current_value[1] - tablet->prev_value[1] , tablet->current_value[2] - tablet->prev_value[2] }; + + normalized.x = normalized.x / TABLET_TOOL_SCROLL_REDUCER; + normalized.y = normalized.y / TABLET_TOOL_SCROLL_REDUCER; + + if (fabs(normalized.x) < TABLET_TOOL_SCROLL_MINIMUM) + normalized.x = 0; + else + normalized.x -= __SIGN(normalized.x)*(TABLET_TOOL_SCROLL_MINIMUM-1); + + if (fabs(normalized.y) < TABLET_TOOL_SCROLL_MINIMUM) + normalized.y = 0; + else + normalized.y -= __SIGN(normalized.y)*(TABLET_TOOL_SCROLL_MINIMUM-1); + + evdev_post_tablet_tool_scroll(device, time, + tablet_get_current_tool(tablet), + LIBINPUT_TABLET_TOOL_AXIS_SOURCE_CONTINUOUS, + &normalized); + } + return true; + } + + assert(!"invalid scroll button state"); +} +#undef TABLET_TOOL_SCROLL_REDUCER +#undef TABLET_TOOL_SCROLL_MINIMUM +#undef __SIGN + static void tablet_notify_button_mask(struct tablet_dispatch *tablet, struct evdev_device *device, @@ -1346,6 +1499,11 @@ tablet_notify_button_mask(struct tablet_dispatch *tablet, if (!bit_is_set(buttons->bits, i)) continue; + if (device->scroll.method == LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN && i == device->scroll.button){ + tablet_notify_button_scroll(device, tablet, time, state == LIBINPUT_BUTTON_STATE_PRESSED); + continue; + } + tablet_notify_button(base, time, tool, @@ -2117,6 +2275,8 @@ reprocess: sanitize_tablet_axes(tablet, tool); } + post_button_scroll(device, tablet, time); + tablet_send_events(tablet, tool, device, time); if (process_tool_twice) diff --git a/src/evdev-tablet.h b/src/evdev-tablet.h index 48469a2b..64f0242b 100644 --- a/src/evdev-tablet.h +++ b/src/evdev-tablet.h @@ -47,6 +47,7 @@ enum tablet_status { TABLET_TOOL_ENTERING_CONTACT = bit(9), TABLET_TOOL_LEAVING_CONTACT = bit(10), TABLET_TOOL_OUT_OF_RANGE = bit(11), + TABLET_IN_SCROLL = bit(12), }; struct button_state {