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.
#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; }
#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; }
Am Mittwoch 29 November 2006 19:51 schrieb Vitaliy Margolen:
I gave your patch and test apps a try, and it seems to work fine here :-)
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.
Seems to work. It writes out relative mouse movement on the console and terminates after a while(well, the while loop).
It works too with the current wine git code, but as I understand it that is ok - You want to show that it still works after your change.
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.
Writes out a bunch of output like that: Hook: code=0 w=200 [(136 125) 0 0 0] cur(142 129) d(-6 -4) Th: (142 129) dt(0 0) Hook: code=0 w=200 [(128 121) 0 0 0] cur(136 125) d(-8 -4) Th: (136 125) dt(0 0) Hook: code=0 w=200 [(114 119) 0 0 0] cur(128 121) d(-14 -2) Th: (128 121) dt(0 0) Hook: code=0 w=200 [(100 119) 0 0 0] cur(114 119) d(-14 0) Th: (114 119) dt(0 0) Hook: code=0 w=200 [(88 119) 0 0 0] cur(100 119) d(-12 0) Th: (100 119) dt(0 0) Hook: code=0 w=200 [(78 119) 0 0 0] cur(88 119) d(-10 0) Th: (88 119) dt(0 0) Hook: code=0 w=200 [(77 120) 0 0 0] cur(78 119) d(-1 1) Th: (78 119) dt(0 0) Hook: code=0 w=200 [(81 116) 0 0 0] cur(77 120) d(4 -4) Th: (77 120) dt(0 0) Hook: code=0 w=200 [(85 110) 0 0 0] cur(81 116) d(4 -6) Th: (81 116) dt(0 0) Hook: code=0 w=200 [(86 108) 0 0 0] cur(85 110) d(1 -2) Th: (85 110) dt(0 0) Hook: code=0 w=200 [(86 106) 0 0 0] cur(86 108) d(0 -2) Th: (86 108) dt(0 0) Hook: code=0 w=200 [(82 102) 0 0 0] cur(86 106) d(-4 -4) Th: (86 106) dt(0 0) Hook: code=0 w=200 [(81 101) 0 0 0] cur(82 102) d(-1 -1) Th: (82 102) dt(0 0) Hook: code=0 w=200 [(73 97) 0 0 0] cur(81 101) d(-8 -4) Th: (81 101) dt(0 0) Hook: code=0 w=200 [(65 97) 0 0 0] cur(73 97) d(-8 0) Th: (73 97) dt(0 0) Hook: code=0 w=200 [(57 97) 0 0 0] cur(65 97) d(-8 0) Th: (65 97) dt(0 0) Hook: code=0 w=200 [(47 99) 0 0 0] cur(57 97) d(-10 2) Th: (57 97) dt(0 0) Hook: code=0 w=200 [(43 103) 0 0 0] cur(47 99) d(-4 4) Th: (47 99) dt(0 0) Hook: code=0 w=200 [(43 105) 0 0 0] cur(43 103) d(0 2) Th: (43 103) dt(0 0)
I will run both apps on windows(xp sp2) and compare the output.
If anyone has any objections, comment, suggestions, please do send them.
Not really, my knowledge about the input code is too limited to give a qualified comment:-(
Stefan
Hi,
I will run both apps on windows(xp sp2) and compare the output.
Just wanted to add that Windows brings up the same results.