diff --git a/src/evdev-mt-touchpad-edge-scroll.c b/src/evdev-mt-touchpad-edge-scroll.c index bc6831dd..a4dc0939 100644 --- a/src/evdev-mt-touchpad-edge-scroll.c +++ b/src/evdev-mt-touchpad-edge-scroll.c @@ -325,7 +325,9 @@ tp_edge_scroll_post_events(struct tp_dispatch *tp, uint64_t time) if (t->scroll.direction != -1) { /* Send stop scroll event */ pointer_notify_axis(device, time, - t->scroll.direction, 0.0); + t->scroll.direction, + LIBINPUT_POINTER_AXIS_SOURCE_FINGER, + 0.0); t->scroll.direction = -1; } continue; @@ -347,7 +349,9 @@ tp_edge_scroll_post_events(struct tp_dispatch *tp, uint64_t time) if (fabs(*delta) < t->scroll.threshold) continue; - pointer_notify_axis(device, time, axis, *delta); + pointer_notify_axis(device, time, axis, + LIBINPUT_POINTER_AXIS_SOURCE_FINGER, + *delta); t->scroll.direction = axis; tp_edge_scroll_handle_event(tp, t, SCROLL_EVENT_POSTED); @@ -365,7 +369,9 @@ tp_edge_scroll_stop_events(struct tp_dispatch *tp, uint64_t time) tp_for_each_touch(tp, t) { if (t->scroll.direction != -1) { pointer_notify_axis(device, time, - t->scroll.direction, 0.0); + t->scroll.direction, + LIBINPUT_POINTER_AXIS_SOURCE_FINGER, + 0.0); t->scroll.direction = -1; } } diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 0f3e72a6..7e8306d4 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -435,7 +435,10 @@ tp_post_twofinger_scroll(struct tp_dispatch *tp, uint64_t time) tp_filter_motion(tp, &dx, &dy, NULL, NULL, time); - evdev_post_scroll(tp->device, time, dx, dy); + evdev_post_scroll(tp->device, + time, + LIBINPUT_POINTER_AXIS_SOURCE_FINGER, + dx, dy); tp->scroll.twofinger_state = TWOFINGER_SCROLL_STATE_ACTIVE; } @@ -445,7 +448,9 @@ tp_twofinger_stop_scroll(struct tp_dispatch *tp, uint64_t time) struct tp_touch *t, *ptr = NULL; int nfingers_down = 0; - evdev_stop_scroll(tp->device, time); + evdev_stop_scroll(tp->device, + time, + LIBINPUT_POINTER_AXIS_SOURCE_FINGER); /* If we were scrolling and now there's exactly 1 active finger, switch back to pointer movement */ @@ -846,7 +851,9 @@ tp_trackpoint_event(uint64_t time, struct libinput_event *event, void *data) return; if (!tp->sendevents.trackpoint_active) { - evdev_stop_scroll(tp->device, time); + evdev_stop_scroll(tp->device, + time, + LIBINPUT_POINTER_AXIS_SOURCE_FINGER); tp_tap_suspend(tp, time); tp->sendevents.trackpoint_active = true; } diff --git a/src/evdev.c b/src/evdev.c index 06dd1df1..1718491d 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -222,6 +222,7 @@ evdev_flush_pending_event(struct evdev_device *device, uint64_t time) hw_is_key_down(device, device->scroll.button)) { if (device->scroll.button_scroll_active) evdev_post_scroll(device, time, + LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS, dx_unaccel, dy_unaccel); break; } @@ -394,7 +395,8 @@ evdev_button_scroll_button(struct evdev_device *device, } else { libinput_timer_cancel(&device->scroll.timer); if (device->scroll.button_scroll_active) { - evdev_stop_scroll(device, time); + evdev_stop_scroll(device, time, + LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS); device->scroll.button_scroll_active = false; } else { /* If the button is released quickly enough emit the @@ -538,6 +540,7 @@ static void evdev_notify_axis(struct evdev_device *device, uint64_t time, enum libinput_pointer_axis axis, + enum libinput_pointer_axis_source source, double value) { if (device->scroll.natural_scrolling_enabled) @@ -546,6 +549,7 @@ evdev_notify_axis(struct evdev_device *device, pointer_notify_axis(&device->base, time, axis, + source, value); } @@ -572,6 +576,7 @@ evdev_process_relative(struct evdev_device *device, device, time, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, + LIBINPUT_POINTER_AXIS_SOURCE_WHEEL, -1 * e->value * DEFAULT_AXIS_STEP_DISTANCE); break; case REL_HWHEEL: @@ -580,6 +585,7 @@ evdev_process_relative(struct evdev_device *device, device, time, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, + LIBINPUT_POINTER_AXIS_SOURCE_WHEEL, e->value * DEFAULT_AXIS_STEP_DISTANCE); break; } @@ -1781,6 +1787,7 @@ evdev_start_scrolling(struct evdev_device *device, void evdev_post_scroll(struct evdev_device *device, uint64_t time, + enum libinput_pointer_axis_source source, double dx, double dy) { @@ -1831,6 +1838,7 @@ evdev_post_scroll(struct evdev_device *device, evdev_notify_axis(device, time, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, + source, dy); } @@ -1840,23 +1848,28 @@ evdev_post_scroll(struct evdev_device *device, evdev_notify_axis(device, time, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, + source, dx); } } void -evdev_stop_scroll(struct evdev_device *device, uint64_t time) +evdev_stop_scroll(struct evdev_device *device, + uint64_t time, + enum libinput_pointer_axis_source source) { /* terminate scrolling with a zero scroll event */ if (device->scroll.direction & (1 << LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL)) pointer_notify_axis(&device->base, time, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, + source, 0); if (device->scroll.direction & (1 << LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL)) pointer_notify_axis(&device->base, time, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, + source, 0); device->scroll.buildup_horizontal = 0; diff --git a/src/evdev.h b/src/evdev.h index 820fdccd..a75dd134 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -298,12 +298,15 @@ evdev_init_natural_scroll(struct evdev_device *device); void evdev_post_scroll(struct evdev_device *device, uint64_t time, + enum libinput_pointer_axis_source source, double dx, double dy); void -evdev_stop_scroll(struct evdev_device *device, uint64_t time); +evdev_stop_scroll(struct evdev_device *device, + uint64_t time, + enum libinput_pointer_axis_source source); void evdev_device_remove(struct evdev_device *device); diff --git a/src/libinput-private.h b/src/libinput-private.h index b36dc954..84a0d440 100644 --- a/src/libinput-private.h +++ b/src/libinput-private.h @@ -279,6 +279,7 @@ void pointer_notify_axis(struct libinput_device *device, uint64_t time, enum libinput_pointer_axis axis, + enum libinput_pointer_axis_source source, double value); void diff --git a/src/libinput.c b/src/libinput.c index d78e26db..426c3069 100644 --- a/src/libinput.c +++ b/src/libinput.c @@ -65,6 +65,7 @@ struct libinput_event_pointer { uint32_t seat_button_count; enum libinput_button_state state; enum libinput_pointer_axis axis; + enum libinput_pointer_axis_source source; double value; }; @@ -390,6 +391,12 @@ libinput_event_pointer_get_axis_value(struct libinput_event_pointer *event) return event->value; } +LIBINPUT_EXPORT enum libinput_pointer_axis_source +libinput_event_pointer_get_axis_source(struct libinput_event_pointer *event) +{ + return event->source; +} + LIBINPUT_EXPORT uint32_t libinput_event_touch_get_time(struct libinput_event_touch *event) { @@ -986,6 +993,7 @@ void pointer_notify_axis(struct libinput_device *device, uint64_t time, enum libinput_pointer_axis axis, + enum libinput_pointer_axis_source source, double value) { struct libinput_event_pointer *axis_event; @@ -998,6 +1006,7 @@ pointer_notify_axis(struct libinput_device *device, .time = time, .axis = axis, .value = value, + .source = source, }; post_device_event(device, time, diff --git a/src/libinput.h b/src/libinput.h index d43b0f6a..0f251b5e 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -107,6 +107,28 @@ enum libinput_pointer_axis { LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL = 1, }; +/** + * @ingroup device + * + * The source for a libinput_pointer_axis event. See + * libinput_event_pointer_get_axis_source() for details. + */ +enum libinput_pointer_axis_source { + /** + * The event is caused by the rotation of a wheel. + */ + LIBINPUT_POINTER_AXIS_SOURCE_WHEEL = 1, + /** + * The event is caused by the movement of one or more fingers on a + * device. + */ + LIBINPUT_POINTER_AXIS_SOURCE_FINGER, + /** + * The event is caused by the motion of some device. + */ + LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS, +}; + /** * @ingroup base * @@ -651,9 +673,8 @@ libinput_event_pointer_get_axis(struct libinput_event_pointer *event); * @ref LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL and * @ref LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, the value of the event is in * relative scroll units, with the positive direction being down or right, - * respectively. The dimension of a scroll unit is equal to one unit of - * motion in the respective axis, where applicable (e.g. touchpad two-finger - * scrolling). + * respectively. For the interpretation of the value, see + * libinput_event_pointer_get_axis_source(). * * For pointer events that are not of type @ref LIBINPUT_EVENT_POINTER_AXIS, * this function returns 0. @@ -666,6 +687,44 @@ libinput_event_pointer_get_axis(struct libinput_event_pointer *event); double libinput_event_pointer_get_axis_value(struct libinput_event_pointer *event); +/** + * @ingroup event_pointer + * + * Return the source for a given axis event. Axis events (scroll events) can + * be caused by a hardware item such as a scroll wheel or emulated from + * other input sources, such as two-finger or edge scrolling on a + * touchpad. + * + * If the source is @ref LIBINPUT_POINTER_AXIS_SOURCE_FINGER, libinput + * guarantees that a scroll sequence is terminated with a scroll value of 0. + * A caller may use this information to decide on whether kinetic scrolling + * should be triggered on this scroll sequence. + * The coordinate system is identical to the cursor movement, i.e. a + * scroll value of 1 represents the equivalent relative motion of 1. + * + * If the source is @ref LIBINPUT_POINTER_AXIS_SOURCE_WHEEL, no terminating + * event is guaranteed (though it may happen). + * Scrolling is in discreet steps, a value of 10 representing one click + * of a typical mouse wheel. Some mice may have differently grained wheels, + * libinput will adjust the value accordingly. It is up to the caller how to + * interpret such different step sizes. + * + * If the source is @ref LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS, no + * terminating event is guaranteed (though it may happen). + * The coordinate system is identical to the cursor movement, i.e. a + * scroll value of 1 represents the equivalent relative motion of 1. + * + * For pointer events that are not of type LIBINPUT_EVENT_POINTER_AXIS, + * this function returns 0. + * + * @note It is an application bug to call this function for events other than + * LIBINPUT_EVENT_POINTER_AXIS. + * + * @return the source for this axis event + */ +enum libinput_pointer_axis_source +libinput_event_pointer_get_axis_source(struct libinput_event_pointer *event); + /** * @ingroup event_pointer * diff --git a/src/libinput.sym b/src/libinput.sym index 057919c9..826bfde4 100644 --- a/src/libinput.sym +++ b/src/libinput.sym @@ -71,6 +71,7 @@ global: libinput_event_pointer_get_absolute_y; libinput_event_pointer_get_absolute_y_transformed; libinput_event_pointer_get_axis; + libinput_event_pointer_get_axis_source; libinput_event_pointer_get_axis_value; libinput_event_pointer_get_base_event; libinput_event_pointer_get_button_state; diff --git a/test/pointer.c b/test/pointer.c index dfed6b7d..b9bd3cc8 100644 --- a/test/pointer.c +++ b/test/pointer.c @@ -377,6 +377,8 @@ test_wheel_event(struct litest_device *dev, int which, int amount) LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL : LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL); ck_assert_int_eq(libinput_event_pointer_get_axis_value(ptrev), expected); + ck_assert_int_eq(libinput_event_pointer_get_axis_source(ptrev), + LIBINPUT_POINTER_AXIS_SOURCE_WHEEL); libinput_event_destroy(event); } diff --git a/test/touchpad.c b/test/touchpad.c index 19e1c284..422e8fe6 100644 --- a/test/touchpad.c +++ b/test/touchpad.c @@ -1461,6 +1461,29 @@ START_TEST(touchpad_2fg_scroll_slow_distance) } END_TEST +START_TEST(touchpad_2fg_scroll_source) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_event *event; + struct libinput_event_pointer *ptrev; + + litest_drain_events(li); + + test_2fg_scroll(dev, 0, 20, 0); + litest_wait_for_event_of_type(li, LIBINPUT_EVENT_POINTER_AXIS, -1); + + while ((event = libinput_get_event(li))) { + ck_assert_int_eq(libinput_event_get_type(event), + LIBINPUT_EVENT_POINTER_AXIS); + ptrev = libinput_event_get_pointer_event(event); + ck_assert_int_eq(libinput_event_pointer_get_axis_source(ptrev), + LIBINPUT_POINTER_AXIS_SOURCE_FINGER); + libinput_event_destroy(event); + } +} +END_TEST + START_TEST(touchpad_2fg_scroll_return_to_motion) { struct litest_device *dev = litest_current_device(); @@ -1666,6 +1689,32 @@ START_TEST(touchpad_edge_scroll_no_edge_after_motion) } END_TEST +START_TEST(touchpad_edge_scroll_source) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_event *event; + struct libinput_event_pointer *ptrev; + + litest_drain_events(li); + + litest_touch_down(dev, 0, 99, 20); + litest_touch_move_to(dev, 0, 99, 20, 99, 80, 10, 0); + litest_touch_up(dev, 0); + + litest_wait_for_event_of_type(li, LIBINPUT_EVENT_POINTER_AXIS, -1); + + while ((event = libinput_get_event(li))) { + ck_assert_int_eq(libinput_event_get_type(event), + LIBINPUT_EVENT_POINTER_AXIS); + ptrev = libinput_event_get_pointer_event(event); + ck_assert_int_eq(libinput_event_pointer_get_axis_source(ptrev), + LIBINPUT_POINTER_AXIS_SOURCE_FINGER); + libinput_event_destroy(event); + } +} +END_TEST + START_TEST(touchpad_tap_is_available) { struct litest_device *dev = litest_current_device(); @@ -2219,6 +2268,7 @@ int main(int argc, char **argv) { litest_add("touchpad:scroll", touchpad_2fg_scroll, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); litest_add("touchpad:scroll", touchpad_2fg_scroll_slow_distance, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); litest_add("touchpad:scroll", touchpad_2fg_scroll_return_to_motion, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); + litest_add("touchpad:scroll", touchpad_2fg_scroll_source, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); litest_add("touchpad:scroll", touchpad_scroll_natural_defaults, LITEST_TOUCHPAD, LITEST_ANY); litest_add("touchpad:scroll", touchpad_scroll_natural_enable_config, LITEST_TOUCHPAD, LITEST_ANY); litest_add("touchpad:scroll", touchpad_scroll_natural, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH); @@ -2226,6 +2276,7 @@ int main(int argc, char **argv) { litest_add("touchpad:scroll", touchpad_edge_scroll_no_motion, LITEST_TOUCHPAD|LITEST_SINGLE_TOUCH, LITEST_ANY); litest_add("touchpad:scroll", touchpad_edge_scroll_no_edge_after_motion, LITEST_TOUCHPAD|LITEST_SINGLE_TOUCH, LITEST_ANY); litest_add("touchpad:scroll", touchpad_edge_scroll_slow_distance, LITEST_TOUCHPAD|LITEST_SINGLE_TOUCH, LITEST_ANY); + litest_add("touchpad:scroll", touchpad_edge_scroll_source, LITEST_TOUCHPAD|LITEST_SINGLE_TOUCH, LITEST_ANY); litest_add("touchpad:palm", touchpad_palm_detect_at_edge, LITEST_TOUCHPAD, LITEST_ANY); litest_add("touchpad:palm", touchpad_palm_detect_at_bottom_corners, LITEST_TOUCHPAD, LITEST_CLICKPAD); diff --git a/test/trackpoint.c b/test/trackpoint.c index 1d1a10a0..2708bad2 100644 --- a/test/trackpoint.c +++ b/test/trackpoint.c @@ -107,11 +107,35 @@ START_TEST(trackpoint_middlebutton_noscroll) } END_TEST +START_TEST(trackpoint_scroll_source) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_event *event; + struct libinput_event_pointer *ptrev; + + litest_drain_events(li); + + litest_button_scroll(dev, BTN_MIDDLE, 0, 6); + litest_wait_for_event_of_type(li, LIBINPUT_EVENT_POINTER_AXIS, -1); + + while ((event = libinput_get_event(li))) { + ptrev = libinput_event_get_pointer_event(event); + + ck_assert_int_eq(libinput_event_pointer_get_axis_source(ptrev), + LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS); + + libinput_event_destroy(event); + } +} +END_TEST + int main(int argc, char **argv) { litest_add("trackpoint:middlebutton", trackpoint_middlebutton, LITEST_POINTINGSTICK, LITEST_ANY); litest_add("trackpoint:middlebutton", trackpoint_middlebutton_noscroll, LITEST_POINTINGSTICK, LITEST_ANY); litest_add("trackpoint:scroll", trackpoint_scroll, LITEST_POINTINGSTICK, LITEST_ANY); + litest_add("trackpoint:scroll", trackpoint_scroll_source, LITEST_POINTINGSTICK, LITEST_ANY); return litest_run(argc, argv); }