From 505e92b1a5fed7cbd05d3de3b5c09bb4fc950cc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Sun, 18 May 2014 19:20:39 +0200 Subject: [PATCH] Add basic mouse pointer acceleration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Reviewed-by: Hans de Goede --- 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 08a18fd8..d23e349a 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -32,9 +32,11 @@ #include #include #include +#include #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)) @@ -566,6 +578,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) { @@ -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 bb88074e..c9717b56 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 22c3ed8a..45f060f9 100644 --- a/src/filter.c +++ b/src/filter.c @@ -22,6 +22,7 @@ #include "config.h" +#include #include #include #include @@ -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 ada4f930..c0219eeb 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 */