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;
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);
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;
}
}
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;
}
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 */
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;
}
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;
}
} 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
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)
pointer_notify_axis(&device->base,
time,
axis,
+ source,
value);
}
device,
time,
LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL,
+ LIBINPUT_POINTER_AXIS_SOURCE_WHEEL,
-1 * e->value * DEFAULT_AXIS_STEP_DISTANCE);
break;
case REL_HWHEEL:
device,
time,
LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL,
+ LIBINPUT_POINTER_AXIS_SOURCE_WHEEL,
e->value * DEFAULT_AXIS_STEP_DISTANCE);
break;
}
void
evdev_post_scroll(struct evdev_device *device,
uint64_t time,
+ enum libinput_pointer_axis_source source,
double dx,
double dy)
{
evdev_notify_axis(device,
time,
LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL,
+ source,
dy);
}
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;
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);
pointer_notify_axis(struct libinput_device *device,
uint64_t time,
enum libinput_pointer_axis axis,
+ enum libinput_pointer_axis_source source,
double value);
void
uint32_t seat_button_count;
enum libinput_button_state state;
enum libinput_pointer_axis axis;
+ enum libinput_pointer_axis_source source;
double value;
};
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)
{
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;
.time = time,
.axis = axis,
.value = value,
+ .source = source,
};
post_device_event(device, time,
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
*
* @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.
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
*
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;
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);
}
}
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();
}
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();
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);
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);
}
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);
}