From a1fabca162091b50d6f7dd71879d028319e09d80 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Thu, 14 Oct 2021 16:52:21 -0700 Subject: [PATCH] Removed mouse warping for local mice and improved warp handling for mouse over RDP --- src/video/windows/SDL_windowsevents.c | 149 +++++--------------------- src/video/windows/SDL_windowswindow.c | 33 ++++-- 2 files changed, 52 insertions(+), 130 deletions(-) diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c index 60f87d764..f6b80802c 100644 --- a/src/video/windows/SDL_windowsevents.c +++ b/src/video/windows/SDL_windowsevents.c @@ -508,79 +508,6 @@ static SDL_MOUSE_EVENT_SOURCE GetMouseMessageSource() return SDL_MOUSE_EVENT_SOURCE_MOUSE; } -static void -GetDisplayBoundsForPoint(int x, int y, RECT *bounds) -{ - SDL_VideoDevice *_this = SDL_GetVideoDevice(); - int i, dist; - int closest = -1; - int closest_dist = 0x7FFFFFFF; - SDL_Point point; - SDL_Point delta; - SDL_Rect rect; - - point.x = x; - point.y = y; - for (i = 0; i < _this->num_displays; ++i) { - SDL_GetDisplayBounds(i, &rect); - if (SDL_EnclosePoints(&point, 1, &rect, NULL)) { - WIN_RectToRECT(&rect, bounds); - return; - } - - delta.x = point.x - (rect.x + rect.w / 2); - delta.y = point.y - (rect.y + rect.h / 2); - dist = (delta.x*delta.x + delta.y*delta.y); - if (dist < closest_dist) { - closest = i; - closest_dist = dist; - WIN_RectToRECT(&rect, bounds); - } - } - if (closest < 0) { - bounds->left = 0; - bounds->right = GetSystemMetrics(SM_CXSCREEN) - 1; - bounds->top = 0; - bounds->bottom = GetSystemMetrics(SM_CYSCREEN) - 1; - } -} - -static void -WarpWithinBoundsRect(int x, int y, RECT *bounds) -{ - if (x < bounds->left || x > bounds->right || y < bounds->top || y > bounds->bottom) { - const int MIN_BOUNDS_SIZE = 32; - int boundsWidth = (bounds->right - bounds->left) + 1; - int boundsHeight = (bounds->bottom - bounds->top) + 1; - if (boundsWidth >= MIN_BOUNDS_SIZE && boundsHeight >= MIN_BOUNDS_SIZE) { - /* Warp back to the opposite side, assuming more motion in the current direction */ - int targetLeft = bounds->right - (boundsWidth * 3) / 4; - int targetRight = bounds->left + (boundsWidth * 3) / 4; - int targetTop = bounds->bottom - (boundsHeight * 3) / 4; - int targetBottom = bounds->top + (boundsHeight * 3) / 4; - int warpX; - int warpY; - - if (x < bounds->left) { - warpX = targetRight; - } else if (x > bounds->right) { - warpX = targetLeft; - } else { - warpX = SDL_clamp(x, targetLeft, targetRight); - } - - if (y < bounds->top) { - warpY = targetBottom; - } else if (y > bounds->bottom) { - warpY = targetTop; - } else { - warpY = SDL_clamp(y, targetTop, targetBottom); - } - WIN_SetCursorPos(warpX, warpY); - } - } -} - static SDL_WindowData * WIN_GetWindowDataFromHWND(HWND hwnd) { @@ -818,35 +745,8 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) RAWMOUSE* rawmouse = &inp.data.mouse; if ((rawmouse->usFlags & 0x01) == MOUSE_MOVE_RELATIVE) { - POINT pt; - SDL_SendMouseMotion(data->window, mouseID, 1, (int)rawmouse->lLastX, (int)rawmouse->lLastY); - /* Make sure that the mouse doesn't hover over notifications and so forth */ - if (GetCursorPos(&pt)) { - int x = pt.x; - int y = pt.y; - RECT screenRect; - RECT hwndRect; - RECT boundsRect; - - /* Calculate screen rect */ - GetDisplayBoundsForPoint(x, y, &screenRect); - - /* Calculate client rect */ - GetClientRect(hwnd, &hwndRect); - ClientToScreen(hwnd, (LPPOINT) & hwndRect); - ClientToScreen(hwnd, (LPPOINT) & hwndRect + 1); - - /* Calculate bounds rect */ - IntersectRect(&boundsRect, &screenRect, &hwndRect); - InflateRect(&boundsRect, -SAFE_AREA_X, -SAFE_AREA_Y); - - if (!data->in_title_click && !data->focus_click_pending) { - WarpWithinBoundsRect(x, y, &boundsRect); - } - } - } else if (rawmouse->lLastX || rawmouse->lLastY) { /* This is absolute motion, either using a tablet or mouse over RDP @@ -876,33 +776,34 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) relY = (int)(y - data->last_raw_mouse_position.y); if (remote_desktop) { - RECT screenRect; - RECT hwndRect; - RECT boundsRect; - int boundsWidth, boundsHeight; + if (!data->in_title_click && !data->focus_click_pending) { + static int wobble; + float floatX = (float)x / w; + float floatY = (float)y / h; - /* Calculate screen rect */ - GetDisplayBoundsForPoint(x, y, &screenRect); + /* See if the mouse is at the edge of the screen, or in the RDP title bar area */ + if (floatX <= 0.01f || floatX >= 0.99f || floatY <= 0.01f || floatY >= 0.99f || y < 32) { + /* Wobble the cursor position so it's not ignored if the last warp didn't have any effect */ + RECT rect = data->cursor_clipped_rect; + int warpX = rect.left + ((rect.right - rect.left) / 2) + wobble; + int warpY = rect.top + ((rect.bottom - rect.top) / 2); - /* Calculate client rect */ - GetClientRect(hwnd, &hwndRect); - ClientToScreen(hwnd, (LPPOINT) & hwndRect); - ClientToScreen(hwnd, (LPPOINT) & hwndRect + 1); + WIN_SetCursorPos(warpX, warpY); - /* Calculate bounds rect */ - IntersectRect(&boundsRect, &screenRect, &hwndRect); - InflateRect(&boundsRect, -SAFE_AREA_X, -SAFE_AREA_Y); - boundsWidth = (boundsRect.right - boundsRect.left) + 1; - boundsHeight = (boundsRect.bottom - boundsRect.top) + 1; - - if ((boundsWidth > 0 && SDL_abs(relX) > (boundsWidth / 2)) || - (boundsHeight > 0 && SDL_abs(relY) > (boundsHeight / 2))) { - /* Expected motion for warping below, ignore this */ - } else { - SDL_SendMouseMotion(data->window, mouseID, 1, relX, relY); - - if (!data->in_title_click && !data->focus_click_pending) { - WarpWithinBoundsRect(x, y, &boundsRect); + ++wobble; + if (wobble > 1) { + wobble = -1; + } + } else { + /* Send relative motion if we didn't warp last frame (had good position data) + We also sometimes get large deltas due to coalesced mouse motion and warping, + so ignore those. + */ + const int MAX_RELATIVE_MOTION = (h / 6); + if (SDL_abs(relX) < MAX_RELATIVE_MOTION && + SDL_abs(relY) < MAX_RELATIVE_MOTION) { + SDL_SendMouseMotion(data->window, mouseID, 1, relX, relY); + } } } } else { diff --git a/src/video/windows/SDL_windowswindow.c b/src/video/windows/SDL_windowswindow.c index 0cfc006a2..b6e9dc3d9 100644 --- a/src/video/windows/SDL_windowswindow.c +++ b/src/video/windows/SDL_windowswindow.c @@ -974,12 +974,33 @@ WIN_UpdateClipCursor(SDL_Window *window) if ((mouse->relative_mode || (window->flags & SDL_WINDOW_MOUSE_GRABBED)) && (window->flags & SDL_WINDOW_INPUT_FOCUS)) { - if (GetClientRect(data->hwnd, &rect) && !IsRectEmpty(&rect)) { - ClientToScreen(data->hwnd, (LPPOINT) & rect); - ClientToScreen(data->hwnd, (LPPOINT) & rect + 1); - if (SDL_memcmp(&rect, &clipped_rect, sizeof(rect)) != 0) { - if (ClipCursor(&rect)) { - data->cursor_clipped_rect = rect; + if (mouse->relative_mode && !mouse->relative_mode_warp) { + if (GetWindowRect(data->hwnd, &rect)) { + LONG cx, cy; + + cx = (rect.left + rect.right) / 2; + cy = (rect.top + rect.bottom) / 2; + + /* Make an absurdly small clip rect */ + rect.left = cx - 1; + rect.right = cx + 1; + rect.top = cy - 1; + rect.bottom = cy + 1; + + if (SDL_memcmp(&rect, &clipped_rect, sizeof(rect)) != 0) { + if (ClipCursor(&rect)) { + data->cursor_clipped_rect = rect; + } + } + } + } else { + if (GetClientRect(data->hwnd, &rect) && !IsRectEmpty(&rect)) { + ClientToScreen(data->hwnd, (LPPOINT) & rect); + ClientToScreen(data->hwnd, (LPPOINT) & rect + 1); + if (SDL_memcmp(&rect, &clipped_rect, sizeof(rect)) != 0) { + if (ClipCursor(&rect)) { + data->cursor_clipped_rect = rect; + } } } }