xcrypt
xcrypt

Reputation: 3366

How to get (true) mouse displacement with windows

I'm wondering how to get true mouse displacement with windows.

For example, I could save the position of a previous mouse position, and request the new position, and subtract the latter from the previous. But this would not give me true mouse displacement.

Imagine the previous cursor position would be the maximum x coordinate of your screen resolution, and the user is moving his mouse to the right. Is there still a way to capture the true mouse displacement then?

Thanks

Upvotes: 2

Views: 3929

Answers (7)

v.oddou
v.oddou

Reputation: 6775

The method on windows is as such:

// you can #include <hidusage.h> for these defines
#ifndef HID_USAGE_PAGE_GENERIC
#define HID_USAGE_PAGE_GENERIC         ((USHORT) 0x01)
#endif
#ifndef HID_USAGE_GENERIC_MOUSE
#define HID_USAGE_GENERIC_MOUSE        ((USHORT) 0x02)
#endif

RAWINPUTDEVICE Rid[1];
Rid[0].usUsagePage = HID_USAGE_PAGE_GENERIC; 
Rid[0].usUsage = HID_USAGE_GENERIC_MOUSE; 
Rid[0].dwFlags = RIDEV_INPUTSINK;   
Rid[0].hwndTarget = hWnd;
RegisterRawInputDevices(Rid, 1, sizeof(Rid[0]));

then in message loop:

case WM_INPUT: 
{
    UINT dwSize = sizeof(RAWINPUT);
    static BYTE lpb[sizeof(RAWINPUT)];

    GetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb, &dwSize, sizeof(RAWINPUTHEADER));

    RAWINPUT* raw = (RAWINPUT*)lpb;

    if (raw->header.dwType == RIM_TYPEMOUSE) 
    {
        int xPosRelative = raw->data.mouse.lLastX;
        int yPosRelative = raw->data.mouse.lLastY;
    } 
    break;
}

Installing hooks will trigger sensitive antiviruses. MSDN doc to refer

Upvotes: 1

thewhiteambit
thewhiteambit

Reputation: 1436

The most reliable way is to use window hooks. Here is a minimalist sample using C(++)

LRESULT CALLBACK LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam){
    MSLLHOOKSTRUCT* hookStruct = (MSLLHOOKSTRUCT*)lParam;
    int ScreenWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN); 
    int ScreenHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
    int x = hookStruct->pt.x * ScreenWidth / 65536);
    int y = hookStruct->pt.y * ScreenHeight / 65536);
    return CallNextHookEx(NULL, nCode, wParam, lParam);
}

HHOOK LowLevelMouseProcHook = NULL;

void hook_window_procedure()
{
    if (LowLevelMouseProcHook == NULL)
        LowLevelMouseProcHook = SetWindowsHookEx(WH_MOUSE_LL, (HOOKPROC)LowLevelMouseProc, (HINSTANCE)NULL, NULL);    
}

void unhook_window_procedure()
{
    if (LowLevelMouseProcHook != NULL)
        UnhookWindowsHookEx(LowLevelMouseProcHook);     
}

You can hook the mouse calling hook_window_procedure(); and unhook it by calling unhook_window_procedure();

You will receive calls to void LowLevelMouseProc(...) whenever the mouse moves. lParam contains a pointer to MSLLHOOKSTRUCT and you find all needed mouse information in its structs. Most interesting here is POINT pt; that is in relative screen coordinates assuming 1/65536th of the screen. Transform them to real pixels by multiplying with int ScreenWidth or int ScreenHeight and dividing by 65536

If you struggle being clamped by the screen borders, you can make a workaround setting the mouse back to the center of your window each call. This is often seen in older games. If you are not forced to use only the Windows API, I would try using Direct Input.

Another way would be to evaluate WM_INPUT directly in your WindowProc for example. This reads data directly from the Human Interface Device (HID) stack and should have raw Mouse-Data in it. Here is a link to the MS-Documentation

Upvotes: 1

j_kubik
j_kubik

Reputation: 6181

As far as I know DirectX has its own APIs to interact with peripherals, that is recommended for game developers. You should look into it - try for example DirectX 8 and the Mouse, more detailed documentation you can find on MSDN.

Upvotes: 1

Robert Kelly
Robert Kelly

Reputation: 1006

A common method for this (in games):

Every frame of the game, get the position of the mouse and then recenter the mouse in the middle of the window using operating system functions. For every frame other than the first, this should give you an accurate displacement information. The key is to just be re-centering the mouse every frame so it never reaches the blocking outer bounds of the screen.

EDIT: Woops, didn't realize that DXM had already said this.

Upvotes: 0

Software_Designer
Software_Designer

Reputation: 8587

This sort of displacement ? : http://en.wikipedia.org/wiki/Differential_calculus

Try pitch/yaw : How could simply calling Pitch() and Yaw() cause the camera to eventually Roll()?

FPS style : http://cboard.cprogramming.com/game-programming/94944-mouse-input-aiming-fps-style-using-glut.html

and this : Jittering when moving mouse

pseudo code:

int mouseX, mouseY;     
int oldMouseX, oldMouseY;

while(game_is_Running)
{
    oldMouseX = mouseX;
    oldMouseY = mouseY;

    mouseX = get_new_mouse_from_windows_X();
    mouseY = get_new_mouse_from_windows_Y();

    if ((mouseX - oldMouseX) > 0) 
    {
       // mouse moved to the right
    }

    else if ((mouseX - oldMouseX) < 0) 
    {
        // mouse moved to the left
    }



    if ((mouseY - oldMouseY) < 0)
    {
        // mouse moved  down 


    }

    else if ((mouseY - oldMouseY) > 0)   
    {
        // mouse moved    up  


    }

}

Upvotes: 0

xcrypt
xcrypt

Reputation: 3366

It is not possible to track physical mouse displacement with the Windows API. However, DirectInput provides features to keep track of it. You can also 'fake' it using only the Windows API, using the neat little trick in the answer of SO user DXM

Upvotes: -2

DXM
DXM

Reputation: 4543

Although it might be possible to actually read sensor data (after all the mouse itself only reports movement, not location), I'm not aware of how this could be done. I think at the very low levels of windows, that displacement information gets translated into cursor position on the screen and from then on, you will always be limited by your screen resolution.

In whatever you are trying to do, is the mouse cursor still visible?

A little while ago, I wrote a WPF numeric edit box control that mimicked the way those controls work in Expression Blend. The ones where you can drag the mouse from the edit box itself and it'll change the value. I ran into exactly same issue that you found and my solution was to hide the mouse cursor, detect displacement on every tick and reset the cursor to the center of the screen. Then when the user lets go of the button to stop dragging, I would put the cursor back to where I found it before the drag. This worked out really well and Expression Blend also behaves this way in hiding the cursor.

Upvotes: 2

Related Questions