X.org mouse acceleration proposal Author: Simon Thum (simon [dot] thum [at] gmx de) Date: 09/2006 Intent - improve heavy-load behaviour (no jumping) - enable accuracy and fluid motion with every device - provide a better 'feel' for X pointing devices Postulate When the pointer gets accelerated with respect to device motion, it becomes important for the user to be able to predict that acceleration. Otherwise, the user is unable to intuitively use his device. Thus, it is presumed that the most critical part is doing a sophisticated estimate about 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 device to screen. Because this is an intuitive process, easing it just 'feels better'. Current problems adressed 1) On slow movements, current code infers 3 'velocities': 1, 1.41, and 2. As 1 remains unaccelerated, we're left with just 2 acceleration levels. It is hard to foresee what exactly will happen. Worse, when using the simple accelerated/unaccelerated scheme, acceleration either comes to effect or it doesn't, providing no predictability around the threshold. 2) If a system is under load, a device may accumulate its movement delta while the system does not query the device, causing irrational high cursor movement. 3) Some people own very responsive devices, creating a need to reduce speed on precise tasks or in general. 4) With the simple acceleration scheme, acceleration is more sensitive on diagonal movements than on axis-aligned ones. These problems result in a reduced ability for our intuition to predict a matching hand movement for desired screen movement, causing more correctional moves than neccessary. Put simply, the mouse 'feels bad'. Method First, a better approximation of 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 function, i.e. the longer a movement signal is back in time, the less influence it has on the current estimate (This is actually much cheaper in CPU terms than it sounds). Typically during begin and end of a mouse stroke, weighting is not approriate. Therefore, a coupling is employed to override velocity if weighting seems inapproriate. After some short inactivity time, such background data is reset (called non-visible state (reset) in the patch). Second, acceleration profiles are made steady. This avoids sudden jumps in acceleration, enhancing intuitivity furter. Third, reported values are slightly flattened (just below device precision and only if acceleration is actually performed) to improve evolving-speed movements such 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 profile(s) 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 hardware driver support. Even more important, an acceleration profile may 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 (VelocityScale) you can make two attached devices feel similar or intentionally dissimilar. (untested) Users disliking all this can switch it off, retaining constant deceleration if desired. Configuration The defaults should suffice if you had no problems before, and feel quite similar. The settings discussed here are the coarse and the very subtle settings, not the usual xset or GUI panel controls you might know. However, setting treshold to 0 is strongly recommended, to use the more intuitive polynomial acceleration. Acceleration should be about 1.5 to 2.5 then. The settings described below are device-specific and need to be set in the approriate "InputDevice" section in xorg.conf (or what your X reads). Usually it looks like: Section "InputDevice" Identifier "Mouse0" Driver "mouse" [...] EndSection For example to enable the adaptive deceleration feature, put in a line reading Option "AdaptiveDeceleration" "2" or similar. 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. 300 ms, and maybe tweak VelocityScale to give good results. If you are picky about a smooth kick-in of acceleration, for example to ease doing art, I suggest tweaking VelocityScale and using adaptive deceleration. Maybe increasing velocity coupling also helps it. Options AdaptiveDeceleration [integer] Allows acceleration profile to actually decelerate the pointer, resulting in enhanced precision on slow moves. Default is 1, which deactivates adaptive deceleration. Setting 2 or higher allows for respective deceleration. Adaptive deceleration should not affect your normal mouse useage; if it does, VelocityScale is probably too low. ConstantDeceleration [integer] Constantly decelerates the mouse by given factor. Default is 1 (no deceleration). VelocityScale [real] 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. It is important to note there is no 'right' factor, only one that bears the nice property of matching to X controls as if velocity estimation was disabled. 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 as well as identify slow movement. Default is 10, or 10x, which is suitable for devices reporting around 100hz. If your mouse reports x times per second, set to (1000/x). WeightingDecay [real] Default 15 milliseconds. Tweaks the weighting applied to approximate velocity. Higher values exhibit more integrating behaviour, introducing some lag but also may feel smoother. Less is more responsive, but less smooth. However, any lag will only show up if velocity coupling is disabled or too weak. 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 estimate remains correct within this time if the pointer/X is stuck for a short moment, not querying the pointer device. 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. VelocityCoupling [real] Specifies coupling, a feature ensuring responsivity by determining if the weighted velocity is a valid one. Weighted estimate is deemed valid if it differs from current either below 1.0 (hardcoded) or below this factor. 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 deemed valid. Default is 0.2, or 20%. Softening [boolean] Tweaks motion deltas from device before applying acceleration to smooth out 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 provides better subpixel information. However you can set this "off" or "false" if you don't like it. EstimateVelocity [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. AccelerationScheme [int] Select Scheme. This is to really switch off the code discussed here. 0 means previous method, 1 is this one. Acceleration profiles Acceleration profiles translate device velocity into an acceleration to be imposed on the pointer. Xorg offers two profiles: Simple and polynomial. They are selected somewhat strange through the threshold in xset (or some gui): threshold = 0 means polynomial, simple otherwise. The simple acceleration profile is now steady, and the polynomial maintains f(1) = 1. They are designed to mimic previous behaviour. Simply copying old functions would not provide much benefit: The patch would simply make the point when acceleration is performed be more predictable, but not cause the pointer to cease jumping around that point. If you like to play with the profiles, a few nice properties: 1) f(1) = 1 a fixed point, to enable exchanging profiles 2) continuous very nice-to-have since we would otherwise throw away our data (probably causing jumps) 3) continuous over derivative(s) nice to have for smoothness 4) f'(min_acceleration) = 0 Ensures a soft kick-in of acceleration 5) f( < 1) < 1 enables adaptive deceleration - although it is possible to hold all of the properies, included profiles only hold 1, 2, and 5. - Profiles are not meant to enforce constant deceleration or adaptive deceleration. 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. The first motion event after some time will lead to (probalby) underestimated velocity, making it subject to maximum slowdown. When adaptive deceleration is in use, this might not cause a visible movement, appearing to have been skipped. Some mice could push the limit and report so often that milliseconds don't provide reliable timing; in that case, some precision is lost. 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