[PATCH libinput v2 1/2] Introduce unaccelerated motion event vectors

Peter Hutterer peter.hutterer at who-t.net
Wed Dec 3 23:10:20 PST 2014


On Thu, Dec 04, 2014 at 11:44:09AM +0800, Jonas Ådahl wrote:
> For certain applications (such as FPS games) it is necessary to use
> unaccelerated 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 unaccelerated motion
> vectors to the existing motion event.
> 
> Note that the unaccelerated motion event is not equivalent to 'raw'
> events as read from devices.
> 
> Signed-off-by: Jonas Ådahl <jadahl at gmail.com>
> ---
> 
> Changes since v1:
> 
> Renamed non-accelerated to unaccelerated and don't abbreviate in the
> public API.
> 
> Made the tested motion vectors longer in order to have the acceleration
> to potentially affect it.
> 
> Improved documentation (assumes 1000 DPI patch has been applied).
> 
> For tests assuming valid accelerated motion vectors, wait for a motion
> vector with a length more than zero.

Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>
for both with a minor nitpick below.

>  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                      | 22 ++++++++-
>  src/libinput.h                      | 42 +++++++++++++++++
>  test/pointer.c                      | 91 +++++++++++++++++++++++++++++++++----
>  test/touchpad.c                     |  8 +++-
>  9 files changed, 188 insertions(+), 24 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..15120da 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 b2603b4..da9c091 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 908a8ba..1942539 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_unaccel, dy_unaccel;
>  	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_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;
>  
> @@ -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_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 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..40305c7 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;
> @@ -304,6 +306,20 @@ libinput_event_pointer_get_dy(struct libinput_event_pointer *event)
>  }
>  
>  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)
>  {
>  	struct evdev_device *device =
> @@ -885,7 +901,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;
>  
> @@ -897,6 +915,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 a60d41e..c014b00 100644
> --- a/src/libinput.h
> +++ b/src/libinput.h
> @@ -558,6 +558,48 @@ 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
> + * LIBINPUT_EVENT_POINTER_MOTION, this function returns 0.

this and the one below needs @ref prefixed.

> + *
> + * 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 do not equivalent to 'raw' events

s/do not/are not/

> + * as read from the device.
> + *
> + * @note It is an application bug to call this function for events other than
> + * LIBINPUT_EVENT_POINTER_MOTION.

@ref here too

these three go for the get_dy as well.

Cheers,
   Peter

> + *
> + * @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
> + * 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 do not equivalent to 'raw' events
> + * as read from the device.
> + *
> + * @note It is an application bug to call this function for events other than
> + * 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
> + *
>   * 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..dfed6b7 100644
> --- a/test/pointer.c
> +++ b/test/pointer.c
> @@ -29,15 +29,43 @@
>  #include <libinput.h>
>  #include <math.h>
>  #include <unistd.h>
> +#include <values.h>
>  
>  #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);
>  }
> @@ -140,6 +163,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)
>  {
>  	struct libinput *li = dev->libinput;
> @@ -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 2b79aaf..934674c 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);
> -- 
> 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