Add basic mouse pointer acceleration

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@gmail.com>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
This commit is contained in:
Jonas Ådahl 2014-05-18 19:20:39 +02:00
parent d4b66061b3
commit 505e92b1a5
4 changed files with 97 additions and 5 deletions

View file

@ -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))
@ -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);

View file

@ -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)

View file

@ -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));
}
}

View file

@ -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 */