[PATCH libinput 1/2] Add basic mouse pointer acceleration

Jonas Ådahl jadahl at gmail.com
Tue May 20 14:19:49 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>
---
 src/evdev.c  | 29 +++++++++++++++++++++++++++--
 src/evdev.h  |  4 ++++
 src/filter.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++-
 src/filter.h | 14 ++++++++++++++
 4 files changed, 91 insertions(+), 3 deletions(-)

diff --git a/src/evdev.c b/src/evdev.c
index 57dcca7..fedc324 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,6 +114,7 @@ evdev_device_transform_y(struct evdev_device *device,
 static void
 evdev_flush_pending_event(struct evdev_device *device, uint32_t time)
 {
+	struct motion_params motion;
 	int32_t cx, cy;
 	li_fixed_t x, y;
 	int slot;
@@ -125,10 +128,16 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time)
 	case EVDEV_NONE:
 		return;
 	case EVDEV_RELATIVE_MOTION:
+		motion.dx = li_fixed_to_double(device->rel.dx);
+		motion.dy = li_fixed_to_double(device->rel.dy);
+
+		/* Apply pointer acceleration. */
+		filter_dispatch(device->pointer.filter, &motion, device, time);
+
 		pointer_notify_motion(base,
 				      time,
-				      device->rel.dx,
-				      device->rel.dy);
+				      li_fixed_from_double(motion.dx),
+				      li_fixed_from_double(motion.dy));
 		device->rel.dx = 0;
 		device->rel.dy = 0;
 		break;
@@ -567,6 +576,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 +697,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" : "",
diff --git a/src/evdev.h b/src/evdev.h
index 36daf3c..b51728f 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 397e0f6..68fb14c 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
@@ -332,3 +341,39 @@ create_pointer_accelator_filter(accel_profile_func_t profile)
 
 	return &filter->base;
 }
+
+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,
+				    uint32_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 6b2a1d2..e5558b1 100644
--- a/src/filter.h
+++ b/src/filter.h
@@ -59,4 +59,18 @@ typedef double (*accel_profile_func_t)(struct motion_filter *filter,
 struct motion_filter *
 create_pointer_accelator_filter(accel_profile_func_t 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,
+				    uint32_t time);
+
 #endif /* FILTER_H */
-- 
1.9.1



More information about the wayland-devel mailing list