Plenty of duplication there from the normal filter.c, but that also makes it less likely to break if we adjust the other one.
Signed-off-by: Peter Hutterer <peter.hutte...@who-t.net> --- meson.build | 1 + src/filter-low-dpi.c | 253 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/filter.c | 85 ----------------- 3 files changed, 254 insertions(+), 85 deletions(-) create mode 100644 src/filter-low-dpi.c diff --git a/meson.build b/meson.build index 933e2f3f..9473dc12 100644 --- a/meson.build +++ b/meson.build @@ -152,6 +152,7 @@ dep_libinput_util = declare_dependency(link_with : libinput_util) src_libfilter = [ 'src/filter.c', 'src/filter-flat.c', + 'src/filter-low-dpi.c', 'src/filter-touchpad.c', 'src/filter-touchpad-x230.c', 'src/filter-tablet.c', diff --git a/src/filter-low-dpi.c b/src/filter-low-dpi.c new file mode 100644 index 00000000..f22929ad --- /dev/null +++ b/src/filter-low-dpi.c @@ -0,0 +1,253 @@ +/* + * Copyright © 2006-2009 Simon Thum + * Copyright © 2012 Jonas Ådahl + * Copyright © 2014-2015 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "config.h" + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <limits.h> +#include <math.h> + +#include "filter.h" +#include "libinput-util.h" +#include "filter-private.h" + +/* + * Default parameters for pointer acceleration profiles. + */ + +#define DEFAULT_THRESHOLD v_ms2us(0.4) /* in units/us */ +#define MINIMUM_THRESHOLD v_ms2us(0.2) /* in units/us */ +#define DEFAULT_ACCELERATION 2.0 /* unitless factor */ +#define DEFAULT_INCLINE 1.1 /* unitless factor */ + +#define NUM_POINTER_TRACKERS 16 +/** + * Custom acceleration function for mice < 1000dpi. + * At slow motion, a single device unit causes a one-pixel movement. + * The threshold/max accel depends on the DPI, the smaller the DPI the + * earlier we accelerate and the higher the maximum acceleration is. Result: + * at low speeds we get pixel-precision, at high speeds we get approx. the + * same movement as a high-dpi mouse. + * + * Note: data fed to this function is in device units, not normalized. + */ +double +pointer_accel_profile_linear_low_dpi(struct motion_filter *filter, + void *data, + double speed_in, /* in device units (units/us) */ + uint64_t time) +{ + struct pointer_accelerator *accel_filter = + (struct pointer_accelerator *)filter; + + double max_accel = accel_filter->accel; /* unitless factor */ + double threshold = accel_filter->threshold; /* units/us */ + const double incline = accel_filter->incline; + double dpi_factor = accel_filter->dpi/(double)DEFAULT_MOUSE_DPI; + double factor; /* unitless */ + + /* dpi_factor is always < 1.0, increase max_accel, reduce + the threshold so it kicks in earlier */ + max_accel /= dpi_factor; + threshold *= dpi_factor; + + /* see pointer_accel_profile_linear for a long description */ + if (v_us2ms(speed_in) < 0.07) + factor = 10 * v_us2ms(speed_in) + 0.3; + else if (speed_in < threshold) + factor = 1; + else + factor = incline * v_us2ms(speed_in - threshold) + 1; + + factor = min(max_accel, factor); + + return factor; +} + +static inline double +calculate_acceleration_factor(struct pointer_accelerator *accel, + const struct device_float_coords *unaccelerated, + void *data, + uint64_t time) +{ + double velocity; /* units/us in device-native dpi*/ + double accel_factor; + + feed_trackers(&accel->trackers, unaccelerated, time); + velocity = calculate_velocity(&accel->trackers, time); + accel_factor = calculate_acceleration_simpsons(&accel->base, + accel->profile, + data, + velocity, + accel->last_velocity, + time); + accel->last_velocity = velocity; + + return accel_factor; +} + +static struct device_float_coords +accelerator_filter_generic(struct motion_filter *filter, + const struct device_float_coords *unaccelerated, + void *data, uint64_t time) +{ + struct pointer_accelerator *accel = + (struct pointer_accelerator *) filter; + double accel_value; /* unitless factor */ + struct device_float_coords accelerated; + + accel_value = calculate_acceleration_factor(accel, + unaccelerated, + data, + time); + + accelerated.x = accel_value * unaccelerated->x; + accelerated.y = accel_value * unaccelerated->y; + + return accelerated; +} + +static struct normalized_coords +accelerator_filter_unnormalized(struct motion_filter *filter, + const struct device_float_coords *unaccelerated, + void *data, uint64_t time) +{ + struct device_float_coords accelerated; + struct normalized_coords normalized; + + /* Accelerate for device units and return device units */ + accelerated = accelerator_filter_generic(filter, + unaccelerated, + data, + time); + normalized.x = accelerated.x; + normalized.y = accelerated.y; + return normalized; +} + +static struct normalized_coords +accelerator_filter_noop(struct motion_filter *filter, + const struct device_float_coords *unaccelerated, + void *data, uint64_t time) +{ + struct pointer_accelerator *accel = + (struct pointer_accelerator *) filter; + + return normalize_for_dpi(unaccelerated, accel->dpi); +} + +static void +accelerator_restart(struct motion_filter *filter, + void *data, + uint64_t time) +{ + struct pointer_accelerator *accel = + (struct pointer_accelerator *) filter; + + reset_trackers(&accel->trackers, time); +} + +static void +accelerator_destroy(struct motion_filter *filter) +{ + struct pointer_accelerator *accel = + (struct pointer_accelerator *) filter; + + free_trackers(&accel->trackers); + free(accel); +} + +static bool +accelerator_set_speed(struct motion_filter *filter, + double speed_adjustment) +{ + struct pointer_accelerator *accel_filter = + (struct pointer_accelerator *)filter; + + assert(speed_adjustment >= -1.0 && speed_adjustment <= 1.0); + + /* Note: the numbers below are nothing but trial-and-error magic, + don't read more into them other than "they mostly worked ok" */ + + /* delay when accel kicks in */ + accel_filter->threshold = DEFAULT_THRESHOLD - + v_ms2us(0.25) * speed_adjustment; + if (accel_filter->threshold < MINIMUM_THRESHOLD) + accel_filter->threshold = MINIMUM_THRESHOLD; + + /* adjust max accel factor */ + accel_filter->accel = DEFAULT_ACCELERATION + speed_adjustment * 1.5; + + /* higher speed -> faster to reach max */ + accel_filter->incline = DEFAULT_INCLINE + speed_adjustment * 0.75; + + filter->speed_adjustment = speed_adjustment; + return true; +} + +struct motion_filter_interface accelerator_interface_low_dpi = { + .type = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE, + .filter = accelerator_filter_unnormalized, + .filter_constant = accelerator_filter_noop, + .restart = accelerator_restart, + .destroy = accelerator_destroy, + .set_speed = accelerator_set_speed, +}; + +static struct pointer_accelerator * +create_default_filter(int dpi) +{ + struct pointer_accelerator *filter; + + filter = zalloc(sizeof *filter); + filter->last_velocity = 0.0; + + init_trackers(&filter->trackers, NUM_POINTER_TRACKERS); + + filter->threshold = DEFAULT_THRESHOLD; + filter->accel = DEFAULT_ACCELERATION; + filter->incline = DEFAULT_INCLINE; + filter->dpi = dpi; + + return filter; +} + +struct motion_filter * +create_pointer_accelerator_filter_linear_low_dpi(int dpi) +{ + struct pointer_accelerator *filter; + + filter = create_default_filter(dpi); + if (!filter) + return NULL; + + filter->base.interface = &accelerator_interface_low_dpi; + filter->profile = pointer_accel_profile_linear_low_dpi; + + return &filter->base; +} diff --git a/src/filter.c b/src/filter.c index 1261bc22..82d0ccce 100644 --- a/src/filter.c +++ b/src/filter.c @@ -401,24 +401,6 @@ accelerator_filter_pre_normalized(struct motion_filter *filter, return normalized; } -static struct normalized_coords -accelerator_filter_unnormalized(struct motion_filter *filter, - const struct device_float_coords *unaccelerated, - void *data, uint64_t time) -{ - struct device_float_coords accelerated; - struct normalized_coords normalized; - - /* Accelerate for device units and return device units */ - accelerated = accelerator_filter_generic(filter, - unaccelerated, - data, - time); - normalized.x = accelerated.x; - normalized.y = accelerated.y; - return normalized; -} - /** * Generic filter that does nothing beyond converting from the device's * native dpi into normalized coordinates. @@ -491,49 +473,6 @@ accelerator_set_speed(struct motion_filter *filter, return true; } -/** - * Custom acceleration function for mice < 1000dpi. - * At slow motion, a single device unit causes a one-pixel movement. - * The threshold/max accel depends on the DPI, the smaller the DPI the - * earlier we accelerate and the higher the maximum acceleration is. Result: - * at low speeds we get pixel-precision, at high speeds we get approx. the - * same movement as a high-dpi mouse. - * - * Note: data fed to this function is in device units, not normalized. - */ -double -pointer_accel_profile_linear_low_dpi(struct motion_filter *filter, - void *data, - double speed_in, /* in device units (units/us) */ - uint64_t time) -{ - struct pointer_accelerator *accel_filter = - (struct pointer_accelerator *)filter; - - double max_accel = accel_filter->accel; /* unitless factor */ - double threshold = accel_filter->threshold; /* units/us */ - const double incline = accel_filter->incline; - double dpi_factor = accel_filter->dpi/(double)DEFAULT_MOUSE_DPI; - double factor; /* unitless */ - - /* dpi_factor is always < 1.0, increase max_accel, reduce - the threshold so it kicks in earlier */ - max_accel /= dpi_factor; - threshold *= dpi_factor; - - /* see pointer_accel_profile_linear for a long description */ - if (v_us2ms(speed_in) < 0.07) - factor = 10 * v_us2ms(speed_in) + 0.3; - else if (speed_in < threshold) - factor = 1; - else - factor = incline * v_us2ms(speed_in - threshold) + 1; - - factor = min(max_accel, factor); - - return factor; -} - double pointer_accel_profile_linear(struct motion_filter *filter, void *data, @@ -651,27 +590,3 @@ create_pointer_accelerator_filter_linear(int dpi) return &filter->base; } - -struct motion_filter_interface accelerator_interface_low_dpi = { - .type = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE, - .filter = accelerator_filter_unnormalized, - .filter_constant = accelerator_filter_noop, - .restart = accelerator_restart, - .destroy = accelerator_destroy, - .set_speed = accelerator_set_speed, -}; - -struct motion_filter * -create_pointer_accelerator_filter_linear_low_dpi(int dpi) -{ - struct pointer_accelerator *filter; - - filter = create_default_filter(dpi); - if (!filter) - return NULL; - - filter->base.interface = &accelerator_interface_low_dpi; - filter->profile = pointer_accel_profile_linear_low_dpi; - - return &filter->base; -} -- 2.14.3 _______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/wayland-devel