[PATCH libinput 4/7 v2] Add basic mouse pointer acceleration

Jonas Ådahl jadahl at gmail.com
Mon May 26 14:27:27 PDT 2014


This patch reimplements the simple smooth pointer acceleration profile
from X.org xserver. The algorithm is identical to the classic profile
with a non-zero pointer acceleration threshold.

When support for changable parameters is in place, to get a pointer
acceleration the same as the default classic profile of X.org a
polynomial acceleration profile should be used for when the threshold
parameter is zero.

Signed-off-by: Jonas Ådahl <jadahl at gmail.com>
---

Changes since v1:
 - Don't send (0, 0) motion events
 - Destroy filter when destroying device

 src/evdev.c  | 37 +++++++++++++++++++++++++++++++++----
 src/evdev.h  |  4 ++++
 src/filter.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++-
 src/filter.h | 14 ++++++++++++++
 4 files changed, 97 insertions(+), 5 deletions(-)

diff --git a/src/evdev.c b/src/evdev.c
index 08a18fd..d23e349 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -32,9 +32,11 @@
 #include <mtdev-plumbing.h>
 #include <assert.h>
 #include <time.h>
+#include <math.h>
 
 #include "libinput.h"
 #include "evdev.h"
+#include "filter.h"
 #include "libinput-private.h"
 
 #define DEFAULT_AXIS_STEP_DISTANCE li_fixed_from_int(10)
@@ -112,8 +114,10 @@ evdev_device_transform_y(struct evdev_device *device,
 static void
 evdev_flush_pending_event(struct evdev_device *device, uint64_t time)
 {
+	struct motion_params motion;
 	int32_t cx, cy;
 	li_fixed_t x, y;
+	li_fixed_t dx, dy;
 	int slot;
 	int seat_slot;
 	struct libinput_device *base = &device->base;
@@ -125,12 +129,20 @@ evdev_flush_pending_event(struct evdev_device *device, uint64_t time)
 	case EVDEV_NONE:
 		return;
 	case EVDEV_RELATIVE_MOTION:
-		pointer_notify_motion(base,
-				      time,
-				      device->rel.dx,
-				      device->rel.dy);
+		motion.dx = li_fixed_to_double(device->rel.dx);
+		motion.dy = li_fixed_to_double(device->rel.dy);
 		device->rel.dx = 0;
 		device->rel.dy = 0;
+
+		/* Apply pointer acceleration. */
+		filter_dispatch(device->pointer.filter, &motion, device, time);
+
+		dx = li_fixed_from_double(motion.dx);
+		dy = li_fixed_from_double(motion.dy);
+		if (dx == 0 && dy == 0)
+			break;
+
+		pointer_notify_motion(base, time, dx, dy);
 		break;
 	case EVDEV_ABSOLUTE_MT_DOWN:
 		if (!(device->seat_caps & EVDEV_DEVICE_TOUCH))
@@ -567,6 +579,18 @@ evdev_device_dispatch(void *data)
 }
 
 static int
+configure_pointer_acceleration(struct evdev_device *device)
+{
+	device->pointer.filter =
+		create_pointer_accelator_filter(
+			pointer_accel_profile_smooth_simple);
+	if (!device->pointer.filter)
+		return -1;
+
+	return 0;
+}
+
+static int
 evdev_configure_device(struct evdev_device *device)
 {
 	struct libevdev *evdev = device->evdev;
@@ -676,7 +700,11 @@ evdev_configure_device(struct evdev_device *device)
 		has_keyboard = 1;
 
 	if ((has_abs || has_rel) && has_button) {
+		if (configure_pointer_acceleration(device) == -1)
+			return -1;
+
 		device->seat_caps |= EVDEV_DEVICE_POINTER;
+
 		log_info("input device '%s', %s is a pointer caps =%s%s%s\n",
 			 device->devname, device->devnode,
 			 has_abs ? " absolute-motion" : "",
@@ -849,6 +877,7 @@ evdev_device_destroy(struct evdev_device *device)
 	if (dispatch)
 		dispatch->interface->destroy(dispatch);
 
+	motion_filter_destroy(device->pointer.filter);
 	libinput_seat_unref(device->base.seat);
 	libevdev_free(device->evdev);
 	free(device->mt.slots);
diff --git a/src/evdev.h b/src/evdev.h
index bb88074..c9717b5 100644
--- a/src/evdev.h
+++ b/src/evdev.h
@@ -90,6 +90,10 @@ struct evdev_device {
 	enum evdev_device_seat_capability seat_caps;
 
 	int is_mt;
+
+	struct {
+		struct motion_filter *filter;
+	} pointer;
 };
 
 #define EVDEV_UNHANDLED_DEVICE ((struct evdev_device *) 1)
diff --git a/src/filter.c b/src/filter.c
index 22c3ed8..45f060f 100644
--- a/src/filter.c
+++ b/src/filter.c
@@ -22,6 +22,7 @@
 
 #include "config.h"
 
+#include <stdio.h>
 #include <stdlib.h>
 #include <stdint.h>
 #include <limits.h>
@@ -38,7 +39,15 @@ filter_dispatch(struct motion_filter *filter,
 }
 
 /*
- * Pointer acceleration filter
+ * Default parameters for pointer acceleration profiles.
+ */
+
+#define DEFAULT_CONSTANT_ACCELERATION 10.0
+#define DEFAULT_THRESHOLD 4.0
+#define DEFAULT_ACCELERATION 2.0
+
+/*
+ * Pointer acceleration filter constants
  */
 
 #define MAX_VELOCITY_DIFF	1.0
@@ -340,3 +349,39 @@ motion_filter_destroy(struct motion_filter *filter)
 
 	filter->interface->destroy(filter);
 }
+
+static inline double
+calc_penumbral_gradient(double x)
+{
+	x *= 2.0;
+	x -= 1.0;
+	return 0.5 + (x * sqrt(1.0 - x * x) + asin(x)) / M_PI;
+}
+
+double
+pointer_accel_profile_smooth_simple(struct motion_filter *filter,
+				    void *data,
+				    double velocity,
+				    uint64_t time)
+{
+	double threshold = DEFAULT_THRESHOLD;
+	double accel = DEFAULT_ACCELERATION;
+	double smooth_accel_coefficient;
+
+	velocity *= DEFAULT_CONSTANT_ACCELERATION;
+
+	if (velocity < 1.0)
+		return calc_penumbral_gradient(0.5 + velocity * 0.5) * 2.0 - 1.0;
+	if (threshold < 1.0)
+		threshold = 1.0;
+	if (velocity <= threshold)
+		return 1;
+	velocity /= threshold;
+	if (velocity >= accel) {
+		return accel;
+	} else {
+		smooth_accel_coefficient =
+			calc_penumbral_gradient(velocity / accel);
+		return 1.0 + (smooth_accel_coefficient * (accel - 1.0));
+	}
+}
diff --git a/src/filter.h b/src/filter.h
index ada4f93..c0219ee 100644
--- a/src/filter.h
+++ b/src/filter.h
@@ -62,4 +62,18 @@ create_pointer_accelator_filter(accel_profile_func_t filter);
 void
 motion_filter_destroy(struct motion_filter *filter);
 
+/*
+ * Pointer acceleration profiles.
+ */
+
+/*
+ * Profile similar which is similar to nonaccelerated but with a smooth
+ * transition between accelerated and non-accelerated.
+ */
+double
+pointer_accel_profile_smooth_simple(struct motion_filter *filter,
+				    void *data,
+				    double velocity,
+				    uint64_t time);
+
 #endif /* FILTER_H */
-- 
1.9.1



More information about the wayland-devel mailing list