|
@@ -386,12 +386,6 @@ bool WIN_SetWindowPositionInternal(SDL_Window *window, UINT flags, SDL_WindowRec
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
-static void SDLCALL WIN_MouseRelativeModeCenterChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
|
|
|
-{
|
|
|
- SDL_WindowData *data = (SDL_WindowData *)userdata;
|
|
|
- data->mouse_relative_mode_center = SDL_GetStringBoolean(hint, true);
|
|
|
-}
|
|
|
-
|
|
|
static SDL_WindowEraseBackgroundMode GetEraseBackgroundModeHint(void)
|
|
|
{
|
|
|
const char *hint = SDL_GetHint(SDL_HINT_WINDOWS_ERASE_BACKGROUND_MODE);
|
|
@@ -443,6 +437,14 @@ static bool SetupWindowData(SDL_VideoDevice *_this, SDL_Window *window, HWND hwn
|
|
|
data->dwma_border_color = DWMWA_COLOR_DEFAULT;
|
|
|
data->hint_erase_background_mode = GetEraseBackgroundModeHint();
|
|
|
|
|
|
+
|
|
|
+ // WIN_WarpCursor() jitters by +1, and remote desktop warp wobble is +/- 1
|
|
|
+ LONG remote_desktop_adjustment = GetSystemMetrics(SM_REMOTESESSION) ? 2 : 0;
|
|
|
+ data->cursor_ctrlock_rect.left = 0 - remote_desktop_adjustment;
|
|
|
+ data->cursor_ctrlock_rect.top = 0;
|
|
|
+ data->cursor_ctrlock_rect.right = 1 + remote_desktop_adjustment;
|
|
|
+ data->cursor_ctrlock_rect.bottom = 1;
|
|
|
+
|
|
|
if (SDL_GetHintBoolean("SDL_WINDOW_RETAIN_CONTENT", false)) {
|
|
|
data->copybits_flag = 0;
|
|
|
} else {
|
|
@@ -453,8 +455,6 @@ static bool SetupWindowData(SDL_VideoDevice *_this, SDL_Window *window, HWND hwn
|
|
|
SDL_Log("SetupWindowData: initialized data->scaling_dpi to %d", data->scaling_dpi);
|
|
|
#endif
|
|
|
|
|
|
- SDL_AddHintCallback(SDL_HINT_MOUSE_RELATIVE_MODE_CENTER, WIN_MouseRelativeModeCenterChanged, data);
|
|
|
-
|
|
|
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
|
|
// Associate the data with the window
|
|
|
if (!SetProp(hwnd, TEXT("SDL_WindowData"), data)) {
|
|
@@ -626,7 +626,6 @@ static void CleanupWindowData(SDL_VideoDevice *_this, SDL_Window *window)
|
|
|
SDL_WindowData *data = window->internal;
|
|
|
|
|
|
if (data) {
|
|
|
- SDL_RemoveHintCallback(SDL_HINT_MOUSE_RELATIVE_MODE_CENTER, WIN_MouseRelativeModeCenterChanged, data);
|
|
|
|
|
|
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
|
|
if (data->drop_target) {
|
|
@@ -1588,107 +1587,109 @@ static BOOL GetClientScreenRect(HWND hwnd, RECT *rect)
|
|
|
ClientToScreen(hwnd, (LPPOINT)rect + 1); // POINT( right , bottom )
|
|
|
}
|
|
|
|
|
|
+void WIN_UnclipCursorForWindow(SDL_Window *window) {
|
|
|
+ SDL_WindowData *data = window->internal;
|
|
|
+ RECT rect;
|
|
|
+ if (GetClipCursor(&rect) && SDL_memcmp(&rect, &data->cursor_clipped_rect, sizeof(rect)) == 0) {
|
|
|
+ ClipCursor(NULL);
|
|
|
+ SDL_zero(data->cursor_clipped_rect);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
void WIN_UpdateClipCursor(SDL_Window *window)
|
|
|
{
|
|
|
- SDL_VideoDevice *videodevice = SDL_GetVideoDevice();
|
|
|
SDL_WindowData *data = window->internal;
|
|
|
- SDL_Mouse *mouse = SDL_GetMouse();
|
|
|
- RECT rect, clipped_rect;
|
|
|
-
|
|
|
- if (data->in_title_click || data->focus_click_pending) {
|
|
|
- return;
|
|
|
- }
|
|
|
- if (data->skip_update_clipcursor) {
|
|
|
+ if (data->in_title_click || data->focus_click_pending || data->skip_update_clipcursor) {
|
|
|
return;
|
|
|
}
|
|
|
- if (!GetClipCursor(&clipped_rect)) {
|
|
|
+
|
|
|
+ SDL_Rect mouse_rect = window->mouse_rect;
|
|
|
+ bool win_mouse_rect = (mouse_rect.w > 0 && mouse_rect.h > 0);
|
|
|
+ bool win_have_focus = (window->flags & SDL_WINDOW_INPUT_FOCUS);
|
|
|
+ bool win_is_grabbed = (window->flags & SDL_WINDOW_MOUSE_GRABBED);
|
|
|
+ bool win_in_relmode = (window->flags & SDL_WINDOW_MOUSE_RELATIVE_MODE);
|
|
|
+ bool cursor_confine = win_in_relmode || win_is_grabbed || win_mouse_rect;
|
|
|
+
|
|
|
+ // This is verbatim translation of the old logic,
|
|
|
+ // but I don't quite get what it's trying to do.
|
|
|
+ // A clean-room implementation according to MSDN
|
|
|
+ // documentation of GetClipCursor is provided in
|
|
|
+ // a commented-out block below.
|
|
|
+ if (!win_have_focus || !cursor_confine) {
|
|
|
+ SDL_VideoDevice *videodevice = SDL_GetVideoDevice();
|
|
|
+ RECT current;
|
|
|
+ if (!GetClipCursor(¤t)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (videodevice && (
|
|
|
+ current.left != videodevice->desktop_bounds.x ||
|
|
|
+ current.top != videodevice->desktop_bounds.y
|
|
|
+ )) {
|
|
|
+ POINT first, second;
|
|
|
+ first.x = current.left;
|
|
|
+ first.y = current.top;
|
|
|
+ second.x = current.right - 1;
|
|
|
+ second.y = current.bottom - 1;
|
|
|
+ if (!PtInRect(&data->cursor_clipped_rect, first) ||
|
|
|
+ !PtInRect(&data->cursor_clipped_rect, second)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ClipCursor(NULL);
|
|
|
+ SDL_zero(data->cursor_clipped_rect);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- if ((mouse->relative_mode || (window->flags & SDL_WINDOW_MOUSE_GRABBED) ||
|
|
|
- (window->mouse_rect.w > 0 && window->mouse_rect.h > 0)) &&
|
|
|
- (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
|
|
|
- if (mouse->relative_mode && !mouse->relative_mode_warp && data->mouse_relative_mode_center) {
|
|
|
- if (GetClientScreenRect(data->hwnd, &rect)) {
|
|
|
- // WIN_WarpCursor() jitters by +1, and remote desktop warp wobble is +/- 1
|
|
|
- LONG remote_desktop_adjustment = GetSystemMetrics(SM_REMOTESESSION) ? 2 : 0;
|
|
|
- LONG cx, cy;
|
|
|
-
|
|
|
- cx = (rect.left + rect.right) / 2;
|
|
|
- cy = (rect.top + rect.bottom) / 2;
|
|
|
+ // if (!win_have_focus || !cursor_confine) {
|
|
|
+ // RECT current;
|
|
|
+ // SDL_VideoDevice *videodevice = SDL_GetVideoDevice();
|
|
|
+ // if (GetClipCursor(¤t) && (!videodevice ||
|
|
|
+ // current.left != videodevice->desktop_bounds.x ||
|
|
|
+ // current.top != videodevice->desktop_bounds.y ||
|
|
|
+ // current.right != videodevice->desktop_bounds.x + videodevice->desktop_bounds.w ||
|
|
|
+ // current.bottom != videodevice->desktop_bounds.y + videodevice->desktop_bounds.h )) {
|
|
|
+ // ClipCursor(NULL);
|
|
|
+ // SDL_zero(data->cursor_clipped_rect);
|
|
|
+ // }
|
|
|
+ // return;
|
|
|
+ // }
|
|
|
|
|
|
- // Make an absurdly small clip rect
|
|
|
- rect.left = cx - remote_desktop_adjustment;
|
|
|
- rect.right = cx + 1 + remote_desktop_adjustment;
|
|
|
- rect.top = cy;
|
|
|
- rect.bottom = cy + 1;
|
|
|
+ SDL_Mouse *mouse = SDL_GetMouse();
|
|
|
+ bool lock_to_ctr = (mouse->relative_mode_center && mouse->relative_mode && !mouse->relative_mode_warp);
|
|
|
|
|
|
- if (SDL_memcmp(&rect, &clipped_rect, sizeof(rect)) != 0) {
|
|
|
- if (ClipCursor(&rect)) {
|
|
|
- data->cursor_clipped_rect = rect;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- } else {
|
|
|
- if (GetClientScreenRect(data->hwnd, &rect)) {
|
|
|
- if (window->mouse_rect.w > 0 && window->mouse_rect.h > 0) {
|
|
|
- SDL_Rect mouse_rect_win_client;
|
|
|
- RECT mouse_rect, intersection;
|
|
|
-
|
|
|
- // mouse_rect_win_client is the mouse rect in Windows client space
|
|
|
- mouse_rect_win_client = window->mouse_rect;
|
|
|
-
|
|
|
- // mouse_rect is the rect in Windows screen space
|
|
|
- mouse_rect.left = rect.left + mouse_rect_win_client.x;
|
|
|
- mouse_rect.top = rect.top + mouse_rect_win_client.y;
|
|
|
- mouse_rect.right = mouse_rect.left + mouse_rect_win_client.w;
|
|
|
- mouse_rect.bottom = mouse_rect.top + mouse_rect_win_client.h;
|
|
|
- if (IntersectRect(&intersection, &rect, &mouse_rect)) {
|
|
|
- SDL_memcpy(&rect, &intersection, sizeof(rect));
|
|
|
- } else if (window->flags & SDL_WINDOW_MOUSE_GRABBED) {
|
|
|
- // Mouse rect was invalid, just do the normal grab
|
|
|
- } else {
|
|
|
- SDL_zero(rect);
|
|
|
- }
|
|
|
- }
|
|
|
- if (SDL_memcmp(&rect, &clipped_rect, sizeof(rect)) != 0) {
|
|
|
- if (!WIN_IsRectEmpty(&rect)) {
|
|
|
- if (ClipCursor(&rect)) {
|
|
|
- data->cursor_clipped_rect = rect;
|
|
|
- }
|
|
|
- } else {
|
|
|
- ClipCursor(NULL);
|
|
|
- SDL_zero(data->cursor_clipped_rect);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+ RECT client;
|
|
|
+ if (!GetClientScreenRect(data->hwnd, &client)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ RECT target = client;
|
|
|
+ if (lock_to_ctr) {
|
|
|
+ LONG cx = (client.left + client.right ) / 2;
|
|
|
+ LONG cy = (client.top + client.bottom) / 2;
|
|
|
+ target = data->cursor_ctrlock_rect;
|
|
|
+ target.left += cx;
|
|
|
+ target.right += cx;
|
|
|
+ target.top += cy;
|
|
|
+ target.bottom += cy;
|
|
|
+ } else if (win_mouse_rect) {
|
|
|
+ RECT custom, overlap;
|
|
|
+ custom.left = client.left + mouse_rect.x;
|
|
|
+ custom.top = client.top + mouse_rect.y;
|
|
|
+ custom.right = client.left + mouse_rect.x + mouse_rect.w;
|
|
|
+ custom.bottom = client.top + mouse_rect.y + mouse_rect.h;
|
|
|
+ if (IntersectRect(&overlap, &client, &custom)) {
|
|
|
+ target = overlap;
|
|
|
+ } else if (!win_is_grabbed) {
|
|
|
+ WIN_UnclipCursorForWindow(window);
|
|
|
+ return;
|
|
|
}
|
|
|
- } else {
|
|
|
- bool unclip_cursor = false;
|
|
|
-
|
|
|
- // If the cursor is clipped to the screen, clear the clip state
|
|
|
- if (!videodevice ||
|
|
|
- (clipped_rect.left == videodevice->desktop_bounds.x &&
|
|
|
- clipped_rect.top == videodevice->desktop_bounds.y)) {
|
|
|
- unclip_cursor = true;
|
|
|
- } else {
|
|
|
- POINT first, second;
|
|
|
+ }
|
|
|
|
|
|
- first.x = clipped_rect.left;
|
|
|
- first.y = clipped_rect.top;
|
|
|
- second.x = clipped_rect.right - 1;
|
|
|
- second.y = clipped_rect.bottom - 1;
|
|
|
- if (PtInRect(&data->cursor_clipped_rect, first) &&
|
|
|
- PtInRect(&data->cursor_clipped_rect, second)) {
|
|
|
- unclip_cursor = true;
|
|
|
- }
|
|
|
- }
|
|
|
- if (unclip_cursor) {
|
|
|
- ClipCursor(NULL);
|
|
|
- SDL_zero(data->cursor_clipped_rect);
|
|
|
- }
|
|
|
+ if (GetClipCursor(&client) &&
|
|
|
+ 0 != SDL_memcmp(&target, &client, sizeof(client)) &&
|
|
|
+ ClipCursor(&target)) {
|
|
|
+ data->cursor_clipped_rect = target; // ClipCursor may fail if rect beyond screen
|
|
|
}
|
|
|
- data->last_updated_clipcursor = SDL_GetTicks();
|
|
|
}
|
|
|
|
|
|
bool WIN_SetWindowHitTest(SDL_Window *window, bool enabled)
|