Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

streamline cursor clipping logic on windows #11237

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 0 additions & 17 deletions include/SDL3/SDL_hints.h
Original file line number Diff line number Diff line change
Expand Up @@ -2560,23 +2560,6 @@ extern "C" {
*/
#define SDL_HINT_MOUSE_RELATIVE_CURSOR_VISIBLE "SDL_MOUSE_RELATIVE_CURSOR_VISIBLE"

/**
* Controls how often SDL issues cursor confinement commands to the operating
* system while relative mode is active, in case the desired confinement state
* became out-of-sync due to interference from other running programs.
*
* The variable can be integers representing milliseconds between each
* refresh. A value of zero means SDL will not automatically refresh the
* confinement. The default value varies depending on the operating system,
* this variable might not have any effects on inapplicable platforms such as
* those without a cursor.
*
* This hint can be set anytime.
*
* \since This hint is available since SDL 3.1.3.
*/
#define SDL_HINT_MOUSE_RELATIVE_CLIP_INTERVAL "SDL_MOUSE_RELATIVE_CLIP_INTERVAL"

/**
* A variable controlling whether mouse events should generate synthetic touch
* events.
Expand Down
30 changes: 13 additions & 17 deletions src/events/SDL_mouse.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,17 +65,6 @@ static void SDLCALL SDL_MouseDoubleClickTimeChanged(void *userdata, const char *
}
}

static void SDLCALL SDL_MouseRelativeClipIntervalChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
{
SDL_Mouse *mouse = (SDL_Mouse *)userdata;

if (hint && *hint) {
mouse->relative_mode_clip_interval = SDL_atoi(hint);
} else {
mouse->relative_mode_clip_interval = 3000;
}
}

static void SDLCALL SDL_MouseDoubleClickRadiusChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
{
SDL_Mouse *mouse = (SDL_Mouse *)userdata;
Expand Down Expand Up @@ -113,6 +102,13 @@ static void SDLCALL SDL_MouseRelativeSpeedScaleChanged(void *userdata, const cha
}
}

static void SDLCALL SDL_MouseRelativeModeCenterChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
{
SDL_Mouse *mouse = (SDL_Mouse *)userdata;

mouse->relative_mode_center = SDL_GetStringBoolean(hint, true);
}

static void SDLCALL SDL_MouseRelativeSystemScaleChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
{
SDL_Mouse *mouse = (SDL_Mouse *)userdata;
Expand Down Expand Up @@ -226,6 +222,9 @@ bool SDL_PreInitMouse(void)
SDL_AddHintCallback(SDL_HINT_MOUSE_RELATIVE_SYSTEM_SCALE,
SDL_MouseRelativeSystemScaleChanged, mouse);

SDL_AddHintCallback(SDL_HINT_MOUSE_RELATIVE_MODE_CENTER,
SDL_MouseRelativeModeCenterChanged, mouse);

SDL_AddHintCallback(SDL_HINT_MOUSE_EMULATE_WARP_WITH_RELATIVE,
SDL_MouseWarpEmulationChanged, mouse);

Expand All @@ -249,9 +248,6 @@ bool SDL_PreInitMouse(void)
SDL_AddHintCallback(SDL_HINT_MOUSE_RELATIVE_CURSOR_VISIBLE,
SDL_MouseRelativeCursorVisibleChanged, mouse);

SDL_AddHintCallback(SDL_HINT_MOUSE_RELATIVE_CLIP_INTERVAL,
SDL_MouseRelativeClipIntervalChanged, mouse);

mouse->was_touch_mouse_events = false; // no touch to mouse movement event pending

mouse->cursor_shown = true;
Expand Down Expand Up @@ -1042,6 +1038,9 @@ void SDL_QuitMouse(void)
SDL_RemoveHintCallback(SDL_HINT_MOUSE_RELATIVE_SYSTEM_SCALE,
SDL_MouseRelativeSystemScaleChanged, mouse);

SDL_RemoveHintCallback(SDL_HINT_MOUSE_RELATIVE_MODE_CENTER,
SDL_MouseRelativeModeCenterChanged, mouse);

SDL_RemoveHintCallback(SDL_HINT_MOUSE_EMULATE_WARP_WITH_RELATIVE,
SDL_MouseWarpEmulationChanged, mouse);

Expand All @@ -1060,9 +1059,6 @@ void SDL_QuitMouse(void)
SDL_RemoveHintCallback(SDL_HINT_MOUSE_RELATIVE_CURSOR_VISIBLE,
SDL_MouseRelativeCursorVisibleChanged, mouse);

SDL_RemoveHintCallback(SDL_HINT_MOUSE_RELATIVE_CLIP_INTERVAL,
SDL_MouseRelativeClipIntervalChanged, mouse);

for (int i = SDL_mouse_count; i--; ) {
SDL_RemoveMouse(SDL_mice[i].instance_id, false);
}
Expand Down
2 changes: 1 addition & 1 deletion src/events/SDL_mouse_c.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,11 @@ typedef struct
bool relative_mode_warp;
bool relative_mode_warp_motion;
bool relative_mode_cursor_visible;
bool relative_mode_center;
bool warp_emulation_hint;
bool warp_emulation_active;
bool warp_emulation_prohibited;
Uint64 last_center_warp_time_ns;
int relative_mode_clip_interval;
bool enable_normal_speed_scale;
float normal_speed_scale;
bool enable_relative_speed_scale;
Expand Down
60 changes: 29 additions & 31 deletions src/video/windows/SDL_windowsevents.c
Original file line number Diff line number Diff line change
Expand Up @@ -350,8 +350,6 @@ static void WIN_UpdateFocus(SDL_Window *window, bool expect_focus)

WIN_UpdateWindowICCProfile(data->window, true);
} else {
RECT rect;

data->in_window_deactivation = true;

SDL_SetKeyboardFocus(NULL);
Expand All @@ -361,10 +359,7 @@ static void WIN_UpdateFocus(SDL_Window *window, bool expect_focus)
}
WIN_ResetDeadKeys();

if (GetClipCursor(&rect) && SDL_memcmp(&rect, &data->cursor_clipped_rect, sizeof(rect)) == 0) {
ClipCursor(NULL);
SDL_zero(data->cursor_clipped_rect);
}
WIN_UnclipCursorForWindow(window);

data->in_window_deactivation = false;
}
Expand Down Expand Up @@ -1086,6 +1081,10 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
case WM_NCACTIVATE:
{
// Don't immediately clip the cursor in case we're clicking minimize/maximize buttons
// This is the only place that this flag is set. This causes all subsequent calls to
// WIN_UpdateClipCursor for this window to be no-ops in this frame's message-pumping.
// This flag is unset at the end of message pumping each frame for every window, and
// should never be carried over between frames.
data->skip_update_clipcursor = true;

/* Update the focus here, since it's possible to get WM_ACTIVATE and WM_SETFOCUS without
Expand Down Expand Up @@ -1128,7 +1127,18 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara

case WM_MOUSEMOVE:
{
/* SDL_Mouse *mouse = SDL_GetMouse(); */
SDL_Window *window = data->window;

if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
bool wish_clip_cursor = (
window->flags & (SDL_WINDOW_MOUSE_RELATIVE_MODE | SDL_WINDOW_MOUSE_GRABBED) ||
(window->mouse_rect.w > 0 && window->mouse_rect.h > 0)
);
if (wish_clip_cursor) {
data->skip_update_clipcursor = false;
WIN_UpdateClipCursor(window);
}
}

if (!data->mouse_tracked) {
TRACKMOUSEEVENT trackMouseEvent;
Expand All @@ -1146,7 +1156,7 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
// Only generate mouse events for real mouse
if (GetMouseMessageSource((ULONG)GetMessageExtraInfo()) != SDL_MOUSE_EVENT_SOURCE_TOUCH &&
lParam != data->last_pointer_update) {
SDL_SendMouseMotion(WIN_GetEventTimestamp(), data->window, SDL_GLOBAL_MOUSE_ID, false, (float)GET_X_LPARAM(lParam), (float)GET_Y_LPARAM(lParam));
SDL_SendMouseMotion(WIN_GetEventTimestamp(), window, SDL_GLOBAL_MOUSE_ID, false, (float)GET_X_LPARAM(lParam), (float)GET_Y_LPARAM(lParam));
}
}
} break;
Expand Down Expand Up @@ -2102,28 +2112,6 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
}

#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
static void WIN_UpdateClipCursorForWindows(void)
{
SDL_VideoDevice *_this = SDL_GetVideoDevice();
SDL_Window *window;
Uint64 now = SDL_GetTicks();
const int CLIPCURSOR_UPDATE_INTERVAL_MS = SDL_GetMouse()->relative_mode_clip_interval;

if (_this) {
for (window = _this->windows; window; window = window->next) {
SDL_WindowData *data = window->internal;
if (data) {
if (data->skip_update_clipcursor) {
data->skip_update_clipcursor = false;
WIN_UpdateClipCursor(window);
} else if (CLIPCURSOR_UPDATE_INTERVAL_MS > 0 && now >= (data->last_updated_clipcursor + CLIPCURSOR_UPDATE_INTERVAL_MS)) {
WIN_UpdateClipCursor(window);
}
}
}
}
}

static void WIN_UpdateMouseCapture(void)
{
SDL_Window *focusWindow = SDL_GetKeyboardFocus();
Expand Down Expand Up @@ -2318,7 +2306,17 @@ void WIN_PumpEvents(SDL_VideoDevice *_this)
}

// Update the clipping rect in case someone else has stolen it
WIN_UpdateClipCursorForWindows();
if (_this) {
SDL_Window *window = _this->windows;
while (window) {
SDL_WindowData *data = window->internal;
if (data && data->skip_update_clipcursor) {
data->skip_update_clipcursor = false;
WIN_UpdateClipCursor(window);
}
window = window->next;
}
}

// Update mouse capture
WIN_UpdateMouseCapture();
Expand Down
Loading
Loading