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".
This commit is contained in:
crs 2004-05-01 15:18:59 +00:00
parent 320cc754a2
commit 16110acaa2
22 changed files with 138 additions and 12 deletions

View File

@ -257,6 +257,12 @@ CClient::mouseMove(SInt32 x, SInt32 y)
m_screen->mouseMove(x, y); m_screen->mouseMove(x, y);
} }
void
CClient::mouseRelativeMove(SInt32 dx, SInt32 dy)
{
m_screen->mouseRelativeMove(dx, dy);
}
void void
CClient::mouseWheel(SInt32 delta) CClient::mouseWheel(SInt32 delta)
{ {

View File

@ -135,6 +135,7 @@ public:
virtual void mouseDown(ButtonID); virtual void mouseDown(ButtonID);
virtual void mouseUp(ButtonID); virtual void mouseUp(ButtonID);
virtual void mouseMove(SInt32 xAbs, SInt32 yAbs); virtual void mouseMove(SInt32 xAbs, SInt32 yAbs);
virtual void mouseRelativeMove(SInt32 xRel, SInt32 yRel);
virtual void mouseWheel(SInt32 delta); virtual void mouseWheel(SInt32 delta);
virtual void screensaver(bool activate); virtual void screensaver(bool activate);
virtual void resetOptions(); virtual void resetOptions();

View File

@ -550,6 +550,19 @@ CXWindowsScreen::fakeMouseMove(SInt32 x, SInt32 y) const
XFlush(m_display); 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 void
CXWindowsScreen::fakeMouseWheel(SInt32 delta) const CXWindowsScreen::fakeMouseWheel(SInt32 delta) const
{ {

View File

@ -55,6 +55,7 @@ public:
// ISecondaryScreen overrides // ISecondaryScreen overrides
virtual void fakeMouseButton(ButtonID id, bool press) const; virtual void fakeMouseButton(ButtonID id, bool press) const;
virtual void fakeMouseMove(SInt32 x, SInt32 y) const; virtual void fakeMouseMove(SInt32 x, SInt32 y) const;
virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const;
virtual void fakeMouseWheel(SInt32 delta) const; virtual void fakeMouseWheel(SInt32 delta) const;
// IPlatformScreen overrides // IPlatformScreen overrides

View File

@ -96,6 +96,7 @@ public:
virtual void mouseDown(ButtonID) = 0; virtual void mouseDown(ButtonID) = 0;
virtual void mouseUp(ButtonID) = 0; virtual void mouseUp(ButtonID) = 0;
virtual void mouseMove(SInt32 xAbs, SInt32 yAbs) = 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 mouseWheel(SInt32 delta) = 0;
virtual void screensaver(bool activate) = 0; virtual void screensaver(bool activate) = 0;
virtual void resetOptions() = 0; virtual void resetOptions() = 0;

View File

@ -316,6 +316,12 @@ CClientProxy1_0::mouseMove(SInt32 xAbs, SInt32 yAbs)
CProtocolUtil::writef(getStream(), kMsgDMouseMove, xAbs, yAbs); CProtocolUtil::writef(getStream(), kMsgDMouseMove, xAbs, yAbs);
} }
void
CClientProxy1_0::mouseRelativeMove(SInt32, SInt32)
{
// ignore -- not supported in protocol 1.0
}
void void
CClientProxy1_0::mouseWheel(SInt32 delta) CClientProxy1_0::mouseWheel(SInt32 delta)
{ {

View File

@ -49,6 +49,7 @@ public:
virtual void mouseDown(ButtonID); virtual void mouseDown(ButtonID);
virtual void mouseUp(ButtonID); virtual void mouseUp(ButtonID);
virtual void mouseMove(SInt32 xAbs, SInt32 yAbs); virtual void mouseMove(SInt32 xAbs, SInt32 yAbs);
virtual void mouseRelativeMove(SInt32 xRel, SInt32 yRel);
virtual void mouseWheel(SInt32 delta); virtual void mouseWheel(SInt32 delta);
virtual void screensaver(bool activate); virtual void screensaver(bool activate);
virtual void resetOptions(); virtual void resetOptions();

View File

@ -15,6 +15,7 @@
#include "CClientProxyUnknown.h" #include "CClientProxyUnknown.h"
#include "CClientProxy1_0.h" #include "CClientProxy1_0.h"
#include "CClientProxy1_1.h" #include "CClientProxy1_1.h"
#include "CClientProxy1_2.h"
#include "ProtocolTypes.h" #include "ProtocolTypes.h"
#include "CProtocolUtil.h" #include "CProtocolUtil.h"
#include "XSynergy.h" #include "XSynergy.h"
@ -214,6 +215,10 @@ CClientProxyUnknown::handleData(const CEvent&, void*)
case 1: case 1:
m_proxy = new CClientProxy1_1(name, m_stream); m_proxy = new CClientProxy1_1(name, m_stream);
break; break;
case 2:
m_proxy = new CClientProxy1_2(name, m_stream);
break;
} }
} }

View File

@ -629,6 +629,9 @@ CConfig::getOptionName(OptionID id)
if (id == kOptionXTestXineramaUnaware) { if (id == kOptionXTestXineramaUnaware) {
return "xtestIsXineramaUnaware"; return "xtestIsXineramaUnaware";
} }
if (id == kOptionRelativeMouseMoves) {
return "relativeMouseMoves";
}
return NULL; return NULL;
} }
@ -638,7 +641,8 @@ CConfig::getOptionValue(OptionID id, OptionValue value)
if (id == kOptionHalfDuplexCapsLock || if (id == kOptionHalfDuplexCapsLock ||
id == kOptionHalfDuplexNumLock || id == kOptionHalfDuplexNumLock ||
id == kOptionScreenSaverSync || id == kOptionScreenSaverSync ||
id == kOptionXTestXineramaUnaware) { id == kOptionXTestXineramaUnaware ||
id == kOptionRelativeMouseMoves) {
return (value != 0) ? "true" : "false"; return (value != 0) ? "true" : "false";
} }
if (id == kOptionModifierMapForShift || if (id == kOptionModifierMapForShift ||
@ -778,6 +782,9 @@ CConfig::readSectionOptions(std::istream& s)
else if (name == "screenSaverSync") { else if (name == "screenSaverSync") {
addOption("", kOptionScreenSaverSync, parseBoolean(value)); addOption("", kOptionScreenSaverSync, parseBoolean(value));
} }
else if (name == "relativeMouseMoves") {
addOption("", kOptionRelativeMouseMoves, parseBoolean(value));
}
else { else {
throw XConfigRead("unknown argument"); throw XConfigRead("unknown argument");
} }

View File

@ -185,6 +185,12 @@ CPrimaryClient::mouseMove(SInt32 x, SInt32 y)
m_screen->warpCursor(x, y); m_screen->warpCursor(x, y);
} }
void
CPrimaryClient::mouseRelativeMove(SInt32, SInt32)
{
// ignore
}
void void
CPrimaryClient::mouseWheel(SInt32) CPrimaryClient::mouseWheel(SInt32)
{ {

View File

@ -102,6 +102,7 @@ public:
virtual void mouseDown(ButtonID); virtual void mouseDown(ButtonID);
virtual void mouseUp(ButtonID); virtual void mouseUp(ButtonID);
virtual void mouseMove(SInt32 xAbs, SInt32 yAbs); virtual void mouseMove(SInt32 xAbs, SInt32 yAbs);
virtual void mouseRelativeMove(SInt32 xRel, SInt32 yRel);
virtual void mouseWheel(SInt32 delta); virtual void mouseWheel(SInt32 delta);
virtual void screensaver(bool activate); virtual void screensaver(bool activate);
virtual void resetOptions(); virtual void resetOptions();

View File

@ -53,7 +53,8 @@ CServer::CServer(const CConfig& config, CPrimaryClient* primaryClient) :
m_switchTwoTapDelay(0.0), m_switchTwoTapDelay(0.0),
m_switchTwoTapEngaged(false), m_switchTwoTapEngaged(false),
m_switchTwoTapArmed(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 // must have a primary client and it must have a canonical name
assert(m_primaryClient != NULL); assert(m_primaryClient != NULL);
@ -283,6 +284,9 @@ CServer::onCommandKey(KeyID id, KeyModifierMask /*mask*/, bool /*down*/)
{ {
if (id == kKeyScrollLock) { if (id == kKeyScrollLock) {
m_primaryClient->reconfigure(getActivePrimarySides()); m_primaryClient->reconfigure(getActivePrimarySides());
if (!isLockedToScreenServer()) {
stopRelativeMoves();
}
} }
return false; return false;
} }
@ -322,13 +326,7 @@ bool
CServer::isLockedToScreenServer() const CServer::isLockedToScreenServer() const
{ {
// locked if scroll-lock is toggled on // locked if scroll-lock is toggled on
if ((m_primaryClient->getToggleMask() & KeyModifierScrollLock) != 0) { return ((m_primaryClient->getToggleMask() & KeyModifierScrollLock) != 0);
LOG((CLOG_DEBUG "locked by ScrollLock"));
return true;
}
// not locked
return false;
} }
bool bool
@ -336,6 +334,7 @@ CServer::isLockedToScreen() const
{ {
// locked if we say we're locked // locked if we say we're locked
if (isLockedToScreenServer()) { if (isLockedToScreenServer()) {
LOG((CLOG_DEBUG "locked by ScrollLock"));
return true; return true;
} }
@ -841,6 +840,24 @@ CServer::isSwitchWaitStarted() const
return (m_switchWaitTimer != NULL); 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 void
CServer::sendOptions(IClient* client) const CServer::sendOptions(IClient* client) const
{ {
@ -883,6 +900,7 @@ CServer::processOptions()
return; return;
} }
bool newRelativeMoves = m_relativeMoves;
for (CConfig::CScreenOptions::const_iterator index = options->begin(); for (CConfig::CScreenOptions::const_iterator index = options->begin();
index != options->end(); ++index) { index != options->end(); ++index) {
const OptionID id = index->first; const OptionID id = index->first;
@ -901,9 +919,17 @@ CServer::processOptions()
} }
stopSwitchTwoTap(); stopSwitchTwoTap();
} }
else if (id == kOptionRelativeMouseMoves) {
newRelativeMoves = (value != 0);
} }
} }
if (m_relativeMoves && !newRelativeMoves) {
stopRelativeMoves();
}
m_relativeMoves = newRelativeMoves;
}
void void
CServer::handleShapeChanged(const CEvent&, void* vclient) CServer::handleShapeChanged(const CEvent&, void* vclient)
{ {
@ -1339,6 +1365,18 @@ CServer::onMouseMoveSecondary(SInt32 dx, SInt32 dy)
return; 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 // save old position
const SInt32 xOld = m_x; const SInt32 xOld = m_x;
const SInt32 yOld = m_y; const SInt32 yOld = m_y;

View File

@ -26,8 +26,6 @@
#include "stdset.h" #include "stdset.h"
#include "stdvector.h" #include "stdvector.h"
class CClientProxy;
class CClientProxyUnknown;
class CEventQueueTimer; class CEventQueueTimer;
class CPrimaryClient; class CPrimaryClient;
class IClient; class IClient;
@ -183,6 +181,9 @@ private:
// returns true iff the delay switch timer is started // returns true iff the delay switch timer is started
bool isSwitchWaitStarted() const; bool isSwitchWaitStarted() const;
// stop relative mouse moves
void stopRelativeMoves();
// send screen options to \c client // send screen options to \c client
void sendOptions(IClient* client) const; void sendOptions(IClient* client) const;
@ -312,6 +313,9 @@ private:
bool m_switchTwoTapArmed; bool m_switchTwoTapArmed;
SInt32 m_switchTwoTapZone; SInt32 m_switchTwoTapZone;
// relative mouse move option
bool m_relativeMoves;
static CEvent::Type s_errorEvent; static CEvent::Type s_errorEvent;
static CEvent::Type s_disconnectedEvent; static CEvent::Type s_disconnectedEvent;
}; };

View File

@ -27,6 +27,7 @@ libserver_a_SOURCES = \
CClientProxy.cpp \ CClientProxy.cpp \
CClientProxy1_0.cpp \ CClientProxy1_0.cpp \
CClientProxy1_1.cpp \ CClientProxy1_1.cpp \
CClientProxy1_2.cpp \
CClientProxyUnknown.cpp \ CClientProxyUnknown.cpp \
CConfig.cpp \ CConfig.cpp \
CPrimaryClient.cpp \ CPrimaryClient.cpp \
@ -35,6 +36,7 @@ libserver_a_SOURCES = \
CClientProxy.h \ CClientProxy.h \
CClientProxy1_0.h \ CClientProxy1_0.h \
CClientProxy1_1.h \ CClientProxy1_1.h \
CClientProxy1_2.h \
CClientProxyUnknown.h \ CClientProxyUnknown.h \
CConfig.h \ CConfig.h \
CPrimaryClient.h \ CPrimaryClient.h \

View File

@ -45,6 +45,7 @@ public:
// ISecondaryScreen overrides // ISecondaryScreen overrides
virtual void fakeMouseButton(ButtonID id, bool press) const = 0; virtual void fakeMouseButton(ButtonID id, bool press) const = 0;
virtual void fakeMouseMove(SInt32 x, SInt32 y) 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; virtual void fakeMouseWheel(SInt32 delta) const = 0;
// IKeyState overrides // IKeyState overrides

View File

@ -222,6 +222,13 @@ CScreen::mouseMove(SInt32 x, SInt32 y)
m_screen->fakeMouseMove(x, y); m_screen->fakeMouseMove(x, y);
} }
void
CScreen::mouseRelativeMove(SInt32 dx, SInt32 dy)
{
assert(!m_isPrimary);
m_screen->fakeMouseRelativeMove(dx, dy);
}
void void
CScreen::mouseWheel(SInt32 delta) CScreen::mouseWheel(SInt32 delta)
{ {

View File

@ -146,6 +146,13 @@ public:
*/ */
void mouseMove(SInt32 xAbs, SInt32 yAbs); 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 //! Notify of mouse wheel motion
/*! /*!
Synthesize mouse events to generate mouse wheel motion of \c delta. Synthesize mouse events to generate mouse wheel motion of \c delta.

View File

@ -120,6 +120,13 @@ public:
*/ */
virtual void mouseMove(SInt32 xAbs, SInt32 yAbs) = 0; 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 //! Notify of mouse wheel motion
/*! /*!
Synthesize mouse events to generate mouse wheel motion of \c delta. Synthesize mouse events to generate mouse wheel motion of \c delta.

View File

@ -153,6 +153,7 @@ public:
// ISecondaryScreen overrides // ISecondaryScreen overrides
virtual void fakeMouseButton(ButtonID id, bool press) const = 0; virtual void fakeMouseButton(ButtonID id, bool press) const = 0;
virtual void fakeMouseMove(SInt32 x, SInt32 y) 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; virtual void fakeMouseWheel(SInt32 delta) const = 0;
// IKeyState overrides // IKeyState overrides

View File

@ -40,6 +40,12 @@ public:
*/ */
virtual void fakeMouseMove(SInt32 x, SInt32 y) const = 0; 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 //! Fake mouse wheel
/*! /*!
Synthesize a mouse wheel event of amount \c delta. Synthesize a mouse wheel event of amount \c delta.

View File

@ -55,6 +55,7 @@ static const OptionID kOptionScreenSwitchDelay = OPTION_CODE("SSWT");
static const OptionID kOptionScreenSwitchTwoTap = OPTION_CODE("SSTT"); static const OptionID kOptionScreenSwitchTwoTap = OPTION_CODE("SSTT");
static const OptionID kOptionScreenSaverSync = OPTION_CODE("SSVR"); static const OptionID kOptionScreenSaverSync = OPTION_CODE("SSVR");
static const OptionID kOptionXTestXineramaUnaware = OPTION_CODE("XTXU"); static const OptionID kOptionXTestXineramaUnaware = OPTION_CODE("XTXU");
static const OptionID kOptionRelativeMouseMoves = OPTION_CODE("MDLT");
//@} //@}
#undef OPTION_CODE #undef OPTION_CODE

View File

@ -21,7 +21,7 @@
// 1.0: initial protocol // 1.0: initial protocol
// 1.1: adds KeyCode to key press, release, and repeat // 1.1: adds KeyCode to key press, release, and repeat
static const SInt16 kProtocolMajorVersion = 1; static const SInt16 kProtocolMajorVersion = 1;
static const SInt16 kProtocolMinorVersion = 1; static const SInt16 kProtocolMinorVersion = 2;
// default contact port number // default contact port number
static const UInt16 kDefaultPort = 24800; 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. // $1 = x, $2 = y. x,y are absolute screen coordinates.
static const char kMsgDMouseMove[] = "DMMV%2i%2i"; 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 // mouse button pressed: primary -> secondary
// $1 = delta. the delta should be +120 for one tick forward (away // $1 = delta. the delta should be +120 for one tick forward (away
// from the user) and -120 for one tick backward (toward the user). // from the user) and -120 for one tick backward (toward the user).