(I know this question has been posted before; I reposted a more detailed explanation on the situation because the previous question isn't answered and has over 6k views.)
The mouse speed Windows multiplier can either be controlled through Pointer Options in Control Panel or through a more advanced way by calling and changing SystemParametersInfo or Registry values.
- Detailed list showing mouse speeds and their multipliers from Liquipedia:
1 speed: 0.03125 (1st tick) | 11 speed: 1.25 2 speed: 0.0625 (2nd tick) | 12 speed: 1.5 (7th tick) 3 speed: 0.125 | 13 speed: 1.75 4 speed: 0.25 (3rd tick) | 14 speed: 2 (8th tick) 5 speed: 0.375 | 15 speed: 2.25 6 speed: 0.5 (4th tick) | 16 speed: 2.5 (9th tick) 7 speed: 0.625 | 17 speed: 2.75 8 speed: 0.75 (5th tick) | 18 speed: 3 (10th tick) 9 speed: 0.875 | 19 speed: 3.25 10 speed: 1.0 (6th tick) | 20 speed: 3.5 (11th tick)
Is there a way to set the speed through SystemParameterInfo, or the Registry, using a floating-point number, allowing for a more precise multiplier value like x0.8 (looking at the list, it's not reachable)? If so, how do I do that?
1 Answer
When "enhance pointer precision" is off, there is no way to set an arbitrary speed multiplier. The slider controls the MouseSensitivity value in the Registry, which is always an integer between 1 and 20. win32kbase.sys always passes the sensitivity setting around as an integer and numerous functions include range checks. The most relevant function is UpdateMouseSensitivity, which converts a MouseSensitvity-style integer to a 24.8 fixed-point speed multiplier. Ghidra decompiles that function to (comments mine)...
void __thiscall UpdateMouseSensitivity(MOUSE_SENSITIVITY_INFO *this,uint param_1)
// param_1 is the MouseSensitivity value
{ uint uVar1; // Temporary variable to store the Speed multiplier if (0x13 < param_1 - 1) { // If param_1 is zero, param_1 - 1 wraps around to a big number // Fail if MouseSensitivity is less than 1 or greater than 20 MicrosoftTelemetryAssertTriggeredNoArgsKM(); } *(uint *)this = param_1; // Store the raw MouseSensitivity value if (param_1 < 3) { // For MouseSensitivity 1-2, uVar1 = (param_1 << 8) >> 5; // Speed = MouseSensitivity / 32 } else { if (param_1 < 0xb) { // For MouseSensitivity 3-10, uVar1 = param_1 * 0x100 - 0x200 >> 3; // Speed = (MouseSensitivity - 2) / 8 } else { // For MouseSensitivity 11-20, uVar1 = param_1 * 0x100 - 0x600 >> 2; // Speed = (MouseSensitivity - 6) / 4 } } *(uint *)(this + 4) = uVar1; // Store Speed in the MOUSE_SENSITIVITY_INFO structure, return; // thereby making it available to the caller
}...which generates the values listed in your question.
However, there is an alternative way to set the mouse sensitivity. When "enhance pointer precision" is on, Windows uses the SmoothMouseXCurve and SmoothMouseYCurve values—along with the other row of sensitivity multipliers from your linked page—to determine the speed multiplier as a function of how fast you're moving the mouse. By default it makes the pointer go extra slow when you move the mouse slowly, but the curve can be changed to a straight line to disable acceleration yet allow fine tuning. This page offers a set of Registry tweaks to give various environments a 1:1 mouse:pointer response even when enhanced pointer precision is on. This provides it at the sixth tick mark on Windows 10:
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Control Panel\Mouse]
"SmoothMouseXCurve"=hex:\ 00,00,00,00,00,00,00,00,\ C0,CC,0C,00,00,00,00,00,\ 80,99,19,00,00,00,00,00,\ 40,66,26,00,00,00,00,00,\ 00,33,33,00,00,00,00,00
"SmoothMouseYCurve"=hex:\ 00,00,00,00,00,00,00,00,\ 00,00,38,00,00,00,00,00,\ 00,00,70,00,00,00,00,00,\ 00,00,A8,00,00,00,00,00,\ 00,00,E0,00,00,00,00,00Since your desired speed of 0.8 is one of the EPP-on multipliers, you can get it by installing that tweak (save it as a .reg file and double-click it) and adjusting the slider, in this case to the fifth tick. You may need to log off and back on for the curve Registry change to take effect.
If your desired multiplier is not one of the EPP-on defaults, you can change the slope of the curve. In each row of hexadecimal numbers above, the first four comma-separated numbers are the coordinate in little-endian, so the third row of the X value is the coordinate 0x00199980. When Y/X is ≈4.375 you get the standard 100% scaling; to get different scaling, multiply all the Y coordinates or divide all the X coordinates by your desired scale factor. You may find it helpful to use PowerShell to do math with a mix of hexadecimal and decimal numbers and get the results as a hexadecimal string...
'{0:x8}' -f [int](MATH HERE)...for example...
'{0:x8}' -f [int](0x00199980 / 0.8)...which produces 001fffe0, which would be E0,FF,1F,00 as a sequence of bytes in little-endian.
For example, this produces 80% speed at the default sixth tick mark with EPP enabled:
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Control Panel\Mouse]
"SmoothMouseXCurve"=hex:\ 00,00,00,00,00,00,00,00,\ F0,FF,0F,00,00,00,00,00,\ E0,FF,1F,00,00,00,00,00,\ D0,FF,2F,00,00,00,00,00,\ C0,FF,3F,00,00,00,00,00
"SmoothMouseYCurve"=hex:\ 00,00,00,00,00,00,00,00,\ 00,00,38,00,00,00,00,00,\ 00,00,70,00,00,00,00,00,\ 00,00,A8,00,00,00,00,00,\ 00,00,E0,00,00,00,00,00 2