From 27a66310fc0651022e0de7fbb8a64b2e97340344 Mon Sep 17 00:00:00 2001 From: Louis Goyard Date: Tue, 12 Mar 2024 00:08:21 +0900 Subject: [PATCH] tablet: add evdev/libinput functions for tablet scroll --- src/evdev.c | 129 +++++++++++++++++++++++++++++++++++++++++ src/evdev.h | 24 ++++++++ src/libinput-private.h | 16 +++++ src/libinput.c | 125 +++++++++++++++++++++++++++++++++++++++ src/libinput.h | 29 +++++++++ src/libinput.sym | 3 + 6 files changed, 326 insertions(+) diff --git a/src/evdev.c b/src/evdev.c index da538df7..9ff26d7f 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -499,6 +499,27 @@ evdev_notify_axis_continous(struct evdev_device *device, &delta); } +void +evdev_notify_axis_tablet_tool_continous(struct evdev_device *device, + uint64_t time, + struct libinput_tablet_tool *tool, + uint32_t scroll_axes, + const struct normalized_coords *delta_in) +{ + struct normalized_coords delta = *delta_in; + + if (device->scroll.natural_scrolling_enabled) { + delta.x *= -1; + delta.y *= -1; + } + + tablet_tool_notify_axis_continuous(&device->base, + time, + tool, + scroll_axes, + &delta); +} + static void evdev_tag_external_mouse(struct evdev_device *device, struct udev_device *udev_device) @@ -2932,6 +2953,114 @@ evdev_stop_scroll(struct evdev_device *device, device->scroll.direction = 0; } +void +evdev_post_tablet_tool_scroll(struct evdev_device *device, + uint64_t time, + struct libinput_tablet_tool *tool, + enum libinput_tablet_tool_axis_source source, + const struct normalized_coords *delta) +{ + const struct normalized_coords *trigger; + struct normalized_coords event; + + if (!evdev_is_scrolling(device, + LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL)) + device->scroll.buildup.y += delta->y; + if (!evdev_is_scrolling(device, + LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL)) + device->scroll.buildup.x += delta->x; + + trigger = &device->scroll.buildup; + + /* If we're not scrolling yet, use a distance trigger: moving + past a certain distance starts scrolling */ + if (!evdev_is_scrolling(device, + LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL) && + !evdev_is_scrolling(device, + LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL)) { + if (fabs(trigger->y) >= device->scroll.threshold) + evdev_start_scrolling(device, + LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL); + if (fabs(trigger->x) >= device->scroll.threshold) + evdev_start_scrolling(device, + LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL); + /* We're already scrolling in one direction. Require some + trigger speed to start scrolling in the other direction */ + } else if (!evdev_is_scrolling(device, + LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL)) { + if (fabs(delta->y) >= device->scroll.direction_lock_threshold) + evdev_start_scrolling(device, + LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL); + } else if (!evdev_is_scrolling(device, + LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL)) { + if (fabs(delta->x) >= device->scroll.direction_lock_threshold) + evdev_start_scrolling(device, + LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL); + } + + event = *delta; + + /* We use the trigger to enable, but the delta from this event for + * the actual scroll movement. Otherwise we get a jump once + * scrolling engages */ + if (!evdev_is_scrolling(device, + LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL)) + event.y = 0.0; + + if (!evdev_is_scrolling(device, + LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL)) + event.x = 0.0; + + if (!normalized_is_zero(event)) { + uint32_t scroll_axes = device->scroll.direction; + + if (event.y == 0.0) + scroll_axes &= ~bit(LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL); + if (event.x == 0.0) + scroll_axes &= ~bit(LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL); + + switch (source) { + case LIBINPUT_TABLET_TOOL_AXIS_SOURCE_CONTINUOUS: + evdev_notify_axis_tablet_tool_continous(device, time, tool, scroll_axes, &event); + break; + default: + evdev_log_bug_libinput(device, + "Posting invalid scroll source %d\n", + source); + break; + } + } +} + +void +evdev_stop_tablet_tool_scroll(struct evdev_device *device, + 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: + pointer_notify_axis_continuous(&device->base, + time, + 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; +} + void evdev_notify_suspended_device(struct evdev_device *device) { diff --git a/src/evdev.h b/src/evdev.h index f954938c..43e8c300 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -568,6 +568,11 @@ evdev_pointer_notify_button(struct evdev_device *device, unsigned int button, enum libinput_button_state state); void +evdev_tablet_tool_notify_button(struct evdev_device *device, + uint64_t time, + unsigned int button, + enum libinput_button_state state); +void evdev_pointer_notify_physical_button(struct evdev_device *device, uint64_t time, int button, @@ -612,6 +617,13 @@ evdev_notify_axis_continous(struct evdev_device *device, uint32_t axes, const struct normalized_coords *delta_in); +void +evdev_notify_axis_tablet_tool_continous(struct evdev_device *device, + uint64_t time, + struct libinput_tablet_tool *tool, + uint32_t scroll_axes, + const struct normalized_coords *delta_in); + void evdev_post_scroll(struct evdev_device *device, uint64_t time, @@ -623,6 +635,18 @@ evdev_stop_scroll(struct evdev_device *device, uint64_t time, enum libinput_pointer_axis_source source); +void +evdev_post_tablet_tool_scroll(struct evdev_device *device, + uint64_t time, + struct libinput_tablet_tool *tool, + enum libinput_tablet_tool_axis_source source, + const struct normalized_coords *delta); + +void +evdev_stop_tablet_tool_scroll(struct evdev_device *device, + uint64_t time, + enum libinput_tablet_tool_axis_source source); + void evdev_device_remove(struct evdev_device *device); diff --git a/src/libinput-private.h b/src/libinput-private.h index de1d7d64..fc48728b 100644 --- a/src/libinput-private.h +++ b/src/libinput-private.h @@ -672,6 +672,13 @@ pointer_notify_axis_continuous(struct libinput_device *device, uint32_t axes, const struct normalized_coords *delta); +void +tablet_tool_notify_axis_continuous(struct libinput_device *device, + uint64_t time, + struct libinput_tablet_tool *tool, + uint32_t scroll_axes, + const struct normalized_coords *delta); + void pointer_notify_axis_legacy_wheel(struct libinput_device *device, uint64_t time, @@ -782,6 +789,15 @@ tablet_notify_tip(struct libinput_device *device, unsigned char *changed_axes, const struct tablet_axes *axes); +void +tablet_tool_notify_button(struct libinput_device *device, + uint64_t time, + struct libinput_tablet_tool *tool, + enum libinput_tablet_tool_tip_state tip_state, + const struct tablet_axes *axes, + int32_t button, + enum libinput_button_state state); + void tablet_notify_button(struct libinput_device *device, uint64_t time, diff --git a/src/libinput.c b/src/libinput.c index c5d9ea5d..dccc1043 100644 --- a/src/libinput.c +++ b/src/libinput.c @@ -58,6 +58,7 @@ ASSERT_INT_SIZE(enum libinput_pointer_axis); ASSERT_INT_SIZE(enum libinput_pointer_axis_source); ASSERT_INT_SIZE(enum libinput_tablet_pad_ring_axis_source); ASSERT_INT_SIZE(enum libinput_tablet_pad_strip_axis_source); +ASSERT_INT_SIZE(enum libinput_tablet_tool_axis_source); ASSERT_INT_SIZE(enum libinput_tablet_tool_type); ASSERT_INT_SIZE(enum libinput_tablet_tool_proximity_state); ASSERT_INT_SIZE(enum libinput_tablet_tool_tip_state); @@ -214,11 +215,15 @@ struct libinput_event_tablet_tool { enum libinput_button_state state; uint32_t seat_button_count; uint64_t time; + struct normalized_coords delta; struct tablet_axes axes; unsigned char changed_axes[NCHARS(LIBINPUT_TABLET_TOOL_AXIS_MAX + 1)]; struct libinput_tablet_tool *tool; enum libinput_tablet_tool_proximity_state proximity_state; enum libinput_tablet_tool_tip_state tip_state; + + enum libinput_tablet_tool_axis_source source; + uint32_t scroll_axes; }; struct libinput_event_tablet_pad { @@ -728,6 +733,24 @@ libinput_event_pointer_has_axis(struct libinput_event_pointer *event, return 0; } +LIBINPUT_EXPORT int +libinput_event_tablet_tool_has_axis(struct libinput_event_tablet_tool *event, + enum libinput_pointer_axis axis) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TABLET_TOOL_SCROLL_CONTINUOUS); + + switch (axis) { + case LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL: + case LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL: + return !!(event->scroll_axes & bit(axis)); + } + + return 0; +} + LIBINPUT_EXPORT double libinput_event_pointer_get_axis_value(struct libinput_event_pointer *event, enum libinput_pointer_axis axis) @@ -812,6 +835,33 @@ libinput_event_pointer_get_scroll_value(struct libinput_event_pointer *event, return value; } +LIBINPUT_EXPORT double +libinput_event_tablet_tool_get_scroll_value(struct libinput_event_tablet_tool *event, + enum libinput_pointer_axis axis) +{ + struct libinput *libinput = event->base.device->seat->libinput; + double value = 0; + + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0.0, + LIBINPUT_EVENT_TABLET_TOOL_SCROLL_CONTINUOUS); + + if (!libinput_event_tablet_tool_has_axis(event, axis)) { + log_bug_client(libinput, "value requested for unset axis\n"); + } else { + switch (axis) { + case LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL: + value = event->delta.x; + break; + case LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL: + value = event->delta.y; + break; + } + } + return value; +} + LIBINPUT_EXPORT double libinput_event_pointer_get_scroll_value_v120(struct libinput_event_pointer *event, enum libinput_pointer_axis axis) @@ -2552,6 +2602,43 @@ pointer_notify_button(struct libinput_device *device, &button_event->base); } +void +tablet_tool_notify_button(struct libinput_device *device, + uint64_t time, + struct libinput_tablet_tool *tool, + enum libinput_tablet_tool_tip_state tip_state, + const struct tablet_axes *axes, + int32_t button, + enum libinput_button_state state) +{ + struct libinput_event_tablet_tool *button_event; + int32_t seat_button_count; + + if (!device_has_cap(device, LIBINPUT_DEVICE_CAP_TABLET_TOOL)) + return; + + button_event = zalloc(sizeof *button_event); + + seat_button_count = update_seat_button_count(device->seat, + button, + state); + + *button_event = (struct libinput_event_tablet_tool) { + .time = time, + .tool = libinput_tablet_tool_ref(tool), + .button = button, + .state = state, + .seat_button_count = seat_button_count, + .proximity_state = LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN, + .tip_state = tip_state, + .axes = *axes, + }; + + post_device_event(device, time, + LIBINPUT_EVENT_TABLET_TOOL_BUTTON, + &button_event->base); +} + void pointer_notify_axis_finger(struct libinput_device *device, uint64_t time, @@ -2620,6 +2707,33 @@ pointer_notify_axis_continuous(struct libinput_device *device, &axis_event_legacy->base); } +void +tablet_tool_notify_axis_continuous(struct libinput_device *device, + uint64_t time, + struct libinput_tablet_tool *tool, + uint32_t scroll_axes, + const struct normalized_coords *delta) +{ + struct libinput_event_tablet_tool *axis_event; + + if (!device_has_cap(device, LIBINPUT_DEVICE_CAP_TABLET_TOOL)) + return; + + axis_event = zalloc(sizeof *axis_event); + + *axis_event = (struct libinput_event_tablet_tool) { + .time = time, + .tool = libinput_tablet_tool_ref(tool), + .delta = *delta, + .source = LIBINPUT_TABLET_TOOL_AXIS_SOURCE_CONTINUOUS, + .scroll_axes = scroll_axes, + }; + + post_device_event(device, time, + LIBINPUT_EVENT_TABLET_TOOL_SCROLL_CONTINUOUS, + &axis_event->base); +} + void pointer_notify_axis_legacy_wheel(struct libinput_device *device, uint64_t time, @@ -3771,6 +3885,17 @@ libinput_event_tablet_pad_get_strip_source(struct libinput_event_tablet_pad *eve return event->strip.source; } +LIBINPUT_EXPORT enum libinput_tablet_tool_axis_source +libinput_event_tablet_tool_get_axis_source(struct libinput_event_tablet_tool *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + LIBINPUT_TABLET_TOOL_AXIS_SOURCE_CONTINUOUS, + LIBINPUT_EVENT_TABLET_TOOL_SCROLL_CONTINUOUS); + + return event->source; +} + LIBINPUT_EXPORT uint32_t libinput_event_tablet_pad_get_button_number(struct libinput_event_tablet_pad *event) { diff --git a/src/libinput.h b/src/libinput.h index 21e35710..782f2fad 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -321,6 +321,24 @@ enum libinput_tablet_pad_strip_axis_source { LIBINPUT_TABLET_PAD_STRIP_SOURCE_FINGER, }; +/** + * @ingroup event_tablet_pad + * + * The source for a @ref LIBINPUT_EVENT_TABLET_TOOL_SCROLL_CONTINUOUS event. + * See libinput_event_tablet_tool_get_axis_source() for details. + * + * @since 1.3 + */ +enum libinput_tablet_tool_axis_source { + LIBINPUT_TABLET_TOOL_AXIS_SOURCE_UNKNOWN = 1, + + /** + * The event is caused by the movement of the tool + * while the scroll button is being held down + */ + LIBINPUT_TABLET_TOOL_AXIS_SOURCE_CONTINUOUS, +}; + /** * @ingroup device * @@ -1542,6 +1560,10 @@ int libinput_event_pointer_has_axis(struct libinput_event_pointer *event, enum libinput_pointer_axis axis); +int +libinput_event_tablet_tool_has_axis(struct libinput_event_tablet_tool *event, + enum libinput_pointer_axis axis); + /** * @ingroup event_pointer * @@ -1700,6 +1722,10 @@ double libinput_event_pointer_get_scroll_value(struct libinput_event_pointer *event, enum libinput_pointer_axis axis); +double +libinput_event_tablet_tool_get_scroll_value(struct libinput_event_tablet_tool *event, + enum libinput_pointer_axis axis); + /** * @ingroup event_pointer * @@ -3269,6 +3295,9 @@ libinput_event_tablet_pad_get_strip_number(struct libinput_event_tablet_pad *eve enum libinput_tablet_pad_strip_axis_source libinput_event_tablet_pad_get_strip_source(struct libinput_event_tablet_pad *event); +enum libinput_tablet_tool_axis_source +libinput_event_tablet_tool_get_axis_source(struct libinput_event_tablet_tool *event); + /** * @ingroup event_tablet_pad * diff --git a/src/libinput.sym b/src/libinput.sym index 3624401c..1930e350 100644 --- a/src/libinput.sym +++ b/src/libinput.sym @@ -346,4 +346,7 @@ LIBINPUT_1.26 { libinput_tablet_tool_config_pressure_range_get_maximum; libinput_tablet_tool_config_pressure_range_get_default_minimum; libinput_tablet_tool_config_pressure_range_get_default_maximum; + libinput_event_tablet_tool_has_axis; + libinput_event_tablet_tool_get_scroll_value; + libinput_event_tablet_tool_get_axis_source; } LIBINPUT_1.23;