Mouse Ballistics

I said the mouse feels a bit jerky in my demo, so I bought a higher DPI mouse instead of my ancient mouse I was using. Well, apparently the issue was not with the mouse itself, but rather the way I was handling input. But buying a new mouse is also a way to debug, albeit an expensive one.
On windows I am reading mouse input using the raw input message (WM_INPUT).

I will just put a bit of code just in case it’s useful for someone, but the point here is not to show how to read Raw input.
First we need to register the input devices:

RAWINPUTDEVICE Rid[3];

Rid[0].usUsagePage = 0x01;
Rid[0].usUsage = 0x05;
Rid[0].dwFlags = 0; // adds game pad
Rid[0].hwndTarget = 0;

Rid[1].usUsagePage = 0x01;
Rid[1].usUsage = 0x04;
Rid[1].dwFlags = 0; // adds joystick
Rid[1].hwndTarget = 0;

// Mouse registration
Rid[2].usUsagePage = 0x01;
Rid[2].usUsage = 0x02;
Rid[2].dwFlags = RIDEV_NOLEGACY; // adds HID mouse and also ignores legacy mouse messages
Rid[2].hwndTarget = 0;

if (RegisterRawInputDevices(Rid, 3, sizeof(Rid[0])) == FALSE) {
//registration failed. Call GetLastError for the cause of the error.
}

Then we need to handle WM_INPUT to get the raw data:

case WM_INPUT:
{
UINT dwSize;

GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &dwSize,
sizeof(RAWINPUTHEADER));
LPBYTE lpb = new BYTE[dwSize];
if (lpb == NULL)
break;

if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb, &dwSize,
sizeof(RAWINPUTHEADER)) != dwSize )
OutputDebugString (TEXT("GetRawInputData does not return correct size !\n"));

RAWINPUT* raw = (RAWINPUT*)lpb;

if (raw->header.dwType == RIM_TYPEMOUSE)
{
Mouse->SetRaw((double)raw->data.mouse.lLastX, (double)raw->data.mouse.lLastY);
Mouse->SetMove();
}
delete[] lpb;
break;
}

The code reads raw input from the mouse, but the issue is that the raw input is linear.
That means we get movement values that are linearly proportional to the actual mouse movement on the surface.
Most FPS games have mouse ballistics. The mouse accelerate as you move it faster, so it is not 1:1 linear mapping to actual mouse movement.

I have searched for resources about mouse ballistics in windows, but didn’t find a definitive answer. There was something about thresholds you can get with SystemParametersInfo and SPI_GETMOUSE.
However, it seems like it might be deprecated and does not return useful values.

Another thing I found is how windows XP models mouse ballistics. This is an old article but it gives an idea how to model mouse ballistics from the raw input on my own.
http://msdn.microsoft.com/en-us/windows/hardware/gg463319.aspx

The way I modeled mouse movement is by using a function f(x) where x is the raw input, such as the horizontal movement or vertical movement, and the result is the desired movement.
Notice that this function does not have a time component so although we talk about acceleration we actually calculate the movement per sample.

I had to normalize the mouse data to values of about [0..1] because I wanted to use te square function to reduce the small values and that only happen on values bellow 1(unless you normalize the values afterwards).

The link about mouse ballistics in Windows XP is doing a lot more to make sure the mouse response is hardware independent, but I didn’t go to this length. I simply used the game’s resolution to normalize the mouse.

After considering that, all that was left was to do is to tweak the mouse to my liking. The final function I came up with looks like this:

MoveX = dynamic_cast(a.operator->())->GetRawX();

MoveX = min(MoveX, 1);

double a1 = 0.075;

MoveX=MoveX

Mouse ballistics model, f(x)

I feel like there is a lot more to do in this area, and I need to learn more about how other games model the mouse movement. It is easy to neglect this part because it’s usually easy to “make it work” and be “good enough”.
I have a feeling I will get back to this subject later.

One thought on “Mouse Ballistics

  1. Pingback: FPS mouse revisted « PompiDev

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s