double trackpoint_accel_profile(struct motion_filter *filter, void *data, double speed_in, /* 1000-dpi normalized */ 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/ms */ const double incline = accel_filter->incline; double factor; double dpi_factor = accel_filter->dpi_factor; /* 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; }
/** * 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 touchpad_lenovo_x230_accel_profile(struct motion_filter *filter, void *data, double speed_in, uint64_t time) { /* Those touchpads presents an actual lower resolution that what is * advertised. We see some jumps from the cursor due to the big steps * in X and Y when we are receiving data. * Apply a factor to minimize those jumps at low speed, and try * keeping the same feeling as regular touchpads at high speed. * It still feels slower but it is usable at least */ double factor; /* unitless */ struct pointer_accelerator *accel_filter = (struct pointer_accelerator *)filter; double f1, f2; /* unitless */ const double max_accel = accel_filter->accel * X230_TP_MAGIC_LOW_RES_FACTOR; /* unitless factor */ const double threshold = accel_filter->threshold / X230_TP_MAGIC_LOW_RES_FACTOR; /* units/us */ const double incline = accel_filter->incline * X230_TP_MAGIC_LOW_RES_FACTOR; /* Note: the magic values in this function are obtained by * trial-and-error. No other meaning should be interpreted. * The calculation is a compressed form of * pointer_accel_profile_linear(), look at the git history of that * function for an explanation of what the min/max/etc. does. */ speed_in *= X230_MAGIC_SLOWDOWN / X230_TP_MAGIC_LOW_RES_FACTOR; f1 = min(1, v_us2ms(speed_in) * 5); f2 = 1 + (v_us2ms(speed_in) - v_us2ms(threshold)) * incline; factor = min(max_accel, f2 > 1 ? f2 : f1); return factor * X230_MAGIC_SLOWDOWN / X230_TP_MAGIC_LOW_RES_FACTOR; }
double pointer_accel_profile_linear(struct motion_filter *filter, void *data, double speed_in, /* 1000-dpi normalized */ uint64_t time) { struct pointer_accelerator *accel_filter = (struct pointer_accelerator *)filter; const double max_accel = accel_filter->accel; /* unitless factor */ const double threshold = accel_filter->threshold; /* units/us */ const double incline = accel_filter->incline; double factor; /* unitless */ /* Our acceleration function calculates a factor to accelerate input deltas with. The function is a double incline with a plateau, with a rough shape like this: accel factor ^ | / | _____/ | / |/ +-------------> speed in The two inclines are linear functions in the form y = ax + b where y is speed_out x is speed_in a is the incline of acceleration b is minimum acceleration factor for speeds up to 0.07 u/ms, we decelerate, down to 30% of input speed. hence 1 = a * 0.07 + 0.3 0.3 = a * 0.00 + 0.3 => a := 10 deceleration function is thus: y = 10x + 0.3 Note: * 0.07u/ms as threshold is a result of trial-and-error and has no other intrinsic meaning. * 0.3 is chosen simply because it is above the Nyquist frequency for subpixel motion within a pixel. */ if (v_us2ms(speed_in) < 0.07) { factor = 10 * v_us2ms(speed_in) + 0.3; /* up to the threshold, we keep factor 1, i.e. 1:1 movement */ } else if (speed_in < threshold) { factor = 1; } else { /* Acceleration function above the threshold: y = ax' + b where T is threshold x is speed_in x' is speed and y(T) == 1 hence 1 = ax' + 1 => x' := (x - T) */ factor = incline * v_us2ms(speed_in - threshold) + 1; } /* Cap at the maximum acceleration factor */ factor = min(max_accel, factor); return factor; }