From 16110acaa2377bc284d3b68bf36d087b1b33ec33 Mon Sep 17 00:00:00 2001 From: crs Date: Sat, 1 May 2004 15:18:59 +0000 Subject: [PATCH] Added support for a global relative mouse motion option. When true and on a secondary screen and locked to the screen (via scroll lock) mouse motion is sent as motion deltas. When true and scroll lock is toggled off the mouse is warped to the secondary screen's center so the server knows where it is. This option is intended to support games and other programs that repeatedly warp the mouse to the center of the screen. This change adds general and X11 support but not win32. The option name is "relativeMouseMoves". --- lib/client/CClient.cpp | 6 ++++ lib/client/CClient.h | 1 + lib/platform/CXWindowsScreen.cpp | 13 +++++++ lib/platform/CXWindowsScreen.h | 1 + lib/server/CClientProxy.h | 1 + lib/server/CClientProxy1_0.cpp | 6 ++++ lib/server/CClientProxy1_0.h | 1 + lib/server/CClientProxyUnknown.cpp | 5 +++ lib/server/CConfig.cpp | 9 ++++- lib/server/CPrimaryClient.cpp | 6 ++++ lib/server/CPrimaryClient.h | 1 + lib/server/CServer.cpp | 54 +++++++++++++++++++++++++----- lib/server/CServer.h | 8 +++-- lib/server/Makefile.am | 2 ++ lib/synergy/CPlatformScreen.h | 1 + lib/synergy/CScreen.cpp | 7 ++++ lib/synergy/CScreen.h | 7 ++++ lib/synergy/IClient.h | 7 ++++ lib/synergy/IPlatformScreen.h | 1 + lib/synergy/ISecondaryScreen.h | 6 ++++ lib/synergy/OptionTypes.h | 1 + lib/synergy/ProtocolTypes.h | 6 +++- 22 files changed, 138 insertions(+), 12 deletions(-) diff --git a/lib/client/CClient.cpp b/lib/client/CClient.cpp index f1f4ae22..59bbc4fc 100644 --- a/lib/client/CClient.cpp +++ b/lib/client/CClient.cpp @@ -257,6 +257,12 @@ CClient::mouseMove(SInt32 x, SInt32 y) m_screen->mouseMove(x, y); } +void +CClient::mouseRelativeMove(SInt32 dx, SInt32 dy) +{ + m_screen->mouseRelativeMove(dx, dy); +} + void CClient::mouseWheel(SInt32 delta) { diff --git a/lib/client/CClient.h b/lib/client/CClient.h index 9c49d3cd..5087759b 100644 --- a/lib/client/CClient.h +++ b/lib/client/CClient.h @@ -135,6 +135,7 @@ public: virtual void mouseDown(ButtonID); virtual void mouseUp(ButtonID); virtual void mouseMove(SInt32 xAbs, SInt32 yAbs); + virtual void mouseRelativeMove(SInt32 xRel, SInt32 yRel); virtual void mouseWheel(SInt32 delta); virtual void screensaver(bool activate); virtual void resetOptions(); diff --git a/lib/platform/CXWindowsScreen.cpp b/lib/platform/CXWindowsScreen.cpp index ffe5a64e..7aee2341 100644 --- a/lib/platform/CXWindowsScreen.cpp +++ b/lib/platform/CXWindowsScreen.cpp @@ -550,6 +550,19 @@ CXWindowsScreen::fakeMouseMove(SInt32 x, SInt32 y) const XFlush(m_display); } +void +CXWindowsScreen::fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const +{ + // FIXME -- ignore xinerama for now + if (false && m_xinerama && m_xtestIsXineramaUnaware) { +// XWarpPointer(m_display, None, m_root, 0, 0, 0, 0, x, y); + } + else { + XTestFakeRelativeMotionEvent(m_display, dx, dy, CurrentTime); + } + XFlush(m_display); +} + void CXWindowsScreen::fakeMouseWheel(SInt32 delta) const { diff --git a/lib/platform/CXWindowsScreen.h b/lib/platform/CXWindowsScreen.h index c7be5bb4..d1289dca 100644 --- a/lib/platform/CXWindowsScreen.h +++ b/lib/platform/CXWindowsScreen.h @@ -55,6 +55,7 @@ public: // ISecondaryScreen overrides virtual void fakeMouseButton(ButtonID id, bool press) const; virtual void fakeMouseMove(SInt32 x, SInt32 y) const; + virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const; virtual void fakeMouseWheel(SInt32 delta) const; // IPlatformScreen overrides diff --git a/lib/server/CClientProxy.h b/lib/server/CClientProxy.h index 9453a203..b8e38fa8 100644 --- a/lib/server/CClientProxy.h +++ b/lib/server/CClientProxy.h @@ -96,6 +96,7 @@ public: virtual void mouseDown(ButtonID) = 0; virtual void mouseUp(ButtonID) = 0; virtual void mouseMove(SInt32 xAbs, SInt32 yAbs) = 0; + virtual void mouseRelativeMove(SInt32 xRel, SInt32 yRel) = 0; virtual void mouseWheel(SInt32 delta) = 0; virtual void screensaver(bool activate) = 0; virtual void resetOptions() = 0; diff --git a/lib/server/CClientProxy1_0.cpp b/lib/server/CClientProxy1_0.cpp index 617e12a2..2bb412ce 100644 --- a/lib/server/CClientProxy1_0.cpp +++ b/lib/server/CClientProxy1_0.cpp @@ -316,6 +316,12 @@ CClientProxy1_0::mouseMove(SInt32 xAbs, SInt32 yAbs) CProtocolUtil::writef(getStream(), kMsgDMouseMove, xAbs, yAbs); } +void +CClientProxy1_0::mouseRelativeMove(SInt32, SInt32) +{ + // ignore -- not supported in protocol 1.0 +} + void CClientProxy1_0::mouseWheel(SInt32 delta) { diff --git a/lib/server/CClientProxy1_0.h b/lib/server/CClientProxy1_0.h index 503dcba9..4f752085 100644 --- a/lib/server/CClientProxy1_0.h +++ b/lib/server/CClientProxy1_0.h @@ -49,6 +49,7 @@ public: virtual void mouseDown(ButtonID); virtual void mouseUp(ButtonID); virtual void mouseMove(SInt32 xAbs, SInt32 yAbs); + virtual void mouseRelativeMove(SInt32 xRel, SInt32 yRel); virtual void mouseWheel(SInt32 delta); virtual void screensaver(bool activate); virtual void resetOptions(); diff --git a/lib/server/CClientProxyUnknown.cpp b/lib/server/CClientProxyUnknown.cpp index 4c45ba07..806f23b8 100644 --- a/lib/server/CClientProxyUnknown.cpp +++ b/lib/server/CClientProxyUnknown.cpp @@ -15,6 +15,7 @@ #include "CClientProxyUnknown.h" #include "CClientProxy1_0.h" #include "CClientProxy1_1.h" +#include "CClientProxy1_2.h" #include "ProtocolTypes.h" #include "CProtocolUtil.h" #include "XSynergy.h" @@ -214,6 +215,10 @@ CClientProxyUnknown::handleData(const CEvent&, void*) case 1: m_proxy = new CClientProxy1_1(name, m_stream); break; + + case 2: + m_proxy = new CClientProxy1_2(name, m_stream); + break; } } diff --git a/lib/server/CConfig.cpp b/lib/server/CConfig.cpp index a4893cc8..03e0eb2d 100644 --- a/lib/server/CConfig.cpp +++ b/lib/server/CConfig.cpp @@ -629,6 +629,9 @@ CConfig::getOptionName(OptionID id) if (id == kOptionXTestXineramaUnaware) { return "xtestIsXineramaUnaware"; } + if (id == kOptionRelativeMouseMoves) { + return "relativeMouseMoves"; + } return NULL; } @@ -638,7 +641,8 @@ CConfig::getOptionValue(OptionID id, OptionValue value) if (id == kOptionHalfDuplexCapsLock || id == kOptionHalfDuplexNumLock || id == kOptionScreenSaverSync || - id == kOptionXTestXineramaUnaware) { + id == kOptionXTestXineramaUnaware || + id == kOptionRelativeMouseMoves) { return (value != 0) ? "true" : "false"; } if (id == kOptionModifierMapForShift || @@ -778,6 +782,9 @@ CConfig::readSectionOptions(std::istream& s) else if (name == "screenSaverSync") { addOption("", kOptionScreenSaverSync, parseBoolean(value)); } + else if (name == "relativeMouseMoves") { + addOption("", kOptionRelativeMouseMoves, parseBoolean(value)); + } else { throw XConfigRead("unknown argument"); } diff --git a/lib/server/CPrimaryClient.cpp b/lib/server/CPrimaryClient.cpp index a8e21c3c..7ec681bc 100644 --- a/lib/server/CPrimaryClient.cpp +++ b/lib/server/CPrimaryClient.cpp @@ -185,6 +185,12 @@ CPrimaryClient::mouseMove(SInt32 x, SInt32 y) m_screen->warpCursor(x, y); } +void +CPrimaryClient::mouseRelativeMove(SInt32, SInt32) +{ + // ignore +} + void CPrimaryClient::mouseWheel(SInt32) { diff --git a/lib/server/CPrimaryClient.h b/lib/server/CPrimaryClient.h index 985fc4a3..2006508c 100644 --- a/lib/server/CPrimaryClient.h +++ b/lib/server/CPrimaryClient.h @@ -102,6 +102,7 @@ public: virtual void mouseDown(ButtonID); virtual void mouseUp(ButtonID); virtual void mouseMove(SInt32 xAbs, SInt32 yAbs); + virtual void mouseRelativeMove(SInt32 xRel, SInt32 yRel); virtual void mouseWheel(SInt32 delta); virtual void screensaver(bool activate); virtual void resetOptions(); diff --git a/lib/server/CServer.cpp b/lib/server/CServer.cpp index 27a8651a..fce2584a 100644 --- a/lib/server/CServer.cpp +++ b/lib/server/CServer.cpp @@ -53,7 +53,8 @@ CServer::CServer(const CConfig& config, CPrimaryClient* primaryClient) : m_switchTwoTapDelay(0.0), m_switchTwoTapEngaged(false), m_switchTwoTapArmed(false), - m_switchTwoTapZone(3) + m_switchTwoTapZone(3), + m_relativeMoves(false) { // must have a primary client and it must have a canonical name assert(m_primaryClient != NULL); @@ -283,6 +284,9 @@ CServer::onCommandKey(KeyID id, KeyModifierMask /*mask*/, bool /*down*/) { if (id == kKeyScrollLock) { m_primaryClient->reconfigure(getActivePrimarySides()); + if (!isLockedToScreenServer()) { + stopRelativeMoves(); + } } return false; } @@ -322,13 +326,7 @@ bool CServer::isLockedToScreenServer() const { // locked if scroll-lock is toggled on - if ((m_primaryClient->getToggleMask() & KeyModifierScrollLock) != 0) { - LOG((CLOG_DEBUG "locked by ScrollLock")); - return true; - } - - // not locked - return false; + return ((m_primaryClient->getToggleMask() & KeyModifierScrollLock) != 0); } bool @@ -336,6 +334,7 @@ CServer::isLockedToScreen() const { // locked if we say we're locked if (isLockedToScreenServer()) { + LOG((CLOG_DEBUG "locked by ScrollLock")); return true; } @@ -841,6 +840,24 @@ CServer::isSwitchWaitStarted() const return (m_switchWaitTimer != NULL); } +void +CServer::stopRelativeMoves() +{ + if (m_relativeMoves && m_active != m_primaryClient) { + // warp to the center of the active client so we know where we are + SInt32 ax, ay, aw, ah; + m_active->getShape(ax, ay, aw, ah); + m_x = ax + (aw >> 1); + m_y = ay + (ah >> 1); + m_xDelta = 0; + m_yDelta = 0; + m_xDelta2 = 0; + m_yDelta2 = 0; + LOG((CLOG_DEBUG2 "synchronize move on %s by %d,%d", getName(m_active).c_str(), m_x, m_y)); + m_active->mouseMove(m_x, m_y); + } +} + void CServer::sendOptions(IClient* client) const { @@ -883,6 +900,7 @@ CServer::processOptions() return; } + bool newRelativeMoves = m_relativeMoves; for (CConfig::CScreenOptions::const_iterator index = options->begin(); index != options->end(); ++index) { const OptionID id = index->first; @@ -901,7 +919,15 @@ CServer::processOptions() } stopSwitchTwoTap(); } + else if (id == kOptionRelativeMouseMoves) { + newRelativeMoves = (value != 0); + } } + + if (m_relativeMoves && !newRelativeMoves) { + stopRelativeMoves(); + } + m_relativeMoves = newRelativeMoves; } void @@ -1339,6 +1365,18 @@ CServer::onMouseMoveSecondary(SInt32 dx, SInt32 dy) return; } + // if doing relative motion on secondary screens and we're locked + // to the screen (which activates relative moves) then send a + // relative mouse motion. when we're doing this we pretend as if + // the mouse isn't actually moving because we're expecting some + // program on the secondary screen to warp the mouse on us, so we + // have no idea where it really is. + if (m_relativeMoves && isLockedToScreenServer()) { + LOG((CLOG_DEBUG2 "relative move on %s by %d,%d", getName(m_active).c_str(), dx, dy)); + m_active->mouseRelativeMove(dx, dy); + return; + } + // save old position const SInt32 xOld = m_x; const SInt32 yOld = m_y; diff --git a/lib/server/CServer.h b/lib/server/CServer.h index 0e28eee7..3272d837 100644 --- a/lib/server/CServer.h +++ b/lib/server/CServer.h @@ -26,8 +26,6 @@ #include "stdset.h" #include "stdvector.h" -class CClientProxy; -class CClientProxyUnknown; class CEventQueueTimer; class CPrimaryClient; class IClient; @@ -183,6 +181,9 @@ private: // returns true iff the delay switch timer is started bool isSwitchWaitStarted() const; + // stop relative mouse moves + void stopRelativeMoves(); + // send screen options to \c client void sendOptions(IClient* client) const; @@ -312,6 +313,9 @@ private: bool m_switchTwoTapArmed; SInt32 m_switchTwoTapZone; + // relative mouse move option + bool m_relativeMoves; + static CEvent::Type s_errorEvent; static CEvent::Type s_disconnectedEvent; }; diff --git a/lib/server/Makefile.am b/lib/server/Makefile.am index 7ffb76b4..90f3d6e1 100644 --- a/lib/server/Makefile.am +++ b/lib/server/Makefile.am @@ -27,6 +27,7 @@ libserver_a_SOURCES = \ CClientProxy.cpp \ CClientProxy1_0.cpp \ CClientProxy1_1.cpp \ + CClientProxy1_2.cpp \ CClientProxyUnknown.cpp \ CConfig.cpp \ CPrimaryClient.cpp \ @@ -35,6 +36,7 @@ libserver_a_SOURCES = \ CClientProxy.h \ CClientProxy1_0.h \ CClientProxy1_1.h \ + CClientProxy1_2.h \ CClientProxyUnknown.h \ CConfig.h \ CPrimaryClient.h \ diff --git a/lib/synergy/CPlatformScreen.h b/lib/synergy/CPlatformScreen.h index b5fcde01..d5bb7fbb 100644 --- a/lib/synergy/CPlatformScreen.h +++ b/lib/synergy/CPlatformScreen.h @@ -45,6 +45,7 @@ public: // ISecondaryScreen overrides virtual void fakeMouseButton(ButtonID id, bool press) const = 0; virtual void fakeMouseMove(SInt32 x, SInt32 y) const = 0; + virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const = 0; virtual void fakeMouseWheel(SInt32 delta) const = 0; // IKeyState overrides diff --git a/lib/synergy/CScreen.cpp b/lib/synergy/CScreen.cpp index 787e72ba..67140498 100644 --- a/lib/synergy/CScreen.cpp +++ b/lib/synergy/CScreen.cpp @@ -222,6 +222,13 @@ CScreen::mouseMove(SInt32 x, SInt32 y) m_screen->fakeMouseMove(x, y); } +void +CScreen::mouseRelativeMove(SInt32 dx, SInt32 dy) +{ + assert(!m_isPrimary); + m_screen->fakeMouseRelativeMove(dx, dy); +} + void CScreen::mouseWheel(SInt32 delta) { diff --git a/lib/synergy/CScreen.h b/lib/synergy/CScreen.h index ae605d9b..01b10417 100644 --- a/lib/synergy/CScreen.h +++ b/lib/synergy/CScreen.h @@ -146,6 +146,13 @@ public: */ void mouseMove(SInt32 xAbs, SInt32 yAbs); + //! Notify of mouse motion + /*! + Synthesize mouse events to generate mouse motion by the relative + amount \c xRel,yRel. + */ + void mouseRelativeMove(SInt32 xRel, SInt32 yRel); + //! Notify of mouse wheel motion /*! Synthesize mouse events to generate mouse wheel motion of \c delta. diff --git a/lib/synergy/IClient.h b/lib/synergy/IClient.h index b4ef2eca..7679d104 100644 --- a/lib/synergy/IClient.h +++ b/lib/synergy/IClient.h @@ -120,6 +120,13 @@ public: */ virtual void mouseMove(SInt32 xAbs, SInt32 yAbs) = 0; + //! Notify of mouse motion + /*! + Synthesize mouse events to generate mouse motion by the relative + amount \c xRel,yRel. + */ + virtual void mouseRelativeMove(SInt32 xRel, SInt32 yRel) = 0; + //! Notify of mouse wheel motion /*! Synthesize mouse events to generate mouse wheel motion of \c delta. diff --git a/lib/synergy/IPlatformScreen.h b/lib/synergy/IPlatformScreen.h index 13bd0a31..8a5da677 100644 --- a/lib/synergy/IPlatformScreen.h +++ b/lib/synergy/IPlatformScreen.h @@ -153,6 +153,7 @@ public: // ISecondaryScreen overrides virtual void fakeMouseButton(ButtonID id, bool press) const = 0; virtual void fakeMouseMove(SInt32 x, SInt32 y) const = 0; + virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const = 0; virtual void fakeMouseWheel(SInt32 delta) const = 0; // IKeyState overrides diff --git a/lib/synergy/ISecondaryScreen.h b/lib/synergy/ISecondaryScreen.h index 1311e7af..092cd805 100644 --- a/lib/synergy/ISecondaryScreen.h +++ b/lib/synergy/ISecondaryScreen.h @@ -40,6 +40,12 @@ public: */ virtual void fakeMouseMove(SInt32 x, SInt32 y) const = 0; + //! Fake mouse move + /*! + Synthesize a mouse move to the relative coordinates \c dx,dy. + */ + virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const = 0; + //! Fake mouse wheel /*! Synthesize a mouse wheel event of amount \c delta. diff --git a/lib/synergy/OptionTypes.h b/lib/synergy/OptionTypes.h index aaefe7fa..31504993 100644 --- a/lib/synergy/OptionTypes.h +++ b/lib/synergy/OptionTypes.h @@ -55,6 +55,7 @@ static const OptionID kOptionScreenSwitchDelay = OPTION_CODE("SSWT"); static const OptionID kOptionScreenSwitchTwoTap = OPTION_CODE("SSTT"); static const OptionID kOptionScreenSaverSync = OPTION_CODE("SSVR"); static const OptionID kOptionXTestXineramaUnaware = OPTION_CODE("XTXU"); +static const OptionID kOptionRelativeMouseMoves = OPTION_CODE("MDLT"); //@} #undef OPTION_CODE diff --git a/lib/synergy/ProtocolTypes.h b/lib/synergy/ProtocolTypes.h index c1162c2d..4fd6d475 100644 --- a/lib/synergy/ProtocolTypes.h +++ b/lib/synergy/ProtocolTypes.h @@ -21,7 +21,7 @@ // 1.0: initial protocol // 1.1: adds KeyCode to key press, release, and repeat static const SInt16 kProtocolMajorVersion = 1; -static const SInt16 kProtocolMinorVersion = 1; +static const SInt16 kProtocolMinorVersion = 2; // default contact port number static const UInt16 kDefaultPort = 24800; @@ -180,6 +180,10 @@ static const char kMsgDMouseUp[] = "DMUP%1i"; // $1 = x, $2 = y. x,y are absolute screen coordinates. static const char kMsgDMouseMove[] = "DMMV%2i%2i"; +// relative mouse move: primary -> secondary +// $1 = dx, $2 = dy. dx,dy are motion deltas. +static const char kMsgDMouseRelMove[] = "DMRM%2i%2i"; + // mouse button pressed: primary -> secondary // $1 = delta. the delta should be +120 for one tick forward (away // from the user) and -120 for one tick backward (toward the user).