dinput & [Get|Set]CursorPos conandrum
Vitaliy Margolen
wine-devel at kievinfo.com
Tue Aug 8 08:21:01 CDT 2006
Tuesday, August 8, 2006, 1:48:51 AM, Alexandre Julliard wrote:
> Vitaliy Margolen <wine-devel at kievinfo.com> writes:
>>> GetCursorPos really needs to query X, because there's no guarantee
>>> that the app is processing X events, and even if we hack around that
>> What do you mean here? X will always send notifies to a window (or am I wrong
>> here?) And in notify handler we pretty much setting the cursor_pos.
> But that requires that we pull events from the queue, and
> GetCursorPos() doesn't do that (and can't since we don't want to
> generate repaints etc. in there).
Ah you mean Wine's message queue? I thought we get X's notifies via direct
callback. Is this not the case then?
>>> we won't receive events from other processes anyway. Now it probably
>> That's the thing. We either need to send mouse notifications to all processes
>> (via wineserver?) or don't really need them, as long as we can synch cursor_pos
>> between processes.
> That doesn't help, the other process is not necessarily a Wine
> process.
Well app shouldn't really need to know if cursor is outside it's window. And
since we won't be generating WM_* messages in such case why even bother? Or...
we can do something what native does - spurious WM_MOUSEMOVE messages (well
known ... feature it seems) that probably come from querying mouse on some
interval.
>> Not so. According to few tests native always sets cursor_pos (what ever it's
>> called internally - I'll call it that ;-) in SetCursorPos(). But on mouse moves
>> it's not being set immediately but after calling hooks and generating WM_
>> messages. And that's the part lots of games relay on, including native dinput.
> Any chance you could write a small test case that replicates the
> behavior you have observed?
Attached. Small test and patch to fix it (against current git).
Vitaliy
-------------- next part --------------
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
static HINSTANCE g_hInstance;
LRESULT CALLBACK hook_proc( int code, WPARAM wparam, LPARAM lparam )
{
MSLLHOOKSTRUCT *hook = (MSLLHOOKSTRUCT *)lparam;
POINT pt;
GetCursorPos(&pt);
if (code == HC_ACTION)
{
printf("code=%d w=%p [(%ld %ld) %lx %lx %p] cur(%ld %ld) dl(%ld %ld)\n", 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);
}
return CallNextHookEx( 0, code, wparam, lparam );
}
#define SEND(x,y) \
i.mi.time = GetCurrentTime(); \
i.mi.dx = x; i.mi.dy = y; \
SendInput(1, &i, sizeof(INPUT));
inline void send_abs(int x, int y, LPINPUT i, LPPOINT pt)
{
int accel[3], xMult = 1, yMult = 1;
int width = GetSystemMetrics(SM_CXSCREEN);
int height = GetSystemMetrics(SM_CYSCREEN);
SystemParametersInfoW(SPI_GETMOUSE, 0, accel, 0);
if (abs(x) > accel[0] && accel[2] != 0) {
if ((abs(x) > accel[1]) && (accel[2] == 2)) xMult = 4; else xMult = 2;
}
if (abs(y) > accel[0] && accel[2] != 0) {
if ((abs(y) > accel[1]) && (accel[2] == 2)) yMult = 4; else yMult = 2;
}
i->mi.dx = ((pt->x + (long)(x) * xMult) << 16) / width;
i->mi.dy = ((pt->y + (long)(y) * yMult) << 16) / height;
i->mi.time = GetCurrentTime();
SendInput(1, i, sizeof(INPUT));
}
void send_input(void)
{
INPUT i;
POINT pt, ptorg;
GetCursorPos(&ptorg);
pt = ptorg;
printf("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, 0)
SEND(+4, 0)
SEND(0, -4)
SEND(0, +4)
SetCursorPos(100, 100);
GetCursorPos(&pt);
fprintf(stderr, "Moved cursor to 100-100 cur(%ld %ld)\n", pt.x, pt.y);
i.mi.dwFlags = MOUSEEVENTF_MOVE;
SEND(-4, 0)
i.mi.dwFlags |= MOUSEEVENTF_ABSOLUTE;
send_abs(-10, 0, &i, &pt);
send_abs(+10, 0, &i, &pt);
/* Restopre position */
SetCursorPos(ptorg.x, ptorg.y);
}
void test1(void)
{
HHOOK hook;
hook = SetWindowsHookExA(WH_MOUSE_LL, hook_proc, g_hInstance, 0);
send_input();
UnhookWindowsHookEx(hook);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
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,
CW_USEDEFAULT, 0, 200, 200, NULL, NULL, NULL, NULL);
ShowWindow(hwnd, SW_SHOW);
test1();
DestroyWindow(hwnd);
return 0;
}
-------------- next part --------------
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c
index 1373a88..badb44a 100644
--- a/dlls/winex11.drv/mouse.c
+++ b/dlls/winex11.drv/mouse.c
@@ -69,7 +69,18 @@ static const UINT button_up_flags[NB_BUT
MOUSEEVENTF_XUP
};
-POINT cursor_pos;
+POINT cursor_pos = {-10, -10};
+
+static CRITICAL_SECTION cursor_CritSection;
+static CRITICAL_SECTION_DEBUG critsect_debug =
+{
+ 0, 0, &cursor_CritSection,
+ { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
+ 0, 0, { (DWORD_PTR)(__FILE__ ": cursor_CritSection") }
+};
+static CRITICAL_SECTION cursor_CritSection = { &critsect_debug, -1, 0, 0, 0, 0 };
+
+BOOL X11DRV_SetCursorPos( INT x, INT y );
/***********************************************************************
* get_coords
@@ -109,8 +120,10 @@ static inline void update_button_state(
*/
static inline void update_key_state( unsigned int state )
{
- key_state_table[VK_SHIFT] = (state & ShiftMask ? 0x80 : 0);
- key_state_table[VK_CONTROL] = (state & ControlMask ? 0x80 : 0);
+ DWORD time = GetCurrentTime();
+
+ KEYBOARD_UpdateOneState( VK_SHIFT, 0x2a, (state & ShiftMask) != 0, time );
+ KEYBOARD_UpdateOneState( VK_CONTROL, 0x1d, (state & ControlMask) != 0, time );
}
@@ -241,9 +254,6 @@ void X11DRV_send_mouse_input( HWND hwnd,
pt.x = x;
pt.y = y;
}
- wine_tsx11_lock();
- cursor_pos = pt;
- wine_tsx11_unlock();
}
else if (flags & MOUSEEVENTF_MOVE)
{
@@ -263,23 +273,22 @@ void X11DRV_send_mouse_input( HWND hwnd,
if ((abs(y) > accel[1]) && (accel[2] == 2)) yMult = 4;
}
- wine_tsx11_lock();
+ EnterCriticalSection( &cursor_CritSection );
pt.x = cursor_pos.x + (long)x * xMult;
pt.y = cursor_pos.y + (long)y * yMult;
+ LeaveCriticalSection( &cursor_CritSection );
/* Clip to the current screen size */
if (pt.x < 0) pt.x = 0;
else if (pt.x >= screen_width) pt.x = screen_width - 1;
if (pt.y < 0) pt.y = 0;
else if (pt.y >= screen_height) pt.y = screen_height - 1;
- cursor_pos = pt;
- wine_tsx11_unlock();
}
else
{
- wine_tsx11_lock();
+ EnterCriticalSection( &cursor_CritSection );
pt = cursor_pos;
- wine_tsx11_unlock();
+ LeaveCriticalSection( &cursor_CritSection );
}
if (flags & MOUSEEVENTF_MOVE)
@@ -289,10 +298,11 @@ void X11DRV_send_mouse_input( HWND hwnd,
if ((injected_flags & LLMHF_INJECTED) &&
((flags & MOUSEEVENTF_ABSOLUTE) || x || y)) /* we have to actually move the cursor */
{
- TRACE( "warping to (%ld,%ld)\n", pt.x, pt.y );
- wine_tsx11_lock();
- XWarpPointer( thread_display(), root_window, root_window, 0, 0, 0, 0, pt.x, pt.y );
- wine_tsx11_unlock();
+ X11DRV_SetCursorPos(pt.x, pt.y);
+ } else {
+ EnterCriticalSection( &cursor_CritSection );
+ cursor_pos = pt;
+ LeaveCriticalSection( &cursor_CritSection );
}
}
if (flags & MOUSEEVENTF_LEFTDOWN)
@@ -689,16 +699,29 @@ void X11DRV_SetCursor( CURSORICONINFO *l
*/
BOOL X11DRV_SetCursorPos( INT x, INT y )
{
- Display *display = thread_display();
+ Display *display;
+
+ /* Cursor position hasn't changed at all or not yet. */
+ EnterCriticalSection(&cursor_CritSection);
+ if (cursor_pos.x == x && cursor_pos.y == y)
+ {
+ LeaveCriticalSection(&cursor_CritSection);
+ return TRUE;
+ }
+ LeaveCriticalSection(&cursor_CritSection);
TRACE( "warping to (%d,%d)\n", x, y );
+ display = thread_display();
wine_tsx11_lock();
XWarpPointer( display, root_window, root_window, 0, 0, 0, 0, x, y );
XFlush( display ); /* avoids bad mouse lag in games that do their own mouse warping */
+ wine_tsx11_unlock();
+
+ EnterCriticalSection( &cursor_CritSection );
cursor_pos.x = x;
cursor_pos.y = y;
- wine_tsx11_unlock();
+ LeaveCriticalSection( &cursor_CritSection );
return TRUE;
}
@@ -707,23 +730,33 @@ BOOL X11DRV_SetCursorPos( INT x, INT y )
*/
BOOL X11DRV_GetCursorPos(LPPOINT pos)
{
- Display *display = thread_display();
- Window root, child;
- int rootX, rootY, winX, winY;
- unsigned int xstate;
-
- wine_tsx11_lock();
- if (XQueryPointer( display, root_window, &root, &child,
- &rootX, &rootY, &winX, &winY, &xstate ))
+ if (cursor_pos.x == -10 && cursor_pos.y == -10)
{
- update_key_state( xstate );
- update_button_state( xstate );
- TRACE("pointer at (%d,%d)\n", winX, winY );
- cursor_pos.x = winX;
- cursor_pos.y = winY;
+ Display *display = thread_display();
+ Window root, child;
+ int rootX, rootY, winX, winY;
+ unsigned int xstate;
+ BOOL res;
+
+ wine_tsx11_lock();
+ res = XQueryPointer( display, root_window, &root, &child,
+ &rootX, &rootY, &winX, &winY, &xstate );
+ wine_tsx11_unlock();
+ if (res)
+ {
+ update_key_state( xstate );
+ update_button_state( xstate );
+ TRACE("pointer at (%d,%d)\n", winX, winY );
+ EnterCriticalSection( &cursor_CritSection );
+ cursor_pos.x = winX;
+ cursor_pos.y = winY;
+ LeaveCriticalSection( &cursor_CritSection );
+ }
}
+ EnterCriticalSection( &cursor_CritSection );
*pos = cursor_pos;
- wine_tsx11_unlock();
+ LeaveCriticalSection( &cursor_CritSection );
+
return TRUE;
}
More information about the wine-devel
mailing list