Sunday, February 28, 2010

Windows mouse pointer acceleration (Enhance pointer precision) is partially broken - Part zero

Until Windows 7, mouse handling in Windows has been subtly broken in some ways, and it has taken Microsoft 8 years to fix those problems.

You can fairly easily see these problems (in Vista and XP).
They appear when the Mouse Properties 'Enhance pointer precision' option is turned on (* Note).

In a previous blog I wrote about one of the problems: mouse pointer DPI scaling is wrong in Vista and XP. I'll summarise that problem and also describe another problem.

Rounding of Fractional Intermediate Results Causes Pointer Jitter and Drift

The various internal acceleration and scaling calculations result in a fractional mouse-pointer movement.
This fractional movement is turned into an integer actual number of pixels moved and a fractional remainder.
The fractional remainder is saved internally and applied to the next mouse input.

Such calculations have been done for some while for the 'Mouse Speed' slider, at least since Windows 98.
Typically the fractional result is truncated towards zero, leaving a remainder that has the same sign as the integer part.
(For example, +2.7 is truncated to +2 with remainder +0.7; -3.3 is truncated to -3 with remainder -0.3)

  • Windows 7 adds in the previous remainder, then truncates the fractional result towards zero, and stores the new remainder.
    This is desirable and good.

    If you record how the Windows 7 pointer responds to mouse input, you can create a picture like this (* Note):
    (The small red dot is on-mouse-pad mouse movement, moving slowly in a circle of diameter 20 'dots' or Mickeys.
    The pointer is how the Windows 7 pointer moves on the screen in response.
    Note that the red dot moves in a larger circle than the pointer does: This is what the 'Enhance pointer precision' option does: If you move the mouse slowly, the pointer moves even slower to allow you fine control over objects selected.)


  • Vista sometimes adds in the previous remainder and sometimes discards the previous remainder, then truncates towards -infinity, and stores the new remainder.

    Truncating towards -infinity means that the remainders are always +ve numbers. Sometimes discarding the +ve remainder can cause the mouse pointer to drift up and left over time relative to the actual on-mouse-pad mouse position.

    (You can see the drift if you move your on-mouse-pad mouse in a slow circle, making sure to keep the physical mouse near the same point on the mouse pad. Over time the mouse pointer drifts up and left.)

  • XP sometimes adds in the previous remainder and sometimes discards the previous remainder, then truncates towards -infinity, and stores the new remainder.
    It discards the remainder more frequently than Vista.

    Truncating towards -infinity means that the remainders are always +ve numbers. Sometimes discarding the +ve remainder can cause the mouse pointer to drift up and left over time relative to the actual on-mouse-pad mouse position, and may cause gently curved near-horizontal or gently curved near-vertical mouse input to result in the mouse pointer 'snapping' to exactly-horizontal or exactly-vertical lines.
    These effects are far more pronounced in XP than they are in Vista.

    (You can see the drift the same as for Vista. Also, slow movement at 45 degrees down and right is grossly slowed down and slow movement 45 degrees up and left is sped up.)

    If you record how the Windows XP pointer responds to mouse input, you can create a picture like this (* Note):
    (The small red dot is on-mouse-pad mouse movement, moving slowly in a circle of diameter 20 'dots' or Mickeys.
    The pointer is how the Windows XP pointer moves on the screen in response.
    Note that the pointer slowly moves up and left even though the mouse is circling in place.)

Mouse Pointer DPI Scaling is Completely Wrong in Vista and XP

For a long while (Win9x+), Windows has scaled user interface (UI) elements according to the monitor DPI Setting.
Larger DPI settings cause UI elements to be drawn larger on-screen.

Starting in XP, Microsoft attempted to apply DPI scaling to mouse pointer movement.

  • In Windows 7, mouse pointer movement is scaled according to DPI. For a given on-mouse-pad mouse movement, larger DPI settings cause larger on-screen pointer movement.
    An internal calculation includes a factor '* DPI'.

  • In XP and Vista, Microsoft got the internal scaling calculation wrong. For a given on-mouse-pad mouse movement, larger DPI settings cause smaller on-screen pointer movement.
    An internal calculation includes a divisor '/ DPI'.

Mouse Pointer Monitor Refresh Rate Scaling Occurs in Vista and XP When It Should Not

  • Windows 7 does not scale mouse pointer movement according to the monitor refresh rate.

  • XP and Vista do scale mouse pointer movement according to monitor refresh rate.
    This is incorrect (see my previous post for details).
    An internal calculation includes a factor '* RefreshRate'.

* Note. To see these effects requires the Mouse Properties 'Enhance pointer precision' checkbox to be ON, and might be masked by mouse drivers specific to a particular mouse, for example: Logitech SetPoint mouse drivers with the 'Game Mode > Speed and Acceleration > SetPoint implemention' option selected do not exhibit the above behaviours. The animations were created with the Control Panel Mouse Speed slider set to the middle, 6th position.

26 comments:

Anonymous said...

Thank you for documenting this, excellent work!

It should be noted that the jitter and the drift towards left and up is more pronounced when the pointer sensitivity ("speed") in the Mouse Control Panel is set to a low value (try the first or second notch).

Since for high-quality, high-resolution mice the sensitivity needs to be set lower than usual, the drift and jitter are paradoxically more pronounced for those mice. In other words, the issue can make high-quality, high-resolution mice appear to be of bad quality.

Mark Cranness said...

Yes, I see that the left & up drift is faster when using low pointer speed slider settings.

More or less, the lower sensitivity slows down the right & down movements, but the left & up stay at about the same speed.

Anonymous said...

Any help anyone can give would be greatly appreciated. I used WinXP/SP3 for 7.5 years until my Hard Drive died this npast December. My monitor was of the 20" square type. With my new computer, I also purchased a 25" widescreen monitor. I never in my wildest dreams thought I would have the problem that has developed.

I love my new monitor. I delivers a wonderful interface/user experience for Win7 Pro. However, with the increased size (left to right), I am experience significant pain in my right hand, arm, and shoulder. whenever I switch back to my old monitor, the problem disappears.

Someone in another forum recommended that I get a gaming mouse, even though I am not a gamer. So, I recently purchase Logitech's M500 mouse. I previously had the basic optical mouse that Logitech made for Dell.

I have downloaded the software for the M500 and tried configuring it so that I could move around the screen with ease. It seems like pointer speed allows me to move from one side to another much more quickly than before. I am no certain what pointer acceleration does, however.

In any event, if anyone could make suggestions to some of the basic settings that could help me use this mouse in such a way that it is comfortable. I have already adjusted it so that the pointer goes to the default button on a new diaglogue box/window.

Overall, however, I am still getting hand, arm, and shoudler pain. I would hate to go back to my old monitor as the viewing experience is just not the same. Any suggetions ladies and gentlemen? Thanks in advance for your help.

Jim

Mark Cranness said...

Hi Jim,

I would say it was good advice to try a quality mouse.

- Logitech mouse drivers can turn off Windows control panel speed and acceleration and instead use Logitech mouse speed and acceleration, so try it both ways to see which works best for you.

- Acceleration (in Windows = "Enhance pointer precision"), makes fast mouse movements EXTRA fast and (usually) slow mouse movements EXTRA slow.
For example a quick mouse movement of 20 counts-per-whatever might move the pointer 40 pixels-per-whatever (20:40 = 1:2, doubling movement), but a slow mouse movement of 2 counts-per-whatever might move the pointer by 1 pixel-per-whatever (giving enhanced precision), (2:1 = 1:0.5).

It can help with large monitors because a small quick movement can move the pointer the same as a larger slow movement.

What hurts the most? Large movements or quick movements?

- Change hands and mouse with your left hand!

I damaged my right wrist a long time ago playing minesweeper (how sad is that?), and fairly quickly got used to mousing left-handed.
(You might need a to buy a left-handed or ambidextrous mouse.)

Mark

Leo said...

I have windows xp pro x64 edition. Well when I have mouse pointer precision "off" and put pointer speed dot "1-5" the sens is higher dragging mouse to left and slower right, like when i drag to left and right pretty fast it automatically goes to left, and it's impossible to play with, it responds exactly like the second picture. This does not happen taking pointer precision "on", but I dont wanna use that during mouseacceleration. How to I fix this? been searching everywhere for this, and im not kidding, going crazy.

Best regards,
Kent

Ken said...

Or I could always check pointer precision "on" during this problem. But then mousepointer get's unprecise for me, "small movements" = very jerky. So I was wondering if I could download cpl mousefix or something like that with "check enhance pointer precision" on, (so I could lower my sens to "3", would that fix the wierd behavior? And what fix would be best for windows xp pro x64 edition?

thx again
Ken

Mark Cranness said...

Hi Ken,

I remember reading a Microsoft support article about this exact problem with Windows XP x64, but I can't find it anymore...

As I understand:
- Windows XP (both x86 and x64), when 'Enhance pointer precision' (EPP) is ON, have the jitter and drift problem I write about above.
- Windows XP x64, when EPP is OFF, have a separate jitter or drift problem, as you describe.

- Try installing SP2 for XP x64 (it is possible that SP2 fixes the problem).

- Maybe the EPP ON drift is not as bad as the EPP OFF drift?
Apply the Cheese Fix, or my MarkC Fix Builder, set EPP ON, set 3/11 and try it out?
(I recommend Cheese or my fix builder fix rather than CPL.)

- Can you reduce the DPI or sensitivity using a mouse driver, and set 6/11?
(For in-game, you would want to also apply Cheese Fix or MarkC Fix Builder.)

- If not, does this 3rd party driver work for you:
3rd party mouse driver GUI @ ESReality.com
... it will let you use 6/11, and has its own separate sensitivity.

Anonymous said...

Hi.

i read the article about XP's Mouse scaling.. and i was tested several times like you about EPP's bug. i was told to everyone, they didn't belive me before read your article.
but don't you know SP1 is correct movement?

i didn't read all your article, there is no review about SP1.

SP2, 3, Vista has same bug. but SP1's EPP movement work is fine.

so if you know about this, please check SP1's EPP.

and my email ckshin74@hotmail.com

Regards
Shin

Mark Cranness said...

Hi Shin,

I have not tested the different Vista service packs to see if the EPP drift is different for each.

I did examine Vista SP1, but sorry to say, I did not test how bad or good the EPP drift was for SP1.
I do think there must be SOME drift for SP1, but less than Windows XP.

It is interesting to hear that SP1 is correct but that SP2 and SP3 are not correct!

If I get some time, I may test Vista further, but I don't have any installed versions of Vista to test with.

Regards,
Mark

Anonymous said...

thx for your reply.

and i mean Windows XP SP1 no Vista.
XP SP1 is correct movement. SP2, 3 is something wrong.

i am looking for solution.


best wishes
Shin

Anonymous said...

today i tested same enviroment=Win XP SP1 and 60hz monitor and EPP on(i dont use any fix before you met)

sure, XP SP1's EPP movement scaling is correct circle(don't move left up like SP2, 3 or Vista).
but i think SP1's some mouse file or resistry, is this possible instead of SP2, 3 or vista's one?

if that is possible i can use low sensi with EPP's On.
(iam using MS WMO Mouse and windows XP sensi 2/11=this is for game. for work using Razer high DPI Mouse)

if you have a time, please check XP's SP1 EPP ON without any fixes

Shin

Anonymous said...

and if you know Windows XP's Mouse control file, i will copy from SP1's one. and i will copy to SP's 3.

but what file control Mouse?

Mark Cranness said...

> i mean Windows XP SP1 not Vista

I am sorry, I misread your post : you did say XP but I missed that.

> what file control Mouse?

Unfortunately, that file is "C:\Windows\System32\win32k.sys", and it does much more than just control the mouse, and would be very very unsafe to replace it with another version.

Does your game have an in-game sensitivity adjustment? Can you adjust in-game mouse using a game setting, separate from the Windows control panel?

Mark Cranness said...

> i mean Windows XP SP1 not Vista

I am sorry, I misread your post : you did say XP but I missed that.

> what file control Mouse?

Unfortunately, that file is "C:\Windows\System32\win32k.sys", and it does much more than just control the mouse, and would be very very unsafe to replace it with another version.

Does your game have an in-game sensitivity adjustment? Can you adjust in-game mouse using a game setting, separate from the Windows control panel?

Anonymous said...

you mean, windows and in-game mouse setting is seperated?

no, in_game sensitiiviy with windows sensi.

i tested XP SP1's win32k.sys file copy to SP3's win32k.sys. but failed. :)

but really thanks for your kind answer.
maybe will be found new answer!

regards

Mark Cranness said...

> you mean, windows and in-game mouse setting is seperated?

For some games : yes, and for some games : no.

Some games use DirectInput or Raw Input to read the mouse (these are different program APIs to read mouse input).
For those games, the total sensitivity is [mouse driver (Logitech, Razer...) sensitivity] × [in-game sensitivity].
An example is CounterStrike:Source when Raw Input is enabled.

Some games use WM_INPUT or GetPointerPos to read the mouse (these are older APIs to read mouse input).
For those games, the total sensitivity is [mouse driver (Logitech, Razer...) sensitivity] × [in-game sensitivity] × [Control Panel sensitivity].

The reason I asked about in-game sensitivity, is this:
I *think*, that if you use a high [Control Panel sensitivity], by setting the 'Pointer speed slider' to a higher value, that the drift and jitter is smaller (I think it might be, but I am not sure).

If your game can set an in-game sensitivity, then you might be able to increase the 'Pointer speed slider' sensitivity, and ALSO DECREASE the in-game sensitivity to compensate, and have the same overall sens as before, but maybe with reduced drift and jitter. Maybe.

Rhys Jones said...

Hi markc i noticed you did a reg file with semphis to add the default mouse accel from windows xp onto window 7 computers, i currently need the 75 hz reg file, atm he only has a 100 hz reg file. Please can you create this for me would be MASSIVELY appreciated! been trying to contact you for so long

Osmo Jaakkola said...

> > what file control Mouse?

> Unfortunately, that file is "C:\Windows\System32\win32k.sys", and it does much more than just control the mouse, and would be very very unsafe to replace it with another version.

You say it would be unsafe but is it indeed even possible? The following might be of interest to you and the other readers.


The mouse movement code is seriously broken in Windows XP 64-bit.

With Enhanced Pointer Precision OFF and sensitivity set to anything but 1:1 ratio, the cursor moves a lot faster in the negative directions (up & left). The cursor moves at least 1 whole pixel up or left on every update with negative mickeys, which becomes most apparent at the lowest sensitivity.

With help from the leaked Windows 2000 sources (ntos\w32\ntuser\kernel\ntinput.c for the curious) I tracked the problem down to the function GetMouseCoord in win32k.sys (the Win32 subsystem kernel driver)

The code in question takes in dx and dy values (mickeys) and scales them by a precalculated factor so that 256 means 1:1, 128 would be half speed etc:

iNumerator = dx * gMouseSensitivityFactor + idxRemainder;
dx = iNumerator / 256 ;
idxRemainder = iNumerator % 256 ;

However, the C standard doesn't completely specify integer division behavior with negative numbers. E.g. if:
Q = -2 / 5;
R = -2 % 5;
The result could be either
Q == -1 && R == 3 (rounded down) or
Q == 0 && R == -2 (rounded toward zero)
depending on the compiler's implementation, as long as the rule (*1) [ (A/B)*B + A%B = A ] holds.

So if we move 1 mickey left with sensitivity at half:
dx = -1
gMouseSensitivityFactor = 128
idxRemainder = 0

The end result should be either
dx == -1
idxRemainder == 128
or
dx == 0
idxRemainder == -128


The function GetMouseCoord remedies the inspecificity with an additional check:
if ((iNumerator < 0) && (idxRemainder > 0)) {
dx++ ;
idxRemainder -= 256 ;
}

...thus ensuring the rounding is always toward zero.

However, the actual disassembly shows that the result in above becomes
dx == -1
idxRemainder == -128

The division by 256 is implemented by shifting >> 8 bits, i.e. truncating down, and the modulo operation seems optimized in a way that eventually yields a nonpositive remainder for a negative numerator. In essence, the optimizing compiler used to compile win32k.sys has a bug and violates the integer division rule (*1).

The problem could be fixed by bypassing the (idxRemainder > 0) condition and the subtraction idxRemainder -= 256. As the remainder is already negative (when iNumerator is), we just need to increment dx to account for the asymmetry of the bit-shift division. I.e. replace the check with:

if (iNumerator < 0) {
dx++ ;
}

In disassembly the later part of the check looks like:
(eax == idxRemainder, r11d == dx, iNumerator < 0)

test eax, eax
jle short $+0Eh
inc r11d
sub eax, 100h

My goal is thereby accomplished by skipping the conditional jump jle and the subtraction.
test eax, eax
nop
nop
inc r11d
nop
nop
nop
nop
nop

In hex view the patch looks like:
85 C0 7E 0E 41 FF C3 2D 00 01 00 00
=>
85 C0 90 90 41 FF C3 90 90 90 90 90

Then repeat for the dy scaling. Find the next occurrence of 85 C0 around 60 bytes later and replace

85 C0 0F 8E ## ## ## ## 41 FF C2 2D 00 01 00 00
with
85 C0 90 90 90 90 90 90 41 FF C2 90 90 90 90 90

...where the ###'s are a longer jump which may vary between versions.

So far so good, but I've been unable to make Windows boot with a modified win32k.sys, even if the modification is trivial. So it must be due to a bad digital driver signature. How could I make windows load non signed kernel drivers, or win32k.sys in particular?

Osmo Jaakkola said...

(Replying to self)

On second inspection The fix is actually simpler:

Here's the dx scaling code disassembled in IDA.
r8d contains the sensitivity factor, and r11d the original dx.

mov ecx, r8d
imul ecx, r11d
add ecx, cs:idxRemainder

mov eax, ecx
cdq
mov r11d, eax
movzx edx, dl
add eax, edx
sar r11d, 8
movzx eax, al
sub eax, edx

test ecx, ecx
mov cs:idxRemainder, eax
jns short loc_FFFFF97FFF1DE634

The compiler apparently employs the C99 or C++11 standard, which states that negative integer division is rounded toward zero. The compiler has included the stuff to do this (cdq;movzx edx,dl...) but gets confused with r11d and eax for some reason.

The code should make r11d = ecx/256 and eax = ecx%256. Let's see how to do that in detail:

mov eax, ecx
//// ecx is the numerator, which needs to be in eax to utilize cdq (convert double to quad)

cdq
movzx edx, dl
//// cdq makes edx -1 if eax < 0, and 0 otherwise
//// the movzx is equivalent to edx &= 0xFF, edx becomes either 255 or 0

add eax, edx
mov r11d, eax
sar r11d, 8
//// So, if eax was negative, it gets +255
//// The value is copied because we need eax for the remainder
//// r11d /= 256 such that it remains zero for any [-255..255] value of ecx

movzx eax, al
sub eax, edx
//// eax &= 0xFF and the 255 offset is removed
//// eax now holds the correct signed remainder [-255..255]


The only difference to the original is that the line (mov r11d, eax) happens 2 steps too early. Same thing happens with dy calculation (mov r10d, eax).
In hex the operations are (44 8B D8) and (44 8B D0) and should be moved to just before the sar opcode (41 C1 ...).

8B C1 99 _44 8B D8_ 0F B6 D2 03 C2 41 C1 FB 08
=>
8B C1 99 0F B6 D2 03 C2 _44 8B D8_ 41 C1 FB 08

and

41 8B C0 99 _44 8B D0_ 0F B6 D2 03 C2 41 C1 FA 08
=>
41 8B C0 99 0F B6 D2 03 C2 _44 8B D0_ 41 C1 FA 08

Mark Cranness said...

Osmo Jaakkola said:
> The mouse movement code is seriously broken in Windows XP 64-bit.

... and far *MORE* seriously broken than the smaller problems I describe in this blog-post!

Your analysis is excellent and I enjoyed reading it (really!)

(Could you, or would you mind if I, turn it into a guest blog post and added it to my blog?)

Is the problem fixable?

Some solutions come to mind:
- Allow Windows to boot with your patched/fixed version of win32k.sys
- Apply a MarkC mouse fix and run with “Enhance pointer precision” (EPP) ON
- Use EPP OFF and the pointer speed slider set to the middle 6/11 position and use third party mouse drivers to control the overall sensitivity (examples might be Razer or Logitech, which have their own internal sensitivity/CPI adjustments)
- Is this fixed in a Windows XP service pack?

* Allow Windows to boot with your patched/fixed version of win32k.sys

Geoff Chappell discusses signing of Windows kernel stuff in his article about Windows memory licensing [link] (scroll to “Checksum” & “Digital Signature”).

Likely you will have to sign the modified win32k.sys file and run XP x64 in Test Mode as he describes.

Driver Signature Enforcement Overrider is a tool that should make using Test Mode as painless as possible.
(Further info on test mode and DSEO might be found in this post about How to Increase USB Sample Rate in Windows Vista/7 and in the comments.

* Apply a MarkC mouse fix and run with “Enhance pointer precision” ON

My mouse fix builder can build a fix that emulates EPP=OFF for any single setting of the Control Panel pointer speed slider.

So instead of using EPP=OFF and (for example) the pointer speed slider set to 4/11, instead use a fix-builder fix for 4/11 with EPP=ON.
(Usually the fix builder creates a fix with a ×1 sensitivity, but if when the fix builder asks : “Pointer Speed Scaling” you enter ‘N’, the fix will have the same sensitivity as when EPP=OFF.)

As I describe in this blog post, there are problems on Vista when EPP=ON, but they are FAR smaller than the problem you describe.
Unfortunately the fix only works at a single Pointer speed slider setting .

Some years ago I recall seeing a Microsoft KB support article about a Windows XP x64 problem, but when I later went to find it, I could not find it : It had gone from the internet!
I wonder if that support article was about this?

Mark Cranness said...

I said:
>> Unfortunately, that file is "C:\Windows\System32\win32k.sys", and it does much more than just control the mouse, and would be very very unsafe to replace it with another version.

Osmo Jaakkola said:
> You say it would be unsafe but is it indeed even possible?

I'm not sure why I used the word "unsafe", that would be a severe understatement!

Obviously win32k.sys is a central component of Windows and swapping it out with a copy from another version of Windows would be like trying to perform a spinal cord and cerebellum transplant on a patient...

Osmo Jaakkola said...

Mark Cranness said:
> Your analysis is excellent and I enjoyed reading it (really!)

> (Could you, or would you mind if I, turn it into a guest blog post and added it to my blog?)

I would be honored. Although my interest in the topic is focused on making my own system work properly, and mainly came here for help. Also the findings really only concern a rarely used version of Windows.

Mark Cranness said:

> Allow Windows to boot with your patched/fixed version of win32k.sys

> Likely you will have to sign the modified win32k.sys file and run XP x64 in Test Mode as he describes.

> Driver Signature Enforcement Overrider is a tool that should make using Test Mode as painless as possible.

Yes, DSEO does both the signing and enabling test mode, although I'm not sure whether the latter was necessary, or indeed if Test Mode even exists in XP x64, as the tool doesn't list it as a supported OS.

I was now able to boot with the modified win32k.sys, and the patch works perfectly!

http://ihme.org/~orbik/random_stuff/xp64_mousemovement_after_patch.png

The red line in the above image happened occasionally, but seems relatively benign, as if MouseMovementRecorder sometimes processed the incoming raw mouse events faster than the Windows could update the cursor position.

Mark Cranness said:

> * Apply a MarkC mouse fix and run with “Enhance pointer precision” ON

> My mouse fix builder can build a fix that emulates EPP=OFF for any single setting of the Control Panel pointer speed slider.

Yes, but unfortunately a similar problem exists (independently!) for EPP mouse movement. I used your fix builder to make the cursor move at a constant 1:2 speed at sensitivity=4, and recorded the output when moving slowly and diagonally (as close to 45° as I could) up+left and down+right.

http://ihme.org/~orbik/random_stuff/xp64_mouse_movement_broken_epp.png

Although there's no acceleration per se, the position updates are now calculated in another function, DoNewMouseAccel(), which wasn't implemented yet in Windows 2000. Meaning no help from leaked sources, so it's harder to say exactly what's happening.

Judging from the values, it's possible that the remainders are reset to 0 whenever a raw 0 is received for either direction. If you move fast enough in an oblique enough angle, or in a completely straight orthogonal line, there are no problems. Also, this time the integer division rounds down (toward negative infinity), possibly by design, but if you move slowly up&left, the disappearing positive remainders increase speed, and decrease it down+left.

I did look at the disassembly of DoNewMouseAccel, but it seems an order of magnitude more complicated (than GetMouseCoord/DoMouseAccel). The function seems to have 5 static variables, 2 of which are likely the dx and dy remainders, so it shouldn't be an impossible task to find when and why the remainders are reset.

Mark Cranness said...

> ... guest blog post ...

Thanks, when I get some time, I may do so.

> I was now able to boot with the modified win32k.sys, and the patch works perfectly!

Excellent!

Version 1.8 MouseMovementRecorder should try and not display the 0x0 just above the red line (which is why the red line occured).
If you weren't using 1.8, try that, otherwise try 1.8 again with -shopwcatchupdelay command line option.

> as if MouseMovementRecorder sometimes processed the incoming raw mouse events faster than the Windows could update the cursor position.

Yes, that does happen sometimes.

> Yes, but unfortunately a similar problem exists (independently!)

Yes, that's what this blog post is mostly about, that remainders are reset sometimes.

I said: "there are problems on Vista when EPP=ON, but they are FAR smaller than the problem you describe", which was me being caffeine deprived and confused, because XP x64 != Vista ... Doh!
IF this problem had been on Vista, my suggestion of using a reg fix would have made sense... (sorry!)

As you've seen, the EPP=On problem is quite severe for XP.
My guess would be slightly more severe (than the XPx64 EPP=Off problem) when moving the mouse slowly, but less severe when moving the mouse faster, just as you found "If you move fast enough in an oblique..."

Remainders are reset to zero like so (on Windows XP):
if (Sign(mouseRawX) != Sign(previousMouseRawX) || mouseRawX == 0) previousMouseXRemainder = 0
(same for the Y axis, independently)

> DoNewMouseAccel()

LOL!
Look at the URL for my blog...

Osmo Jaakkola said...

> Yes, that's what this blog post is mostly about
> Look at the URL for my blog...

Haha, I had noticed actually, but it's somehow easier to write from an independent perspective. Didn't sound that strange at the time.
But I wasn't satisfied with the result yet, and just had to try to fix the EPP=ON problem, no matter how tedious. I think I've just done it, not tested though. I'll let you know if it actually works.

Flow chart with added comments, analysis etc.
Changed bytes in DoNewMouseAccel
Changed bytes in GetMouseCoord (same as earlier)

Unfortunately the fixes aren't too simple, required moving around some code and adding some new. This was still possible without having to recalculate every address, because I could remove redundant code, but that might not be true for the 32-bit one. It would be hard to make a patch that works for multiple versions anyway.

Anonymous said...

I noticed that you consider that Windows mouse pointer acceleration (Enhance pointer precision) is partially broken in Windows XP and Vista, but from my experience it is totally broken in Window 7 64 bit and was almost perfect in Windows XP 32 bit.

I miss the mouse pointer movement from Windows XP. Is there any way to 'import' the way the mouse was behaving in Windows XP to Windows 7?

In Windows XP with the Enhance pointer precision turned on the mouse moved as it should, i.e. quite smoothly all the time and with good precision. While in Windows 7 I cannot find setting neither with Windows Mouse options nor with the Logitech SetPoint for Wireless Mouse M305 so that it would move smoothly and precisely. It moves jerky to so extent that I have great troubles pointing precisely. I often have to move the mouse several times to point precisely enough in the place I want to click (in Windows XP with the Enhance pointer precision turned on usually I was able to point preciselly the first time instantly). That is so very distracting, and annoying that it hinders normal work with computer, and I spent already, all in vain, several days looking for a solution.
Also sometimes the mouse pointer gets stuck for as long as a second or even two.

I uninstalled Catalyst drivers hoping that perhaps they interfere. Nope. I even installed on a separate disk Windows XP in this computer to test if it is not a hardware problem. Nope. The mouse works as it should in Windows XP with Enhance pointer precision turned on.

Turning on the Enhance pointer precision in Windows 7 seems to work exactly opposite to Windows XP. While in Win XP it made the mouse pointer more precise and moving more smoothly all the time, in Windows 7 it only accelerates the mouse pointer considerably, but does not increase precision at all, makes it rather even less precise.

Is there a way to fix this problem? Do I really have to suffer like this with this jerky mouse pointer? Is the only solution to go back and install Windows XP as my main system again with its memory limitation, no build in TRIM and so on?

BTW, I use 150% DPI set in system Control Panel for text magnification. But when it was less than 150% the problems with the mouse were the same in Windows 7.

Hope to hear from you soon.

Mark Cranness said...

There is almost certainly a fix for you.

The problem is the different scaling (sensitivity) calculation that Windows XP has, compared to Windows 7.

A custom reg file can adjust for that difference, and give you same response as XP.

The calculation is :
The Windows XP 'Enhance pointer precision' (EPP) ON calculation includes : monitor_refresh_rate / text_dpi
Assuming that your monitor refresh rate on XP was 60 Hz, and that you also used 150% DPI on XP for magnification (144 DPI when displayed in the Custom DPI Setting dialog), that is : 60 / 144 = 0.417

The Windows 7 calculation includes :
text_dpi_percent × 96 / 150
For 150%, that is 150 × 96 / 150 = 144 / 150 = 0.96

And so the Windows 7 sensitivity is × 2.304 faster than XP, and would feel jerky in comparison.

The fix is a custom reg file where the SmoothMouseYCurve values have been divided by 2.304 to slow the mouse response down to what it was in XP.

OR to see if that is the correct fix, try temporarily setting the mouse speed slider to the 3/11 position, which should make Windows 7 be the same as XP (within 10%, a little slower than XP). If 3/11 feels almost right, then 2.304 is the right divisor.

Here is an adjusted default curve for Old XP DPI = 144, Old XP monitor refresh rate = 60 Hz, New Windows 7 DPI = 150%:
---
Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\Control Panel\Mouse]
"SmoothMouseXCurve"=hex:\00,00,00,00,00,00,00,00,\
15,6e,00,00,00,00,00,00,\
00,40,01,00,00,00,00,00,\
29,dc,03,00,00,00,00,00,\
00,00,28,00,00,00,00,00
"SmoothMouseYCurve"=hex:\
00,00,00,00,00,00,00,00,\
39,98,00,00,00,00,00,00,\
e4,4c,02,00,00,00,00,00,\
00,8c,0a,00,00,00,00,00,\
1c,87,f6,00,00,00,00,00
---

If 144, 60 & 150% are not the right numbers, let me know.