11
\$\begingroup\$

I'm using C# and trying to get hardware mouse position. First thing I tryed was simple XNA functionality that is simple to use

Vector2 position = new Vector2(Mouse.GetState().X, Mouse.GetState().Y);

After that i do the drawing of mouse as well, and comparing to windows hardware mouse, this new mouse with xna provided coordinates is "slacking off". By that i mean, that it is behind by few frames. For example if game is runing at 600 fps, of curse it will be responsive, but at 60 fps software mouse delay is no longer acceptable. Therefore I tried using what I thought was a hardware mouse,

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetCursorPos(out POINT lpPoint);

but the result was exactly the same. I also tried geting Windows form cursor, and that was a dead end as well - worked, but with the same delay. Messing around with xna functionality:

GraphicsDeviceManager.SynchronizeWithVerticalRetrace = true/false
Game.IsFixedTimeStep = true/fale

did change the delay time for somewhat obvious reasons, but the bottom line is that regardless it still was behind default Windows mouse. I'v seen in some games, that they provide option for hardware acelerated mouse, and in others(I think) it is already by default. Can anyone give some lead on how to achieve that.

\$\endgroup\$
4
  • 2
    \$\begingroup\$ I don't think Mouse.GetState() is broken. Are you sure that you're getting the mouse position in the same frame as you're drawing it? Also remember that the Windows cursor has acceleration/deceleration enabled, so it feels more responsive. If you want to get closer to the hardware, you should hit DirectInput, which will give you movement deltas instead of absolute mouse positions. But I believe Mouse.GetState() is still the correct way to do it in XNA. \$\endgroup\$ Dec 13, 2012 at 10:53
  • \$\begingroup\$ No, Mouse.GetState() is not broken, and as long as IsFixedTimeStep == true people should not be able to see delay unless compared directly with visible windows mouse. However setting IsFixedTimeStep to false at lower framerate it becomes visible to everyone. About direct input I considered that a posability(last resort). \$\endgroup\$
    – Sunder
    Dec 13, 2012 at 11:05
  • \$\begingroup\$ Not sure if it's what you want, but what about changing the cursor sprite while it's in your window, and then make it always visible? \$\endgroup\$
    – William
    Dec 13, 2012 at 11:09
  • \$\begingroup\$ Thats exactly what i am doing, the thing is that I dont want to only show it, but to know exact position of the mouse as well. But what i am getting is slightly behind to what it should be. \$\endgroup\$
    – Sunder
    Dec 13, 2012 at 11:12

1 Answer 1

17
\$\begingroup\$

What you are seeing is not input lag.

To get the position of the cursor in Windows you can use WM_MOUSEMOVE or GetCursorPos. They both provide the position of the cursor after Windows has processed it, applying things like acceleration. This is the cursor position that Windows uses, including for drawing. And almost always what you want to use too.

This is what XNA uses. Specifically GetCursorPos (MSDN). This means that, when you call Mouse.GetState, you are getting the true position of the cursor as Windows sees it - with practically zero delay.

Now, you could use WM_INPUT (or DirectInput, although that's deprecated). This gives you the raw pointer data. This is before Windows can apply things like acceleration, and is usually not what you want.

What you are seeing is output lag.

This is because of the "hardware cursor". This is a small sprite that gets drawn over the screen by the GPU at the very end of its pipeline. And I mean the end. It comes after the frame buffer - it gets inserted into the data stream as the image is being sent to the monitor. The reason it reacts so quickly is because its position is set by directly setting GPU registers. There is no waiting around in the pipeline at all.

Your game, on the other hand, has to go through the GPU pipeline. This adds plenty of delays on its own. The most problematic of these for you is double-buffering - which (I'm pretty sure) you can't turn off in XNA 4. You don't draw directly to the frame buffer - you draw to the backbuffer. Which gets presented every ~16ms (at 60FPS). That means you're looking at a minimum of about 16ms between receiving the result of Mouse.GetState getting something based on that result on-screen. Probably longer. Certainly much slower than the hardware cursor.

So what are the solutions?

One is to use SetCursor (MSDN) to change the image that gets displayed by the hardware cursor, to am image that better suits your game (or just live with the Windows cursor).

And the other (far easier) is to just accept the lag, and set Game.IsMouseVisible = false to hide the relative lag. Display your own cursor in-game. It will be 16ms slower than the hidden Windows cursor - but who cares? Gamers are used to it. And 16ms is almost visually imperceptible anyway (it's why we render things at 60FPS).

\$\endgroup\$
2
  • \$\begingroup\$ Thank you for detailed explanation of the matter. Most likely I'll just stick with XNA mouse. Going to wait a bit before accepting in case someone have some additional workaround for it. \$\endgroup\$
    – Sunder
    Dec 14, 2012 at 9:35
  • \$\begingroup\$ I guess accepting the lag or not is a question that should be answered by playtesting. \$\endgroup\$
    – Zonko
    Dec 15, 2012 at 1:01

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .