diff --git a/include/SDL_hints.h b/include/SDL_hints.h index 25383b1a7..140d37d7f 100644 --- a/include/SDL_hints.h +++ b/include/SDL_hints.h @@ -933,6 +933,22 @@ extern "C" { */ #define SDL_HINT_MOUSE_NORMAL_SPEED_SCALE "SDL_MOUSE_NORMAL_SPEED_SCALE" +/** + * \brief A variable controlling whether relative mouse mode constrains the mouse to the center of the window + * + * This variable can be set to the following values: + * "0" - Relative mouse mode constrains the mouse to the window + * "1" - Relative mouse mode constrains the mouse to the center of the window + * + * Constraining to the center of the window works better for FPS games and when the + * application is running over RDP. Constraining to the whole window works better + * for 2D games and increases the chance that the mouse will be in the correct + * position when using high DPI mice. + * + * By default SDL will constrain the mouse to the center of the window + */ +#define SDL_HINT_MOUSE_RELATIVE_MODE_CENTER "SDL_MOUSE_RELATIVE_MODE_CENTER" + /** * \brief A variable controlling whether relative mouse mode is implemented using mouse warping * diff --git a/src/video/windows/SDL_windowswindow.c b/src/video/windows/SDL_windowswindow.c index ccf492025..890d790ea 100644 --- a/src/video/windows/SDL_windowswindow.c +++ b/src/video/windows/SDL_windowswindow.c @@ -28,6 +28,7 @@ #include "../SDL_pixels_c.h" #include "../../events/SDL_keyboard_c.h" #include "../../events/SDL_mouse_c.h" +#include "../../SDL_hints_c.h" #include "SDL_windowsvideo.h" #include "SDL_windowswindow.h" @@ -170,6 +171,13 @@ WIN_SetWindowPositionInternal(_THIS, SDL_Window * window, UINT flags) data->expected_resize = SDL_FALSE; } +static void SDLCALL +WIN_MouseRelativeModeCenterChanged(void *userdata, const char *name, const char *oldValue, const char *hint) +{ + SDL_WindowData *data = (SDL_WindowData *)userdata; + data->mouse_relative_mode_center = SDL_GetStringBoolean(hint, SDL_TRUE); +} + static int SetupWindowData(_THIS, SDL_Window * window, HWND hwnd, HWND parent, SDL_bool created) { @@ -193,6 +201,8 @@ SetupWindowData(_THIS, SDL_Window * window, HWND hwnd, HWND parent, SDL_bool cre data->videodata = videodata; data->initializing = SDL_TRUE; + SDL_AddHintCallback(SDL_HINT_MOUSE_RELATIVE_MODE_CENTER, WIN_MouseRelativeModeCenterChanged, data); + window->driverdata = data; /* Associate the data with the window */ @@ -297,7 +307,39 @@ SetupWindowData(_THIS, SDL_Window * window, HWND hwnd, HWND parent, SDL_bool cre return 0; } +static void CleanupWindowData(_THIS, SDL_Window * window) +{ + SDL_WindowData *data = (SDL_WindowData *) window->driverdata; + if (data) { + SDL_DelHintCallback(SDL_HINT_MOUSE_RELATIVE_MODE_CENTER, WIN_MouseRelativeModeCenterChanged, data); + + if (data->keyboard_hook) { + UnhookWindowsHookEx(data->keyboard_hook); + } + ReleaseDC(data->hwnd, data->hdc); + RemoveProp(data->hwnd, TEXT("SDL_WindowData")); + if (data->created) { + DestroyWindow(data->hwnd); + if (data->parent) { + DestroyWindow(data->parent); + } + } else { + /* Restore any original event handler... */ + if (data->wndproc != NULL) { +#ifdef GWLP_WNDPROC + SetWindowLongPtr(data->hwnd, GWLP_WNDPROC, + (LONG_PTR) data->wndproc); +#else + SetWindowLong(data->hwnd, GWL_WNDPROC, + (LONG_PTR) data->wndproc); +#endif + } + } + SDL_free(data); + } + window->driverdata = NULL; +} int WIN_CreateWindow(_THIS, SDL_Window * window) @@ -873,34 +915,7 @@ WIN_SetWindowKeyboardGrab(_THIS, SDL_Window * window, SDL_bool grabbed) void WIN_DestroyWindow(_THIS, SDL_Window * window) { - SDL_WindowData *data = (SDL_WindowData *) window->driverdata; - - if (data) { - if (data->keyboard_hook) { - UnhookWindowsHookEx(data->keyboard_hook); - } - ReleaseDC(data->hwnd, data->hdc); - RemoveProp(data->hwnd, TEXT("SDL_WindowData")); - if (data->created) { - DestroyWindow(data->hwnd); - if (data->parent) { - DestroyWindow(data->parent); - } - } else { - /* Restore any original event handler... */ - if (data->wndproc != NULL) { -#ifdef GWLP_WNDPROC - SetWindowLongPtr(data->hwnd, GWLP_WNDPROC, - (LONG_PTR) data->wndproc); -#else - SetWindowLong(data->hwnd, GWL_WNDPROC, - (LONG_PTR) data->wndproc); -#endif - } - } - SDL_free(data); - } - window->driverdata = NULL; + CleanupWindowData(_this, window); } SDL_bool @@ -1032,7 +1047,7 @@ WIN_UpdateClipCursor(SDL_Window *window) if ((mouse->relative_mode || (window->flags & SDL_WINDOW_MOUSE_GRABBED) || (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 (mouse->relative_mode && !mouse->relative_mode_warp && data->mouse_relative_mode_center) { if (GetWindowRect(data->hwnd, &rect)) { LONG cx, cy; diff --git a/src/video/windows/SDL_windowswindow.h b/src/video/windows/SDL_windowswindow.h index d1570fdb0..659366a9f 100644 --- a/src/video/windows/SDL_windowswindow.h +++ b/src/video/windows/SDL_windowswindow.h @@ -49,6 +49,7 @@ typedef struct Uint8 focus_click_pending; SDL_bool skip_update_clipcursor; Uint32 last_updated_clipcursor; + SDL_bool mouse_relative_mode_center; SDL_bool windowed_mode_was_maximized; SDL_bool in_window_deactivation; RECT cursor_clipped_rect;