From e67485046e22aa6acde6439a61be7cac2b8fb27e Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Wed, 7 Nov 2012 15:55:43 -0800 Subject: [PATCH] SDL no longer grabs the keyboard by default on X11. You can re-enable that functionality by setting a new hint SDL_HINT_GRAB_KEYBOARD --- include/SDL_hints.h | 11 ++++++++ src/video/SDL_sysvideo.h | 3 ++- src/video/SDL_video.c | 23 +++++++++-------- src/video/bwindow/SDL_bwindow.cc | 2 +- src/video/bwindow/SDL_bwindow.h | 2 +- src/video/cocoa/SDL_cocoawindow.h | 2 +- src/video/cocoa/SDL_cocoawindow.m | 5 ++-- src/video/windows/SDL_windowswindow.c | 5 ++-- src/video/windows/SDL_windowswindow.h | 2 +- src/video/x11/SDL_x11window.c | 36 +++++++++++++++++++-------- src/video/x11/SDL_x11window.h | 2 +- 11 files changed, 59 insertions(+), 34 deletions(-) diff --git a/include/SDL_hints.h b/include/SDL_hints.h index d882d3af4..c3a366181 100644 --- a/include/SDL_hints.h +++ b/include/SDL_hints.h @@ -152,6 +152,17 @@ extern "C" { */ #define SDL_HINT_VIDEO_X11_XRANDR "SDL_VIDEO_X11_XRANDR" +/** + * \brief A variable controlling whether grabbing input grabs the keyboard + * + * This variable can be set to the following values: + * "0" - Grab will affect only the mouse + * "1" - Grab will affect mouse and keyboard + * + * By default SDL will not grab the keyboard so system shortcuts still work. + */ +#define SDL_HINT_GRAB_KEYBOARD "SDL_GRAB_KEYBOARD" + /** * \brief A variable controlling whether the idle timer is disabled on iOS. * diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h index f4044e819..5060a358b 100644 --- a/src/video/SDL_sysvideo.h +++ b/src/video/SDL_sysvideo.h @@ -191,7 +191,7 @@ struct SDL_VideoDevice void (*SetWindowFullscreen) (_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen); int (*SetWindowGammaRamp) (_THIS, SDL_Window * window, const Uint16 * ramp); int (*GetWindowGammaRamp) (_THIS, SDL_Window * window, Uint16 * ramp); - void (*SetWindowGrab) (_THIS, SDL_Window * window); + void (*SetWindowGrab) (_THIS, SDL_Window * window, SDL_bool grabbed); void (*DestroyWindow) (_THIS, SDL_Window * window); int (*CreateWindowFramebuffer) (_THIS, SDL_Window * window, Uint32 * format, void ** pixels, int *pitch); int (*UpdateWindowFramebuffer) (_THIS, SDL_Window * window, SDL_Rect * rects, int numrects); @@ -364,6 +364,7 @@ extern void SDL_OnWindowMinimized(SDL_Window * window); extern void SDL_OnWindowRestored(SDL_Window * window); extern void SDL_OnWindowFocusGained(SDL_Window * window); extern void SDL_OnWindowFocusLost(SDL_Window * window); +extern void SDL_UpdateWindowGrab(SDL_Window * window); extern SDL_Window * SDL_GetFocusWindow(void); #endif /* _SDL_sysvideo_h */ diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index b7a07f624..9bb1bf1ff 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -1850,11 +1850,18 @@ SDL_GetWindowGammaRamp(SDL_Window * window, Uint16 * red, return 0; } -static void +void SDL_UpdateWindowGrab(SDL_Window * window) { - if ((window->flags & SDL_WINDOW_INPUT_FOCUS) && _this->SetWindowGrab) { - _this->SetWindowGrab(_this, window); + if (_this->SetWindowGrab) { + SDL_bool grabbed; + if ((window->flags & SDL_WINDOW_INPUT_GRABBED) && + (window->flags & SDL_WINDOW_INPUT_FOCUS)) { + grabbed = SDL_TRUE; + } else { + grabbed = SDL_FALSE; + } + _this->SetWindowGrab(_this, window, grabbed); } } @@ -1924,10 +1931,7 @@ SDL_OnWindowFocusGained(SDL_Window * window) _this->SetWindowGammaRamp(_this, window, window->gamma); } - if ((window->flags & (SDL_WINDOW_INPUT_GRABBED | SDL_WINDOW_FULLSCREEN)) && - _this->SetWindowGrab) { - _this->SetWindowGrab(_this, window); - } + SDL_UpdateWindowGrab(window); } void @@ -1937,10 +1941,7 @@ SDL_OnWindowFocusLost(SDL_Window * window) _this->SetWindowGammaRamp(_this, window, window->saved_gamma); } - if ((window->flags & (SDL_WINDOW_INPUT_GRABBED | SDL_WINDOW_FULLSCREEN)) && - _this->SetWindowGrab) { - _this->SetWindowGrab(_this, window); - } + SDL_UpdateWindowGrab(window); /* If we're fullscreen on a single-head system and lose focus, minimize */ if ((window->flags & SDL_WINDOW_FULLSCREEN) && _this->num_displays == 1) { diff --git a/src/video/bwindow/SDL_bwindow.cc b/src/video/bwindow/SDL_bwindow.cc index 47f9316c0..bc3ae0167 100644 --- a/src/video/bwindow/SDL_bwindow.cc +++ b/src/video/bwindow/SDL_bwindow.cc @@ -195,7 +195,7 @@ int BE_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp) { } -void BE_SetWindowGrab(_THIS, SDL_Window * window) { +void BE_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed) { /* TODO: Implement this! */ } diff --git a/src/video/bwindow/SDL_bwindow.h b/src/video/bwindow/SDL_bwindow.h index 26b33aacc..a5c992eca 100644 --- a/src/video/bwindow/SDL_bwindow.h +++ b/src/video/bwindow/SDL_bwindow.h @@ -42,7 +42,7 @@ extern void BE_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered); extern void BE_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen); extern int BE_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp); extern int BE_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp); -extern void BE_SetWindowGrab(_THIS, SDL_Window * window); +extern void BE_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed); extern void BE_DestroyWindow(_THIS, SDL_Window * window); extern SDL_bool BE_GetWindowWMInfo(_THIS, SDL_Window * window, struct SDL_SysWMinfo *info); diff --git a/src/video/cocoa/SDL_cocoawindow.h b/src/video/cocoa/SDL_cocoawindow.h index cc9fcf1ba..427356149 100644 --- a/src/video/cocoa/SDL_cocoawindow.h +++ b/src/video/cocoa/SDL_cocoawindow.h @@ -106,7 +106,7 @@ extern void Cocoa_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordere extern void Cocoa_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen); extern int Cocoa_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp); extern int Cocoa_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp); -extern void Cocoa_SetWindowGrab(_THIS, SDL_Window * window); +extern void Cocoa_SetWindowGrab(_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); diff --git a/src/video/cocoa/SDL_cocoawindow.m b/src/video/cocoa/SDL_cocoawindow.m index 274c456da..2d9b5a957 100644 --- a/src/video/cocoa/SDL_cocoawindow.m +++ b/src/video/cocoa/SDL_cocoawindow.m @@ -992,11 +992,10 @@ - (void)rightMouseDown:(NSEvent *)theEvent } void -Cocoa_SetWindowGrab(_THIS, SDL_Window * window) +Cocoa_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed) { /* Move the cursor to the nearest point in the window */ - if ((window->flags & SDL_WINDOW_INPUT_GRABBED) && - (window->flags & SDL_WINDOW_INPUT_FOCUS)) { + if (grabbed) { int x, y; CGPoint cgpoint; diff --git a/src/video/windows/SDL_windowswindow.c b/src/video/windows/SDL_windowswindow.c index 38902ac80..bb6a786a9 100644 --- a/src/video/windows/SDL_windowswindow.c +++ b/src/video/windows/SDL_windowswindow.c @@ -538,12 +538,11 @@ WIN_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp) } void -WIN_SetWindowGrab(_THIS, SDL_Window * window) +WIN_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed) { HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd; - if ((window->flags & SDL_WINDOW_INPUT_GRABBED) && - (window->flags & SDL_WINDOW_INPUT_FOCUS)) { + if (grabbed) { RECT rect; GetClientRect(hwnd, &rect); ClientToScreen(hwnd, (LPPOINT) & rect); diff --git a/src/video/windows/SDL_windowswindow.h b/src/video/windows/SDL_windowswindow.h index f02efb689..542f6ea65 100644 --- a/src/video/windows/SDL_windowswindow.h +++ b/src/video/windows/SDL_windowswindow.h @@ -52,7 +52,7 @@ extern void WIN_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered) extern void WIN_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen); extern int WIN_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp); extern int WIN_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp); -extern void WIN_SetWindowGrab(_THIS, SDL_Window * window); +extern void WIN_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed); extern void WIN_DestroyWindow(_THIS, SDL_Window * window); extern SDL_bool WIN_GetWindowWMInfo(_THIS, SDL_Window * window, struct SDL_SysWMinfo *info); diff --git a/src/video/x11/SDL_x11window.c b/src/video/x11/SDL_x11window.c index 2c883a573..308768c85 100644 --- a/src/video/x11/SDL_x11window.c +++ b/src/video/x11/SDL_x11window.c @@ -22,6 +22,7 @@ #if SDL_VIDEO_DRIVER_X11 +#include "SDL_hints.h" #include "../SDL_sysvideo.h" #include "../SDL_pixels_c.h" #include "../../events/SDL_keyboard_c.h" @@ -1089,7 +1090,7 @@ X11_BeginWindowFullscreenLegacy(_THIS, SDL_Window * window, SDL_VideoDisplay * _ XIfEvent(display, &ev, &isMapNotify, (XPointer)&data->xwindow); XCheckIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->xwindow); - X11_SetWindowGrab(_this, window); + SDL_UpdateWindowGrab(window); } static void @@ -1115,7 +1116,7 @@ X11_EndWindowFullscreenLegacy(_THIS, SDL_Window * window, SDL_VideoDisplay * _di } #endif - X11_SetWindowGrab(_this, window); + SDL_UpdateWindowGrab(window); XReparentWindow(display, data->xwindow, root, window->x, window->y); @@ -1238,19 +1239,21 @@ X11_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp) } void -X11_SetWindowGrab(_THIS, SDL_Window * window) +X11_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed) { SDL_WindowData *data = (SDL_WindowData *) window->driverdata; Display *display = data->videodata->display; SDL_bool oldstyle_fullscreen; + SDL_bool grab_keyboard; + const char *hint; - /* ICCCM2.0-compliant window managers can handle fullscreen windows */ + /* ICCCM2.0-compliant window managers can handle fullscreen windows + If we're using XVidMode to change resolution we need to confine + the cursor so we don't pan around the virtual desktop. + */ oldstyle_fullscreen = X11_IsWindowLegacyFullscreen(_this, window); - if (oldstyle_fullscreen || - ((window->flags & SDL_WINDOW_INPUT_GRABBED) && - (window->flags & SDL_WINDOW_INPUT_FOCUS))) { - + if (oldstyle_fullscreen || grabbed) { /* Try to grab the mouse */ for (;;) { int result = @@ -1259,15 +1262,26 @@ X11_SetWindowGrab(_THIS, SDL_Window * window) if (result == GrabSuccess) { break; } - SDL_Delay(100); + SDL_Delay(50); } /* Raise the window if we grab the mouse */ XRaiseWindow(display, data->xwindow); /* Now grab the keyboard */ - XGrabKeyboard(display, data->xwindow, True, GrabModeAsync, - GrabModeAsync, CurrentTime); + hint = SDL_GetHint(SDL_HINT_GRAB_KEYBOARD); + if (hint && SDL_atoi(hint)) { + grab_keyboard = SDL_TRUE; + } else { + /* We need to do this with the old style override_redirect + fullscreen window otherwise we won't get keyboard focus. + */ + grab_keyboard = oldstyle_fullscreen; + } + if (grab_keyboard) { + XGrabKeyboard(display, data->xwindow, True, GrabModeAsync, + GrabModeAsync, CurrentTime); + } } else { XUngrabPointer(display, CurrentTime); XUngrabKeyboard(display, CurrentTime); diff --git a/src/video/x11/SDL_x11window.h b/src/video/x11/SDL_x11window.h index b13895ef0..d65e08127 100644 --- a/src/video/x11/SDL_x11window.h +++ b/src/video/x11/SDL_x11window.h @@ -78,7 +78,7 @@ extern void X11_RestoreWindow(_THIS, SDL_Window * window); extern void X11_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered); extern void X11_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen); extern int X11_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp); -extern void X11_SetWindowGrab(_THIS, SDL_Window * window); +extern void X11_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed); extern void X11_DestroyWindow(_THIS, SDL_Window * window); extern SDL_bool X11_GetWindowWMInfo(_THIS, SDL_Window * window, struct SDL_SysWMinfo *info);