From c3f2ec8fb65735eaf376c55904d3a613155246c7 Mon Sep 17 00:00:00 2001 From: LIU Hao Date: Thu, 23 Jan 2025 11:09:15 +0800 Subject: [PATCH] Recover cursor state when editor window loses focus The show count [1] of the mouse cursor, controlled by `ShowCursor()`, is thread-local and has an effect only when the cursor is above a window of the same thread. On the other hand, `GetCursorInfo()` reports the asynchronous state of the cursor, which may be outside the editor window and doesn't reflect the show count of our thread. So, it is incorrect to manipulate the show count according to the result of `GetCursorInfo()`. This commit reverts relevant changes about `cursorIsHidden` in upstream Scintilla. When the editor window loses focus but the cursor is not above it, the system does not send a `WM_MOUSELEAVE` notification. So we also have to recover the cursor state in `WM_KILLFOCUS`. This closes https://github.com/rizonesoft/Notepad3/issues/5369 [1] https://devblogs.microsoft.com/oldnewthing/20091217-00/?p=15643 Signed-off-by: LIU Hao --- scintilla/win32/ScintillaWin.cxx | 46 +++++++++++++------------------- 1 file changed, 19 insertions(+), 27 deletions(-) diff --git a/scintilla/win32/ScintillaWin.cxx b/scintilla/win32/ScintillaWin.cxx index f1f489d9a..615a70786 100644 --- a/scintilla/win32/ScintillaWin.cxx +++ b/scintilla/win32/ScintillaWin.cxx @@ -356,9 +356,7 @@ class ScintillaWin : bool capturedMouse; bool trackedMouseLeave; BOOL typingWithoutCursor; - // >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>> - //bool cursorIsHidden; - // <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<< + bool cursorIsHidden; SetCoalescableTimerSig SetCoalescableTimerFn; unsigned int linesPerScroll; ///< Intellimouse support @@ -505,9 +503,6 @@ class ScintillaWin : void ClaimSelection() override; void GetMouseParameters() noexcept; - // >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>> - bool IsMouseCursorHidden() noexcept; - // <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<< void CopyToGlobal(GlobalMemory &gmUnicode, const SelectionText &selectedText); void CopyToClipboard(const SelectionText &selectedText) override; void ScrollMessage(WPARAM wParam); @@ -593,9 +588,7 @@ ScintillaWin::ScintillaWin(HWND hwnd) { capturedMouse = false; trackedMouseLeave = false; typingWithoutCursor = false; - // >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>> - //cursorIsHidden = false; - // <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<< + cursorIsHidden = false; SetCoalescableTimerFn = nullptr; linesPerScroll = 0; @@ -1632,9 +1625,9 @@ sptr_t ScintillaWin::MouseMessage(unsigned int iMessage, uptr_t wParam, sptr_t l // Windows might send WM_MOUSEMOVE even though the mouse has not been moved: // http://blogs.msdn.com/b/oldnewthing/archive/2003/10/01/55108.aspx if (ptMouseLast != pt) { - if (IsMouseCursorHidden()) { + if (cursorIsHidden) { ::ShowCursor(TRUE); - //cursorIsHidden = false; // to be shown by ButtonMoveWithModifiers + cursorIsHidden = false; // to be shown by ButtonMoveWithModifiers } SetTrackMouseLeaveEvent(true); ButtonMoveWithModifiers(pt, ::GetMessageTime(), MouseModifiers(wParam)); @@ -1645,7 +1638,10 @@ sptr_t ScintillaWin::MouseMessage(unsigned int iMessage, uptr_t wParam, sptr_t l case WM_MOUSELEAVE: // >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>> - if (IsMouseCursorHidden()) { ::ShowCursor(TRUE); } + if (cursorIsHidden) { + ::ShowCursor(TRUE); + cursorIsHidden = false; + } // <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<< SetTrackMouseLeaveEvent(false); MouseLeave(); @@ -1813,6 +1809,12 @@ sptr_t ScintillaWin::KeyMessage(unsigned int iMessage, uptr_t wParam, sptr_t lPa sptr_t ScintillaWin::FocusMessage(unsigned int iMessage, uptr_t wParam, sptr_t) { switch (iMessage) { case WM_KILLFOCUS: { + // >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>> + if (cursorIsHidden) { + ::ShowCursor(TRUE); + cursorIsHidden = false; + } + // <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<< HWND wOther = reinterpret_cast(wParam); HWND wThis = MainHWND(); const HWND wCT = HwndFromWindow(ct.wCallTip); @@ -2147,10 +2149,7 @@ sptr_t ScintillaWin::WndProc(Message iMessage, uptr_t wParam, sptr_t lParam) { case WM_SETCURSOR: if (LOWORD(lParam) == HTCLIENT) { - // >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>> - //if (!cursorIsHidden) { - if (!IsMouseCursorHidden()) { - // <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<< + if (!cursorIsHidden) { POINT pt; if (::GetCursorPos(&pt)) { ::ScreenToClient(MainHWND(), &pt); @@ -2426,13 +2425,13 @@ void ScintillaWin::SetTrackMouseLeaveEvent(bool on) noexcept { void ScintillaWin::HideCursorIfPreferred() noexcept { // SPI_GETMOUSEVANISH from OS. - // >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>> - if (typingWithoutCursor && !IsMouseCursorHidden()) { + if (typingWithoutCursor && !cursorIsHidden) { + // >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>> //::SetCursor(NULL); ::ShowCursor(FALSE); - //cursorIsHidden = true; + // <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<< + cursorIsHidden = true; } - // <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<< } void ScintillaWin::UpdateBaseElements() { @@ -3325,13 +3324,6 @@ void ScintillaWin::GetMouseParameters() noexcept { ::SystemParametersInfo(SPI_GETMOUSEVANISH, 0, &typingWithoutCursor, 0); } -// >>>>>>>>>>>>>>> BEG NON STD SCI PATCH >>>>>>>>>>>>>>> -bool ScintillaWin::IsMouseCursorHidden() noexcept { - CURSORINFO curInfo = { sizeof(CURSORINFO) }; - return GetCursorInfo(&curInfo) ? (curInfo.flags == 0UL) : false; -} -// <<<<<<<<<<<<<<< END NON STD SCI PATCH <<<<<<<<<<<<<<< - void ScintillaWin::CopyToGlobal(GlobalMemory &gmUnicode, const SelectionText &selectedText) { const std::string_view svSelected(selectedText.Data(), selectedText.LengthWithTerminator()); if (IsUnicodeMode()) {