diff --git a/src/evdev.c b/src/evdev.c index 62e6b838..4c147b3d 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -1828,6 +1828,19 @@ evdev_configure_mt_device(struct evdev_device *device) return 0; } +static inline int +evdev_init_accel(struct evdev_device *device) +{ + accel_profile_func_t profile; + + if (device->dpi < DEFAULT_MOUSE_DPI) + profile = pointer_accel_profile_linear_low_dpi; + else + profile = pointer_accel_profile_linear; + + return evdev_device_init_pointer_acceleration(device, profile); +} + static int evdev_configure_device(struct evdev_device *device) { @@ -1923,9 +1936,7 @@ evdev_configure_device(struct evdev_device *device) udev_tags & EVDEV_UDEV_TAG_POINTINGSTICK) { if (libevdev_has_event_code(evdev, EV_REL, REL_X) && libevdev_has_event_code(evdev, EV_REL, REL_Y) && - evdev_device_init_pointer_acceleration( - device, - pointer_accel_profile_linear) == -1) + evdev_init_accel(device) == -1) return -1; device->seat_caps |= EVDEV_DEVICE_POINTER; diff --git a/src/filter.c b/src/filter.c index 23e33495..35449f56 100644 --- a/src/filter.c +++ b/src/filter.c @@ -264,8 +264,16 @@ accelerator_filter(struct motion_filter *filter, double velocity; /* units/ms */ double accel_value; /* unitless factor */ struct normalized_coords accelerated; + struct normalized_coords unnormalized; + double dpi_factor = accel->dpi_factor; - feed_trackers(accel, unaccelerated, time); + /* For low-dpi mice, use device units, everything else uses + 1000dpi normalized */ + dpi_factor = min(1.0, dpi_factor); + unnormalized.x = unaccelerated->x * dpi_factor; + unnormalized.y = unaccelerated->y * dpi_factor; + + feed_trackers(accel, &unnormalized, time); velocity = calculate_velocity(accel, time); accel_value = calculate_acceleration(accel, data, @@ -273,10 +281,10 @@ accelerator_filter(struct motion_filter *filter, accel->last_velocity, time); - accelerated.x = accel_value * unaccelerated->x; - accelerated.y = accel_value * unaccelerated->y; + accelerated.x = accel_value * unnormalized.x; + accelerated.y = accel_value * unnormalized.y; - accel->last = *unaccelerated; + accel->last = unnormalized; accel->last_velocity = velocity; @@ -377,10 +385,46 @@ create_pointer_accelerator_filter(accel_profile_func_t profile, return &filter->base; } +/** + * 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 */ + uint64_t time) +{ + struct pointer_accelerator *accel_filter = + (struct pointer_accelerator *)filter; + + double s1, s2; + double max_accel = accel_filter->accel; /* unitless factor */ + const double threshold = accel_filter->threshold; /* units/ms */ + const double incline = accel_filter->incline; + double factor; + double dpi_factor = accel_filter->dpi_factor; + + max_accel /= dpi_factor; + + s1 = min(1, 0.3 + speed_in * 10); + s2 = 1 + (speed_in - threshold * dpi_factor) * incline; + + factor = min(max_accel, s2 > 1 ? s2 : s1); + + return factor; +} + double pointer_accel_profile_linear(struct motion_filter *filter, void *data, - double speed_in, + double speed_in, /* 1000-dpi normalized */ uint64_t time) { struct pointer_accelerator *accel_filter = diff --git a/src/filter.h b/src/filter.h index 64a8b50b..617fab1f 100644 --- a/src/filter.h +++ b/src/filter.h @@ -66,6 +66,11 @@ create_pointer_accelerator_filter(accel_profile_func_t filter, */ double +pointer_accel_profile_linear_low_dpi(struct motion_filter *filter, + void *data, + double speed_in, + uint64_t time); +double pointer_accel_profile_linear(struct motion_filter *filter, void *data, double speed_in,