Added the hint SDL_HINT_MOUSE_RELATIVE_MODE_CENTER, controlling whether the mouse should be constrained to the center of the window or the whole window in relative mode.

For further info about the pros and cons, check out the discussion in https://github.com/libsdl-org/SDL/issues/5271
This commit is contained in:
Sam Lantinga 2022-03-18 10:07:59 -07:00
parent d3cc5764c0
commit 6c96217727
3 changed files with 61 additions and 29 deletions

View File

@ -933,6 +933,22 @@ extern "C" {
*/ */
#define SDL_HINT_MOUSE_NORMAL_SPEED_SCALE "SDL_MOUSE_NORMAL_SPEED_SCALE" #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 * \brief A variable controlling whether relative mouse mode is implemented using mouse warping
* *

View File

@ -28,6 +28,7 @@
#include "../SDL_pixels_c.h" #include "../SDL_pixels_c.h"
#include "../../events/SDL_keyboard_c.h" #include "../../events/SDL_keyboard_c.h"
#include "../../events/SDL_mouse_c.h" #include "../../events/SDL_mouse_c.h"
#include "../../SDL_hints_c.h"
#include "SDL_windowsvideo.h" #include "SDL_windowsvideo.h"
#include "SDL_windowswindow.h" #include "SDL_windowswindow.h"
@ -170,6 +171,13 @@ WIN_SetWindowPositionInternal(_THIS, SDL_Window * window, UINT flags)
data->expected_resize = SDL_FALSE; 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 static int
SetupWindowData(_THIS, SDL_Window * window, HWND hwnd, HWND parent, SDL_bool created) 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->videodata = videodata;
data->initializing = SDL_TRUE; data->initializing = SDL_TRUE;
SDL_AddHintCallback(SDL_HINT_MOUSE_RELATIVE_MODE_CENTER, WIN_MouseRelativeModeCenterChanged, data);
window->driverdata = data; window->driverdata = data;
/* Associate the data with the window */ /* Associate the data with the window */
@ -297,7 +307,39 @@ SetupWindowData(_THIS, SDL_Window * window, HWND hwnd, HWND parent, SDL_bool cre
return 0; 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 int
WIN_CreateWindow(_THIS, SDL_Window * window) WIN_CreateWindow(_THIS, SDL_Window * window)
@ -873,34 +915,7 @@ WIN_SetWindowKeyboardGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
void void
WIN_DestroyWindow(_THIS, SDL_Window * window) WIN_DestroyWindow(_THIS, SDL_Window * window)
{ {
SDL_WindowData *data = (SDL_WindowData *) window->driverdata; CleanupWindowData(_this, window);
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;
} }
SDL_bool SDL_bool
@ -1032,7 +1047,7 @@ WIN_UpdateClipCursor(SDL_Window *window)
if ((mouse->relative_mode || (window->flags & SDL_WINDOW_MOUSE_GRABBED) || if ((mouse->relative_mode || (window->flags & SDL_WINDOW_MOUSE_GRABBED) ||
(window->mouse_rect.w > 0 && window->mouse_rect.h > 0)) && (window->mouse_rect.w > 0 && window->mouse_rect.h > 0)) &&
(window->flags & SDL_WINDOW_INPUT_FOCUS)) { (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)) { if (GetWindowRect(data->hwnd, &rect)) {
LONG cx, cy; LONG cx, cy;

View File

@ -49,6 +49,7 @@ typedef struct
Uint8 focus_click_pending; Uint8 focus_click_pending;
SDL_bool skip_update_clipcursor; SDL_bool skip_update_clipcursor;
Uint32 last_updated_clipcursor; Uint32 last_updated_clipcursor;
SDL_bool mouse_relative_mode_center;
SDL_bool windowed_mode_was_maximized; SDL_bool windowed_mode_was_maximized;
SDL_bool in_window_deactivation; SDL_bool in_window_deactivation;
RECT cursor_clipped_rect; RECT cursor_clipped_rect;