X.org mouse acceleration proposal Author: Simon Thum (simon [dot] thum [at] gmx de) Date: 09/2006 Intent - provide a better 'feel' for the X pointing device - fix current problems, especially with polynomial acceleration Postulate or How to provide a better mouse feeling for the user? It is presumed that the most critical part is doing a sophisticated guess on the velocity of the device in a user's hand, as this is the reference the user's brain has to build its own knowledge about the applied translation from mouse to screen. Because this is an intuitive process, easing it just 'feels better'. Velocity is a physical quantity usually measured in m/s. This is what is accessible to our nerves and brains, delivering the data for intuition. Acceleration therefore needs to depend on velocity, which we try to deduct from the measurements the device provides us with. It follows that any introduced lag should be small enough not to be noted, and any behind-the-scenes data should not counter intuitive mechanisms. Current problems adressed 1) Current acceleration code devises velocity (and thus acceleration) directly from device data at any given instant. This makes it very vunerable to precision problems, such as a 'jumpy' mouse. 2) If a system is under load, a device may accumulate its movement delta over some time, causing irrational high cursor movement in case of polynomial acceleration (threshold = 0, acc > 1) because velocity is guessed in an oversimplified fashion. 3) Some people have overly responsive devices, creating a need to reduce speed on precise tasks or in general. Current implementation will discard precision if pushed there (threshold = 1, acc < 1). These problems result in a reduced ability for our intuition to predict a correct hand movement for desired screen movement, causing more correctional moves than neccessary. Put simply, the mouse 'feels bad'. Method First, a better guess on velocity is done. Given available data, we calc dots per millisecond. This is quite intractable in integers, so we multiply by a configurable factor to arrive at values the usual X controls, treshold and acceleration, can be applied with some sense. This velocity is then weighted with an exponentially dropping curve, i.e. the longer a movement signal is back in time, the less influence it has on the current guess. Typically during begin and end of a mouse stroke, such weighting is not approriate. Therefore, a coupling is employed to use current data if weighted data is too far apart. After some short inactivity time, such background data is reset (called non-visible state (reset) in the patch). Second,the applied acceleration is made steady (over velocity) to enhance intuitivity furter. Third, reported values are slightly flattened (just below mouse precision) ONLY if acceleration is actually performed to improve evolving-speed movements as painting w/mouse typically requires. This can be independently turned off (Softening). Fourth, for too responsive devices, two methods are available (together if desired): 1) a constant deceleration can be applied 2) acceleration curve can be allowed to decelerate on slow movements (adaptive deceleration) Benefits Mostly, the polynomial acceleration becomes more usable. It can be used with higher acceleration coefficients (x > 2), still providing enough control. But also the classic acceleration should become less jumpy since it now graduates (rather) soft towards accelerated motion. Users with too precise devices can slow them without loosing precision, independent of hw driver support. Even more important, polynomial acceleration can now decelerate on slow movements, giving (sub)pixel precision without sacrificing on pointer speed. The code is more robust towards different devices: One could imagine a mouse reporting very often, but only 1 dot per event. Old code would not accelerate such a device at all. While this is a theoretical case, there is robustness against jitter in device event frequency, as could be caused by system load. By introducing a coefficient in xorg.conf you can make two attached devices feel similar, as is often the case on laptops. (untested) Users disliking all this can switch it off, retaining constant deceleration if desired. Problems / Todo I am not an experienced X dev, so some points are left. More complex algorithms have more knobs, and currently they can only be set in the server config. If you have suitable values however, change should only be needed when the device changes. Better would be access via xset and/or API. However, even removing the PerCent in VelocityScalePerCent would be an improvement [by reading a float from cfg]. Or simply to make the code cease reading those options into keyboards. If adaptive deceleration is used, the first motion event after some time will lead to (probalby) underestimated velocity, making it subject to maximum slowdown, so it might appear to be skipped. Hard to note anyway. Some mice could push the limit and report so often that milliseconds don't provide reliable timing; in that case, some precision is lost. A mouse velocity monitor would be nice-to-have for tweaking. Any tracing in X? The simple acceleration curve (threshold > 0) is now steady, but a function steady also over its derivative(s) would be preferred. Also, it does not support adaptive deceleration since it won't go below 1. Configuration The defaults should suffice if you had no big problems before, and feel quite similar. Setting treshold to 0 is strongly recommended, to use the more intuitive polynomial acceleration. Acceleration should be about 1.5 to 2.5 then. A few tips If you have a feeling your mouse moves far too fast, ConstantDeceleration is your friend. Set to 2 or higher to divide speed accordingly. This will not discard precision (at least only on nv-reset, see Method or below). If you like the speed but need some more control at pixel-level, you should set AdaptiveDeceleration to 2 or more. This allows to decelerate slow movements down to the given factor. You might want to keep nv-resets away by setting VelocityReset to e.g. 500 ms, and maybe tweak VelocityScalePerCent to give good results. [Note this only works with polynomial acceleration] If you are picky about a smooth kick-in of acceleration, for example to ease doing art, I suggest tweaking VelocityScalePerCent so acceleration is done before the device starts reporting axis deltas above 1 (which is the point the old code starts accelerating). A good value for VelocityScalePerCent should IMHO be around 200 to 2000, 1000 being default (x10). Unfortunately, there is no live-monitor program for tweaking. Settings AdaptiveDeceleration [integer] Allows polynomial acceleration funtion (threshold = 0) to actually decelerate the pointer, giving enhanced precision on slow moves. Default is 1, which deactivates adaptive deceleration. 2 or higher allows respective deceleration. Adaptive deceleration should not affect your normal mouse useage; if it does, VelocityScalePerCent is probably too low. ConstantDeceleration [integer] Constantly decelerates the mouse by given factor. Default is 1 (no deceleration). VelocityScalePerCent [integer] In short, this controls sensitivity of acceleration. It is designed to be device-dependent, i.e. you set it once to match your device, then modify behaviour using the classical controls. This factor is given in Percent, so multiply by 100 first. Rationale: Device deltas are being divided by delta milliseconds before being weighted, so they are about 10 times too small compared to a device reporting every 10 ms. Because the reporting rate is usually unknown in advance, this is the only way to scale up to 'normal' values. Default is 1000, or 10x, which is suitable for devices reporting at 100hz maximum. If your mouse reports x times per second, set to (100000/x). WeightingDecay [integer] Default 15 milliseconds. Tweaks the weighting applied to approximate velocity. Higher values exhibit more integrating behaviour, introducing some lag but also may feel smoother. Lesser is more responsive, but less smooth. However, any lag will only show up if velocity coupling is disabled. VelocityReset [integer] Specifies after how many milliseconds of inactivity non-visible state (i.e. background info not reflected by pointer position) is discarded. This affects two issues: 1) Velocity guesing remains correct within this time if the pointer/X is stuck for a short moment 2) slow movements are guessed correctly if all device movement events are inside this time from each other. An increment might be neccessary to fully take advantage of adaptive deceleration. Default 200 ms. VelocityCouplingPerCent [integer] Specifies coupling, a feature ensuring responsivity by determining if the weighted guess is a valid one. Weighted guess is deemed valid if it differs from current either below 1.0 (hardcoded) or below this percentage. 0 disables, so only weighted velocity is used. This may exhibit some lag, depending on WeightingDecay. Higher setting means it is more likely that weighted velocity is taken into account. Default is 25%. Softening [boolean] Tweaks motion deltas from device before applying acceleration a bit to smooth rather constant moves. Tweaking is always below device precision to make sure it doesn't get in the way. Also, when ConstantDeceleration is used, Softening is not enabled by default because this already provides some subpixel precision. However you can set this "off" or "false" if you don't like it. VelocityGuessing [boolean] Setting this to "off" retains the simpler, old-fashioned algorithm for determining velocity. It doesn't behave exactly like the old algorithm but similar enough most people wouldn't note a difference. Reference http://lists.freedesktop.org/archives/xorg/2005-September/010211.html https://bugs.freedesktop.org/show_bug.cgi?id=138 https://bugs.freedesktop.org/show_bug.cgi?id=2927