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; };