Removed mouse warping for local mice and improved warp handling for mouse over RDP

This commit is contained in:
Sam Lantinga 2021-10-14 16:52:21 -07:00
parent 82793ac279
commit a1fabca162
2 changed files with 52 additions and 130 deletions

View file

@ -508,79 +508,6 @@ static SDL_MOUSE_EVENT_SOURCE GetMouseMessageSource()
return SDL_MOUSE_EVENT_SOURCE_MOUSE; 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 * static SDL_WindowData *
WIN_GetWindowDataFromHWND(HWND hwnd) WIN_GetWindowDataFromHWND(HWND hwnd)
{ {
@ -818,35 +745,8 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
RAWMOUSE* rawmouse = &inp.data.mouse; RAWMOUSE* rawmouse = &inp.data.mouse;
if ((rawmouse->usFlags & 0x01) == MOUSE_MOVE_RELATIVE) { if ((rawmouse->usFlags & 0x01) == MOUSE_MOVE_RELATIVE) {
POINT pt;
SDL_SendMouseMotion(data->window, mouseID, 1, (int)rawmouse->lLastX, (int)rawmouse->lLastY); 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) { } else if (rawmouse->lLastX || rawmouse->lLastY) {
/* This is absolute motion, either using a tablet or mouse over RDP /* 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); relY = (int)(y - data->last_raw_mouse_position.y);
if (remote_desktop) { if (remote_desktop) {
RECT screenRect; if (!data->in_title_click && !data->focus_click_pending) {
RECT hwndRect; static int wobble;
RECT boundsRect; float floatX = (float)x / w;
int boundsWidth, boundsHeight; float floatY = (float)y / h;
/* Calculate screen rect */ /* See if the mouse is at the edge of the screen, or in the RDP title bar area */
GetDisplayBoundsForPoint(x, y, &screenRect); 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 */ WIN_SetCursorPos(warpX, warpY);
GetClientRect(hwnd, &hwndRect);
ClientToScreen(hwnd, (LPPOINT) & hwndRect);
ClientToScreen(hwnd, (LPPOINT) & hwndRect + 1);
/* Calculate bounds rect */ ++wobble;
IntersectRect(&boundsRect, &screenRect, &hwndRect); if (wobble > 1) {
InflateRect(&boundsRect, -SAFE_AREA_X, -SAFE_AREA_Y); wobble = -1;
boundsWidth = (boundsRect.right - boundsRect.left) + 1; }
boundsHeight = (boundsRect.bottom - boundsRect.top) + 1; } else {
/* Send relative motion if we didn't warp last frame (had good position data)
if ((boundsWidth > 0 && SDL_abs(relX) > (boundsWidth / 2)) || We also sometimes get large deltas due to coalesced mouse motion and warping,
(boundsHeight > 0 && SDL_abs(relY) > (boundsHeight / 2))) { so ignore those.
/* Expected motion for warping below, ignore this */ */
} else { const int MAX_RELATIVE_MOTION = (h / 6);
SDL_SendMouseMotion(data->window, mouseID, 1, relX, relY); if (SDL_abs(relX) < MAX_RELATIVE_MOTION &&
SDL_abs(relY) < MAX_RELATIVE_MOTION) {
if (!data->in_title_click && !data->focus_click_pending) { SDL_SendMouseMotion(data->window, mouseID, 1, relX, relY);
WarpWithinBoundsRect(x, y, &boundsRect); }
} }
} }
} else { } else {

View file

@ -974,12 +974,33 @@ WIN_UpdateClipCursor(SDL_Window *window)
if ((mouse->relative_mode || (window->flags & SDL_WINDOW_MOUSE_GRABBED)) && if ((mouse->relative_mode || (window->flags & SDL_WINDOW_MOUSE_GRABBED)) &&
(window->flags & SDL_WINDOW_INPUT_FOCUS)) { (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
if (GetClientRect(data->hwnd, &rect) && !IsRectEmpty(&rect)) { if (mouse->relative_mode && !mouse->relative_mode_warp) {
ClientToScreen(data->hwnd, (LPPOINT) & rect); if (GetWindowRect(data->hwnd, &rect)) {
ClientToScreen(data->hwnd, (LPPOINT) & rect + 1); LONG cx, cy;
if (SDL_memcmp(&rect, &clipped_rect, sizeof(rect)) != 0) {
if (ClipCursor(&rect)) { cx = (rect.left + rect.right) / 2;
data->cursor_clipped_rect = rect; 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;
}
} }
} }
} }