[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