diff --git a/src/evdev-mt-touchpad-edge-scroll.c b/src/evdev-mt-touchpad-edge-scroll.c index 1dca0eab..d68fc686 100644 --- a/src/evdev-mt-touchpad-edge-scroll.c +++ b/src/evdev-mt-touchpad-edge-scroll.c @@ -338,7 +338,7 @@ tp_edge_scroll_post_events(struct tp_dispatch *tp, uint64_t time) } tp_get_delta(t, &dx, &dy); - tp_filter_motion(tp, &dx, &dy, time); + tp_filter_motion(tp, &dx, &dy, NULL, NULL, time); if (fabs(*delta) < t->scroll.threshold) continue; diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index aa9c8197..8149c001 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -58,13 +58,20 @@ tp_motion_history_offset(struct tp_touch *t, int offset) void tp_filter_motion(struct tp_dispatch *tp, - double *dx, double *dy, uint64_t time) + double *dx, double *dy, + double *dx_unaccel, double *dy_unaccel, + uint64_t time) { struct motion_params motion; motion.dx = *dx * tp->accel.x_scale_coeff; motion.dy = *dy * tp->accel.y_scale_coeff; + if (dx_unaccel) + *dx_unaccel = motion.dx; + if (dy_unaccel) + *dy_unaccel = motion.dy; + if (motion.dx != 0.0 || motion.dy != 0.0) filter_dispatch(tp->device->pointer.filter, &motion, tp, time); @@ -426,7 +433,7 @@ tp_post_twofinger_scroll(struct tp_dispatch *tp, uint64_t time) dx /= nchanged; dy /= nchanged; - tp_filter_motion(tp, &dx, &dy, time); + tp_filter_motion(tp, &dx, &dy, NULL, NULL, time); evdev_post_scroll(tp->device, time, dx, dy); } @@ -586,6 +593,7 @@ tp_post_events(struct tp_dispatch *tp, uint64_t time) struct tp_touch *t = tp_current_touch(tp); double dx, dy; int filter_motion = 0; + double dx_unaccel, dy_unaccel; /* Only post (top) button events while suspended */ if (tp->device->suspended) { @@ -617,10 +625,12 @@ tp_post_events(struct tp_dispatch *tp, uint64_t time) return; tp_get_delta(t, &dx, &dy); - tp_filter_motion(tp, &dx, &dy, time); + tp_filter_motion(tp, &dx, &dy, &dx_unaccel, &dy_unaccel, time); - if (dx != 0.0 || dy != 0.0) - pointer_notify_motion(&tp->device->base, time, dx, dy); + if (dx != 0.0 || dy != 0.0 || dx_unaccel != 0.0 || dy_unaccel != 0.0) { + pointer_notify_motion(&tp->device->base, time, + dx, dy, dx_unaccel, dy_unaccel); + } } static void diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index b2603b44..da9c0914 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -276,7 +276,9 @@ tp_set_pointer(struct tp_dispatch *tp, struct tp_touch *t); void tp_filter_motion(struct tp_dispatch *tp, - double *dx, double *dy, uint64_t time); + double *dx, double *dy, + double *dx_unaccel, double *dy_unaccel, + uint64_t time); int tp_tap_handle_state(struct tp_dispatch *tp, uint64_t time); diff --git a/src/evdev.c b/src/evdev.c index c2d10d7e..fbfbcd35 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -196,6 +196,7 @@ evdev_flush_pending_event(struct evdev_device *device, uint64_t time) { struct libinput *libinput = device->base.seat->libinput; struct motion_params motion; + double dx_unaccel, dy_unaccel; int32_t cx, cy; int32_t x, y; int slot; @@ -209,8 +210,10 @@ evdev_flush_pending_event(struct evdev_device *device, uint64_t time) case EVDEV_NONE: return; case EVDEV_RELATIVE_MOTION: - motion.dx = device->rel.dx / ((double)device->dpi / DEFAULT_MOUSE_DPI); - motion.dy = device->rel.dy / ((double)device->dpi / DEFAULT_MOUSE_DPI); + dx_unaccel = device->rel.dx / ((double) device->dpi / + DEFAULT_MOUSE_DPI); + dy_unaccel = device->rel.dy / ((double) device->dpi / + DEFAULT_MOUSE_DPI); device->rel.dx = 0; device->rel.dy = 0; @@ -219,17 +222,23 @@ 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, - motion.dx, motion.dy); + dx_unaccel, dy_unaccel); break; } /* Apply pointer acceleration. */ + motion.dx = dx_unaccel; + motion.dy = dy_unaccel; filter_dispatch(device->pointer.filter, &motion, device, time); - if (motion.dx == 0.0 && motion.dy == 0.0) + if (motion.dx == 0.0 && motion.dy == 0.0 && + dx_unaccel == 0.0 && dy_unaccel == 0.0) { break; + } - pointer_notify_motion(base, time, motion.dx, motion.dy); + pointer_notify_motion(base, time, + motion.dx, motion.dy, + dx_unaccel, dy_unaccel); break; case EVDEV_ABSOLUTE_MT_DOWN: if (!(device->seat_caps & EVDEV_DEVICE_TOUCH)) diff --git a/src/libinput-private.h b/src/libinput-private.h index 4a9bd540..b36dc954 100644 --- a/src/libinput-private.h +++ b/src/libinput-private.h @@ -259,7 +259,9 @@ void pointer_notify_motion(struct libinput_device *device, uint64_t time, double dx, - double dy); + double dy, + double dx_noaccel, + double dy_noaccel); void pointer_notify_motion_absolute(struct libinput_device *device, diff --git a/src/libinput.c b/src/libinput.c index 60505f67..279cce0f 100644 --- a/src/libinput.c +++ b/src/libinput.c @@ -59,6 +59,8 @@ struct libinput_event_pointer { uint32_t time; double x; double y; + double dx_unaccel; + double dy_unaccel; uint32_t button; uint32_t seat_button_count; enum libinput_button_state state; @@ -303,6 +305,20 @@ libinput_event_pointer_get_dy(struct libinput_event_pointer *event) return event->y; } +LIBINPUT_EXPORT double +libinput_event_pointer_get_dx_unaccelerated( + struct libinput_event_pointer *event) +{ + return event->dx_unaccel; +} + +LIBINPUT_EXPORT double +libinput_event_pointer_get_dy_unaccelerated( + struct libinput_event_pointer *event) +{ + return event->dy_unaccel; +} + LIBINPUT_EXPORT double libinput_event_pointer_get_absolute_x(struct libinput_event_pointer *event) { @@ -891,7 +907,9 @@ void pointer_notify_motion(struct libinput_device *device, uint64_t time, double dx, - double dy) + double dy, + double dx_unaccel, + double dy_unaccel) { struct libinput_event_pointer *motion_event; @@ -903,6 +921,8 @@ pointer_notify_motion(struct libinput_device *device, .time = time, .x = dx, .y = dy, + .dx_unaccel = dx_unaccel, + .dy_unaccel = dy_unaccel, }; post_device_event(device, time, diff --git a/src/libinput.h b/src/libinput.h index be4a2225..0e2ba6b2 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -555,6 +555,48 @@ libinput_event_pointer_get_dx(struct libinput_event_pointer *event); double libinput_event_pointer_get_dy(struct libinput_event_pointer *event); +/** + * @ingroup event_pointer + * + * Return the relative delta of the unaccelerated motion vector of the + * current event. For pointer events that are not of type @ref + * LIBINPUT_EVENT_POINTER_MOTION, this function returns 0. + * + * Relative unaccelerated motion deltas are normalized to represent those of a + * device with 1000dpi resolution. See @ref motion_normalization for more + * details. Note that unaccelerated events are not equivalent to 'raw' events + * as read from the device. + * + * @note It is an application bug to call this function for events other than + * @ref LIBINPUT_EVENT_POINTER_MOTION. + * + * @return the unaccelerated relative x movement since the last event + */ +double +libinput_event_pointer_get_dx_unaccelerated( + struct libinput_event_pointer *event); + +/** + * @ingroup event_pointer + * + * Return the relative delta of the unaccelerated motion vector of the + * current event. For pointer events that are not of type @ref + * LIBINPUT_EVENT_POINTER_MOTION, this function returns 0. + * + * Relative unaccelerated motion deltas are normalized to represent those of a + * device with 1000dpi resolution. See @ref motion_normalization for more + * details. Note that unaccelerated events are not equivalent to 'raw' events + * as read from the device. + * + * @note It is an application bug to call this function for events other than + * @ref LIBINPUT_EVENT_POINTER_MOTION. + * + * @return the unaccelerated relative y movement since the last event + */ +double +libinput_event_pointer_get_dy_unaccelerated( + struct libinput_event_pointer *event); + /** * @ingroup event_pointer * diff --git a/test/pointer.c b/test/pointer.c index 206accd5..dfed6b7d 100644 --- a/test/pointer.c +++ b/test/pointer.c @@ -29,15 +29,43 @@ #include #include #include +#include #include "libinput-util.h" #include "litest.h" +static struct libinput_event_pointer * +get_accelerated_motion_event(struct libinput *li) +{ + struct libinput_event *event; + struct libinput_event_pointer *ptrev; + + while (1) { + event = libinput_get_event(li); + ck_assert_notnull(event); + ck_assert_int_eq(libinput_event_get_type(event), + LIBINPUT_EVENT_POINTER_MOTION); + + ptrev = libinput_event_get_pointer_event(event); + ck_assert_notnull(ptrev); + + if (fabs(libinput_event_pointer_get_dx(ptrev)) < DBL_MIN && + fabs(libinput_event_pointer_get_dy(ptrev)) < DBL_MIN) { + libinput_event_destroy(event); + continue; + } + + return ptrev; + } + + ck_abort_msg("No accelerated pointer motion event found"); + return NULL; +} + static void test_relative_event(struct litest_device *dev, int dx, int dy) { struct libinput *li = dev->libinput; - struct libinput_event *event; struct libinput_event_pointer *ptrev; double ev_dx, ev_dy; double expected_dir; @@ -56,12 +84,7 @@ test_relative_event(struct litest_device *dev, int dx, int dy) libinput_dispatch(li); - event = libinput_get_event(li); - ck_assert(event != NULL); - ck_assert_int_eq(libinput_event_get_type(event), LIBINPUT_EVENT_POINTER_MOTION); - - ptrev = libinput_event_get_pointer_event(event); - ck_assert(ptrev != NULL); + ptrev = get_accelerated_motion_event(li); expected_length = sqrt(4 * dx*dx + 4 * dy*dy); expected_dir = atan2(dx, dy); @@ -78,7 +101,7 @@ test_relative_event(struct litest_device *dev, int dx, int dy) * indifference). */ ck_assert(fabs(expected_dir - actual_dir) < M_PI_2); - libinput_event_destroy(event); + libinput_event_destroy(libinput_event_pointer_get_base_event(ptrev)); litest_drain_events(dev->libinput); } @@ -139,6 +162,57 @@ START_TEST(pointer_motion_absolute) } END_TEST +static void +test_unaccel_event(struct litest_device *dev, int dx, int dy) +{ + struct libinput *li = dev->libinput; + struct libinput_event *event; + struct libinput_event_pointer *ptrev; + double ev_dx, ev_dy; + + litest_event(dev, EV_REL, REL_X, dx); + litest_event(dev, EV_REL, REL_Y, dy); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + + libinput_dispatch(li); + + event = libinput_get_event(li); + ck_assert_notnull(event); + ck_assert_int_eq(libinput_event_get_type(event), + LIBINPUT_EVENT_POINTER_MOTION); + + ptrev = libinput_event_get_pointer_event(event); + ck_assert(ptrev != NULL); + + ev_dx = libinput_event_pointer_get_dx_unaccelerated(ptrev); + ev_dy = libinput_event_pointer_get_dy_unaccelerated(ptrev); + + ck_assert_int_eq(dx, ev_dx); + ck_assert_int_eq(dy, ev_dy); + + libinput_event_destroy(event); + + litest_drain_events(dev->libinput); +} + +START_TEST(pointer_motion_unaccel) +{ + struct litest_device *dev = litest_current_device(); + + litest_drain_events(dev->libinput); + + test_unaccel_event(dev, 10, 0); + test_unaccel_event(dev, 10, 10); + test_unaccel_event(dev, 10, -10); + test_unaccel_event(dev, 0, 10); + + test_unaccel_event(dev, -10, 0); + test_unaccel_event(dev, -10, 10); + test_unaccel_event(dev, -10, -10); + test_unaccel_event(dev, 0, -10); +} +END_TEST + static void test_button_event(struct litest_device *dev, unsigned int button, int state) { @@ -652,6 +726,7 @@ int main (int argc, char **argv) { litest_add("pointer:motion", pointer_motion_relative, LITEST_RELATIVE, LITEST_ANY); litest_add("pointer:motion", pointer_motion_absolute, LITEST_ABSOLUTE, LITEST_ANY); + litest_add("pointer:motion", pointer_motion_unaccel, LITEST_RELATIVE, LITEST_ANY); litest_add("pointer:button", pointer_button, LITEST_BUTTON, LITEST_CLICKPAD); litest_add_no_device("pointer:button_auto_release", pointer_button_auto_release); litest_add("pointer:scroll", pointer_scroll_wheel, LITEST_WHEEL, LITEST_ANY); diff --git a/test/touchpad.c b/test/touchpad.c index 2b79aafe..934674c1 100644 --- a/test/touchpad.c +++ b/test/touchpad.c @@ -1173,8 +1173,12 @@ START_TEST(clickpad_softbutton_left_2nd_fg_move) x = libinput_event_pointer_get_dx(p); y = libinput_event_pointer_get_dy(p); - ck_assert(x > 0); - ck_assert(y == 0); + /* Ignore events only containing an unaccelerated motion + * vector. */ + if (x != 0 || y != 0) { + ck_assert(x > 0); + ck_assert(y == 0); + } libinput_event_destroy(event); libinput_dispatch(li);