* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "config.h"
+
+#include <assert.h>
+#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <limits.h>
#include <math.h>
-#include <wayland-util.h>
-
-#include "compositor.h"
#include "filter.h"
+#include "libinput-util.h"
+#include "filter-private.h"
void
-weston_filter_dispatch(struct weston_motion_filter *filter,
- struct weston_motion_params *motion,
- void *data, uint32_t time)
+filter_dispatch(struct motion_filter *filter,
+ struct motion_params *motion,
+ void *data, uint64_t time)
{
filter->interface->filter(filter, motion, data, time);
}
+void
+filter_destroy(struct motion_filter *filter)
+{
+ if (!filter)
+ return;
+
+ filter->interface->destroy(filter);
+}
+
+bool
+filter_set_speed(struct motion_filter *filter,
+ double speed)
+{
+ return filter->interface->set_speed(filter, speed);
+}
+
+double
+filter_get_speed(struct motion_filter *filter)
+{
+ return filter->speed;
+}
+
+/*
+ * Default parameters for pointer acceleration profiles.
+ */
+
+#define DEFAULT_THRESHOLD 0.4 /* in units/ms */
+#define DEFAULT_ACCELERATION 2.0 /* unitless factor */
+#define DEFAULT_INCLINE 1.1 /* unitless factor */
+
/*
- * Pointer acceleration filter
+ * Pointer acceleration filter constants
*/
-#define MAX_VELOCITY_DIFF 1.0
+#define MAX_VELOCITY_DIFF 1.0 /* units/ms */
#define MOTION_TIMEOUT 300 /* (ms) */
#define NUM_POINTER_TRACKERS 16
struct pointer_tracker {
- double dx;
- double dy;
- uint32_t time;
+ double dx; /* delta to most recent event, in device units */
+ double dy; /* delta to most recent event, in device units */
+ uint64_t time; /* ms */
int dir;
};
struct pointer_accelerator;
struct pointer_accelerator {
- struct weston_motion_filter base;
+ struct motion_filter base;
accel_profile_func_t profile;
- double velocity;
- double last_velocity;
- int last_dx;
- int last_dy;
+ double velocity; /* units/ms */
+ double last_velocity; /* units/ms */
+ int last_dx; /* device units */
+ int last_dy; /* device units */
struct pointer_tracker *trackers;
int cur_tracker;
-};
-enum directions {
- N = 1 << 0,
- NE = 1 << 1,
- E = 1 << 2,
- SE = 1 << 3,
- S = 1 << 4,
- SW = 1 << 5,
- W = 1 << 6,
- NW = 1 << 7,
- UNDEFINED_DIRECTION = 0xff
+ double threshold; /* units/ms */
+ double accel; /* unitless factor */
+ double incline; /* incline of the function */
};
-static int
-get_direction(int dx, int dy)
-{
- int dir = UNDEFINED_DIRECTION;
- int d1, d2;
- double r;
-
- if (abs(dx) < 2 && abs(dy) < 2) {
- if (dx > 0 && dy > 0)
- dir = S | SE | E;
- else if (dx > 0 && dy < 0)
- dir = N | NE | E;
- else if (dx < 0 && dy > 0)
- dir = S | SW | W;
- else if (dx < 0 && dy < 0)
- dir = N | NW | W;
- else if (dx > 0)
- dir = NW | W | SW;
- else if (dx < 0)
- dir = NE | E | SE;
- else if (dy > 0)
- dir = SE | S | SW;
- else if (dy < 0)
- dir = NE | N | NW;
- }
- else {
- /* Calculate r within the interval [0 to 8)
- *
- * r = [0 .. 2π] where 0 is North
- * d_f = r / 2π ([0 .. 1))
- * d_8 = 8 * d_f
- */
- r = atan2(dy, dx);
- r = fmod(r + 2.5*M_PI, 2*M_PI);
- r *= 4*M_1_PI;
-
- /* Mark one or two close enough octants */
- d1 = (int)(r + 0.9) % 8;
- d2 = (int)(r + 0.1) % 8;
-
- dir = (1 << d1) | (1 << d2);
- }
-
- return dir;
-}
-
static void
feed_trackers(struct pointer_accelerator *accel,
double dx, double dy,
- uint32_t time)
+ uint64_t time)
{
int i, current;
struct pointer_tracker *trackers = accel->trackers;
trackers[current].dx = 0.0;
trackers[current].dy = 0.0;
trackers[current].time = time;
- trackers[current].dir = get_direction(dx, dy);
+ trackers[current].dir = vector_get_direction(dx, dy);
}
static struct pointer_tracker *
}
static double
-calculate_tracker_velocity(struct pointer_tracker *tracker, uint32_t time)
+calculate_tracker_velocity(struct pointer_tracker *tracker, uint64_t time)
{
int dx;
int dy;
dx = tracker->dx;
dy = tracker->dy;
distance = sqrt(dx*dx + dy*dy);
- return distance / (double)(time - tracker->time);
+ return distance / (double)(time - tracker->time); /* units/ms */
}
static double
-calculate_velocity(struct pointer_accelerator *accel, uint32_t time)
+calculate_velocity(struct pointer_accelerator *accel, uint64_t time)
{
struct pointer_tracker *tracker;
double velocity;
double result = 0.0;
- double initial_velocity;
+ double initial_velocity = 0.0;
double velocity_diff;
unsigned int offset;
unsigned int dir = tracker_by_offset(accel, 0)->dir;
- /* Find first velocity */
- for (offset = 1; offset < NUM_POINTER_TRACKERS; offset++) {
- tracker = tracker_by_offset(accel, offset);
-
- if (time <= tracker->time)
- continue;
-
- result = initial_velocity =
- calculate_tracker_velocity(tracker, time);
- if (initial_velocity > 0.0)
- break;
- }
-
/* Find least recent vector within a timelimit, maximum velocity diff
* and direction threshold. */
- for (; offset < NUM_POINTER_TRACKERS; offset++) {
+ for (offset = 1; offset < NUM_POINTER_TRACKERS; offset++) {
tracker = tracker_by_offset(accel, offset);
/* Stop if too far away in time */
velocity = calculate_tracker_velocity(tracker, time);
- /* Stop if velocity differs too much from initial */
- velocity_diff = fabs(initial_velocity - velocity);
- if (velocity_diff > MAX_VELOCITY_DIFF)
- break;
+ if (initial_velocity == 0.0) {
+ result = initial_velocity = velocity;
+ } else {
+ /* Stop if velocity differs too much from initial */
+ velocity_diff = fabs(initial_velocity - velocity);
+ if (velocity_diff > MAX_VELOCITY_DIFF)
+ break;
- result = velocity;
+ result = velocity;
+ }
}
- return result;
+ return result; /* units/ms */
}
static double
acceleration_profile(struct pointer_accelerator *accel,
- void *data, double velocity, uint32_t time)
+ void *data, double velocity, uint64_t time)
{
return accel->profile(&accel->base, data, velocity, time);
}
static double
calculate_acceleration(struct pointer_accelerator *accel,
- void *data, double velocity, uint32_t time)
+ void *data, double velocity, uint64_t time)
{
double factor;
factor = factor / 6.0;
- return factor;
-}
-
-static double
-soften_delta(double last_delta, double delta)
-{
- if (delta < -1.0 || delta > 1.0) {
- if (delta > last_delta)
- return delta - 0.5;
- else if (delta < last_delta)
- return delta + 0.5;
- }
-
- return delta;
+ return factor; /* unitless factor */
}
static void
-apply_softening(struct pointer_accelerator *accel,
- struct weston_motion_params *motion)
-{
- motion->dx = soften_delta(accel->last_dx, motion->dx);
- motion->dy = soften_delta(accel->last_dy, motion->dy);
-}
-
-static void
-accelerator_filter(struct weston_motion_filter *filter,
- struct weston_motion_params *motion,
- void *data, uint32_t time)
+accelerator_filter(struct motion_filter *filter,
+ struct motion_params *motion,
+ void *data, uint64_t time)
{
struct pointer_accelerator *accel =
(struct pointer_accelerator *) filter;
- double velocity;
- double accel_value;
+ double velocity; /* units/ms */
+ double accel_value; /* unitless factor */
feed_trackers(accel, motion->dx, motion->dy, time);
velocity = calculate_velocity(accel, time);
motion->dx = accel_value * motion->dx;
motion->dy = accel_value * motion->dy;
- apply_softening(accel, motion);
-
accel->last_dx = motion->dx;
accel->last_dy = motion->dy;
}
static void
-accelerator_destroy(struct weston_motion_filter *filter)
+accelerator_destroy(struct motion_filter *filter)
{
struct pointer_accelerator *accel =
(struct pointer_accelerator *) filter;
free(accel);
}
-struct weston_motion_filter_interface accelerator_interface = {
+static bool
+accelerator_set_speed(struct motion_filter *filter,
+ double speed)
+{
+ struct pointer_accelerator *accel_filter =
+ (struct pointer_accelerator *)filter;
+
+ assert(speed >= -1.0 && speed <= 1.0);
+
+ /* delay when accel kicks in */
+ accel_filter->threshold = DEFAULT_THRESHOLD - speed/6.0;
+
+ /* adjust max accel factor */
+ accel_filter->accel = DEFAULT_ACCELERATION + speed;
+
+ /* higher speed -> faster to reach max */
+ accel_filter->incline = DEFAULT_INCLINE + speed/2.0;
+
+ filter->speed = speed;
+ return true;
+}
+
+struct motion_filter_interface accelerator_interface = {
accelerator_filter,
- accelerator_destroy
+ accelerator_destroy,
+ accelerator_set_speed,
};
-struct weston_motion_filter *
+struct motion_filter *
create_pointer_accelator_filter(accel_profile_func_t profile)
{
struct pointer_accelerator *filter;
return NULL;
filter->base.interface = &accelerator_interface;
- wl_list_init(&filter->base.link);
filter->profile = profile;
filter->last_velocity = 0.0;
calloc(NUM_POINTER_TRACKERS, sizeof *filter->trackers);
filter->cur_tracker = 0;
+ filter->threshold = DEFAULT_THRESHOLD;
+ filter->accel = DEFAULT_ACCELERATION;
+ filter->incline = DEFAULT_INCLINE;
+
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_linear(struct motion_filter *filter,
+ void *data,
+ double speed_in,
+ uint64_t time)
+{
+ struct pointer_accelerator *accel_filter =
+ (struct pointer_accelerator *)filter;
+
+ double s1, s2;
+ const double max_accel = accel_filter->accel; /* unitless factor */
+ const double threshold = accel_filter->threshold; /* units/ms */
+ const double incline = accel_filter->incline;
+
+ s1 = min(1, speed_in * 5);
+ s2 = 1 + (speed_in - threshold) * incline;
+
+ return min(max_accel, s2 > 1 ? s2 : s1);
+}