diff --git a/include/SDL_video.h b/include/SDL_video.h index 2f684beaa..0860ea04b 100644 --- a/include/SDL_video.h +++ b/include/SDL_video.h @@ -68,6 +68,8 @@ typedef struct * \sa SDL_GetWindowData() * \sa SDL_GetWindowFlags() * \sa SDL_GetWindowGrab() + * \sa SDL_GetWindowKeyboardGrab() + * \sa SDL_GetWindowMouseGrab() * \sa SDL_GetWindowPosition() * \sa SDL_GetWindowSize() * \sa SDL_GetWindowTitle() @@ -79,6 +81,8 @@ typedef struct * \sa SDL_SetWindowData() * \sa SDL_SetWindowFullscreen() * \sa SDL_SetWindowGrab() + * \sa SDL_SetWindowKeyboardGrab() + * \sa SDL_SetWindowMouseGrab() * \sa SDL_SetWindowIcon() * \sa SDL_SetWindowPosition() * \sa SDL_SetWindowSize() @@ -104,7 +108,7 @@ typedef enum SDL_WINDOW_RESIZABLE = 0x00000020, /**< window can be resized */ SDL_WINDOW_MINIMIZED = 0x00000040, /**< window is minimized */ SDL_WINDOW_MAXIMIZED = 0x00000080, /**< window is maximized */ - SDL_WINDOW_INPUT_GRABBED = 0x00000100, /**< window has grabbed input focus */ + SDL_WINDOW_MOUSE_GRABBED = 0x00000100, /**< window has grabbed mouse input */ SDL_WINDOW_INPUT_FOCUS = 0x00000200, /**< window has input focus */ SDL_WINDOW_MOUSE_FOCUS = 0x00000400, /**< window has mouse focus */ SDL_WINDOW_FULLSCREEN_DESKTOP = ( SDL_WINDOW_FULLSCREEN | 0x00001000 ), @@ -112,14 +116,17 @@ typedef enum SDL_WINDOW_ALLOW_HIGHDPI = 0x00002000, /**< window should be created in high-DPI mode if supported. On macOS NSHighResolutionCapable must be set true in the application's Info.plist for this to have any effect. */ - SDL_WINDOW_MOUSE_CAPTURE = 0x00004000, /**< window has mouse captured (unrelated to INPUT_GRABBED) */ - SDL_WINDOW_ALWAYS_ON_TOP = 0x00008000, /**< window should always be above others */ - SDL_WINDOW_SKIP_TASKBAR = 0x00010000, /**< window should not be added to the taskbar */ - SDL_WINDOW_UTILITY = 0x00020000, /**< window should be treated as a utility window */ - SDL_WINDOW_TOOLTIP = 0x00040000, /**< window should be treated as a tooltip */ - SDL_WINDOW_POPUP_MENU = 0x00080000, /**< window should be treated as a popup menu */ - SDL_WINDOW_VULKAN = 0x10000000, /**< window usable for Vulkan surface */ - SDL_WINDOW_METAL = 0x20000000 /**< window usable for Metal view */ + SDL_WINDOW_MOUSE_CAPTURE = 0x00004000, /**< window has mouse captured (unrelated to MOUSE_GRABBED) */ + SDL_WINDOW_ALWAYS_ON_TOP = 0x00008000, /**< window should always be above others */ + SDL_WINDOW_SKIP_TASKBAR = 0x00010000, /**< window should not be added to the taskbar */ + SDL_WINDOW_UTILITY = 0x00020000, /**< window should be treated as a utility window */ + SDL_WINDOW_TOOLTIP = 0x00040000, /**< window should be treated as a tooltip */ + SDL_WINDOW_POPUP_MENU = 0x00080000, /**< window should be treated as a popup menu */ + SDL_WINDOW_KEYBOARD_GRABBED = 0x00100000, /**< window has grabbed keyboard input */ + SDL_WINDOW_VULKAN = 0x10000000, /**< window usable for Vulkan surface */ + SDL_WINDOW_METAL = 0x20000000, /**< window usable for Metal view */ + + SDL_WINDOW_INPUT_GRABBED = SDL_WINDOW_MOUSE_GRABBED /**< equivalent to SDL_WINDOW_MOUSE_GRABBED for compatibility */ } SDL_WindowFlags; /** @@ -486,9 +493,9 @@ extern DECLSPEC Uint32 SDLCALL SDL_GetWindowPixelFormat(SDL_Window * window); * ::SDL_WINDOW_FULLSCREEN, ::SDL_WINDOW_OPENGL, * ::SDL_WINDOW_HIDDEN, ::SDL_WINDOW_BORDERLESS, * ::SDL_WINDOW_RESIZABLE, ::SDL_WINDOW_MAXIMIZED, - * ::SDL_WINDOW_MINIMIZED, ::SDL_WINDOW_INPUT_GRABBED, - * ::SDL_WINDOW_ALLOW_HIGHDPI, ::SDL_WINDOW_VULKAN - * ::SDL_WINDOW_METAL. + * ::SDL_WINDOW_MINIMIZED, ::SDL_WINDOW_MOUSE_GRABBED, + * ::SDL_WINDOW_ALLOW_HIGHDPI, ::SDL_WINDOW_KEYBOARD_GRABBED, + * ::SDL_WINDOW_VULKAN, ::SDL_WINDOW_METAL. * * \return The created window, or NULL if window creation failed. * @@ -881,20 +888,78 @@ extern DECLSPEC int SDLCALL SDL_UpdateWindowSurfaceRects(SDL_Window * window, * If the caller enables a grab while another window is currently grabbed, * the other window loses its grab in favor of the caller's window. * + * If SDL_HINT_GRAB_KEYBOARD=1, this also grabs keyboard input. + * * \sa SDL_GetWindowGrab() + * \sa SDL_SetWindowKeyboardGrab() + * \sa SDL_SetWindowMouseGrab() */ extern DECLSPEC void SDLCALL SDL_SetWindowGrab(SDL_Window * window, SDL_bool grabbed); /** - * \brief Get a window's input grab mode. + * \brief Set a window's keyboard grab mode. * - * \return This returns SDL_TRUE if input is grabbed, and SDL_FALSE otherwise. + * \param window The window for which the keyboard grab mode should be set. + * \param grabbed This is SDL_TRUE to grab keyboard, and SDL_FALSE to release keyboard grab. * + * If the caller enables a grab while another window is currently grabbed, + * the other window loses its grab in favor of the caller's window. + * + * \sa SDL_GetWindowKeyboardGrab() + * \sa SDL_SetWindowMouseGrab() * \sa SDL_SetWindowGrab() */ +extern DECLSPEC void SDLCALL SDL_SetWindowKeyboardGrab(SDL_Window * window, + SDL_bool grabbed); + +/** + * \brief Set a window's mouse grab mode. + * + * \param window The window for which the mouse grab mode should be set. + * \param grabbed This is SDL_TRUE to grab mouse, and SDL_FALSE to release mouse grab. + * + * If the caller enables a grab while another window is currently grabbed, + * the other window loses its grab in favor of the caller's window. + * + * \sa SDL_GetWindowMouseGrab() + * \sa SDL_SetWindowKeyboardGrab() + * \sa SDL_SetWindowGrab() + */ +extern DECLSPEC void SDLCALL SDL_SetWindowMouseGrab(SDL_Window * window, + SDL_bool grabbed); + +/** + * \brief Get a window's input grab mode. + * + * \return This returns SDL_TRUE if keyboard or mouse input is grabbed, and SDL_FALSE otherwise. + * + * \sa SDL_SetWindowGrab() + * \sa SDL_GetWindowMouseGrab() + * \sa SDL_GetWindowKeyboardGrab() + */ extern DECLSPEC SDL_bool SDLCALL SDL_GetWindowGrab(SDL_Window * window); +/** + * \brief Get a window's keyboard grab mode. + * + * \return This returns SDL_TRUE if keyboard is grabbed, and SDL_FALSE otherwise. + * + * \sa SDL_SetWindowKeyboardGrab() + * \sa SDL_GetWindowGrab() + */ +extern DECLSPEC SDL_bool SDLCALL SDL_GetWindowKeyboardGrab(SDL_Window * window); + +/** + * \brief Get a window's mouse grab mode. + * + * \return This returns SDL_TRUE if mouse is grabbed, and SDL_FALSE otherwise. + * + * \sa SDL_SetWindowKeyboardGrab() + * \sa SDL_GetWindowGrab() + */ +extern DECLSPEC SDL_bool SDLCALL SDL_GetWindowMouseGrab(SDL_Window * window); + /** * \brief Get the window that currently has an input grab enabled. * diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index e6d682deb..bb592c07b 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -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 diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index ce1ce72c8..b461985ff 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -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) diff --git a/src/test/SDL_test_common.c b/src/test/SDL_test_common.c index 13bec3a74..3384a82a3 100644 --- a/src/test/SDL_test_common.c +++ b/src/test/SDL_test_common.c @@ -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 */ diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index 7c5b8191a..d750a356c 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -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; } diff --git a/src/video/cocoa/SDL_cocoamousetap.m b/src/video/cocoa/SDL_cocoamousetap.m index 503a524e7..f1ed18a23 100644 --- a/src/video/cocoa/SDL_cocoamousetap.m +++ b/src/video/cocoa/SDL_cocoamousetap.m @@ -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; } diff --git a/src/video/cocoa/SDL_cocoawindow.m b/src/video/cocoa/SDL_cocoawindow.m index f27c1f61c..802cb3abe 100644 --- a/src/video/cocoa/SDL_cocoawindow.m +++ b/src/video/cocoa/SDL_cocoawindow.m @@ -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; diff --git a/src/video/directfb/SDL_DirectFB_events.c b/src/video/directfb/SDL_DirectFB_events.c index 1d4c19906..146bb99ea 100644 --- a/src/video/directfb/SDL_DirectFB_events.c +++ b/src/video/directfb/SDL_DirectFB_events.c @@ -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 { diff --git a/src/video/os2/SDL_os2video.c b/src/video/os2/SDL_os2video.c index 5ae2c71a5..0ec0f1e61 100644 --- a/src/video/os2/SDL_os2video.c +++ b/src/video/os2/SDL_os2video.c @@ -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. */ diff --git a/src/video/windows/SDL_windowswindow.c b/src/video/windows/SDL_windowswindow.c index c8b57cdf7..6eb26ebc7 100644 --- a/src/video/windows/SDL_windowswindow.c +++ b/src/video/windows/SDL_windowswindow.c @@ -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)) { diff --git a/src/video/x11/SDL_x11window.c b/src/video/x11/SDL_x11window.c index dbe114f6e..3b090f7d5 100644 --- a/src/video/x11/SDL_x11window.c +++ b/src/video/x11/SDL_x11window.c @@ -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 { diff --git a/test/testautomation_video.c b/test/testautomation_video.c index 7b86cfba9..bd59e8edd 100644 --- a/test/testautomation_video.c +++ b/test/testautomation_video.c @@ -265,7 +265,7 @@ video_createWindowVariousFlags(void *arg) w = SDLTest_RandomIntegerInRange(320, 1024); h = SDLTest_RandomIntegerInRange(320, 768); - for (fVariation = 0; fVariation < 13; fVariation++) { + for (fVariation = 0; fVariation < 14; fVariation++) { switch(fVariation) { case 0: flags = SDL_WINDOW_FULLSCREEN; @@ -299,7 +299,7 @@ video_createWindowVariousFlags(void *arg) flags = SDL_WINDOW_MAXIMIZED; break; case 9: - flags = SDL_WINDOW_INPUT_GRABBED; + flags = SDL_WINDOW_MOUSE_GRABBED; break; case 10: flags = SDL_WINDOW_INPUT_FOCUS; @@ -310,6 +310,9 @@ video_createWindowVariousFlags(void *arg) case 12: flags = SDL_WINDOW_FOREIGN; break; + case 13: + flags = SDL_WINDOW_KEYBOARD_GRABBED; + break; } window = SDL_CreateWindow(title, x, y, w, h, flags); @@ -744,87 +747,213 @@ video_getWindowGammaRampNegative(void *arg) return TEST_COMPLETED; } -/* Helper for setting and checking the window grab state */ +/* Helper for setting and checking the window mouse grab state */ void -_setAndCheckWindowGrabState(SDL_Window* window, SDL_bool desiredState) +_setAndCheckWindowMouseGrabState(SDL_Window* window, SDL_bool desiredState) { SDL_bool currentState; /* Set state */ - SDL_SetWindowGrab(window, desiredState); - SDLTest_AssertPass("Call to SDL_SetWindowGrab(%s)", (desiredState == SDL_FALSE) ? "SDL_FALSE" : "SDL_TRUE"); + SDL_SetWindowMouseGrab(window, desiredState); + SDLTest_AssertPass("Call to SDL_SetWindowMouseGrab(%s)", (desiredState == SDL_FALSE) ? "SDL_FALSE" : "SDL_TRUE"); /* Get and check state */ - currentState = SDL_GetWindowGrab(window); - SDLTest_AssertPass("Call to SDL_GetWindowGrab()"); + currentState = SDL_GetWindowMouseGrab(window); + SDLTest_AssertPass("Call to SDL_GetWindowMouseGrab()"); SDLTest_AssertCheck( currentState == desiredState, "Validate returned state; expected: %s, got: %s", (desiredState == SDL_FALSE) ? "SDL_FALSE" : "SDL_TRUE", (currentState == SDL_FALSE) ? "SDL_FALSE" : "SDL_TRUE"); + + if (desiredState) { + SDLTest_AssertCheck( + SDL_GetGrabbedWindow() == window, + "Grabbed window should be to our window"); + SDLTest_AssertCheck( + SDL_GetWindowGrab(window), + "SDL_GetWindowGrab() should return SDL_TRUE"); + SDLTest_AssertCheck( + SDL_GetWindowFlags(window) & SDL_WINDOW_MOUSE_GRABBED, + "SDL_WINDOW_MOUSE_GRABBED should be set"); + } else { + SDLTest_AssertCheck( + !(SDL_GetWindowFlags(window) & SDL_WINDOW_MOUSE_GRABBED), + "SDL_WINDOW_MOUSE_GRABBED should be unset"); + } +} + +/* Helper for setting and checking the window keyboard grab state */ +void +_setAndCheckWindowKeyboardGrabState(SDL_Window* window, SDL_bool desiredState) +{ + SDL_bool currentState; + + /* Set state */ + SDL_SetWindowKeyboardGrab(window, desiredState); + SDLTest_AssertPass("Call to SDL_SetWindowKeyboardGrab(%s)", (desiredState == SDL_FALSE) ? "SDL_FALSE" : "SDL_TRUE"); + + /* Get and check state */ + currentState = SDL_GetWindowKeyboardGrab(window); + SDLTest_AssertPass("Call to SDL_GetWindowKeyboardGrab()"); + SDLTest_AssertCheck( + currentState == desiredState, + "Validate returned state; expected: %s, got: %s", + (desiredState == SDL_FALSE) ? "SDL_FALSE" : "SDL_TRUE", + (currentState == SDL_FALSE) ? "SDL_FALSE" : "SDL_TRUE"); + + if (desiredState) { + SDLTest_AssertCheck( + SDL_GetGrabbedWindow() == window, + "Grabbed window should be set to our window"); + SDLTest_AssertCheck( + SDL_GetWindowGrab(window), + "SDL_GetWindowGrab() should return SDL_TRUE"); + SDLTest_AssertCheck( + SDL_GetWindowFlags(window) & SDL_WINDOW_KEYBOARD_GRABBED, + "SDL_WINDOW_KEYBOARD_GRABBED should be set"); + } else { + SDLTest_AssertCheck( + !(SDL_GetWindowFlags(window) & SDL_WINDOW_KEYBOARD_GRABBED), + "SDL_WINDOW_KEYBOARD_GRABBED should be unset"); + } } /** - * @brief Tests call to SDL_GetWindowGrab and SDL_SetWindowGrab + * @brief Tests keyboard and mouse grab support * - * @sa http://wiki.libsdl.org/moin.fcg/SDL_GetWindowGrab - * @sa http://wiki.libsdl.org/moin.fcg/SDL_SetWindowGrab + * @sa http://wiki.libsdl.org/SDL_GetWindowGrab + * @sa http://wiki.libsdl.org/SDL_SetWindowGrab */ int video_getSetWindowGrab(void *arg) { const char* title = "video_getSetWindowGrab Test Window"; SDL_Window* window; - SDL_bool originalState, dummyState, currentState, desiredState; + SDL_bool originalMouseState, originalKeyboardState, dummyState; /* Call against new test window */ window = _createVideoSuiteTestWindow(title); if (window == NULL) return TEST_ABORTED; /* Get state */ - originalState = SDL_GetWindowGrab(window); - SDLTest_AssertPass("Call to SDL_GetWindowGrab()"); + originalMouseState = SDL_GetWindowMouseGrab(window); + SDLTest_AssertPass("Call to SDL_GetWindowMouseGrab()"); + originalKeyboardState = SDL_GetWindowKeyboardGrab(window); + SDLTest_AssertPass("Call to SDL_GetWindowKeyboardGrab()"); /* F */ - _setAndCheckWindowGrabState(window, SDL_FALSE); + _setAndCheckWindowKeyboardGrabState(window, SDL_FALSE); + _setAndCheckWindowMouseGrabState(window, SDL_FALSE); + SDLTest_AssertCheck(!SDL_GetWindowGrab(window), + "SDL_GetWindowGrab should return SDL_FALSE"); + SDLTest_AssertCheck(SDL_GetGrabbedWindow() == NULL, + "Expected NULL grabbed window"); /* F --> F */ - _setAndCheckWindowGrabState(window, SDL_FALSE); + _setAndCheckWindowMouseGrabState(window, SDL_FALSE); + _setAndCheckWindowKeyboardGrabState(window, SDL_FALSE); + SDLTest_AssertCheck(SDL_GetGrabbedWindow() == NULL, + "Expected NULL grabbed window"); /* F --> T */ - _setAndCheckWindowGrabState(window, SDL_TRUE); + _setAndCheckWindowMouseGrabState(window, SDL_TRUE); + _setAndCheckWindowKeyboardGrabState(window, SDL_TRUE); + SDLTest_AssertCheck(SDL_GetWindowGrab(window), + "SDL_GetWindowGrab() should return SDL_TRUE"); /* T --> T */ - _setAndCheckWindowGrabState(window, SDL_TRUE); + _setAndCheckWindowKeyboardGrabState(window, SDL_TRUE); + _setAndCheckWindowMouseGrabState(window, SDL_TRUE); + SDLTest_AssertCheck(SDL_GetWindowGrab(window), + "SDL_GetWindowGrab() should return SDL_TRUE"); - /* T --> F */ - _setAndCheckWindowGrabState(window, SDL_FALSE); + /* M: T --> F */ + /* K: T --> T */ + _setAndCheckWindowKeyboardGrabState(window, SDL_TRUE); + _setAndCheckWindowMouseGrabState(window, SDL_FALSE); + SDLTest_AssertCheck(SDL_GetWindowGrab(window), + "SDL_GetWindowGrab() should return SDL_TRUE"); + + /* M: F --> T */ + /* K: T --> F */ + _setAndCheckWindowMouseGrabState(window, SDL_TRUE); + _setAndCheckWindowKeyboardGrabState(window, SDL_FALSE); + SDLTest_AssertCheck(SDL_GetWindowGrab(window), + "SDL_GetWindowGrab() should return SDL_TRUE"); + + /* M: T --> F */ + /* K: F --> F */ + _setAndCheckWindowMouseGrabState(window, SDL_FALSE); + _setAndCheckWindowKeyboardGrabState(window, SDL_FALSE); + SDLTest_AssertCheck(!SDL_GetWindowGrab(window), + "SDL_GetWindowGrab() should return SDL_FALSE"); + SDLTest_AssertCheck(SDL_GetGrabbedWindow() == NULL, + "Expected NULL grabbed window"); + + /* Using the older SDL_SetWindowGrab API should only grab mouse by default */ + SDL_SetWindowGrab(window, SDL_TRUE); + SDLTest_AssertPass("Call to SDL_SetWindowGrab(SDL_TRUE)"); + SDLTest_AssertCheck(SDL_GetWindowGrab(window), + "SDL_GetWindowGrab() should return SDL_TRUE"); + SDLTest_AssertCheck(SDL_GetWindowMouseGrab(window), + "SDL_GetWindowMouseGrab() should return SDL_TRUE"); + SDLTest_AssertCheck(!SDL_GetWindowKeyboardGrab(window), + "SDL_GetWindowKeyboardGrab() should return SDL_FALSE"); + SDL_SetWindowGrab(window, SDL_FALSE); + SDLTest_AssertCheck(!SDL_GetWindowGrab(window), + "SDL_GetWindowGrab() should return SDL_FALSE"); + SDLTest_AssertCheck(!SDL_GetWindowMouseGrab(window), + "SDL_GetWindowMouseGrab() should return SDL_FALSE"); + SDLTest_AssertCheck(!SDL_GetWindowKeyboardGrab(window), + "SDL_GetWindowKeyboardGrab() should return SDL_FALSE"); + + /* Now test with SDL_HINT_GRAB_KEYBOARD set. We should get keyboard grab now. */ + SDL_SetHint(SDL_HINT_GRAB_KEYBOARD, "1"); + SDL_SetWindowGrab(window, SDL_TRUE); + SDLTest_AssertPass("Call to SDL_SetWindowGrab(SDL_TRUE)"); + SDLTest_AssertCheck(SDL_GetWindowGrab(window), + "SDL_GetWindowGrab() should return SDL_TRUE"); + SDLTest_AssertCheck(SDL_GetWindowMouseGrab(window), + "SDL_GetWindowMouseGrab() should return SDL_TRUE"); + SDLTest_AssertCheck(SDL_GetWindowKeyboardGrab(window), + "SDL_GetWindowKeyboardGrab() should return SDL_TRUE"); + SDL_SetWindowGrab(window, SDL_FALSE); + SDLTest_AssertCheck(!SDL_GetWindowGrab(window), + "SDL_GetWindowGrab() should return SDL_FALSE"); + SDLTest_AssertCheck(!SDL_GetWindowMouseGrab(window), + "SDL_GetWindowMouseGrab() should return SDL_FALSE"); + SDLTest_AssertCheck(!SDL_GetWindowKeyboardGrab(window), + "SDL_GetWindowKeyboardGrab() should return SDL_FALSE"); /* Negative tests */ dummyState = SDL_GetWindowGrab(NULL); SDLTest_AssertPass("Call to SDL_GetWindowGrab(window=NULL)"); _checkInvalidWindowError(); + dummyState = SDL_GetWindowKeyboardGrab(NULL); + SDLTest_AssertPass("Call to SDL_GetWindowKeyboardGrab(window=NULL)"); + _checkInvalidWindowError(); + SDL_SetWindowGrab(NULL, SDL_FALSE); SDLTest_AssertPass("Call to SDL_SetWindowGrab(window=NULL,SDL_FALSE)"); _checkInvalidWindowError(); - SDL_SetWindowGrab(NULL, SDL_TRUE); - SDLTest_AssertPass("Call to SDL_SetWindowGrab(window=NULL,SDL_FALSE)"); + SDL_SetWindowKeyboardGrab(NULL, SDL_FALSE); + SDLTest_AssertPass("Call to SDL_SetWindowKeyboardGrab(window=NULL,SDL_FALSE)"); _checkInvalidWindowError(); - /* State should still be F */ - desiredState = SDL_FALSE; - currentState = SDL_GetWindowGrab(window); - SDLTest_AssertPass("Call to SDL_GetWindowGrab()"); - SDLTest_AssertCheck( - currentState == desiredState, - "Validate returned state; expected: %s, got: %s", - (desiredState == SDL_FALSE) ? "SDL_FALSE" : "SDL_TRUE", - (currentState == SDL_FALSE) ? "SDL_FALSE" : "SDL_TRUE"); + SDL_SetWindowGrab(NULL, SDL_TRUE); + SDLTest_AssertPass("Call to SDL_SetWindowGrab(window=NULL,SDL_TRUE)"); + _checkInvalidWindowError(); + + SDL_SetWindowKeyboardGrab(NULL, SDL_TRUE); + SDLTest_AssertPass("Call to SDL_SetWindowKeyboardGrab(window=NULL,SDL_TRUE)"); + _checkInvalidWindowError(); /* Restore state */ - _setAndCheckWindowGrabState(window, originalState); + _setAndCheckWindowMouseGrabState(window, originalMouseState); + _setAndCheckWindowKeyboardGrabState(window, originalKeyboardState); /* Clean up */ _destroyVideoSuiteTestWindow(window);