One more go at fixing GetCursorPos()

Vitaliy Margolen wine-devel at kievinfo.com
Wed Nov 29 12:51:18 CST 2006


Here is one more shot at fixing GetCursorPos() to make it usable in
dinput.

This time I used a refcount of sorts. Because the problem appears only
during processing of hook chain.

Just to remind about what is the problem:
when hook handler calls GetCursorPos() position returned is the "old"
position. While hook parameters contain "new" coordinates. This is on
windows. On Wine returned position queried directly from X and might be
even "newer" then position in hook parameters.

Attached are two tests (out of lots more that I've used to find and fix
the problem).

test_msg.c - tests major problem that Alexandre pointed out about last
fix attempt. Application in question does not process messages while
calling GetCursorPos(). It still works properly with proposed patch.

di_mouse_2th.c - 2 threads showing that there are no extra thread local
position involved (if there is such a thing). Cached cursor position is
global to all threads. (Last numbers should stay at dt(0 0) at all
times). Inside hook handler d(x y) should show relative mouse move
delta.

If anyone has any objections, comment, suggestions, please do send them.

Vitaliy Margolen.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: winex11drv_GetCursorPos.diff
Type: text/x-patch
Size: 2732 bytes
Desc: not available
Url : http://www.winehq.org/pipermail/wine-devel/attachments/20061129/32715a2f/winex11drv_GetCursorPos.bin
-------------- next part --------------
#define COBJMACROS
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <windowsx.h>

#include <stdio.h>

static HANDLE event1, event2;
static HINSTANCE g_hInstance;
static POINT pt_global;

LRESULT CALLBACK hook_proc( int code, WPARAM wparam, LPARAM lparam )
{
    MSLLHOOKSTRUCT *hook = (MSLLHOOKSTRUCT *)lparam;
    POINT pt;
    GetCursorPos(&pt);

    if (code == HC_ACTION)
    {
        fprintf(stderr, "Hook: code=%d w=%x [(%ld %ld) %lx %lx %lx] cur(%ld %ld) d(%ld %ld) ", code, wparam,
                hook->pt.x, hook->pt.y, hook->mouseData, hook->flags, hook->dwExtraInfo,
                pt.x, pt.y, hook->pt.x - pt.x, hook->pt.y - pt.y);

        pt_global = pt;
        SetEvent(event1);
        WaitForSingleObject(event2, INFINITE);
    }
    return CallNextHookEx( 0, code, wparam, lparam );
}

static DWORD CALLBACK thread_proc(LPVOID arg)
{
    while (WaitForSingleObject(event1, INFINITE) == WAIT_OBJECT_0)
    {
        POINT pt;

        GetCursorPos(&pt);
        fprintf(stderr, "Th: (%ld %ld) dt(%ld %ld)\n", pt.x, pt.y, pt.x - pt_global.x, pt.y - pt_global.y);
        SetEvent(event2);
    }

    return 0;
}

static DWORD wnd_proc(void)
{
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) 
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}

#define SEND(x,y) \
    i.mi.time = GetCurrentTime(); \
    i.mi.dx = x; i.mi.dy = y; \
    SendInput(1, &i, sizeof(INPUT));

void send_input(void)
{
    INPUT i;
    POINT ptorg, pt;

    GetCursorPos(&ptorg);
    fprintf(stderr, "Cur pos: %ld %ld\n", ptorg.x, ptorg.y);

    i.type = INPUT_MOUSE;
    i.mi.dwFlags = MOUSEEVENTF_MOVE;
    i.mi.dwExtraInfo = 0;
    i.mi.mouseData = 0;

    SEND(-4, -4)

    GetCursorPos(&pt);
    fprintf(stderr, "%ld %ld\n", pt.x, pt.y);

    SetCursorPos(ptorg.x, ptorg.y);
    Sleep(250);
    fprintf(stderr, "***DONE***\n");
}

void test1(HWND hwnd)
{
    HANDLE thread;
    HHOOK hook;
    MSG msg;

    event1 = CreateEvent(NULL, FALSE, FALSE, NULL);
    event2 = CreateEvent(NULL, FALSE, FALSE, NULL);
    thread = CreateThread(NULL, 0, thread_proc, NULL, 0, NULL);
    Sleep(250);
    hook = SetWindowsHookExA(WH_MOUSE_LL, hook_proc, g_hInstance, 0);
    Sleep(250);

//    send_input();
    wnd_proc();

    while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
    UnhookWindowsHookEx(hook);

    CloseHandle(event1);
    CloseHandle(event2);
    CloseHandle(thread);
    Sleep(250);
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message) 
    {
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hWnd, message, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                     LPSTR lpCmdLine, int nCmdShow)
{
    WNDCLASSEX wcex;
    HWND hwnd;

    g_hInstance = hInstance;
    wcex.cbSize         = sizeof(WNDCLASSEX);
    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = (WNDPROC)WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = NULL;
    wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = NULL;
    wcex.lpszClassName  = "MainWindow";
    wcex.hIconSm        = NULL;
    RegisterClassEx(&wcex);


    hwnd = CreateWindow("MainWindow", "Title", WS_OVERLAPPEDWINDOW,
                        10, 10, 200, 200, NULL, NULL, NULL, NULL);
    ShowWindow(hwnd, SW_SHOW);

    test1(hwnd);

    DestroyWindow(hwnd);
    return 0;
}
-------------- next part --------------
#include <windows.h>
#include <stdio.h>

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                     LPSTR lpCmdLine, int nCmdShow)
{
    LONG started = GetTickCount();
    POINT pt, pt_org;
    HWND hwnd;
    MSG msg;

    hwnd = CreateWindow("static", "Title", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
                        10, 10, 200, 200, NULL, NULL, NULL, NULL);
    GetCursorPos(&pt_org);

    while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );

    while (started + 10000 > GetTickCount())
    {
        GetCursorPos(&pt);
        if ((pt.x - pt_org.x) || (pt.y - pt_org.y))
            printf("(%ld %ld)\n", pt.x - pt_org.x, pt.y - pt_org.y);
        pt_org = pt;
    }

    DestroyWindow(hwnd);
    return 0;
}


More information about the wine-devel mailing list