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 <lh_mouse@126.com>
This commit is contained in:
LIU Hao 2025-01-23 11:09:15 +08:00
parent ff33e11996
commit c3f2ec8fb6
No known key found for this signature in database

View File

@ -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<HWND>(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()) {