As you know Wine has number of problems with it's mouse handling. Just enough to look at the bugzilla to see how many programs affected. After spending several weeks trying to find and fix this problems I in the dead-end now.
Most of Wines problems coming from the way Wine receives and handles it's mouse events. On windows mouse events generated by the mouse driver itself and the mouse pointer just another "user" of these events. Wine works backwards - from mouse pointer.
In short we have 3 major problems that needs to be fixed: 1. GetCursorPos() have to return old (cached) cursor position inside hook handler. 2. Any changes to the cursor position inside hook handler will be lost after all hooks are handled. 3. Mouse move events generated event when pointer is "stuck" at the edge of the screen. 4. Hook handler can see mouse events that happen anywhere not just in application's window(s).
1) used by number of programs to generate relative mouse movements. Using this might be the only way to fix mouse warping problems in dinput. There is no other way to know if application itself set new cursor position.
2) this is more of the consequence of 1). I have a simple test to prove it.
3) most games don't warp mouse pointer themselves because there is no need for that. We have to do it because of this and next problem.
4) it's a limitation of X that forces us to do mouse warping. That brings lots of other problems that is pretty hard to deal with.
Does anyone have any additional ideas suggestions and comments for my patches that I have submitted to fix these problems? Or no one really cares about having working mouse? It's been broken this way for number of years now and the only "fix" people attempted to submit was move of "MOUSE_HACK" from define into registry.
Yet I haven't seen a single person commenting on these patches. And as usual I have a misunderstanding with Alexandre about this patches. I can't understand what other testes required to prove that what we have is not correct then attached test? It's simple and straight forward test for 1) and 2). I do understand Alexandre's concern that some parts create a 'race condition' but it is not clear to me how can it happen nor how else to archive the same results.
x11drv fixes: [1] http://winehq.org/pipermail/wine-patches/2006-October/031772.html [2] http://winehq.org/pipermail/wine-patches/2006-October/031773.html [3] http://winehq.org/pipermail/wine-patches/2006-October/031774.html
x11drv, dinput and wined3d changes [1] http://winehq.org/pipermail/wine-patches/2006-October/031305.html [2] http://winehq.org/pipermail/wine-patches/2006-October/031309.html [3] http://winehq.org/pipermail/wine-patches/2006-October/031306.html [4] http://winehq.org/pipermail/wine-patches/2006-October/031307.html [5] http://winehq.org/pipermail/wine-patches/2006-October/031308.html
Vitaliy Margolen.
#include <windows.h> #include <stdio.h>
static POINT last_hook_pos;
LRESULT CALLBACK hook_proc( int code, WPARAM wparam, LPARAM lparam ) { MSLLHOOKSTRUCT *hook = (MSLLHOOKSTRUCT *)lparam; POINT pt;
if (code == HC_ACTION) { GetCursorPos(&pt); if (pt.x != last_hook_pos.x || pt.y != last_hook_pos.y) fprintf(stderr, "(%ld %ld) != (%ld %ld)\n", pt.x, pt.y, last_hook_pos.x, last_hook_pos.y); last_hook_pos = hook->pt;
SetCursorPos(pt.x+10, pt.y+10); } return CallNextHookEx( 0, code, wparam, lparam ); }
static DWORD wnd_proc(void) { MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; }
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { POINT pt;
switch (message) { case WM_DESTROY: PostQuitMessage(0); return; case WM_MOUSEMOVE: GetCursorPos(&pt); if (pt.x != last_hook_pos.x || pt.y != last_hook_pos.y) fprintf(stderr, "MSG: (%ld %ld) != (%ld %ld)\n", pt.x, pt.y, last_hook_pos.x, last_hook_pos.y);
break; } return DefWindowProc(hWnd, message, wParam, lParam); }
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { WNDCLASSEX wcex; HWND hwnd; HHOOK hook;
memset(&wcex, 0, sizeof(wcex)); wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = (WNDPROC)WndProc; wcex.hInstance = hInstance; wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.lpszClassName = "MainWindow"; RegisterClassEx(&wcex);
hwnd = CreateWindow("MainWindow", "Title", WS_OVERLAPPEDWINDOW, 10, 10, 200, 200, NULL, NULL, NULL, NULL); ShowWindow(hwnd, SW_SHOW);
GetCursorPos(&last_hook_pos); hook = SetWindowsHookExA(WH_MOUSE_LL, hook_proc, hInstance, 0);
wnd_proc(); UnhookWindowsHookEx(hook);
DestroyWindow(hwnd); return 0; }