Added SDL_GetWindowMouseRect()

Also guarantee that we won't get mouse movement outside the confining area, even if the OS implementation allows it (e.g. macOS)
This commit is contained in:
Sam Lantinga 2021-11-08 21:34:48 -08:00
parent 4db546b092
commit fd79607eb0
13 changed files with 111 additions and 66 deletions

View File

@ -1381,6 +1381,36 @@ extern DECLSPEC SDL_bool SDLCALL SDL_GetWindowMouseGrab(SDL_Window * window);
*/
extern DECLSPEC SDL_Window * SDLCALL SDL_GetGrabbedWindow(void);
/**
* Confines the cursor to the specified area of a window.
*
* Note that this does NOT grab the cursor, it only defines the area a cursor
* is restricted to when the window has mouse focus.
*
* \param window The window that will be associated with the barrier.
* \param rect A rectangle area in window-relative coordinates. If NULL the
* barrier for the specified window will be destroyed.
*
* \returns 0 on success or a negative error code on failure; call
* SDL_GetError() for more information.
*
* \sa SDL_GetWindowMouseRect
* \sa SDL_SetWindowGrab
*/
extern DECLSPEC int SDLCALL SDL_SetWindowMouseRect(SDL_Window * window, const SDL_Rect * rect);
/**
* Get the mouse confinement rectangle of a window.
*
* \param window The window to query
*
* \returns A pointer to the mouse confinement rectangle of a window,
* or NULL if there isn't one.
*
* \sa SDL_SetWindowMouseRect
*/
extern DECLSPEC const SDL_Rect * SDLCALL SDL_GetWindowMouseRect(SDL_Window * window);
/**
* Set the brightness (gamma multiplier) for a given window's display.
*
@ -1497,23 +1527,6 @@ extern DECLSPEC int SDLCALL SDL_SetWindowModalFor(SDL_Window * modal_window, SDL
*/
extern DECLSPEC int SDLCALL SDL_SetWindowInputFocus(SDL_Window * window);
/**
* Confines the cursor in the specified rect area of a window.
*
* Note that this does NOT grab the cursor, it only defines the area a cursor
* is restricted to when the window has mouse focus.
*
* \param window The window that will be associated with the barrier.
* \param rect A rectangle area in window-relative coordinates. If NULL the
* barrier for the specified window will be destroyed.
*
* \returns 0 on success or a negative error code on failure; call
* SDL_GetError() for more information.
*
* \sa SDL_SetWindowGrab
*/
extern DECLSPEC int SDLCALL SDL_SetWindowMouseRect(SDL_Window * window, const SDL_Rect * rect);
/**
* Set the gamma ramp for the display that owns a given window.
*

View File

@ -843,3 +843,4 @@
#define SDL_hid_get_serial_number_string SDL_hid_get_serial_number_string_REAL
#define SDL_hid_get_indexed_string SDL_hid_get_indexed_string_REAL
#define SDL_SetWindowMouseRect SDL_SetWindowMouseRect_REAL
#define SDL_GetWindowMouseRect SDL_GetWindowMouseRect_REAL

View File

@ -912,3 +912,4 @@ SDL_DYNAPI_PROC(int,SDL_hid_get_product_string,(SDL_hid_device *a, wchar_t *b, s
SDL_DYNAPI_PROC(int,SDL_hid_get_serial_number_string,(SDL_hid_device *a, wchar_t *b, size_t c),(a,b,c),return)
SDL_DYNAPI_PROC(int,SDL_hid_get_indexed_string,(SDL_hid_device *a, int b, wchar_t *c, size_t d),(a,b,c,d),return)
SDL_DYNAPI_PROC(int,SDL_SetWindowMouseRect,(SDL_Window *a, const SDL_Rect *b),(a,b),return)
SDL_DYNAPI_PROC(const SDL_Rect*,SDL_GetWindowMouseRect,(SDL_Window *a),(a),return)

View File

@ -416,24 +416,42 @@ SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relativ
/* make sure that the pointers find themselves inside the windows,
unless we have the mouse captured. */
if (window && ((window->flags & SDL_WINDOW_MOUSE_CAPTURE) == 0)) {
int x_max = 0, y_max = 0;
int x_min = 0, x_max = 0;
int y_min = 0, y_max = 0;
const SDL_Rect *confine = SDL_GetWindowMouseRect(window);
SDL_GetWindowSize(window, &x_max, &y_max);
--x_max;
--y_max;
if (confine) {
SDL_Rect window_rect;
SDL_Rect mouse_rect;
window_rect.x = 0;
window_rect.y = 0;
window_rect.w = x_max + 1;
window_rect.h = y_max + 1;
if (SDL_IntersectRect(confine, &window_rect, &mouse_rect)) {
x_min = mouse_rect.x;
y_min = mouse_rect.y;
x_max = x_min + mouse_rect.w - 1;
y_min = y_min + mouse_rect.h - 1;
}
}
if (mouse->x > x_max) {
mouse->x = x_max;
}
if (mouse->x < 0) {
mouse->x = 0;
if (mouse->x < x_min) {
mouse->x = x_min;
}
if (mouse->y > y_max) {
mouse->y = y_max;
}
if (mouse->y < 0) {
mouse->y = 0;
if (mouse->y < y_min) {
mouse->y = y_min;
}
}

View File

@ -103,6 +103,8 @@ struct SDL_Window
SDL_bool is_destroying;
SDL_bool is_dropping; /* drag/drop in progress, expecting SDL_SendDropComplete(). */
SDL_Rect mouse_rect;
SDL_WindowShaper *shaper;
SDL_HitTest hit_test;
@ -235,7 +237,7 @@ struct SDL_VideoDevice
int (*SetWindowGammaRamp) (_THIS, SDL_Window * window, const Uint16 * ramp);
int (*GetWindowGammaRamp) (_THIS, SDL_Window * window, Uint16 * ramp);
void* (*GetWindowICCProfile) (_THIS, SDL_Window * window, size_t* size);
int (*SetWindowMouseRect)(_THIS, SDL_Window * window, const SDL_Rect * rect);
void (*SetWindowMouseRect)(_THIS, SDL_Window * window);
void (*SetWindowMouseGrab) (_THIS, SDL_Window * window, SDL_bool grabbed);
void (*SetWindowKeyboardGrab) (_THIS, SDL_Window * window, SDL_bool grabbed);
void (*DestroyWindow) (_THIS, SDL_Window * window);

View File

@ -2836,10 +2836,29 @@ int
SDL_SetWindowMouseRect(SDL_Window * window, const SDL_Rect * rect)
{
CHECK_WINDOW_MAGIC(window, -1);
if (!_this->SetWindowMouseRect) {
return SDL_Unsupported();
if (rect) {
SDL_memcpy(&window->mouse_rect, rect, sizeof(*rect));
} else {
SDL_zero(window->mouse_rect);
}
if (_this->SetWindowMouseRect) {
_this->SetWindowMouseRect(_this, window);
}
return 0;
}
const SDL_Rect *
SDL_GetWindowMouseRect(SDL_Window * window)
{
CHECK_WINDOW_MAGIC(window, NULL);
if (SDL_RectEmpty(&window->mouse_rect)) {
return NULL;
} else {
return &window->mouse_rect;
}
return _this->SetWindowMouseRect(_this, window, rect);
}
int

View File

@ -124,7 +124,6 @@ struct SDL_WindowData
SDL_bool created;
SDL_bool inWindowFullscreenTransition;
NSInteger flash_request;
SDL_Rect mouse_rect;
Cocoa_WindowListener *listener;
struct SDL_VideoData *videodata;
#if SDL_VIDEO_OPENGL_EGL
@ -155,7 +154,7 @@ extern void Cocoa_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDispl
extern int Cocoa_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp);
extern void* Cocoa_GetWindowICCProfile(_THIS, SDL_Window * window, size_t * size);
extern int Cocoa_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp);
extern int Cocoa_SetWindowMouseRect(_THIS, SDL_Window * window, const SDL_Rect * rect);
extern void Cocoa_SetWindowMouseRect(_THIS, SDL_Window * window);
extern void Cocoa_SetWindowMouseGrab(_THIS, SDL_Window * window, SDL_bool grabbed);
extern void Cocoa_DestroyWindow(_THIS, SDL_Window * window);
extern SDL_bool Cocoa_GetWindowWMInfo(_THIS, SDL_Window * window, struct SDL_SysWMinfo *info);

View File

@ -335,7 +335,7 @@ ShouldAdjustCoordinatesForGrab(SDL_Window * window)
return SDL_FALSE;
}
if ((window->flags & SDL_WINDOW_MOUSE_GRABBED) || (data->mouse_rect.w > 0 && data->mouse_rect.h > 0)) {
if ((window->flags & SDL_WINDOW_MOUSE_GRABBED) || (window->mouse_rect.w > 0 && window->mouse_rect.h > 0)) {
return SDL_TRUE;
}
return SDL_FALSE;
@ -344,9 +344,7 @@ ShouldAdjustCoordinatesForGrab(SDL_Window * window)
static SDL_bool
AdjustCoordinatesForGrab(SDL_Window * window, int x, int y, CGPoint *adjusted)
{
SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
if (data->mouse_rect.w > 0 && data->mouse_rect.h > 0) {
if (window->mouse_rect.w > 0 && window->mouse_rect.h > 0) {
SDL_Rect window_rect;
SDL_Rect mouse_rect;
@ -355,7 +353,7 @@ AdjustCoordinatesForGrab(SDL_Window * window, int x, int y, CGPoint *adjusted)
window_rect.w = window->w;
window_rect.h = window->h;
if (SDL_IntersectRect(&data->mouse_rect, &window_rect, &mouse_rect)) {
if (SDL_IntersectRect(&window->mouse_rect, &window_rect, &mouse_rect)) {
int left = window->x + mouse_rect.x;
int right = left + mouse_rect.w - 1;
int top = window->y + mouse_rect.y;
@ -2093,17 +2091,9 @@ Cocoa_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp)
return 0;
}
int
Cocoa_SetWindowMouseRect(_THIS, SDL_Window * window, const SDL_Rect * rect)
void
Cocoa_SetWindowMouseRect(_THIS, SDL_Window * window)
{
SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
if (rect) {
SDL_memcpy(&data->mouse_rect, rect, sizeof(*rect));
} else {
SDL_zero(data->mouse_rect);
}
/* Move the cursor to the nearest point in the mouse rect */
if (ShouldAdjustCoordinatesForGrab(window)) {
int x, y;
@ -2115,7 +2105,6 @@ Cocoa_SetWindowMouseRect(_THIS, SDL_Window * window, const SDL_Rect * rect)
CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint);
}
}
return 0;
}
void

View File

@ -814,19 +814,10 @@ void WIN_UngrabKeyboard(SDL_Window *window)
}
}
int
WIN_SetWindowMouseRect(_THIS, SDL_Window * window, const SDL_Rect * rect)
void
WIN_SetWindowMouseRect(_THIS, SDL_Window * window)
{
SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
if (rect) {
SDL_memcpy(&data->mouse_rect, rect, sizeof(*rect));
} else {
SDL_zero(data->mouse_rect);
}
WIN_UpdateClipCursor(window);
return 0;
}
void
@ -1014,7 +1005,7 @@ WIN_UpdateClipCursor(SDL_Window *window)
}
if ((mouse->relative_mode || (window->flags & SDL_WINDOW_MOUSE_GRABBED) ||
(data->mouse_rect.w > 0 && data->mouse_rect.h > 0)) &&
(window->mouse_rect.w > 0 && window->mouse_rect.h > 0)) &&
(window->flags & SDL_WINDOW_INPUT_FOCUS)) {
if (mouse->relative_mode && !mouse->relative_mode_warp) {
if (GetWindowRect(data->hwnd, &rect)) {
@ -1039,7 +1030,7 @@ WIN_UpdateClipCursor(SDL_Window *window)
if (GetClientRect(data->hwnd, &rect)) {
ClientToScreen(data->hwnd, (LPPOINT) & rect);
ClientToScreen(data->hwnd, (LPPOINT) & rect + 1);
if (data->mouse_rect.w > 0 && data->mouse_rect.h > 0) {
if (window->mouse_rect.w > 0 && window->mouse_rect.h > 0) {
RECT mouse_rect, intersection;
mouse_rect.left = rect.left + data->mouse_rect.x;

View File

@ -51,7 +51,6 @@ typedef struct
Uint32 last_updated_clipcursor;
SDL_bool windowed_mode_was_maximized;
SDL_bool in_window_deactivation;
SDL_Rect mouse_rect;
RECT cursor_clipped_rect;
SDL_Point last_raw_mouse_position;
SDL_bool mouse_tracked;
@ -82,7 +81,7 @@ extern void WIN_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay
extern int WIN_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp);
extern void* WIN_GetWindowICCProfile(_THIS, SDL_Window * window, size_t * size);
extern int WIN_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp);
extern int WIN_SetWindowMouseRect(_THIS, SDL_Window * window, const SDL_Rect * rect);
extern void WIN_SetWindowMouseRect(_THIS, SDL_Window * window);
extern void WIN_SetWindowMouseGrab(_THIS, SDL_Window * window, SDL_bool grabbed);
extern void WIN_SetWindowKeyboardGrab(_THIS, SDL_Window * window, SDL_bool grabbed);
extern void WIN_DestroyWindow(_THIS, SDL_Window * window);

View File

@ -1079,7 +1079,7 @@ X11_DispatchEvent(_THIS, XEvent *xevent)
}
#if SDL_VIDEO_DRIVER_X11_XFIXES
/* Disable confiment if the window gets hidden. */
/* Disable confinement if the window gets hidden. */
if (data->pointer_barrier_active == SDL_TRUE) {
X11_ConfineCursorWithFlags(_this, data->window, NULL, X11_BARRIER_HANDLED_BY_EVENT);
}
@ -1095,7 +1095,7 @@ X11_DispatchEvent(_THIS, XEvent *xevent)
X11_DispatchMapNotify(data);
#if SDL_VIDEO_DRIVER_X11_XFIXES
/* Enable confiment if it was activated. */
/* Enable confinement if it was activated. */
if (data->pointer_barrier_active == SDL_TRUE) {
X11_ConfineCursorWithFlags(_this, data->window, &data->barrier_rect, X11_BARRIER_HANDLED_BY_EVENT);
}

View File

@ -73,10 +73,23 @@ X11_XfixesIsInitialized()
return xfixes_initialized;
}
int
X11_SetWindowMouseRect(_THIS, SDL_Window * window, const SDL_Rect * rect)
void
X11_SetWindowMouseRect(_THIS, SDL_Window * window)
{
return X11_ConfineCursorWithFlags(_this, window, rect, 0);
if (SDL_RectEmpty(window->mouse_rect)) {
X11_ConfineCursorWithFlags(_this, window, NULL, 0);
} else {
if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
X11_ConfineCursorWithFlags(_this, window, &window->mouse_rect, 0);
} else {
/* Save the state for when we get focus again */
SDL_WindowData *wdata = (SDL_WindowData *) window->driverdata;
SDL_memcpy(&wdata->barrier_rect, &window->mouse_rect, sizeof(wdata->barrier_rect));
wdata->pointer_barrier_active = SDL_TRUE;
}
}
}
int
@ -102,7 +115,7 @@ X11_ConfineCursorWithFlags(_THIS, SDL_Window * window, const SDL_Rect * rect, in
wdata = (SDL_WindowData *) window->driverdata;
/* If user did not specify an area to confine, destroy the barrier that was/is assigned to
* this window it was assigned*/
* this window it was assigned */
if (rect) {
int x1, y1, x2, y2;
SDL_Rect bounds;

View File

@ -30,7 +30,7 @@
extern void X11_InitXfixes(_THIS);
extern int X11_XfixesIsInitialized(void);
extern int X11_SetWindowMouseRect(_THIS, SDL_Window * window, const SDL_Rect * rect);
extern void X11_SetWindowMouseRect(_THIS, SDL_Window * window);
extern int X11_ConfineCursorWithFlags(_THIS, SDL_Window * window, const SDL_Rect * rect, int flags);
extern void X11_DestroyPointerBarrier(_THIS, SDL_Window * window);