diff --git a/include/SDL3/SDL_hints.h b/include/SDL3/SDL_hints.h index 5e202827b333c..da9313728358d 100644 --- a/include/SDL3/SDL_hints.h +++ b/include/SDL3/SDL_hints.h @@ -4420,11 +4420,29 @@ extern "C" { */ #define SDL_HINT_DEBUG_LOGGING "SDL_DEBUG_LOGGING" +/** + * On Windows, this hint forces SDL to call SetCursor(NULL) to hide the mouse cursor, + * instead of using an invisible blank cursor. + * + * This may be required in certain environments (e.g., VMware or specific RDP configurations), + * where SetCursorPos() does not function correctly if the cursor is not truly hidden using SetCursor(NULL). + * + * By default, SDL uses a transparent cursor surface to simulate a hidden cursor, + * which avoids issues in some scenarios (e.g., multi-window focus handling). + * However, this method may not work properly in all virtualized environments. + * + * Set this hint to "1" to restore the previous behavior and force SetCursor(NULL) to be used. + * + * This hint is only applicable on Windows. + */ +#define SDL_HINT_WINDOWS_FORCE_NULL_CURSOR "SDL_WINDOWS_FORCE_NULL_CURSOR" + /** * An enumeration of hint priorities. * * \since This enum is available since SDL 3.2.0. */ + typedef enum SDL_HintPriority { SDL_HINT_DEFAULT, diff --git a/src/video/windows/SDL_windowsmouse.c b/src/video/windows/SDL_windowsmouse.c index 17666e634ceaf..ceb3d5fec42c9 100644 --- a/src/video/windows/SDL_windowsmouse.c +++ b/src/video/windows/SDL_windowsmouse.c @@ -434,20 +434,28 @@ static HCURSOR GetCachedCursor(SDL_Cursor *cursor) static bool WIN_ShowCursor(SDL_Cursor *cursor) { if (!cursor) { - cursor = SDL_blank_cursor; + if (SDL_GetHintBoolean(SDL_HINT_WINDOWS_FORCE_NULL_CURSOR, true)) { + SDL_cursor = NULL; + SetCursor(NULL); + + return false; + } else { + cursor = SDL_blank_cursor; + } } + if (cursor) { if (cursor->internal->surface) { SDL_cursor = GetCachedCursor(cursor); } else { SDL_cursor = cursor->internal->cursor; } - } else { - SDL_cursor = NULL; } + if (SDL_GetMouseFocus() != NULL) { SetCursor(SDL_cursor); } + return true; }