[PATCH libinput] Introduce non-accelerated motion event vectors
Peter Hutterer
peter.hutterer at who-t.net
Tue Dec 2 17:35:45 PST 2014
On Tue, Dec 02, 2014 at 09:44:16PM +0800, Jonas Ådahl wrote:
> For certain applications (such as FPS games) it is necessary to use
> non-accelerated motion events (the motion vector that is passed to the
> acceleration filter) to get a more natural feeling. Supply this
> information by passing both accelerated and non-accelerated motion
> vectors to the existing motion event.
>
> Note that the non-accelerated motion event is not equivalent to 'raw'
> events as read from devices.
ACK to the patch itself, needs more documentation though. Like this sentence
which should be in the doc.
> Signed-off-by: Jonas Ådahl <jadahl at gmail.com>
> ---
> src/evdev-mt-touchpad-edge-scroll.c | 2 +-
> src/evdev-mt-touchpad.c | 20 ++++++++++----
> src/evdev-mt-touchpad.h | 4 ++-
> src/evdev.c | 19 ++++++++++----
> src/libinput-private.h | 4 ++-
> src/libinput.c | 20 +++++++++++++-
> src/libinput.h | 30 +++++++++++++++++++++
> test/pointer.c | 52 +++++++++++++++++++++++++++++++++++++
> 8 files changed, 137 insertions(+), 14 deletions(-)
>
> diff --git a/src/evdev-mt-touchpad-edge-scroll.c b/src/evdev-mt-touchpad-edge-scroll.c
> index 1dca0ea..d68fc68 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 8f76ddb..ff76fe2 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_noaccel, double *dy_noaccel,
> + 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_noaccel)
> + *dx_noaccel = motion.dx;
> + if (dy_noaccel)
> + *dy_noaccel = 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_noaccel, dy_noaccel;
>
> /* 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_noaccel, &dy_noaccel, 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_noaccel != 0.0 || dy_noaccel != 0.0) {
> + pointer_notify_motion(&tp->device->base, time,
> + dx, dy, dx_noaccel, dy_noaccel);
> + }
> }
>
> static void
> diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h
> index b2603b4..ea77062 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_noaccel, double *dy_noaccel,
> + 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 908a8ba..f7d88c4 100644
> --- a/src/evdev.c
> +++ b/src/evdev.c
> @@ -198,6 +198,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_noaccel, dy_noaccel;
> int32_t cx, cy;
> int32_t x, y;
> int slot;
> @@ -211,8 +212,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_noaccel = device->rel.dx / ((double) device->dpi /
> + DEFAULT_MOUSE_DPI);
> + dy_noaccel = device->rel.dy / ((double) device->dpi /
> + DEFAULT_MOUSE_DPI);
> device->rel.dx = 0;
> device->rel.dy = 0;
>
> @@ -221,17 +224,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_noaccel, dx_noaccel);
> break;
> }
>
> /* Apply pointer acceleration. */
> + motion.dx = dx_noaccel;
> + motion.dy = dy_noaccel;
> 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_noaccel == 0.0 && dy_noaccel == 0.0) {
> break;
> + }
>
> - pointer_notify_motion(base, time, motion.dx, motion.dy);
> + pointer_notify_motion(base, time,
> + motion.dx, motion.dy,
> + dx_noaccel, dy_noaccel);
> 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 4a9bd54..b36dc95 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 c318eee..f179de8 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_noaccel;
> + double dy_noaccel;
> uint32_t button;
> uint32_t seat_button_count;
> enum libinput_button_state state;
> @@ -304,6 +306,18 @@ libinput_event_pointer_get_dy(struct libinput_event_pointer *event)
> }
>
> LIBINPUT_EXPORT double
> +libinput_event_pointer_get_dx_noaccel(struct libinput_event_pointer *event)
> +{
> + return event->dx_noaccel;
> +}
> +
> +LIBINPUT_EXPORT double
> +libinput_event_pointer_get_dy_noaccel(struct libinput_event_pointer *event)
> +{
> + return event->dy_noaccel;
> +}
> +
> +LIBINPUT_EXPORT double
> libinput_event_pointer_get_absolute_x(struct libinput_event_pointer *event)
> {
> struct evdev_device *device =
> @@ -885,7 +899,9 @@ void
> pointer_notify_motion(struct libinput_device *device,
> uint64_t time,
> double dx,
> - double dy)
> + double dy,
> + double dx_noaccel,
> + double dy_noaccel)
> {
> struct libinput_event_pointer *motion_event;
>
> @@ -897,6 +913,8 @@ pointer_notify_motion(struct libinput_device *device,
> .time = time,
> .x = dx,
> .y = dy,
> + .dx_noaccel = dx_noaccel,
> + .dy_noaccel = dy_noaccel,
> };
>
> post_device_event(device, time,
> diff --git a/src/libinput.h b/src/libinput.h
> index 26d94ff..08fef8c 100644
> --- a/src/libinput.h
> +++ b/src/libinput.h
> @@ -497,6 +497,36 @@ libinput_event_pointer_get_dy(struct libinput_event_pointer *event);
> /**
> * @ingroup event_pointer
> *
> + * Return the relative delta of the non-accelerated motion vector of the
> + * current event. For pointer events that are not of type
> + * LIBINPUT_EVENT_POINTER_MOTION, this function returns 0.
this needs some comment about how the input is normalized
to a default resolution (which the old get_dx() needs too, I'll get that
patch out in a bit).
> + *
> + * @note It is an application bug to call this function for events other than
> + * LIBINPUT_EVENT_POINTER_MOTION.
> + *
> + * @return the non-accelerated relative x movement since the last event
> + */
> +double
> +libinput_event_pointer_get_dx_noaccel(struct libinput_event_pointer *event);
I'd personally prefer get_dx_unaccelerated to better match get_x_transformed
from the abs coordinates. maybe some english native speaker can chime in
here in regards to what makes the most sense here.
> +
> +/**
> + * @ingroup event_pointer
> + *
> + * Return the relative delta of the non-accelerated motion vector of the
> + * current event. For pointer events that are not of type
> + * LIBINPUT_EVENT_POINTER_MOTION, this function returns 0.
> + *
> + * @note It is an application bug to call this function for events other than
> + * LIBINPUT_EVENT_POINTER_MOTION.
> + *
> + * @return the non-accelerated relative y movement since the last event
> + */
> +double
> +libinput_event_pointer_get_dy_noaccel(struct libinput_event_pointer *event);
> +
> +/**
> + * @ingroup event_pointer
> + *
> * Return the current absolute x coordinate of the pointer event, in mm from
> * the top left corner of the device. To get the corresponding output screen
> * coordinate, use libinput_event_pointer_get_absolute_x_transformed().
> diff --git a/test/pointer.c b/test/pointer.c
> index 206accd..9de414c 100644
> --- a/test/pointer.c
> +++ b/test/pointer.c
> @@ -140,6 +140,57 @@ START_TEST(pointer_motion_absolute)
> END_TEST
>
> static void
> +test_noaccel_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(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);
> +
> + ev_dx = libinput_event_pointer_get_dx_noaccel(ptrev);
> + ev_dy = libinput_event_pointer_get_dy_noaccel(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_noaccel)
> +{
> + struct litest_device *dev = litest_current_device();
> +
> + litest_drain_events(dev->libinput);
> +
> + test_noaccel_event(dev, 1, 0);
> + test_noaccel_event(dev, 1, 1);
> + test_noaccel_event(dev, 1, -1);
> + test_noaccel_event(dev, 0, 1);
that test would likely pass for accelerated deltas too... maybe test for
something greater than 1 where we can expect acceleration to kick in?
Cheers,
Peter
> +
> + test_noaccel_event(dev, -1, 0);
> + test_noaccel_event(dev, -1, 1);
> + test_noaccel_event(dev, -1, -1);
> + test_noaccel_event(dev, 0, -1);
> +}
> +END_TEST
> +
> +static void
> test_button_event(struct litest_device *dev, unsigned int button, int state)
> {
> struct libinput *li = dev->libinput;
> @@ -652,6 +703,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_noaccel, 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);
> --
> 1.8.5.1
>
> _______________________________________________
> wayland-devel mailing list
> wayland-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel
>
More information about the wayland-devel
mailing list