diff --git a/dlls/user32/cursoricon.c b/dlls/user32/cursoricon.c index 2f8184025dc..c2870099414 100644 --- a/dlls/user32/cursoricon.c +++ b/dlls/user32/cursoricon.c @@ -1565,9 +1565,13 @@ BOOL WINAPI ClipCursor( const RECT *rect ) OffsetRect( &virt, GetSystemMetrics( SM_XVIRTUALSCREEN ), GetSystemMetrics( SM_YVIRTUALSCREEN ) ); + TRACE( "Clipping to: %s was: %s screen: %s\n", wine_dbgstr_rect(rect), + wine_dbgstr_rect(&CURSOR_ClipRect), wine_dbgstr_rect(&virt) ); + if (!IntersectRect( &CURSOR_ClipRect, &virt, rect )) CURSOR_ClipRect = virt; + USER_Driver->pClipCursor( rect ); return TRUE; } diff --git a/dlls/user32/driver.c b/dlls/user32/driver.c index 0c93a67b710..b102fa5a2f2 100644 --- a/dlls/user32/driver.c +++ b/dlls/user32/driver.c @@ -88,6 +88,7 @@ static const USER_DRIVER *load_driver(void) GET_USER_FUNC(SetCursor); GET_USER_FUNC(GetCursorPos); GET_USER_FUNC(SetCursorPos); + GET_USER_FUNC(ClipCursor); GET_USER_FUNC(GetScreenSaveActive); GET_USER_FUNC(SetScreenSaveActive); GET_USER_FUNC(AcquireClipboard); @@ -229,6 +230,11 @@ static BOOL nulldrv_SetCursorPos( INT x, INT y ) return FALSE; } +static BOOL nulldrv_ClipCursor( LPCRECT clip ) +{ + return FALSE; +} + static BOOL nulldrv_GetScreenSaveActive(void) { return FALSE; @@ -431,6 +437,7 @@ static const USER_DRIVER null_driver = nulldrv_SetCursor, nulldrv_GetCursorPos, nulldrv_SetCursorPos, + nulldrv_ClipCursor, /* screen saver functions */ nulldrv_GetScreenSaveActive, nulldrv_SetScreenSaveActive, @@ -560,6 +567,11 @@ static BOOL loaderdrv_SetCursorPos( INT x, INT y ) return load_driver()->pSetCursorPos( x, y ); } +static BOOL loaderdrv_ClipCursor( LPCRECT clip ) +{ + return load_driver()->pClipCursor( clip ); +} + static BOOL loaderdrv_GetScreenSaveActive(void) { return load_driver()->pGetScreenSaveActive(); @@ -754,6 +766,7 @@ static const USER_DRIVER lazy_load_driver = loaderdrv_SetCursor, loaderdrv_GetCursorPos, loaderdrv_SetCursorPos, + loaderdrv_ClipCursor, /* screen saver functions */ loaderdrv_GetScreenSaveActive, loaderdrv_SetScreenSaveActive, diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index a09f001ba2a..cc4326b492b 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -538,6 +538,7 @@ static void test_keynames(void) } static POINT pt_old, pt_new; +static BOOL clipped; #define STEP 20 static LRESULT CALLBACK hook_proc1( int code, WPARAM wparam, LPARAM lparam ) @@ -558,7 +559,10 @@ static LRESULT CALLBACK hook_proc1( int code, WPARAM wparam, LPARAM lparam ) pt.y = pt_old.y + STEP; SetCursorPos(pt.x, pt.y); GetCursorPos(&pt1); - ok(pt.x == pt1.x && pt.y == pt1.y, "Wrong set pos: (%d,%d)\n", pt1.x, pt1.y); + if (clipped) + ok(pt1.x == pt_old.x && pt1.y == pt_old.y, "Wrong set pos: (%d,%d)\n", pt1.x, pt1.y); + else + ok(pt1.x == pt.x && pt1.y == pt.y, "Wrong set pos: (%d,%d)\n", pt1.x, pt1.y); } return CallNextHookEx( 0, code, wparam, lparam ); } @@ -575,8 +579,10 @@ static LRESULT CALLBACK hook_proc2( int code, WPARAM wparam, LPARAM lparam ) /* Should match position set above */ GetCursorPos(&pt); - ok(pt.x == pt_old.x +STEP && pt.y == pt_old.y +STEP, "GetCursorPos: (%d,%d)\n", - pt.x, pt.y); + if (clipped) + ok(pt.x == pt_old.x && pt.y == pt_old.y, "GetCursorPos: (%d,%d)\n", pt.x, pt.y); + else + ok(pt.x == pt_old.x +STEP && pt.y == pt_old.y +STEP, "GetCursorPos: (%d,%d)\n", pt.x, pt.y); } return CallNextHookEx( 0, code, wparam, lparam ); } @@ -586,11 +592,12 @@ static void test_mouse_ll_hook(void) HWND hwnd; HHOOK hook1, hook2; POINT pt_org, pt; + RECT rc; GetCursorPos(&pt_org); - hwnd = CreateWindow("static", "Title", WS_OVERLAPPEDWINDOW, + hwnd = CreateWindow("static", "Title", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 10, 10, 200, 200, NULL, NULL, NULL, NULL); - SetCursorPos(300, 300); + SetCursorPos(100, 100); hook2 = SetWindowsHookExA(WH_MOUSE_LL, hook_proc2, GetModuleHandleA(0), 0); hook1 = SetWindowsHookExA(WH_MOUSE_LL, hook_proc1, GetModuleHandleA(0), 0); @@ -609,6 +616,23 @@ static void test_mouse_ll_hook(void) GetCursorPos(&pt_old); ok(pt_old.x == pt_new.x && pt_old.y == pt_new.y, "Wrong new pos: (%d,%d)\n", pt_old.x, pt_old.y); + SetRect(&rc, 50, 50, 151, 151); + ClipCursor(&rc); + clipped = TRUE; + + SetCursorPos(40, 40); + GetCursorPos(&pt_old); + ok(pt_old.x == 50 && pt_old.y == 50, "Wrong new pos: (%d,%d)\n", pt_new.x, pt_new.y); + SetCursorPos(160, 160); + GetCursorPos(&pt_old); + ok(pt_old.x == 150 && pt_old.y == 150, "Wrong new pos: (%d,%d)\n", pt_new.x, pt_new.y); + mouse_event(MOUSEEVENTF_MOVE, +STEP, +STEP, 0, 0); + GetCursorPos(&pt_old); + ok(pt_old.x == 150 && pt_old.y == 150, "Wrong new pos: (%d,%d)\n", pt_new.x, pt_new.y); + + clipped = FALSE; + pt_new.x = pt_new.y = 150; + ClipCursor(NULL); UnhookWindowsHookEx(hook1); /* Now check that mouse buttons do not change mouse position diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h index f939e4e59e8..99915cc07c5 100644 --- a/dlls/user32/user_private.h +++ b/dlls/user32/user_private.h @@ -120,6 +120,7 @@ typedef struct tagUSER_DRIVER { void (*pSetCursor)(struct tagCURSORICONINFO *); BOOL (*pGetCursorPos)(LPPOINT); BOOL (*pSetCursorPos)(INT,INT); + BOOL (*pClipCursor)(LPCRECT); /* screen saver functions */ BOOL (*pGetScreenSaveActive)(void); void (*pSetScreenSaveActive)(BOOL); diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index e8ae64fe8a9..069333a689e 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -71,6 +71,7 @@ static const UINT button_up_flags[NB_BUTTONS] = POINT cursor_pos; static DWORD last_time_modified; +static RECT cursor_clip; /* Cursor clipping rect */ BOOL X11DRV_SetCursorPos( INT x, INT y ); @@ -89,6 +90,18 @@ static inline void get_coords( HWND hwnd, int x, int y, POINT *pt ) pt->y = y + data->whole_rect.top; } +/*********************************************************************** + * clip_point_to_rect + * + * Clip point to the provided rectangle + */ +static inline void clip_point_to_rect( LPCRECT rect, LPPOINT pt ) +{ + if (pt->x < rect->left) pt->x = rect->left; + else if (pt->x >= rect->right) pt->x = rect->right - 1; + if (pt->y < rect->top) pt->y = rect->top; + else if (pt->y >= rect->bottom) pt->y = rect->bottom - 1; +} /*********************************************************************** * update_button_state @@ -257,12 +270,6 @@ void X11DRV_send_mouse_input( HWND hwnd, DWORD flags, DWORD x, DWORD y, wine_tsx11_lock(); pt.x = cursor_pos.x + (long)x * xMult; pt.y = cursor_pos.y + (long)y * yMult; - - /* 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; wine_tsx11_unlock(); } else @@ -284,6 +291,7 @@ void X11DRV_send_mouse_input( HWND hwnd, DWORD flags, DWORD x, DWORD y, else { wine_tsx11_lock(); + clip_point_to_rect( &cursor_clip, &pt); cursor_pos = pt; wine_tsx11_unlock(); } @@ -683,6 +691,7 @@ void X11DRV_SetCursor( CURSORICONINFO *lpCursor ) BOOL X11DRV_SetCursorPos( INT x, INT y ) { Display *display = thread_display(); + POINT pt; TRACE( "warping to (%d,%d)\n", x, y ); @@ -695,11 +704,12 @@ BOOL X11DRV_SetCursorPos( INT x, INT y ) return TRUE; } + pt.x = x; pt.y = y; + clip_point_to_rect( &cursor_clip, &pt); XWarpPointer( display, root_window, root_window, 0, 0, 0, 0, - x - virtual_screen_rect.left, y - virtual_screen_rect.top ); + pt.x - virtual_screen_rect.left, pt.y - virtual_screen_rect.top ); XFlush( display ); /* avoids bad mouse lag in games that do their own mouse warping */ - cursor_pos.x = x; - cursor_pos.y = y; + cursor_pos = pt; wine_tsx11_unlock(); return TRUE; } @@ -731,6 +741,20 @@ BOOL X11DRV_GetCursorPos(LPPOINT pos) return TRUE; } + +/*********************************************************************** + * ClipCursor (X11DRV.@) + * + * Set the cursor clipping rectangle. + */ +BOOL X11DRV_ClipCursor( LPCRECT clip ) +{ + if (!IntersectRect( &cursor_clip, &virtual_screen_rect, clip )) + cursor_clip = virtual_screen_rect; + + return TRUE; +} + /*********************************************************************** * X11DRV_ButtonPress */ diff --git a/dlls/winex11.drv/winex11.drv.spec b/dlls/winex11.drv/winex11.drv.spec index 95b3d94cdc1..6a6c17355a1 100644 --- a/dlls/winex11.drv/winex11.drv.spec +++ b/dlls/winex11.drv/winex11.drv.spec @@ -79,6 +79,7 @@ @ cdecl SetCursor(ptr) X11DRV_SetCursor @ cdecl GetCursorPos(ptr) X11DRV_GetCursorPos @ cdecl SetCursorPos(long long) X11DRV_SetCursorPos +@ cdecl ClipCursor(ptr) X11DRV_ClipCursor @ cdecl GetScreenSaveActive() X11DRV_GetScreenSaveActive @ cdecl SetScreenSaveActive(long) X11DRV_SetScreenSaveActive @ cdecl ChangeDisplaySettingsEx(ptr ptr long long long) X11DRV_ChangeDisplaySettingsEx diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 32c0db8e79d..dc1d9556443 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -667,6 +667,7 @@ extern int X11DRV_AcquireClipboard(HWND hWndClipWindow); extern void X11DRV_ResetSelectionOwner(void); extern void X11DRV_SetFocus( HWND hwnd ); extern Cursor X11DRV_GetCursor( Display *display, struct tagCURSORICONINFO *ptr ); +extern BOOL X11DRV_ClipCursor( LPCRECT clip ); extern void X11DRV_InitKeyboard(void); extern void X11DRV_send_keyboard_input( WORD wVk, WORD wScan, DWORD dwFlags, DWORD time, DWORD dwExtraInfo, UINT injected_flags ); diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index f6d241a06ba..229ca776dec 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -441,6 +441,7 @@ static BOOL process_attach(void) X11DRV_XRandR_Init(); #endif + X11DRV_ClipCursor( NULL ); X11DRV_InitKeyboard(); X11DRV_InitClipboard();