From 8979d7f94f47e210c3047c772a2d12193ff17523 Mon Sep 17 00:00:00 2001 From: Nick Bolton Date: Mon, 28 Jul 2025 17:09:40 +0100 Subject: [PATCH] feat: Cursor visibility retry mechanism The `ShowCursor` function does not directly show/hide the cursor; it increments or decrements the internal display counter. When that counter reaches a certain positive/negative number, then the cursor is shown or hidden at a particular threshold. --- src/lib/platform/MSWindowsDesks.cpp | 43 +++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/src/lib/platform/MSWindowsDesks.cpp b/src/lib/platform/MSWindowsDesks.cpp index 8126a36b0..552ea5c6c 100644 --- a/src/lib/platform/MSWindowsDesks.cpp +++ b/src/lib/platform/MSWindowsDesks.cpp @@ -452,12 +452,50 @@ void MSWindowsDesks::deskMouseRelativeMove(int32_t dx, int32_t dy) const } } +// the system shows the mouse cursor when an internal display count +// is >= 0. this count is maintained per application but there's +// apparently a system wide count added to the application's count. +// this system count is 0 if there's a mouse attached to the system +// and -1 otherwise. the mouse keys accessibility feature can modify +// this system count by making the system appear to have a mouse. +void setCursorVisibility(bool visible) +{ + LOG_DEBUG("%s cursor", visible ? "showing" : "hiding"); + + const int max = 10; + int attempts = 0; + while (attempts++ < max) { + const auto displayCounter = ShowCursor(visible ? TRUE : FALSE); + LOG_DEBUG1("cursor display counter: %d", displayCounter); + + if (visible) { + if (displayCounter < 0) { + LOG_DEBUG1("cursor still hidden, retrying, attempt: %d", attempts); + } else { + LOG_DEBUG1("cursor is now visible, attempts: %d", attempts); + return; + } + } else { + if (displayCounter >= 0) { + LOG_DEBUG1("cursor still visible, retrying, attempt: %d", attempts); + } else { + LOG_DEBUG1("cursor is now hidden, attempts: %d", attempts); + return; + } + } + } + + LOG_ERR("unable to set cursor visibility after %d attempts", attempts); +} + void MSWindowsDesks::deskEnter(Desk *desk) { if (!m_isPrimary) { ReleaseCapture(); } - ShowCursor(TRUE); + + setCursorVisibility(true); + SetWindowPos(desk->m_window, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_HIDEWINDOW); // restore the foreground window @@ -477,7 +515,8 @@ void MSWindowsDesks::deskEnter(Desk *desk) void MSWindowsDesks::deskLeave(Desk *desk, HKL keyLayout) { - ShowCursor(FALSE); + setCursorVisibility(false); + if (m_isPrimary) { // map a window to hide the cursor and to use whatever keyboard // layout we choose rather than the keyboard layout of the last