Sunday, June 14, 2009

Out of sync and upside down: Windows mouse pointer acceleration (Enhance pointer precision) is partially broken

Windows mouse handling ("Enhance pointer precision" option) has always been partially broken in Vista and XP due to a simple design error which is only now fixed in Windows 7.

The "Enhance pointer precision" code uses a calculation that should have included:
× ScreenResolution(DPI) ÷ MouseBusUpdateRate.
The (incorrect) calculation actually used is:
× ScreenRefreshRate ÷ ScreenResolution(DPI).
"Out of sync and upside down."

The Enhance pointer precision checkbox

Windows has long provided a "mouse pointer acceleration" feature that determines how fast the on-screen mouse pointer (cursor) moves in response to movements of the mouse.
(In Windows XP and Windows Vista, mouse pointer acceleration is turned on using the Control Panel>Mouse>Pointer Options>"Enhance pointer precision" checkbox.)

If acceleration is enabled, when the mouse moves slowly, the pointer is moved at a lower ratio, for example 1 count ('dot') of mouse movement might correspond to 1 pixel or less of pointer movement. But if the mouse moves faster, the system responds by accelerating the movement of the pointer, using a higher ratio, for example 1 count of mouse movement then might correspond to 2 or more pixels of pointer movement.

Starting with Windows XP and continuing through Windows Vista and onto Windows 7 RC1, Windows implements mouse pointer acceleration in a different way than in previous versions of Windows.

The new implementation made important improvements in how acceleration works, and in most cases works well enough.
Some (including myself) consider it essential to enable mouse pointer acceleration [link to Coding Horror blog].

HOWEVER, there is a simple conceptual error in its design, which has been carried into the implementation.

There is a large possibility that the effects of the error were found during testing and an attempt was made to fix it.
BUT that fix did not correct the error, and instead merely masked its effects AND INVERTED and UNDID the intended behaviour.

RIGHT NOW, for millions of people, movement of the mouse pointer on their screens is being controlled by an algorithm which includes that conceptual error and "fix error".

The broken behaviour affects users running Windows XP or Windows Vista.
It was present in the first release of Windows XP in October 2001 and continues through Windows Vista SP2.
The conceptual error and the "fix error" have finally been fixed in Windows 7.

What is the broken behaviour?

The broken behaviour can be very very subtle, which may explain why it has not been more widely recognized as a problem and why it has taken so long for it to be fixed. The behaviour is:

  • How far the on-screen mouse pointer moves in response to on-mouse-pad mouse movement depends on the monitor refresh rate (higher refresh rates cause larger pointer movements). But the monitor refresh rate should have no effect.
  • Increasing the display DPI setting (Large size vs. Normal size in the Control Panel) causes the mouse pointer to move fewer on-screen pixels in response to on-mouse-pad mouse movement. But an increased DPI setting should cause the pointer to move a larger number of on-screen pixels, not fewer.

How should it work?

By reading what Microsoft have written about Windows XP mouse acceleration, and some investigation, we can explain how the acceleration should have worked.

Microsoft intended that the velocity (speed) of the on-screen pointer (measured in inches per second) would depend upon the velocity of the on-mouse-pad mouse (also measured in inches per second).

They defined an acceleration formula that translates the velocity of the on-mouse-pad mouse to the corresponding velocity of the on-screen pointer.

The algorithm works like so:

  1. During a time period, measure the count of mouse movements (also known as 'dots' or Mickeys).
  2. Convert the mouse movement count into a mouse velocity.
  3. Using the acceleration formula, calculate the corresponding pointer velocity.
  4. Convert the pointer velocity into a number of pixels of pointer movement.

Step 4 is where the conceptual error was made and also the "fix error".

To turn the calculated pointer velocity into a number of pixels of mouse movement involves some simple formulae.

Velocity = Distance

If the "Time" term corresponds to a regular periodic interval, such as the time period between mouse updates, or the time period between each screen refresh, then we can also use this:

Rate = 1

For example, a regular time period of 0.2 seconds corresponds to a rate of 5 times a second (5 Hz).

Combining the two formulae, we get:

Velocity = Distance × Rate

If something is moving 2 inches every 0.2 seconds (5 Hz) we can use the Velocity = Distance/Time formula to calculate Velocity=10 inch/s, OR we can use the Velocity=Distance×Rate formula to also calculate 10 inch/s.

In the case of moving the mouse pointer, what is the appropriate "Time" and "Rate" to use?

This is a key question, and where the conceptual error occured.
The correct time interval is the interval that occurs between successive pointer position updates and (identically) the correct rate is the rate at which the pointer position is updated.
In Windows, the mouse position is updated every time mouse movement counts are sent from the mouse to the PC.
The correct rate to use is the Mouse Bus Update Rate.
A moving mouse connected via a PS/2 bus typically sends movement counts 100 times each second (100 Hz).
A moving mouse connected via a USB bus typically sends movement counts 125 times each second (125 Hz).

How to measure "Distance" for the on-screen pointer?

Windows stores and uses an assumed screen resolution, in Dots Per Inch (DPI) in the Control Panel>Display Properties>Settings>Advanced dialog.
That Screen Resolution (DPI) can be used like so:

DistancePointer = PixelsPointer

Putting all of the formula together, we get this formula for pointer velocity:

VPointer = PixelsMouseBusUpdate × MouseBusUpdateRate

The formula above is the formula that SHOULD have been used.
At this point, the team within Microsoft designing and implementing the mouse acceleration got confused.
This confusion is documented in Microsoft's website here:
Pointer Ballistics for Windows XP

The section titled "Relating to Physical Units" indicates that an incorrect formula for Vpointer was used:

VPointer = PixelsMouseBusUpdate × ScreenUpdateRate

Compared to the correct formula, note that ScreenUpdateRate is used where MouseBusUpdateRate should have been used instead.

Using ScreenUpdateRate in the formula would have been appropriate IF the pointer position was updated every screen refresh.
HOWEVER, the pointer position IS NOT updated every screen refresh; it is updated on every mouse bus update.

Of course, it could have been that the Microsoft team had only been imprecise with their formula.
HOWEVER, the example in that section also shows that they have used their incorrect formula: a correct examination of their example gives a physical to virtual gain of 5, NOT the 3 that they calculate.

Of course, it could have been that the Microsoft team had only been imprecise with their formula, AND also clumsy with their example.
HOWEVER, examination of the actual mouse behaviour in Windows XP and Windows Vista shows that they DO have the incorrect ScreenUpdateRate term in their algorithm, AND WORSE!

Considering again the correct formula for Vpointer and rearranging and solving for Pixels:

PixelsMouseBusUpdate = VPointer × ScreenResolution

Let's examine this formula.
Suppose a monitor having a high resolution (a high DPI, in other words, a small pixel size/pitch).
In order to move the mouse pointer a given physical distance on this high resolution monitor (measured in inches), we would have to move the pointer a LARGER number of pixels, because each pixel is smaller. Note that the formula above MULTIPLIES by ScreenResolution, which will have the desired effect of calculating a LARGER number of SMALLER pixels.

What formula is used by Windows XP and Windows Vista?

Despite the confused formula and example on the Microsoft Pointer Ballistics webpage, one would hope that the correct PixelsMouseBusUpdate formula is used, as above.
One might suspect that a formula that had ScreenUpdateRate instead of MouseBusUpdateRate is used.
However, the formula used is:

PixelsMouseBusUpdate = VPointer × ScreenUpdateRate

Note: rather than multiplying by ScreenResolution, the formula divides by ScreenResolution.
Rather than divide by ScreenUpdateRate (or MouseBusUpdateRate) the formula instead multiplies by ScreenUpdateRate.

Consider again the monitor having a high resolution (a small pixel size/pitch).
Rather than compensating for the small pixel size, the formula used amplifies the effect of a small pixel size: For a high resolution monitor, Windows XP and Windows Vista move the mouse pointer a SMALLER number of SMALLER pixels which is undesirable.

Also undesirable is that how far and how fast Windows XP and Windows Vista move the mouse pointer, depends upon the screen refresh rate.
(The Microsoft team put screen refresh rate in their formula because they wanted to REMOVE any possible effect that screen refresh rate might have had on mouse pointer movement, but instead they ADDED an undesirable effect.)

How could this problem have remained unfixed for so long?

Consider a typical monitor with a refresh rate of 75 Hz and 96 DPI, and a typical mouse with a USB bus update rate of 125 Hz.
The correct PixelsMouseBusUpdate formula calculates ScreenResolution/MouseBusUpdateRate = 96/125 = 0.768.
The "out of sync and upside down" formula that Windows XP and Windows Vista use calculates ScreenUpdateRate/ScreenResolution = 75/96 = 0.78125.
These two numbers differ by less than 2%.

Might the Microsoft team have jumped directly to the incorrect ScreenUpdateRate ÷ ScreenResolution calculation and then not realised the mistake?

Might they have started with ScreenResolution ÷ ScreenUpdateRate and realised something was wrong and then "fixed" it by inverting the numerator and divisor?

We may never know.

A silly flash toy...

The real reason why mouse acceleration is broken? [link]


Dae said...

Could you please elaborate on what's Pixels_MouseUpdateRate? I didn't understand this in the Microsoft article either, and there they just called it "Mickey" for some reason...

Additionally, why is mouse resolution not used in the new formula? I.e. on my Razer mouse I've set 500 DPI. I believe it matters too.


Mark Cranness said...

Pixels_MouseBusUpdate means the number of pixels on the screen that the pointer moves in each (or any) particular Mouse Bus Update time period.

I would write Microsoft's first formula (which I didn't discuss above) as:
V_Mouse = MouseCount_MouseBusUpdate * (MouseBusUpdateRate / MouseResolution)

Microsoft use the term 'Mickey', which is short-hand for 'mouse movement count', i.e. the count of how many dots or points sent by the mouse to the computer during any Mouse Bus Update time period.

In Microsoft's example (the 'Relating to Physical Units' paragraph) they are assuming a system with no acceleration applied, where one dot or point moved by the on-mouse-pad mouse translates to one pixel moved by the on-screen pointer.
I.E. in the Microsoft formula: Mickey = MouseCount_MouseBusUpdate = Pixels_MouseBusUpdate

Microsoft do use the mouse resolution in their first (V_Mouse) formula, but they call it 'Pointer Resolution' for some confusing reason.
I didn't use mouse resolution in my formula because I was only discussing the second (V_Pixels) formula which is the formula that has problems.

BTW, In XP, Vista and Windows 7, Micrsoft hard-code the mouse bus update rate to ~120 and hard-code the mouse resolution to ~400. They do this probably because there is no standard API for mouse driver developers to use to let Windows know what the actual DPI and update rate are.

Anonymous said...


I agree with you that Microsoft made an error when they used ScreenUpdateRate instead of BusUpdateRate in their formula for V_pointer. However, I don't see how you come to the conclusion that their calculation is "upside down." In the "What formula is used by Windows XP and Windows Vista?" section, you wrote that Microsoft uses this formula:

Pointer = V × ScreenUpdateRate / ScreenResolution

Where did you get that? I could not find any such information in Microsoft's article you quoted.

Please note also that the screen resolution Microsoft uses is not the DPI setting in the Display Properties. They seem to be using the screen dimensions in pixels in combination with an assumed physical size of the screen in inches to estimate the screen resolution. I doubt that the OS actually queries the monitor properties to find out the screen size in inches.

It has been my observation that the DPI setting in the Display Properties does not work the way you describe. In Windows XP, instead of making each pixel smaller, increasing the DPI makes each inch larger. It seems to me that this setting is supposed to be used in combination with the screen size in pixels to adjust the size of the inch on the screen so that it is closest to the actual inch. Then this DPI setting would be close to the actual screen resolution and could be used in the calculation of pointer movement. I cannot find an equivalent of this DPI setting in Windows Vista. Perhaps, Microsoft eliminated it.

Mark Cranness said...

> Pointer = V × ScreenUpdateRate / ScreenResolution ... Where did you get that?

That formula is not in the Microsoft article.
It was found by testing how actual mouse input caused the pointer to move (including a program that simulates pointer movement according to an algorithm using that formula, and the simulated pointer matches the actual Windows pointer pixel for pixel, and other direct technical ways).

I say that the XP and Vista calculation is "upside down" because they used the UpdateRate/ScreenResolution formula when they should have used ScreenResolution/UpdateRate.

The Microsoft article does describe DPI in terms of screen physical size and resolution, but the actual Windows mouse algorithm uses the control panel display DPI setting.

When I said 'a high DPI, in other words, a small pixel size/pitch', I was not being as clear as I should have been. I did not mean that a larger DPI makes each pixel smaller.
I meant that if you have a monitor with a small pixel size, you would/could set a high DPI so that UI elements appear at a better size.

The display DPI can be used exactly as you describe to make a screen inch closer to an actual inch (but can also be set to whatever value provides the best view of text and UI elements).

This link describes how to change the DPI on Vista.

Nirsoft provide a tool that can be used to test how the mouse:pointer algorithm works!
NirCmd has a sub-command: 'sendmouse move x,y' that can be used to inject controlled mouse movements into Windows and then you could see what effect changing monitor refresh rate or display DPI has for yourself (ask for details).

Anonymous said...

Does this mean that, dpi translates to different resolution, for example:
If I use 1920x1080, will my pointer respond slower than at 800x600?

Mark Cranness said...

> Does this mean that, dpi translates to different resolution?

No. Changing your screen size does not change the Windows DPI and will not change how fast the pointer reponds.
The Windows DPI setting is separate from the screen size.
How to change the DPI on Windows 7.
How to change the DPI on Vista.
How to change the DPI on XP.

eltranced said...

not only is the problem at the tip of their noses they still havent made a fix for xp?

Mark Cranness said...

I also wonder why they have not made a fix for XP!
Sometimes I think I may make a fix myself, along the lines of Anir's WCAFIX...

Allan said...

Very informative and a good read. Thank you.

Anonymous said...

If I don't enable "enhance pointer precision", is cursor movement directly proportional to mouse movement? E.g., if I move my mouse 1/1000 inch then the cursor will move 1 pixel.

Mark Cranness said...

> If I don't enable "enhance pointer precision", is cursor movement directly proportional to mouse movement?

Yes, with "Enhance pointer precision" OFF (unchecked) pointer movement is directly proportional to mouse movement.

Although response linear and proportional, it is scaled according to the control panel "Pointer speed" slider.
In your example, if the slider is set to the middle 6/11 position, then a 1000 DPI mouse if moved 1/1000 inch would move the pointer 1 pixel.

Unknown said...
This comment has been removed by the author.
Unknown said...

Very useful. I'm also having fun changing my mouse cursor and could do the basic personalized mouse pointer . <3

Unknown said...

Hey. I haven't used the mouse fix yet but I tried the mouse movement recorder and it didn't show a single red or green line. Does that mean I don't need the mouse fix at all?

Mark Cranness said...

> Does that mean I don't need the mouse fix at all?

Read my main post The MarkC Windows 8.1 + 8 + 7 Mouse Acceleration Fix and scroll down to "Does my game need a mouse fix?".

Unknown said...

I've actually become quite attached to XP's flawed algorhtyhms lol you might think it's madness but how would i infact emulate it in Windows 10 with games that don't accept direct input is the extra challenge

Unknown said...

I imagine you've accrued quite a lot of familiarity with the XP mouse code, you might be just the man to help me in my quest to best emulate it in Povaaks intercept driver or better still something that is capable of more accurately emulating it..

Thankfully Bologna also decimalised them

Below are the default values converted to decimal figures respectively:

00,00,00,00,00,00,00,00, <-- 0
15,6e,00,00,00,00,00,00, <-- 0.43001
00,40,01,00,00,00,00,00, <-- 1.25
29,dc,03,00,00,00,00,00, <-- 3.86001
00,00,28,00,00,00,00,00 <-- 40

00,00,00,00,00,00,00,00, <-- 0
b8,5e,01,00,00,00,00,00, <-- 1.37
cd,4c,05,00,00,00,00,00, <-- 5.30001
cd,4c,18,00,00,00,00,00, <-- 24.30001
00,00,38,02,00,00,00,00 <-- 568

but i'm not sure where to place the decimal values in the interaccel framework to replicate it's effect and Kovaaak is unsure, maybe your superior XP knowledge can shed some more light

Mark Cranness said...

Carl wrote:
> XP ... how would i infact emulate it in Windows 10 with games that don't accept direct input is the extra challenge

Windows 10 mouse response is exactly the same as XP, when XP was running @ 60Hz monitor refresh rate.

So the best way for games that don't use DirectInput or Raw Input is just use the standard Windows 10 curve.

In the registry the Windows 10 looks different than XP, but there is a different internal scaling inside the code:
XP has: mouse_movement × (60 / 96) × SmoothMouseYCurve,
Windows 10 has: mouse_movement × (96 / 120) × SmoothMouseYCurve.

BUT all of the standard SmoothMouseYCurve values in the registry are the XP values × 100 / 128, so it works out exactly the same.

If your XP monitor refresh rate was not 60 Hz, then an adjustment is needed.
If your XP mouse polling rate is different to your Windows 10 polling rate, then an adjustment is needed.

> ...emulate it in Povaaks intercept driver

This is the Windows XP curve you need to hit:
(The title says Windows 8, but the curve is exactly the same for Windows XP@60Hz, Vista@60Hz, 8, 8.1 & 10, and very close for Windows 7.)

Having just now watched KovaaK's youtube video, I don't think it can quite match the same bumps and rounded curve shape as the XP curve, but you might get close enough?

Unknown said...

Yeah it's funny in hindsight years later when i read your blog explaining how resolution and refresh rate come into the formula in xp, cos i had a monitor with the capability of 120hz even back in early xp but when i put it to 120 from 85, it totally ruined how the mouse felt, which makes a lot more sense now why it would, so i would purposely keep it at 85hz so my aim wouldn't be too erratic.

I used;

800x600 res in game
80 fov
500hz polling rate
85 refresh
85fps cap
21" CRT
WPS at 1 space below default (so 5/11? :S )

Even such things as the modern widescreen monitors scaling the resolution 4:3 to fit seems to skew mouse curves

I've had a nightmare trying to emulate it, anything other than that feels terrible now, got years of muscle memory so specifically to this combination, i've been trying to emulate it for like 2 years with Povaaks driver fml with like 1,000 different permetations of values in each field, i'm out of my depth lol

It seems crazy that a lot of people used the enhanced pointer option in xp, without using your mouse fix and yet new games don't have an inbuilt option for it to cater for the amount of people that want specifically the enhanced point settings :| your tool which did regedits was good, seem to remember it allowed multiple levels of acceleration but i feel like the raw input of games like UT4 doesn't allow it to intercept unfortunately? it seems like it'd be quite popular

Not being able to keep the mouse settings i've always used in the advent of raw input has destroyed my skill competatively now, desperate to find a solution to get it back!:(

Mark Cranness said...

> XP @ 85Hz

If you are still using a 500 Hz mouse polling rate, then try bumping up your in-game sensitivity up by × 85 / 60 (= ×1.42), but leaving everything else the same as XP, ie Mouse at 400cpi and 5/11.

I should have asked at the start: did you have Enhance pointer precision on or off, but I it must have been on because changing the monitor refresh rate changed the sensitivity (120Hz would cause a slower mouse response).

Using FOV = 100 or so might make the centre part of a wide screen look the same as a 4:3 monitor.

mutissj said...

Can anyone tell me how I can emulate mouse movement like Windows XP + 144Hz on @Windows 7 + 144Hz?

Mark Cranness said...

> Windows XP + 144Hz on @Windows 7 + 144Hz?

A very custom mouse curve could do that, but far easier to increase your in-game sensitivity by (144 / 96) / (96 / 150) = × 2.34, which will have the same effect.
(This assumes you still have the same mouse polling rate on Windows 7 as you used on XP.)

mutissj said...

Unfortunately this does not work

- In Windows XP, the more Hz refresh the LCD, the faster the mouse moves, and you need to reduce the sensitivity of the mouse in the [control panel]

- In Windows 7, the more Hz refreshing the LCD, you do not have to do anything then I automatically sync the mouse to the fps indicator so it does not go too fast, so the mouse pointer at 144Hz "very smoothly moves on the screen"

The smooth movement of the pointer annoys me in windows 7 @144Hz (smoothly), because I am accustomed to XP @144Hz (no smooth), year after year searches the internet how to do it :(

Mark Cranness said...

> I am accustomed to XP @144Hz (no smooth)

I should have asked what mouse fixes if any you were using on XP?
CPL, or Cheese?
And what games you played.
And what control panel sensitivity you used in XP and what you now use in 7.

> In Windows XP, the more Hz refresh the LCD, the faster the mouse moves...

Yes that is true, which is why I was suggesting that for Windows 7 you increase your mouse sensitivity.
In Window XP: 144Hz increases mouse speed.
In Windows 7: 144Hz does not increase mouse speed.
So to get new Windows 7 to match old Windows XP, you need to increase mouse speed some way?

OLLEVM said...

Hey, Mark, I hope that you're doing good and that you also still read this blog.

I really need your help, to an extent, that I am willing to pay if everything works.

I have been playing for years with the following settings:

4/11,epp on, 125hz mouse, 85 hz monitor(17"crt) on windows XP

what settings should I use on windows 8.1 to keep the same sens/accel?

now, my mouse might go up to 1000hz(but I can keep the 125hz if needed) and I have a 144hz monitor (24"TN)

thank you in advance

Mark Cranness said...


I'm checking my blog less and less (sorry to those with unanswered questions).

The answer depends on what mouse curve you were using:
Standard Windows, or
CPL mouse fix, or
Cheese mouse fix (for what Hz), or

And it also depends on whether games you play use old-style 'GetCursorPos' to read mouse movements, or use DirectInput or Raw Input.

Assuming you were, and are, using the Standard Windows accel curves (no mouse fix installed at all), AND are also using the same mouse (or a mouse with the same sensitivity) AND are also using Windows 8.1 'Settings, Display, Scale and layout, size of items' setting at 100%, (Windows XP = 'Control Panel, Display, font size (DPI) scaling' Normal Fonts) then the Windows XP refresh rate of 85Hz results in mouse sensitivity 85/60 = × 1.42 higher than on Windows 8.1.

If the Windows XP monitor refresh rate is 'Hz', and Windows DPI is 'DPI', then the XP sensitivity mangle/increase compared to Windows 8/8.1/10 is : 153.6 × Hz / (DPI×DPI)

Including 4/11 is:

85/60 × (2×4-2)/20 = 0.425

To keep the same accel, you will need to keep 125Hz.
(Or, if your mouse can increase its DPI, a custom mouse curve is possible at higher Hz mouse polling rates, but is not that easy to build.)

Now on Windows 8.1, to get × 0.425, easiest might be to set 6/11 in Windows Control Panel, and adjust your in-game sensitivity to × 0.425 of what it is now.
(That would work even if the game uses DirectInput or Raw Input.)

Or you might try using 5/11, which is × 0.4, lower by ~ 6%, perhaps close enough not too notice?
(That would only work for games that use old-style 'GetCursorPos' to read mouse input, because only 'GetCursorPos' games are affected by the pointer speed slider.)

Does that help?

Anonymous said...

Hi Mark,

I'm reading through your post here as well as the posts made on the ESR forums located here:

My goal is to understand how to craft my own custom acceleration curve, and for the most part I understand the process. However, when reading through your blog, and the second link above (particularly the comments you've left), I find myself confused about a few things that I hope you can clear up.

The first confusion comes from your equations. You write the equation for V_Pointer from the Windows XP ballistics page as follows:

V_Pointer = Pixels_MouseBusUpdate × ScreenUpdateRate / ScreenResolution

Later you write a transformed equation in terms of Pixels_MouseBusUpdate that describes the correct equation that Microsoft was supposed to use as follows:

PixelsMouseBusUpdate = VPointer × ScreenResolution / MouseBusUpdateRate

This is transformed from your first equation that you wrote as follows:

V_Pointer = Pixels_MouseBusUpdate × MouseBusUpdateRate / ScreenResolution

This is a valid rewrite and can be verified by writing in terms for Pixels_MouseBusUpdate, MouseBusUpdateRate, and ScreenResolution and solving for V_Pointer. Using a value of 5 for Pixels_MouseBusUpdate, 125 for MouseBusUpdateRate, and 96 for ScreenResolution we get 6.51 as the value for V_Pointer in both equations.

However, in the section titled "What formula is used by Windows XP and Windows Vista?", you write the following equation:

Pixels_MouseBusUpdate = V_Pointer × ScreenUpdateRate / ScreenResolution

This looks to be a rewritten version of Microsoft's formula from the ballistics page which, again, appears as follows:

V_Pointer = Pixels_MouseBusUpdate × ScreenUpdateRate / ScreenResolution

Unlike your correct formula above, if you plug in numbers into these two equations, with Pixels_MouseBusUpdate of 5, ScreenUpdateRate of 60, and ScreenResolution of 96, we get a value of 8 for V_Pointer in your transformed equation, and a value of 3.125 for V_Pointer from the Microsoft equation. This suggests that one of the two equations is wrong. Would you be able to clarify which of the two equations is the one that Windows XP/Vista actually uses?

Thank you!

Mark Cranness said...


The formula used by XP/Vista is:Pixels_MouseBusUpdate = V_Pointer × ScreenUpdateRate / ScreenResolution

You write:
> This looks to be a rewritten version of Microsoft's formula from the ballistics page which, again, appears as follows:

No, the formula actually used is not a re-write of the Microsoft's formula from the ballistics page.

If you re-arrange the ballistics page formula,, it starts like this:
V_Pointer = Pixels_MouseBusUpdate × ScreenUpdateRate / ScreenResolution
… divide both sides by ScreenUpdateRate:
V_Pointer / ScreenUpdateRate = Pixels_MouseBusUpdate / ScreenResolution
… multiply both sides by ScreenResolution:
V_Pointer × ScreenResolution / ScreenUpdateRate = Pixels_MouseBusUpdate
... swap sides:
Pixels_MouseBusUpdate = V_Pointer × ScreenResolution / ScreenUpdateRate

... which is not the same as the formula actually used
(ScreenResolution has been swapped with  ScreenUpdateRate)

I think a good way to build your own curve is to think in terms of acceleration factor at each mouse speed.

To re-create the Windows standard curve for example, suppose you wanted acceleration × 0.757142857 when the mouse moves 4.375 mickeys in each mouse poll period, with a 60Hz refresh rate, then you set:

Set SmoothMouseXCurve = mickeys / 3.5
= 4.375 / 3.5 
= 1.25
(Note: This is exactly the standard Windows curve SmoothMouseXValue)

Set SmoothMouseYCurve = acceleration * mickeys * ScreenResolution / ScreenUpdateRate
= 0.757142857 * 4.375 * 96 / 60
= 5.3
(Note: This is exactly the standard Windows curve SmoothMouseYValue)

So if moving the mouse at 4.375 mickeys per polling interval, the accel is × 0.757142857, and the on-screen pointer moves 4.375 × 0.757142857 = 3.3125 pixels.

The numbers above have too many decimal places, because I'm trying to hit the same values as the standard curve.

Another example: You might decide that at 10 mickeys of mouse movement, you want 1:1 and 10 pixels of pointer movement, the curve calculation would be:

Set SmoothMouseXCurve = mickeys / 3.5 = 10 / 3.5 = 2.86 (approx.)

Set SmoothMouseYCurve = acceleration * mickeys * ScreenResolution / ScreenUpdateRate= 1.0 * 10 * 96 / 60= 16

You would do the curve calculation for curve points 1 thru 5, trusting that Windows will interpolate between those points to give in-between levels of acceleration.(Curve point 0 should be SmoothX=0, SmoothY=0)

If any of that needs explanation, please let me know.

Anonymous said...

I've split my comment up into 2 posts as my single post was too long...

Hi Mark,

Thank you for the very thorough explanation and for clearing up the fact that the ballistics page formula for V_Pointer is not what's actually used, but is what they simply claim is used.

This clears up a lot of confusion and coincidentally, I had stumbled across the fact that a formula was wrong somewhere on some page, be it the ESR forum post or the ballistics page, the day after I made the post here.

The way I figured out the problem was by following a modified version what you stated in the algorithm section which states the following:

1. During a time period, measure the count of mouse movements (also known as 'dots' or Mickeys).
2. Convert the mouse movement count into a mouse velocity.
3. Using the acceleration formula, calculate the corresponding pointer velocity.
4. Convert the pointer velocity into a number of pixels of pointer movement.

I followed these instructions in the following way using an input Mickey of 3, a 60Hz monitor, and the default 96 DPI as follows:

First I converted the mouse movement count into a mouse velocity:

3 / 3.5 = 0.8571428571428571

Then I used the acceleration formula, which I took to mean the gain factor stored in the registry and calculated the pointer velocity:

0.8571428571428571 * 4.792682926829268 = 4.10801393728223

This is the point where I do things differently than what is stated on the XP ballistics page. According to the ballistics page, the formula is as follows:

V_Pointer = Mickey * ScreenUpdateRate / ScreenResolution

Rewritten in our terms it would be:

V_Pointer = Pixels_MouseBusUpdate * ScreenUpdateRate / ScreenResolution

I assumed that there was an error in the formula as shown on the ballistics page and I swapped the position of the V_Pointer and Mickey terms:

Pixels_MouseBusUpdate = V_Pointer * ScreenUpdateRate / ScreenResolution

Applying this flipped formula, I converted the pointer velocity into a number of pixels of pointer movement:

Pixels_MouseBusUpdate = 4.10801393728223 * 60 / 96 = 2.567508710801394

Calculating the ratio between the number of pixels the pointer moved and the original mouse movements, yielded the following:

2.567508710801394 / 3 = 0.8558362369337979 or about 85.58%

Comparing these numbers to hoppan's blog I found that his gain factors for each point beyond the first were mistakenly calculated based on the (0, 0) plot point (e.g. gain of 4.24 vs 4.793 for the second point), but that any calculation made within the first plot area were correct. Doing the calculations with a Mickey of 1 yielded a ratio of 56.89% which matches the numbers found on hoppan's guide, and re-running the calculation with a gain factor of 5.6, which was what hoppan stated was needed for 1:1 tracking in XP with a 60Hz monitor, gave a match at any and all values I input.

Anonymous said...

Part 2...

This also helped me clear up a similar confusion with the Windows 7 formula which isn't covered on your blog. Quoting hoppans's guide, the formula for Windows 7 is:

V(pointer) = count * mouse update rate / screen resolution (DPI)

Rewriting in the terms we use here we get:

V_Pointer = Pixels_MouseBusUpdate * MouseBusUpdateRate / ScreenResolution

Comparing this to the ballistics page...

V_Pointer = Pixels_MouseBusUpdate × ScreenUpdateRate / ScreenResolution

... we see that only MouseBusUpdateRate has changed.

According to hoppan and comments you've left on both ESR posts and here, this value is hard coded to be 150, and is intended to approximate the same ratio as found in the XP formula.

However, whenever I attempted to apply this formula directly, the numbers I got were confusing and didn't work. For example, an input Mickey of 3 and 96 DPI, I was getting the following values:

First, calculate mouse velocity:

3 / 3.5 ~ 0.857

Then calculate pointer velocity:

0.857 * 4.793 = 4.108

Then apply the formula from hoppan's guide:

V_Pointer = 3 * 150 / 96 = 4.6875

Comparing the two results, we can see that 4.6875 is not equal to 4.108, nor does the ratio between the two numbers resemble the values seen on hoppan's post (even accounting for the gain factor errors). Swapping the position of V_Pointer and Mickey didn't fix the problem either; it just made the value larger than the input variable.

It was here that I realized what your blog post meant by "upside down" and what hoppan was referring to regarding your theories about the hard coded 150 and Windows XP. The solution was to flip the MouseBusUpdateRate and ScreenResolution terms in hoppan's formula, and then apply my own swap for where the terms went as I showed above in the Windows XP formula. This is hoppan's "fixed" formula:

V_Pointer = Pixels_MouseBusUpdate * ScreenResolution / MouseBusUpdateRate

Using this formula, and an input Mickey of 3...

First, calculate mouse velocity:

3 / 3.5 = 0.8571428571428571

Then calculate pointer velocity:

0.8571428571428571 * 4.792682926829268 = 4.10801393728223

Here, I apply the exact same swapping of terms that I did with the Windows XP formula, applying it to hoppan's fixed formula::

Pixels_MouseBusUpdate = 4.10801393728223 * 96 / 150 = 2.629128919860627

Calculating the ratio between the pointer and mouse movements yielded the following:

2.629128919860627 / 3 = 0.8763763066202091 or about 87.64%

Referencing back to hoppan's blog, the difference between the Windows 7 formula and the Windows XP formula was 2.4%. Working backwards we get the following:

0.8763763066202091 / 1.024 = 0.8558362369337979

Which is exactly the same as Windows XP.

So with that in mind, I think that I've gotten to the same place as you, although I think I term things differently than you do, and I certainly take different approach to get there. What makes the most sense to me is that the formula for the ballistics page is indeed wrong, but not in that it flips ScreenUpdateRate and ScreenResolution, but that it mislabels and swaps V_Pointer and Mickey. Mickey should be labeled as something different as it refers to the eventual number of pixels that Windows will move the pointer, and V_Pointer should be where the Mickey term is at. This problem is further compounded in hoppan's Windows 7 formula which preserves the mistakenly swapped terms and does not flip the ScreenResolution and MouseBusUpdateRate terms making the math even more confusing.

If I've gotten anything wrong such as math or my understanding, please let me know. I think I've got everything worked out, and making some test registry keys for myself on Windows XP seems to work out, but I could still be wrong.

Mark Cranness said...

I wrote "acceleration", but should have used "gain", as you correctly say.

An HCI (Human Computer Interaction) researcher would use "gain", but their gain is a ratio between control device (mouse) speed, and pointer speed, measures in metres/second or inches/second.

Our/My "gain" is perhaps better named "pixel gain", being the ratio between mouse counts ("Mickeys") and pixels.
When gamers say "1-to-1", they mean 1 count of mouse movement corresponds to 1 pixel of pointer movement, not that 1 inch on the mousepad corresponds to 1 inch on the screen.

Expanding on the SmoothMouse formulas earlier:

To design a SmoothMouse#Curve: choose 4 mouse speeds to build the curve with, and for each mouse speed:

Set SmoothMouseXCurve = mickeys / 3.5

For Windows XP+Vista:
Set SmoothMouseYCurve = pixelgain × mickeys × ScreenResolution / ScreenUpdateRate

For Windows 7:
Set SmoothMouseYCurve = pixelgain × mickeys × 150 / ScreenResolution

For Windows 10+8.1+8:
Set SmoothMouseYCurve = pixelgain × mickeys × 120 / ScreenResolution

Note that for Windows 7+, you divide by ScreenResolution, but for Windows XP+Vista, you multiply by ScreenResolution. This is the "upside down" part of this blog.

ScreenResolution is 96 normally, from the Control Panel Settings, Display, Scale and layout, size of items.
ScreenResolution = Scale_and_layout% × 96

OLLEVM said...

Dear Mark,

Thank you for your help, and sorry for such a delayed reply.

I did not quite get what you've meant by saying

"Now on Windows 8.1, to get × 0.425, easiest might be to set 6/11 in Windows Control Panel, and adjust your in-game sensitivity to × 0.425 of what it is now.
(That would work even if the game uses DirectInput or Raw Input.)

Or you might try using 5/11, which is × 0.4, lower by ~ 6%, perhaps close enough not too notice?
(That would only work for games that use old-style 'GetCursorPos' to read mouse input, because only 'GetCursorPos' games are affected by the pointer speed slider.)"

How should I adjust my current in-game sensitivity to x 0.425, if I do not know what the correct setting should be?

Let me explain: I used to play 4/11 in windows 1.65 in cs 1.6 with windows accel on, but now since I'm trying to use your method, I do not know what to take as a "basis" sens (referring to the feeling of 4/11, 1.65 in-game).

Please let me know if you've understood what I'm talking about or should I rephrase it in some way and once again thank you for your help.

Mark Cranness said...


For CS 1.6, I suggest you try Control Panel 6/11 and CS "sensitivity 0.7"
(1.65 × 0.425 = 0.70125, rounded to 0.7)

OLLEVM said...

Hi Mark,

Thank you for your suggestion, it definitely works for CS 1.6 and sensitivity feels just right, which I am absolutely happy about, however, for some strange reason - using the same settings in CSGO results in slower sens, which is strange since mouse sens and accel commands are same at both games. Do you have any ideas and/or suggestions?

The other question I have to you is:

6/11 sensitivity is 4/11 x 2 as far as I know

so what is the WinXp acceleration curve (or multipliers)?

Knowing that I would be able to adjust my eDPI accordingly (to the desirable medium ground) and play without accel at all ( f.e. 1.65 cs sens with 4/11 win and 400 mouse dpi = 0.825 cs sens with 6/11 win and 400 mouse dpi, eDPI is the same. However, keeping the accel in mind 4/11 sens' eDPI is is significantly higher (at some moments) than 6/11 without accel).

As always, thank you so match for sharing your knowledge and fast replies.


Mark Cranness said...


CSGO does use a later (different) Source game engine than CS 1.6.
In CSGO, make sure that you are NOT using the -useforcedmparms command-line parameter, or if you are doing that, then don't do that, or make sure that the m_mousespeed console var is set to 1, and not to 0.
m_mousespeed 1 turns on EPP (or leaves it on, in your case), and 0 would turn it off.

6/11 is 2 × 4/11 only when Enhance pointer precision (EPP) is OFF.

When EPP is on, the pointer speed scale is quite different.
When EPP is on, 4/11 is × 0.6, and 6/11 is × 1, so 6/11 is 67% higher than 4/11 with EPP on.

The Win XP (60Hz monitor refresh rate) Smooth curve is effectively identical to the Windows 8/8.1/10 curve, no difference. (The Windows 7 curve is slightly different, by a few percent.)

With EPP on, the sensitivity is not a fixed number, and does not just use the speed slider, but also depends on how fast the mouse is moving.
It varies from × 0.5689 for slow movements, to × 1.0 at about 8 mouse counts per polling interval, up to × 2.69 when moving the mouse extremely fast.
It look like this:

Sorry for the slower reply this time.

Unknown said...

Dear Mark
I am writing to ask for information about how to play Valorant with EPP on,I am accustomed to play games with EPP such as CS:GO,but when I play Valorant,I found that the EPP doesn't work.Valorant ignores Windows mouse features and takes mouse input directly,is there anyway to play Valorant with EPP?I would be much obliged to you if you could let me know the procedures I should go through.

Mark Cranness said...

> Valorant EPP

If Valorant reads the mouse directly, then there is unfortunately no way to get Windows control panel (EPP) acceleration applied.

You might try the povohat mouse driver, which allows adding acceleration to games, even when those games don't have accel and bypass EPP.

Unknown said...

Thank you for your generous help

Lucas De Marco said...
This comment has been removed by the author.
Lucas De Marco said...
This comment has been removed by the author.
Lucas De Marco said...

Hello dear mark, I have a problem for years, I played cs 1.6 and I migrated to csgo losing all my muscular ability, I read all the comments but this is still very confusing for me. I played cs 1.6 on windows xp with 3 sensitivity in the game, another peculiarity in the jog I used the mouse filter on, option not existing on csgo, 400 dpi on the mouse with a rate of 125 hz, 3/11 on windows xp with epp on. 75 hz monitor

to do the same on windows 7 and windows 10 and adjust the sensitivity is hell, the biggest problem here is that now I use a 60 hz monitor and the mouse at 500 hz, even the mouse but with the usb update it jumped to 500 hz because the current bus of the usb card reads this speed and the old one would only go up to 125 hz. this already took me thousands of nights of sleep, if you can help thank you for more.

OLLEVM said...

Hello, Mark, it's me again :)

Do you have any idea how can I replicate (to some extent) the behavior of Windows XP accel (4/11, 85 Hz, 125hz, 400 dpi), using the following commands from CSGO

As always, thank you for sharing your knowledge and have a nice one!

Anonymous said...

Hello Mark, thanks for making these fixes, they're great! I just have a question though and it's probably not the easiest to answer.

I use Windows 10 and I use a custom scaling of 110% as I feel this is the best size for me to use comfortably.

My question is how do I calculate the registry tweak for a custom scaling? Thanks in advance if you're still responding to questions! Regards, Ryan.

Mark Cranness said...

Sorry for the late reply

> I use Windows 10 and I use a custom scaling of 110% as I feel this is the best size for me to use comfortably. My question is how do I calculate the registry tweak for a custom scaling?

Use the fix builder, and accept the default answers, and it should create the right fix for 100%.

The fix builder is in the normal ZIP file, open the fix ZIP file, then open, then extract and run MarkC_Windows_10+8.x+7+Vista+XP_MouseFix_Builder.vbs

Anonymous said...

Does this work for Windows 11?

Mark Cranness said...

> Does this work for Windows 11?

I haven't tested it on Windows 11, but I expect that it will work.

OLLEVM said...

Hi Mark,

I'm glad that you are fine during these tough times, and are still replying to these questions.

Is there any chance you can reply to this one?

Do you have any idea how can I replicate (to some extent) the behavior of Windows XP accel (4/11, 85 Hz, 125hz, 400 dpi), using the following commands from CSGO

Thank you in advance.

AG said...

Hi Mark, glad to see you are still here as you might be the only person with an solution to my issue.

So ever since i upgraded from Windows 7 to Windows 10, i instantly noticed the acceleration felt different, so i wanted to get it back to what it was in windows 7 -but no luck.

I have copied all acceleration related registery keys from Windows 7 to 10, (smoothmousex/y curves, mousethreshold1/2, mouse speed, etc.) Literally everything in there, but still no luck, acceleration feels WAY higher on windows 10.

And if this helps - the game i play is Call of Duty 4: Modern Warfare, which is Quake3 based game, and i believe these ask Windows to enable acceleration when the game is launched?

So my question is: what exactly causes the acceleration to be different with exact same registery values, and is there any way possible i could achieve the exact same acceleration as it was in windows 7?

Thanks so much!

Mark Cranness said...

Hi AG,

Acceleration IS higher on Windows 10/8/8.1, than it was on Windows 7, but it should be a simple fix to adjust for that.
Using Windows 7 registry settings on Windows 10 will result in faster/larger mouse movement, when EPP is ON.

Inside Windows 7, a part of the mouse calculation when EPP is ON (but not when it is OFF), is to divide by 150.
For "reasons", in Windows 10, that part of the calculation instead divides by 120.

So for the same SmoothX & SmoothY values, Windows 10 moves the mouse further/faster by 150/120 = × 1.25

The solution is to make your SmoothY values smaller by × 120/150, or × 0.8, OR
Make your Smooth X values larger by 150/120, or × 1.25

AG said...

Hey! Wanted to get back on this Windows 7/10 acceleration issue.

I tested your solution and while it becomes similar to what it was, it's still not quite the same.

I assume this is due to the divide values being different?

Do you have any idea what file Windows is getting these values from and if we could just simply swap the values?
I'd be interested in trying to get it fully to what it was in Windows 7.

Thanks again!

Anonymous said...

Hey @AG could you replicate the Windows7 acceleration under Windows10? I tried SmoothY x 0,8 or SmoothX x 1,25 , but both is still very different to Windows7.

It feels like we have to multiply SmoothX even higher (eg. 1,3) and also SmoothY 1,1 or something like this but until now I couldn't find the right value.

AG said...

unfortunately i never did and moved onto custom acceleration.

I did talk to someone who was able to disassemble the driver which is behind how acceleration behaves and code behind it.

But turned out it's not simple to restore acceleration back to what it was in windows 7 (which was quite complicated) and got to know that the way acceleration works between versions of windows is very different

And as we are a very small minority who play with windows acceleration, let alone feel/know that there are differences on it between versions of windows, i'm afraid there will never be an solution.