Expose separate keyboard and mouse grab support

This adds SDL_SetWindowKeyboardGrab(), SDL_GetWindowKeyboardGrab(),
SDL_SetWindowMouseGrab(), SDL_GetWindowMouseGrab(), and new
SDL_WINDOW_KEYBOARD_GRABBED flag. It also updates the test harness to exercise
this functionality and makes a minor fix to X11 that I missed in
https://hg.libsdl.org/SDL/rev/02a2d609369b

To fit in with this new support, SDL_WINDOW_INPUT_CAPTURE has been renamed to
SDL_WINDOW_MOUSE_CAPTURE with the old name remaining as an alias for backwards
compatibility with older code.
This commit is contained in:
Cameron Gutman
2021-01-26 19:16:17 -06:00
parent ff827fc767
commit 6b057c6783
12 changed files with 367 additions and 84 deletions

View File

@@ -795,3 +795,7 @@
#define SDL_SoftStretchLinear SDL_SoftStretchLinear_REAL
#define SDL_RenderGetD3D11Device SDL_RenderGetD3D11Device_REAL
#define SDL_UpdateNVTexture SDL_UpdateNVTexture_REAL
#define SDL_SetWindowKeyboardGrab SDL_SetWindowKeyboardGrab_REAL
#define SDL_SetWindowMouseGrab SDL_SetWindowMouseGrab_REAL
#define SDL_GetWindowKeyboardGrab SDL_GetWindowKeyboardGrab_REAL
#define SDL_GetWindowMouseGrab SDL_GetWindowMouseGrab_REAL

View File

@@ -858,3 +858,7 @@ SDL_DYNAPI_PROC(int,SDL_SoftStretchLinear,(SDL_Surface *a, const SDL_Rect *b, SD
SDL_DYNAPI_PROC(ID3D11Device*,SDL_RenderGetD3D11Device,(SDL_Renderer *a),(a),return)
#endif
SDL_DYNAPI_PROC(int,SDL_UpdateNVTexture,(SDL_Texture *a, const SDL_Rect *b, const Uint8 *c, int d, const Uint8 *e, int f),(a,b,c,d,e,f),return)
SDL_DYNAPI_PROC(void,SDL_SetWindowKeyboardGrab,(SDL_Window *a, SDL_bool b),(a,b),)
SDL_DYNAPI_PROC(void,SDL_SetWindowMouseGrab,(SDL_Window *a, SDL_bool b),(a,b),)
SDL_DYNAPI_PROC(SDL_bool,SDL_GetWindowKeyboardGrab,(SDL_Window *a),(a),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_GetWindowMouseGrab,(SDL_Window *a),(a),return)

View File

@@ -34,7 +34,7 @@ static const char *video_usage[] = {
"[--icon icon.bmp]", "[--center | --position X,Y]", "[--geometry WxH]",
"[--min-geometry WxH]", "[--max-geometry WxH]", "[--logical WxH]",
"[--scale N]", "[--depth N]", "[--refresh R]", "[--vsync]", "[--noframe]",
"[--resize]", "[--minimize]", "[--maximize]", "[--grab]",
"[--resize]", "[--minimize]", "[--maximize]", "[--grab]", "[--keyboard-grab]",
"[--allow-highdpi]", "[--usable-bounds]"
};
@@ -412,7 +412,11 @@ SDLTest_CommonArg(SDLTest_CommonState * state, int index)
return 1;
}
if (SDL_strcasecmp(argv[index], "--grab") == 0) {
state->window_flags |= SDL_WINDOW_INPUT_GRABBED;
state->window_flags |= SDL_WINDOW_MOUSE_GRABBED;
return 1;
}
if (SDL_strcasecmp(argv[index], "--keyboard-grab") == 0) {
state->window_flags |= SDL_WINDOW_KEYBOARD_GRABBED;
return 1;
}
if (SDL_strcasecmp(argv[index], "--rate") == 0) {
@@ -1764,13 +1768,22 @@ SDLTest_CommonEvent(SDLTest_CommonState * state, SDL_Event * event, int *done)
break;
case SDLK_g:
if (withControl) {
/* Ctrl-G toggle grab */
/* Ctrl-G toggle mouse grab */
SDL_Window *window = SDL_GetWindowFromID(event->key.windowID);
if (window) {
SDL_SetWindowGrab(window, !SDL_GetWindowGrab(window) ? SDL_TRUE : SDL_FALSE);
}
}
break;
case SDLK_k:
if (withControl) {
/* Ctrl-K toggle keyboard grab */
SDL_Window* window = SDL_GetWindowFromID(event->key.windowID);
if (window) {
SDL_SetWindowKeyboardGrab(window, !SDL_GetWindowKeyboardGrab(window) ? SDL_TRUE : SDL_FALSE);
}
}
break;
case SDLK_m:
if (withControl) {
/* Ctrl-M maximize */

View File

@@ -1433,9 +1433,17 @@ SDL_FinishWindowCreation(SDL_Window *window, Uint32 flags)
if (flags & SDL_WINDOW_FULLSCREEN) {
SDL_SetWindowFullscreen(window, flags);
}
if (flags & SDL_WINDOW_INPUT_GRABBED) {
if (flags & SDL_WINDOW_MOUSE_GRABBED) {
/* We must specifically call SDL_SetWindowGrab() and not
SDL_SetWindowMouseGrab() here because older applications may use
this flag plus SDL_HINT_GRAB_KEYBOARD to indicate that they want
the keyboard grabbed too and SDL_SetWindowMouseGrab() won't do that.
*/
SDL_SetWindowGrab(window, SDL_TRUE);
}
if (flags & SDL_WINDOW_KEYBOARD_GRABBED) {
SDL_SetWindowKeyboardGrab(window, SDL_TRUE);
}
if (!(flags & SDL_WINDOW_HIDDEN)) {
SDL_ShowWindow(window);
}
@@ -2638,41 +2646,46 @@ SDL_GetWindowGammaRamp(SDL_Window * window, Uint16 * red,
void
SDL_UpdateWindowGrab(SDL_Window * window)
{
SDL_Window *grabbed_window;
SDL_bool grabbed;
if ((SDL_GetMouse()->relative_mode || (window->flags & SDL_WINDOW_INPUT_GRABBED)) &&
(window->flags & SDL_WINDOW_INPUT_FOCUS)) {
grabbed = SDL_TRUE;
SDL_bool keyboard_grabbed, mouse_grabbed;
if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
if (SDL_GetMouse()->relative_mode || (window->flags & SDL_WINDOW_MOUSE_GRABBED)) {
mouse_grabbed = SDL_TRUE;
} else {
mouse_grabbed = SDL_FALSE;
}
if (window->flags & SDL_WINDOW_KEYBOARD_GRABBED) {
keyboard_grabbed = SDL_TRUE;
} else {
keyboard_grabbed = SDL_FALSE;
}
} else {
grabbed = SDL_FALSE;
mouse_grabbed = SDL_FALSE;
keyboard_grabbed = SDL_FALSE;
}
grabbed_window = _this->grabbed_window;
if (grabbed) {
if (grabbed_window && (grabbed_window != window)) {
if (mouse_grabbed || keyboard_grabbed) {
if (_this->grabbed_window && (_this->grabbed_window != window)) {
/* stealing a grab from another window! */
grabbed_window->flags &= ~SDL_WINDOW_INPUT_GRABBED;
_this->grabbed_window->flags &= ~(SDL_WINDOW_MOUSE_GRABBED | SDL_WINDOW_KEYBOARD_GRABBED);
if (_this->SetWindowMouseGrab) {
_this->SetWindowMouseGrab(_this, grabbed_window, SDL_FALSE);
_this->SetWindowMouseGrab(_this, _this->grabbed_window, SDL_FALSE);
}
if (_this->SetWindowKeyboardGrab) {
_this->SetWindowKeyboardGrab(_this, grabbed_window, SDL_FALSE);
_this->SetWindowKeyboardGrab(_this, _this->grabbed_window, SDL_FALSE);
}
}
_this->grabbed_window = window;
} else if (grabbed_window == window) {
_this->grabbed_window = NULL; /* ungrabbing. */
} else if (_this->grabbed_window == window) {
_this->grabbed_window = NULL; /* ungrabbing input. */
}
if (_this->SetWindowMouseGrab) {
_this->SetWindowMouseGrab(_this, window, grabbed);
_this->SetWindowMouseGrab(_this, window, mouse_grabbed);
}
if (_this->SetWindowKeyboardGrab) {
if (grabbed && SDL_GetHintBoolean(SDL_HINT_GRAB_KEYBOARD, SDL_FALSE)) {
_this->SetWindowKeyboardGrab(_this, window, SDL_TRUE);
} else {
_this->SetWindowKeyboardGrab(_this, window, SDL_FALSE);
}
_this->SetWindowKeyboardGrab(_this, window, keyboard_grabbed);
}
}
@@ -2681,13 +2694,41 @@ SDL_SetWindowGrab(SDL_Window * window, SDL_bool grabbed)
{
CHECK_WINDOW_MAGIC(window,);
if (!!grabbed == !!(window->flags & SDL_WINDOW_INPUT_GRABBED)) {
SDL_SetWindowMouseGrab(window, grabbed);
if (SDL_GetHintBoolean(SDL_HINT_GRAB_KEYBOARD, SDL_FALSE)) {
SDL_SetWindowKeyboardGrab(window, grabbed);
}
}
void
SDL_SetWindowKeyboardGrab(SDL_Window * window, SDL_bool grabbed)
{
CHECK_WINDOW_MAGIC(window,);
if (!!grabbed == !!(window->flags & SDL_WINDOW_KEYBOARD_GRABBED)) {
return;
}
if (grabbed) {
window->flags |= SDL_WINDOW_INPUT_GRABBED;
window->flags |= SDL_WINDOW_KEYBOARD_GRABBED;
} else {
window->flags &= ~SDL_WINDOW_INPUT_GRABBED;
window->flags &= ~SDL_WINDOW_KEYBOARD_GRABBED;
}
SDL_UpdateWindowGrab(window);
}
void
SDL_SetWindowMouseGrab(SDL_Window * window, SDL_bool grabbed)
{
CHECK_WINDOW_MAGIC(window,);
if (!!grabbed == !!(window->flags & SDL_WINDOW_MOUSE_GRABBED)) {
return;
}
if (grabbed) {
window->flags |= SDL_WINDOW_MOUSE_GRABBED;
} else {
window->flags &= ~SDL_WINDOW_MOUSE_GRABBED;
}
SDL_UpdateWindowGrab(window);
}
@@ -2696,14 +2737,34 @@ SDL_bool
SDL_GetWindowGrab(SDL_Window * window)
{
CHECK_WINDOW_MAGIC(window, SDL_FALSE);
SDL_assert(!_this->grabbed_window || ((_this->grabbed_window->flags & SDL_WINDOW_INPUT_GRABBED) != 0));
SDL_assert(!_this->grabbed_window ||
((_this->grabbed_window->flags & SDL_WINDOW_MOUSE_GRABBED) != 0) ||
((_this->grabbed_window->flags & SDL_WINDOW_KEYBOARD_GRABBED) != 0));
return window == _this->grabbed_window;
}
SDL_bool
SDL_GetWindowKeyboardGrab(SDL_Window * window)
{
CHECK_WINDOW_MAGIC(window, SDL_FALSE);
return window == _this->grabbed_window &&
((_this->grabbed_window->flags & SDL_WINDOW_KEYBOARD_GRABBED) != 0);
}
SDL_bool
SDL_GetWindowMouseGrab(SDL_Window * window)
{
CHECK_WINDOW_MAGIC(window, SDL_FALSE);
return window == _this->grabbed_window &&
((_this->grabbed_window->flags & SDL_WINDOW_MOUSE_GRABBED) != 0);
}
SDL_Window *
SDL_GetGrabbedWindow(void)
{
SDL_assert(!_this->grabbed_window || ((_this->grabbed_window->flags & SDL_WINDOW_INPUT_GRABBED) != 0));
SDL_assert(!_this->grabbed_window ||
((_this->grabbed_window->flags & SDL_WINDOW_MOUSE_GRABBED) != 0) ||
((_this->grabbed_window->flags & SDL_WINDOW_KEYBOARD_GRABBED) != 0));
return _this->grabbed_window;
}

View File

@@ -90,7 +90,7 @@ Cocoa_MouseTapCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event
return event;
}
if (!(window->flags & SDL_WINDOW_INPUT_GRABBED)) {
if (!(window->flags & SDL_WINDOW_MOUSE_GRABBED)) {
return event;
}

View File

@@ -1109,7 +1109,7 @@ SetWindowStyle(SDL_Window * window, NSUInteger style)
x = (int)point.x;
y = (int)(window->h - point.y);
if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
if (window->flags & SDL_WINDOW_MOUSE_GRABBED) {
if (x < 0 || x >= window->w || y < 0 || y >= window->h) {
if (x < 0) {
x = 0;

View File

@@ -212,7 +212,7 @@ ProcessWindowEvent(_THIS, SDL_Window *sdlwin, DFBWindowEvent * evt)
case DWET_MOTION:
if (ClientXY(windata, &evt->x, &evt->y)) {
if (!devdata->use_linux_input) {
if (!(sdlwin->flags & SDL_WINDOW_INPUT_GRABBED))
if (!(sdlwin->flags & SDL_WINDOW_MOUSE_GRABBED))
SDL_SendMouseMotion_ex(sdlwin, devdata->mouse_id[0], 0,
evt->x, evt->y, 0);
} else {

View File

@@ -183,7 +183,7 @@ static VOID _mouseCheck(WINDATA *pWinData)
{
SDL_Mouse *pSDLMouse = SDL_GetMouse();
if ((pSDLMouse->relative_mode || (pWinData->window->flags & SDL_WINDOW_INPUT_GRABBED) != 0) &&
if ((pSDLMouse->relative_mode || (pWinData->window->flags & SDL_WINDOW_MOUSE_GRABBED) != 0) &&
((pWinData->window->flags & SDL_WINDOW_INPUT_FOCUS) != 0)) {
/* We will make a real capture in _wmMouseButton() */
} else {
@@ -232,7 +232,7 @@ static VOID _wmMouseMove(WINDATA *pWinData, SHORT lX, SHORT lY)
if (!pSDLMouse->relative_mode || pSDLMouse->relative_mode_warp) {
if (!pSDLMouse->relative_mode && fWinActive &&
((pWinData->window->flags & SDL_WINDOW_INPUT_GRABBED) != 0) &&
((pWinData->window->flags & SDL_WINDOW_MOUSE_GRABBED) != 0) &&
(WinQueryCapture(HWND_DESKTOP) == pWinData->hwnd)) {
pointl.x = lX;
@@ -281,7 +281,7 @@ static VOID _wmMouseButton(WINDATA *pWinData, ULONG ulButton, BOOL fDown)
SDL_BUTTON_MIDDLE };
SDL_Mouse *pSDLMouse = SDL_GetMouse();
if ((pSDLMouse->relative_mode || ((pWinData->window->flags & SDL_WINDOW_INPUT_GRABBED) != 0)) &&
if ((pSDLMouse->relative_mode || ((pWinData->window->flags & SDL_WINDOW_MOUSE_GRABBED) != 0)) &&
((pWinData->window->flags & SDL_WINDOW_INPUT_FOCUS) != 0) &&
(WinQueryCapture(HWND_DESKTOP) != pWinData->hwnd)) {
/* Mouse should be captured. */

View File

@@ -282,7 +282,7 @@ SetupWindowData(_THIS, SDL_Window * window, HWND hwnd, HWND parent, SDL_bool cre
window->flags |= SDL_WINDOW_INPUT_FOCUS;
SDL_SetKeyboardFocus(data->window);
if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
if (window->flags & SDL_WINDOW_MOUSE_GRABBED) {
RECT rect;
GetClientRect(hwnd, &rect);
ClientToScreen(hwnd, (LPPOINT) & rect);
@@ -973,7 +973,7 @@ WIN_UpdateClipCursor(SDL_Window *window)
return;
}
if ((mouse->relative_mode || (window->flags & SDL_WINDOW_INPUT_GRABBED)) &&
if ((mouse->relative_mode || (window->flags & SDL_WINDOW_MOUSE_GRABBED)) &&
(window->flags & SDL_WINDOW_INPUT_FOCUS)) {
if (mouse->relative_mode && !mouse->relative_mode_warp) {
if (GetWindowRect(data->hwnd, &rect)) {

View File

@@ -325,7 +325,7 @@ SetupWindowData(_THIS, SDL_Window * window, Window w, BOOL created)
SDL_SetKeyboardFocus(data->window);
}
if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
if (window->flags & SDL_WINDOW_MOUSE_GRABBED) {
/* Tell x11 to clip mouse */
}
}
@@ -1623,6 +1623,13 @@ X11_SetWindowKeyboardGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
Display *display = data->videodata->display;
if (grabbed) {
/* If the window is unmapped, XGrab calls return GrabNotViewable,
so when we get a MapNotify later, we'll try to update the grab as
appropriate. */
if (window->flags & SDL_WINDOW_HIDDEN) {
return;
}
X11_XGrabKeyboard(display, data->xwindow, True, GrabModeAsync,
GrabModeAsync, CurrentTime);
} else {