[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