From 16141d71563d9a63c16540e9d6f8699476dad0c0 Mon Sep 17 00:00:00 2001 From: Momoyama Date: Tue, 26 May 2026 22:20:19 +0800 Subject: [PATCH] fix(client): restore relative cursor positions locally Avoid stale server enter coordinates in relative mouse mode by saving and reusing the client's local cursor position around leave and enter. Store Windows restore positions per desktop so UAC and secure desktop transitions do not reuse normal desktop coordinates. This affects relative mouse movement restore behavior while preserving the existing center-on-leave path. --- src/lib/client/Client.cpp | 30 +++++++++++++++++- src/lib/client/Client.h | 7 ++++- src/lib/platform/MSWindowsDesks.cpp | 48 ++++++++++++++++++++++++++++- src/lib/platform/MSWindowsDesks.h | 8 ++++- 4 files changed, 89 insertions(+), 4 deletions(-) diff --git a/src/lib/client/Client.cpp b/src/lib/client/Client.cpp index 517f51430..9fbd48d62 100644 --- a/src/lib/client/Client.cpp +++ b/src/lib/client/Client.cpp @@ -1,6 +1,6 @@ /* * Deskflow -- mouse and keyboard sharing utility - * SPDX-FileCopyrightText: (C) 2025 Deskflow Developers + * SPDX-FileCopyrightText: (C) 2025 - 2026 Deskflow Developers * SPDX-FileCopyrightText: (C) 2012 - 2016, 2026 Synergy App Ltd * SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception @@ -154,6 +154,9 @@ void Client::handshakeComplete() { m_ready = true; m_screen->enable(); + if (m_relativeMouseMoves && !m_hasRelativeRestorePosition) { + saveRelativeRestorePosition(); + } sendEvent(EventTypes::ClientConnected); } @@ -195,12 +198,20 @@ void Client::getCursorPos(int32_t &x, int32_t &y) const void Client::enter(int32_t xAbs, int32_t yAbs, uint32_t, KeyModifierMask mask, bool) { m_active = true; + if (m_relativeMouseMoves && m_hasRelativeRestorePosition) { + xAbs = m_relativeRestoreX; + yAbs = m_relativeRestoreY; + LOG_VERBOSE("using relative restore position: %d,%d", xAbs, yAbs); + } m_screen->mouseMove(xAbs, yAbs); m_screen->enter(mask); } bool Client::leave() { + if (m_relativeMouseMoves) { + saveRelativeRestorePosition(); + } m_active = false; m_screen->leave(); @@ -283,6 +294,8 @@ void Client::screensaver(bool activate) void Client::resetOptions() { + m_relativeMouseMoves = false; + m_hasRelativeRestorePosition = false; m_screen->resetOptions(); } @@ -303,6 +316,14 @@ void Client::setOptions(const OptionsList &options) if (index != options.end()) { m_maximumClipboardSize = *index; } + } else if (id == kOptionRelativeMouseMoves) { + index++; + if (index != options.end()) { + m_relativeMouseMoves = (*index != 0); + if (m_relativeMouseMoves && m_ready && !m_hasRelativeRestorePosition) { + saveRelativeRestorePosition(); + } + } } } @@ -314,6 +335,13 @@ void Client::setOptions(const OptionsList &options) m_screen->setOptions(options); } +void Client::saveRelativeRestorePosition() +{ + m_screen->getCursorPos(m_relativeRestoreX, m_relativeRestoreY); + m_hasRelativeRestorePosition = true; + LOG_VERBOSE("saved relative restore position: %d,%d", m_relativeRestoreX, m_relativeRestoreY); +} + std::string Client::getName() const { return m_name; diff --git a/src/lib/client/Client.h b/src/lib/client/Client.h index 465c93de3..4caf51d4e 100644 --- a/src/lib/client/Client.h +++ b/src/lib/client/Client.h @@ -1,6 +1,6 @@ /* * Deskflow -- mouse and keyboard sharing utility - * SPDX-FileCopyrightText: (C) 2025 Deskflow Developers + * SPDX-FileCopyrightText: (C) 2025 - 2026 Deskflow Developers * SPDX-FileCopyrightText: (C) 2012 - 2016, 2026 Synergy App Ltd * SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception @@ -155,6 +155,7 @@ public: std::string getName() const override; private: + void saveRelativeRestorePosition(); void sendClipboard(ClipboardID); void sendEvent(deskflow::EventTypes); void sendConnectionFailedEvent(const char *msg); @@ -200,6 +201,10 @@ private: IEventQueue *m_events = nullptr; bool m_useSecureNetwork = false; bool m_enableClipboard = true; + bool m_relativeMouseMoves = false; + bool m_hasRelativeRestorePosition = false; + int32_t m_relativeRestoreX = 0; + int32_t m_relativeRestoreY = 0; size_t m_maximumClipboardSize = INT_MAX; size_t m_resolvedAddressesCount = 0; }; diff --git a/src/lib/platform/MSWindowsDesks.cpp b/src/lib/platform/MSWindowsDesks.cpp index 4807db62b..fefcec80f 100644 --- a/src/lib/platform/MSWindowsDesks.cpp +++ b/src/lib/platform/MSWindowsDesks.cpp @@ -1,6 +1,6 @@ /* * Deskflow -- mouse and keyboard sharing utility - * SPDX-FileCopyrightText: (C) 2025 Deskflow Developers + * SPDX-FileCopyrightText: (C) 2025 - 2026 Deskflow Developers * SPDX-FileCopyrightText: (C) 2012 - 2016 Synergy App Ltd * SPDX-FileCopyrightText: (C) 2004 Chris Schoeneman * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception @@ -181,6 +181,10 @@ void MSWindowsDesks::leave(HKL keyLayout) void MSWindowsDesks::resetOptions() { m_leaveForegroundOption = false; + m_relativeMouseMoves = false; + for (auto &entry : m_desks) { + entry.second->m_hasRelativeRestorePosition = false; + } } void MSWindowsDesks::setOptions(const OptionsList &options) @@ -189,6 +193,8 @@ void MSWindowsDesks::setOptions(const OptionsList &options) if (options[i] == kOptionWin32KeepForeground) { m_leaveForegroundOption = (options[i + 1] != 0); LOG_VERBOSE("%s the foreground window", m_leaveForegroundOption ? "don\'t grab" : "grab"); + } else if (options[i] == kOptionRelativeMouseMoves) { + m_relativeMouseMoves = (options[i + 1] != 0); } } } @@ -309,6 +315,39 @@ void MSWindowsDesks::fakeMouseWheel(int32_t xDelta, int32_t yDelta) const sendMessage(DESKFLOW_MSG_FAKE_WHEEL, xDelta, yDelta); } +void MSWindowsDesks::saveRelativeRestorePosition(Desk *desk) const +{ + POINT pos{0, 0}; + if (!GetCursorPos(&pos)) { + LOG_DEBUG( + "could not save relative restore position on desk \"%ls\", error: %lu", desk->m_name.c_str(), GetLastError() + ); + return; + } + + desk->m_relativeRestoreX = pos.x; + desk->m_relativeRestoreY = pos.y; + desk->m_hasRelativeRestorePosition = true; + LOG_VERBOSE( + "saved relative restore position on desk \"%ls\": %+d,%+d", desk->m_name.c_str(), desk->m_relativeRestoreX, + desk->m_relativeRestoreY + ); +} + +bool MSWindowsDesks::restoreRelativeCursorPosition(Desk *desk) const +{ + if (!desk->m_hasRelativeRestorePosition) { + return false; + } + + LOG_VERBOSE( + "restoring relative cursor position on desk \"%ls\": %+d,%+d", desk->m_name.c_str(), desk->m_relativeRestoreX, + desk->m_relativeRestoreY + ); + deskMouseMove(desk->m_relativeRestoreX, desk->m_relativeRestoreY); + return true; +} + void MSWindowsDesks::sendMessage(UINT msg, WPARAM wParam, LPARAM lParam) const { if (m_activeDesk != nullptr && m_activeDesk->m_window != nullptr) { @@ -496,6 +535,9 @@ void MSWindowsDesks::deskEnter(Desk *desk) { if (!m_isPrimary) { ReleaseCapture(); + if (m_relativeMouseMoves) { + restoreRelativeCursorPosition(desk); + } } setCursorVisibility(true); @@ -519,6 +561,10 @@ void MSWindowsDesks::deskEnter(Desk *desk) void MSWindowsDesks::deskLeave(Desk *desk, HKL keyLayout) { + if (!m_isPrimary && m_relativeMouseMoves) { + saveRelativeRestorePosition(desk); + } + setCursorVisibility(false); if (m_isPrimary) { diff --git a/src/lib/platform/MSWindowsDesks.h b/src/lib/platform/MSWindowsDesks.h index eb82d3ab0..85c7e11e8 100644 --- a/src/lib/platform/MSWindowsDesks.h +++ b/src/lib/platform/MSWindowsDesks.h @@ -1,6 +1,6 @@ /* * Deskflow -- mouse and keyboard sharing utility - * SPDX-FileCopyrightText: (C) 2025 Deskflow Developers + * SPDX-FileCopyrightText: (C) 2025 - 2026 Deskflow Developers * SPDX-FileCopyrightText: (C) 2012 - 2016 Synergy App Ltd * SPDX-FileCopyrightText: (C) 2004 Chris Schoeneman * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception @@ -187,6 +187,9 @@ private: HWND m_window; HWND m_foregroundWindow; bool m_lowLevel; + bool m_hasRelativeRestorePosition = false; + int32_t m_relativeRestoreX = 0; + int32_t m_relativeRestoreY = 0; }; using Desks = std::map; @@ -201,6 +204,8 @@ private: // message handlers void deskMouseMove(int32_t x, int32_t y) const; void deskMouseRelativeMove(int32_t dx, int32_t dy) const; + void saveRelativeRestorePosition(Desk *desk) const; + bool restoreRelativeCursorPosition(Desk *desk) const; void deskEnter(Desk *desk); void deskLeave(Desk *desk, HKL keyLayout); void deskThread(const void *vdesk); @@ -276,6 +281,7 @@ private: // options bool m_leaveForegroundOption; + bool m_relativeMouseMoves = false; IEventQueue *m_events; };