moving 1.4 to trunk

This commit is contained in:
Nick Bolton
2012-06-10 16:50:54 +00:00
parent cdeb3a7824
commit 488241850c
1291 changed files with 425650 additions and 12 deletions

View File

@@ -0,0 +1,55 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2006 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "CBaseClientProxy.h"
//
// CBaseClientProxy
//
CBaseClientProxy::CBaseClientProxy(const CString& name) :
m_name(name),
m_x(0),
m_y(0)
{
// do nothing
}
CBaseClientProxy::~CBaseClientProxy()
{
// do nothing
}
void
CBaseClientProxy::setJumpCursorPos(SInt32 x, SInt32 y)
{
m_x = x;
m_y = y;
}
void
CBaseClientProxy::getJumpCursorPos(SInt32& x, SInt32& y) const
{
x = m_x;
y = m_y;
}
CString
CBaseClientProxy::getName() const
{
return m_name;
}

View File

@@ -0,0 +1,92 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CBASECLIENTPROXY_H
#define CBASECLIENTPROXY_H
#include "IClient.h"
#include "CString.h"
//! Generic proxy for client or primary
class CBaseClientProxy : public IClient {
public:
/*!
\c name is the name of the client.
*/
CBaseClientProxy(const CString& name);
~CBaseClientProxy();
//! @name manipulators
//@{
//! Save cursor position
/*!
Save the position of the cursor when jumping from client.
*/
void setJumpCursorPos(SInt32 x, SInt32 y);
//@}
//! @name accessors
//@{
//! Get cursor position
/*!
Get the position of the cursor when last jumping from client.
*/
void getJumpCursorPos(SInt32& x, SInt32& y) const;
//@}
// IScreen
virtual void* getEventTarget() const = 0;
virtual bool getClipboard(ClipboardID id, IClipboard*) const = 0;
virtual void getShape(SInt32& x, SInt32& y,
SInt32& width, SInt32& height) const = 0;
virtual void getCursorPos(SInt32& x, SInt32& y) const = 0;
// IClient overrides
virtual void enter(SInt32 xAbs, SInt32 yAbs,
UInt32 seqNum, KeyModifierMask mask,
bool forScreensaver) = 0;
virtual bool leave() = 0;
virtual void setClipboard(ClipboardID, const IClipboard*) = 0;
virtual void grabClipboard(ClipboardID) = 0;
virtual void setClipboardDirty(ClipboardID, bool) = 0;
virtual void keyDown(KeyID, KeyModifierMask, KeyButton) = 0;
virtual void keyRepeat(KeyID, KeyModifierMask,
SInt32 count, KeyButton) = 0;
virtual void keyUp(KeyID, KeyModifierMask, KeyButton) = 0;
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 xDelta, SInt32 yDelta) = 0;
virtual void gameDeviceButtons(GameDeviceID id, GameDeviceButton buttons) = 0;
virtual void gameDeviceSticks(GameDeviceID id, SInt16 x1, SInt16 y1, SInt16 x2, SInt16 y2) = 0;
virtual void gameDeviceTriggers(GameDeviceID id, UInt8 t1, UInt8 t2) = 0;
virtual void gameDeviceTimingReq() = 0;
virtual void screensaver(bool activate) = 0;
virtual void resetOptions() = 0;
virtual void setOptions(const COptionsList& options) = 0;
virtual CString getName() const;
private:
CString m_name;
SInt32 m_x, m_y;
};
#endif

View File

@@ -0,0 +1,207 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2004 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "CClientListener.h"
#include "CClientProxy.h"
#include "CClientProxyUnknown.h"
#include "CPacketStreamFilter.h"
#include "IStreamFilterFactory.h"
#include "IDataSocket.h"
#include "IListenSocket.h"
#include "ISocketFactory.h"
#include "XSocket.h"
#include "CLog.h"
#include "IEventQueue.h"
#include "TMethodEventJob.h"
//
// CClientListener
//
CEvent::Type CClientListener::s_connectedEvent = CEvent::kUnknown;
CClientListener::CClientListener(const CNetworkAddress& address,
ISocketFactory* socketFactory,
IStreamFilterFactory* streamFilterFactory) :
m_socketFactory(socketFactory),
m_streamFilterFactory(streamFilterFactory),
m_server(NULL)
{
assert(m_socketFactory != NULL);
try {
// create listen socket
m_listen = m_socketFactory->createListen();
// bind listen address
LOG((CLOG_DEBUG1 "binding listen socket"));
m_listen->bind(address);
}
catch (XSocketAddressInUse&) {
delete m_listen;
delete m_socketFactory;
delete m_streamFilterFactory;
throw;
}
catch (XBase&) {
delete m_listen;
delete m_socketFactory;
delete m_streamFilterFactory;
throw;
}
LOG((CLOG_DEBUG1 "listening for clients"));
// setup event handler
EVENTQUEUE->adoptHandler(IListenSocket::getConnectingEvent(), m_listen,
new TMethodEventJob<CClientListener>(this,
&CClientListener::handleClientConnecting));
}
CClientListener::~CClientListener()
{
LOG((CLOG_DEBUG1 "stop listening for clients"));
// discard already connected clients
for (CNewClients::iterator index = m_newClients.begin();
index != m_newClients.end(); ++index) {
CClientProxyUnknown* client = *index;
EVENTQUEUE->removeHandler(
CClientProxyUnknown::getSuccessEvent(), client);
EVENTQUEUE->removeHandler(
CClientProxyUnknown::getFailureEvent(), client);
EVENTQUEUE->removeHandler(
CClientProxy::getDisconnectedEvent(), client);
delete client;
}
// discard waiting clients
CClientProxy* client = getNextClient();
while (client != NULL) {
delete client;
client = getNextClient();
}
EVENTQUEUE->removeHandler(IListenSocket::getConnectingEvent(), m_listen);
delete m_listen;
delete m_socketFactory;
delete m_streamFilterFactory;
}
void
CClientListener::setServer(CServer* server)
{
assert(server != NULL);
m_server = server;
}
CClientProxy*
CClientListener::getNextClient()
{
CClientProxy* client = NULL;
if (!m_waitingClients.empty()) {
client = m_waitingClients.front();
m_waitingClients.pop_front();
EVENTQUEUE->removeHandler(CClientProxy::getDisconnectedEvent(), client);
}
return client;
}
CEvent::Type
CClientListener::getConnectedEvent()
{
return EVENTQUEUE->registerTypeOnce(s_connectedEvent,
"CClientListener::connected");
}
void
CClientListener::handleClientConnecting(const CEvent&, void*)
{
// accept client connection
IStream* stream = m_listen->accept();
if (stream == NULL) {
return;
}
LOG((CLOG_NOTE "accepted client connection"));
// filter socket messages, including a packetizing filter
if (m_streamFilterFactory != NULL) {
stream = m_streamFilterFactory->create(stream, true);
}
stream = new CPacketStreamFilter(stream, true);
assert(m_server != NULL);
// create proxy for unknown client
CClientProxyUnknown* client = new CClientProxyUnknown(stream, 30.0, m_server);
m_newClients.insert(client);
// watch for events from unknown client
EVENTQUEUE->adoptHandler(CClientProxyUnknown::getSuccessEvent(), client,
new TMethodEventJob<CClientListener>(this,
&CClientListener::handleUnknownClient, client));
EVENTQUEUE->adoptHandler(CClientProxyUnknown::getFailureEvent(), client,
new TMethodEventJob<CClientListener>(this,
&CClientListener::handleUnknownClient, client));
}
void
CClientListener::handleUnknownClient(const CEvent&, void* vclient)
{
CClientProxyUnknown* unknownClient =
reinterpret_cast<CClientProxyUnknown*>(vclient);
// we should have the client in our new client list
assert(m_newClients.count(unknownClient) == 1);
// get the real client proxy and install it
CClientProxy* client = unknownClient->orphanClientProxy();
if (client != NULL) {
// handshake was successful
m_waitingClients.push_back(client);
EVENTQUEUE->addEvent(CEvent(getConnectedEvent(), this));
// watch for client to disconnect while it's in our queue
EVENTQUEUE->adoptHandler(CClientProxy::getDisconnectedEvent(), client,
new TMethodEventJob<CClientListener>(this,
&CClientListener::handleClientDisconnected,
client));
}
// now finished with unknown client
EVENTQUEUE->removeHandler(CClientProxyUnknown::getSuccessEvent(), client);
EVENTQUEUE->removeHandler(CClientProxyUnknown::getFailureEvent(), client);
m_newClients.erase(unknownClient);
delete unknownClient;
}
void
CClientListener::handleClientDisconnected(const CEvent&, void* vclient)
{
CClientProxy* client = reinterpret_cast<CClientProxy*>(vclient);
// find client in waiting clients queue
for (CWaitingClients::iterator i = m_waitingClients.begin(),
n = m_waitingClients.end(); i != n; ++i) {
if (*i == client) {
m_waitingClients.erase(i);
EVENTQUEUE->removeHandler(CClientProxy::getDisconnectedEvent(),
client);
delete client;
break;
}
}
}

View File

@@ -0,0 +1,88 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2004 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CCLIENTLISTENER_H
#define CCLIENTLISTENER_H
#include "CConfig.h"
#include "CEvent.h"
#include "stddeque.h"
#include "stdset.h"
class CClientProxy;
class CClientProxyUnknown;
class CNetworkAddress;
class IListenSocket;
class ISocketFactory;
class IStreamFilterFactory;
class CServer;
class CClientListener {
public:
// The factories are adopted.
CClientListener(const CNetworkAddress&,
ISocketFactory*, IStreamFilterFactory*);
~CClientListener();
//! @name manipulators
//@{
void setServer(CServer* server);
//@}
//! @name accessors
//@{
//! Get next connected client
/*!
Returns the next connected client and removes it from the internal
list. The client is responsible for deleting the returned client.
Returns NULL if no clients are available.
*/
CClientProxy* getNextClient();
//! Get connected event type
/*!
Returns the connected event type. This is sent whenever a
a client connects.
*/
static CEvent::Type getConnectedEvent();
//@}
private:
// client connection event handlers
void handleClientConnecting(const CEvent&, void*);
void handleUnknownClient(const CEvent&, void*);
void handleClientDisconnected(const CEvent&, void*);
private:
typedef std::set<CClientProxyUnknown*> CNewClients;
typedef std::deque<CClientProxy*> CWaitingClients;
IListenSocket* m_listen;
ISocketFactory* m_socketFactory;
IStreamFilterFactory* m_streamFilterFactory;
CNewClients m_newClients;
CWaitingClients m_waitingClients;
static CEvent::Type s_connectedEvent;
CServer* m_server;
};
#endif

View File

@@ -0,0 +1,93 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "CClientProxy.h"
#include "CProtocolUtil.h"
#include "IStream.h"
#include "CLog.h"
#include "CEventQueue.h"
//
// CClientProxy
//
CEvent::Type CClientProxy::s_readyEvent = CEvent::kUnknown;
CEvent::Type CClientProxy::s_disconnectedEvent = CEvent::kUnknown;
CEvent::Type CClientProxy::s_clipboardChangedEvent= CEvent::kUnknown;
CEvent::Type CClientProxy::s_gameDeviceTimingRecvEvent= CEvent::kUnknown;
CClientProxy::CClientProxy(const CString& name, IStream* stream) :
CBaseClientProxy(name),
m_stream(stream)
{
// do nothing
}
CClientProxy::~CClientProxy()
{
delete m_stream;
}
void
CClientProxy::close(const char* msg)
{
LOG((CLOG_DEBUG1 "send close \"%s\" to \"%s\"", msg, getName().c_str()));
CProtocolUtil::writef(getStream(), msg);
// force the close to be sent before we return
getStream()->flush();
}
IStream*
CClientProxy::getStream() const
{
return m_stream;
}
CEvent::Type
CClientProxy::getReadyEvent()
{
return EVENTQUEUE->registerTypeOnce(s_readyEvent,
"CClientProxy::ready");
}
CEvent::Type
CClientProxy::getDisconnectedEvent()
{
return EVENTQUEUE->registerTypeOnce(s_disconnectedEvent,
"CClientProxy::disconnected");
}
CEvent::Type
CClientProxy::getClipboardChangedEvent()
{
return EVENTQUEUE->registerTypeOnce(s_clipboardChangedEvent,
"CClientProxy::clipboardChanged");
}
CEvent::Type
CClientProxy::getGameDeviceTimingRespEvent()
{
return EVENTQUEUE->registerTypeOnce(s_gameDeviceTimingRecvEvent,
"CClientProxy::gameDeviceTimingRecv");
}
void*
CClientProxy::getEventTarget() const
{
return static_cast<IScreen*>(const_cast<CClientProxy*>(this));
}

View File

@@ -0,0 +1,128 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CCLIENTPROXY_H
#define CCLIENTPROXY_H
#include "CBaseClientProxy.h"
#include "CEvent.h"
#include "CString.h"
class IStream;
//! Generic proxy for client
class CClientProxy : public CBaseClientProxy {
public:
/*!
\c name is the name of the client.
*/
CClientProxy(const CString& name, IStream* adoptedStream);
~CClientProxy();
//! @name manipulators
//@{
//! Disconnect
/*!
Ask the client to disconnect, using \p msg as the reason.
*/
void close(const char* msg);
//@}
//! @name accessors
//@{
//! Get stream
/*!
Returns the stream passed to the c'tor.
*/
IStream* getStream() const;
//! Get ready event type
/*!
Returns the ready event type. This is sent when the client has
completed the initial handshake. Until it is sent, the client is
not fully connected.
*/
static CEvent::Type getReadyEvent();
//! Get disconnect event type
/*!
Returns the disconnect event type. This is sent when the client
disconnects or is disconnected. The target is getEventTarget().
*/
static CEvent::Type getDisconnectedEvent();
//! Get clipboard changed event type
/*!
Returns the clipboard changed event type. This is sent whenever the
contents of the clipboard has changed. The data is a pointer to a
IScreen::CClipboardInfo.
*/
static CEvent::Type getClipboardChangedEvent();
//! Get game device timing receive event type
/*!
Returns the game device timing receive event type. This is set
whenever the server receives to a timing event response from a client.
*/
static CEvent::Type getGameDeviceTimingRespEvent();
//@}
// IScreen
virtual void* getEventTarget() const;
virtual bool getClipboard(ClipboardID id, IClipboard*) const = 0;
virtual void getShape(SInt32& x, SInt32& y,
SInt32& width, SInt32& height) const = 0;
virtual void getCursorPos(SInt32& x, SInt32& y) const = 0;
// IClient overrides
virtual void enter(SInt32 xAbs, SInt32 yAbs,
UInt32 seqNum, KeyModifierMask mask,
bool forScreensaver) = 0;
virtual bool leave() = 0;
virtual void setClipboard(ClipboardID, const IClipboard*) = 0;
virtual void grabClipboard(ClipboardID) = 0;
virtual void setClipboardDirty(ClipboardID, bool) = 0;
virtual void keyDown(KeyID, KeyModifierMask, KeyButton) = 0;
virtual void keyRepeat(KeyID, KeyModifierMask,
SInt32 count, KeyButton) = 0;
virtual void keyUp(KeyID, KeyModifierMask, KeyButton) = 0;
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 xDelta, SInt32 yDelta) = 0;
virtual void screensaver(bool activate) = 0;
virtual void resetOptions() = 0;
virtual void setOptions(const COptionsList& options) = 0;
virtual void gameDeviceButtons(GameDeviceID id, GameDeviceButton buttons) = 0;
virtual void gameDeviceSticks(GameDeviceID id, SInt16 x1, SInt16 y1, SInt16 x2, SInt16 y2) = 0;
virtual void gameDeviceTriggers(GameDeviceID id, UInt8 t1, UInt8 t2) = 0;
virtual void gameDeviceTimingReq() = 0;
private:
IStream* m_stream;
static CEvent::Type s_readyEvent;
static CEvent::Type s_disconnectedEvent;
static CEvent::Type s_clipboardChangedEvent;
static CEvent::Type s_gameDeviceTimingRecvEvent;
};
#endif

View File

@@ -0,0 +1,529 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "CClientProxy1_0.h"
#include "CProtocolUtil.h"
#include "XSynergy.h"
#include "IStream.h"
#include "CLog.h"
#include "IEventQueue.h"
#include "TMethodEventJob.h"
#include <cstring>
//
// CClientProxy1_0
//
CClientProxy1_0::CClientProxy1_0(const CString& name, IStream* stream) :
CClientProxy(name, stream),
m_heartbeatTimer(NULL),
m_parser(&CClientProxy1_0::parseHandshakeMessage)
{
// install event handlers
EVENTQUEUE->adoptHandler(stream->getInputReadyEvent(),
stream->getEventTarget(),
new TMethodEventJob<CClientProxy1_0>(this,
&CClientProxy1_0::handleData, NULL));
EVENTQUEUE->adoptHandler(stream->getOutputErrorEvent(),
stream->getEventTarget(),
new TMethodEventJob<CClientProxy1_0>(this,
&CClientProxy1_0::handleWriteError, NULL));
EVENTQUEUE->adoptHandler(stream->getInputShutdownEvent(),
stream->getEventTarget(),
new TMethodEventJob<CClientProxy1_0>(this,
&CClientProxy1_0::handleDisconnect, NULL));
EVENTQUEUE->adoptHandler(stream->getOutputShutdownEvent(),
stream->getEventTarget(),
new TMethodEventJob<CClientProxy1_0>(this,
&CClientProxy1_0::handleWriteError, NULL));
EVENTQUEUE->adoptHandler(CEvent::kTimer, this,
new TMethodEventJob<CClientProxy1_0>(this,
&CClientProxy1_0::handleFlatline, NULL));
setHeartbeatRate(kHeartRate, kHeartRate * kHeartBeatsUntilDeath);
LOG((CLOG_DEBUG1 "querying client \"%s\" info", getName().c_str()));
CProtocolUtil::writef(getStream(), kMsgQInfo);
}
CClientProxy1_0::~CClientProxy1_0()
{
removeHandlers();
}
void
CClientProxy1_0::disconnect()
{
removeHandlers();
getStream()->close();
EVENTQUEUE->addEvent(CEvent(getDisconnectedEvent(), getEventTarget()));
}
void
CClientProxy1_0::removeHandlers()
{
// uninstall event handlers
EVENTQUEUE->removeHandler(getStream()->getInputReadyEvent(),
getStream()->getEventTarget());
EVENTQUEUE->removeHandler(getStream()->getOutputErrorEvent(),
getStream()->getEventTarget());
EVENTQUEUE->removeHandler(getStream()->getInputShutdownEvent(),
getStream()->getEventTarget());
EVENTQUEUE->removeHandler(getStream()->getOutputShutdownEvent(),
getStream()->getEventTarget());
EVENTQUEUE->removeHandler(CEvent::kTimer, this);
// remove timer
removeHeartbeatTimer();
}
void
CClientProxy1_0::addHeartbeatTimer()
{
if (m_heartbeatAlarm > 0.0) {
m_heartbeatTimer = EVENTQUEUE->newOneShotTimer(m_heartbeatAlarm, this);
}
}
void
CClientProxy1_0::removeHeartbeatTimer()
{
if (m_heartbeatTimer != NULL) {
EVENTQUEUE->deleteTimer(m_heartbeatTimer);
m_heartbeatTimer = NULL;
}
}
void
CClientProxy1_0::resetHeartbeatTimer()
{
// reset the alarm
removeHeartbeatTimer();
addHeartbeatTimer();
}
void
CClientProxy1_0::resetHeartbeatRate()
{
setHeartbeatRate(kHeartRate, kHeartRate * kHeartBeatsUntilDeath);
}
void
CClientProxy1_0::setHeartbeatRate(double, double alarm)
{
m_heartbeatAlarm = alarm;
}
void
CClientProxy1_0::handleData(const CEvent&, void*)
{
// handle messages until there are no more. first read message code.
UInt8 code[4];
UInt32 n = getStream()->read(code, 4);
while (n != 0) {
// verify we got an entire code
if (n != 4) {
LOG((CLOG_ERR "incomplete message from \"%s\": %d bytes", getName().c_str(), n));
disconnect();
return;
}
// parse message
LOG((CLOG_DEBUG2 "msg from \"%s\": %c%c%c%c", getName().c_str(), code[0], code[1], code[2], code[3]));
if (!(this->*m_parser)(code)) {
LOG((CLOG_ERR "invalid message from client \"%s\": %c%c%c%c", getName().c_str(), code[0], code[1], code[2], code[3]));
disconnect();
return;
}
// next message
n = getStream()->read(code, 4);
}
// restart heartbeat timer
resetHeartbeatTimer();
}
bool
CClientProxy1_0::parseHandshakeMessage(const UInt8* code)
{
if (memcmp(code, kMsgCNoop, 4) == 0) {
// discard no-ops
LOG((CLOG_DEBUG2 "no-op from", getName().c_str()));
return true;
}
else if (memcmp(code, kMsgDInfo, 4) == 0) {
// future messages get parsed by parseMessage
m_parser = &CClientProxy1_0::parseMessage;
if (recvInfo()) {
EVENTQUEUE->addEvent(CEvent(getReadyEvent(), getEventTarget()));
addHeartbeatTimer();
return true;
}
}
return false;
}
bool
CClientProxy1_0::parseMessage(const UInt8* code)
{
if (memcmp(code, kMsgDInfo, 4) == 0) {
if (recvInfo()) {
EVENTQUEUE->addEvent(
CEvent(getShapeChangedEvent(), getEventTarget()));
return true;
}
return false;
}
else if (memcmp(code, kMsgCNoop, 4) == 0) {
// discard no-ops
LOG((CLOG_DEBUG2 "no-op from", getName().c_str()));
return true;
}
else if (memcmp(code, kMsgCClipboard, 4) == 0) {
return recvGrabClipboard();
}
else if (memcmp(code, kMsgDClipboard, 4) == 0) {
return recvClipboard();
}
return false;
}
void
CClientProxy1_0::handleDisconnect(const CEvent&, void*)
{
LOG((CLOG_NOTE "client \"%s\" has disconnected", getName().c_str()));
disconnect();
}
void
CClientProxy1_0::handleWriteError(const CEvent&, void*)
{
LOG((CLOG_WARN "error writing to client \"%s\"", getName().c_str()));
disconnect();
}
void
CClientProxy1_0::handleFlatline(const CEvent&, void*)
{
// didn't get a heartbeat fast enough. assume client is dead.
LOG((CLOG_NOTE "client \"%s\" is dead", getName().c_str()));
disconnect();
}
bool
CClientProxy1_0::getClipboard(ClipboardID id, IClipboard* clipboard) const
{
CClipboard::copy(clipboard, &m_clipboard[id].m_clipboard);
return true;
}
void
CClientProxy1_0::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const
{
x = m_info.m_x;
y = m_info.m_y;
w = m_info.m_w;
h = m_info.m_h;
}
void
CClientProxy1_0::getCursorPos(SInt32& x, SInt32& y) const
{
// note -- this returns the cursor pos from when we last got client info
x = m_info.m_mx;
y = m_info.m_my;
}
void
CClientProxy1_0::enter(SInt32 xAbs, SInt32 yAbs,
UInt32 seqNum, KeyModifierMask mask, bool)
{
LOG((CLOG_DEBUG1 "send enter to \"%s\", %d,%d %d %04x", getName().c_str(), xAbs, yAbs, seqNum, mask));
CProtocolUtil::writef(getStream(), kMsgCEnter,
xAbs, yAbs, seqNum, mask);
}
bool
CClientProxy1_0::leave()
{
LOG((CLOG_DEBUG1 "send leave to \"%s\"", getName().c_str()));
CProtocolUtil::writef(getStream(), kMsgCLeave);
// we can never prevent the user from leaving
return true;
}
void
CClientProxy1_0::setClipboard(ClipboardID id, const IClipboard* clipboard)
{
// ignore if this clipboard is already clean
if (m_clipboard[id].m_dirty) {
// this clipboard is now clean
m_clipboard[id].m_dirty = false;
CClipboard::copy(&m_clipboard[id].m_clipboard, clipboard);
CString data = m_clipboard[id].m_clipboard.marshall();
LOG((CLOG_DEBUG "send clipboard %d to \"%s\" size=%d", id, getName().c_str(), data.size()));
CProtocolUtil::writef(getStream(), kMsgDClipboard, id, 0, &data);
}
}
void
CClientProxy1_0::grabClipboard(ClipboardID id)
{
LOG((CLOG_DEBUG "send grab clipboard %d to \"%s\"", id, getName().c_str()));
CProtocolUtil::writef(getStream(), kMsgCClipboard, id, 0);
// this clipboard is now dirty
m_clipboard[id].m_dirty = true;
}
void
CClientProxy1_0::setClipboardDirty(ClipboardID id, bool dirty)
{
m_clipboard[id].m_dirty = dirty;
}
void
CClientProxy1_0::keyDown(KeyID key, KeyModifierMask mask, KeyButton)
{
LOG((CLOG_DEBUG1 "send key down to \"%s\" id=%d, mask=0x%04x", getName().c_str(), key, mask));
CProtocolUtil::writef(getStream(), kMsgDKeyDown1_0, key, mask);
}
void
CClientProxy1_0::keyRepeat(KeyID key, KeyModifierMask mask,
SInt32 count, KeyButton)
{
LOG((CLOG_DEBUG1 "send key repeat to \"%s\" id=%d, mask=0x%04x, count=%d", getName().c_str(), key, mask, count));
CProtocolUtil::writef(getStream(), kMsgDKeyRepeat1_0, key, mask, count);
}
void
CClientProxy1_0::keyUp(KeyID key, KeyModifierMask mask, KeyButton)
{
LOG((CLOG_DEBUG1 "send key up to \"%s\" id=%d, mask=0x%04x", getName().c_str(), key, mask));
CProtocolUtil::writef(getStream(), kMsgDKeyUp1_0, key, mask);
}
void
CClientProxy1_0::mouseDown(ButtonID button)
{
LOG((CLOG_DEBUG1 "send mouse down to \"%s\" id=%d", getName().c_str(), button));
CProtocolUtil::writef(getStream(), kMsgDMouseDown, button);
}
void
CClientProxy1_0::mouseUp(ButtonID button)
{
LOG((CLOG_DEBUG1 "send mouse up to \"%s\" id=%d", getName().c_str(), button));
CProtocolUtil::writef(getStream(), kMsgDMouseUp, button);
}
void
CClientProxy1_0::mouseMove(SInt32 xAbs, SInt32 yAbs)
{
LOG((CLOG_DEBUG2 "send mouse move to \"%s\" %d,%d", getName().c_str(), xAbs, 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, SInt32 yDelta)
{
// clients prior to 1.3 only support the y axis
LOG((CLOG_DEBUG2 "send mouse wheel to \"%s\" %+d", getName().c_str(), yDelta));
CProtocolUtil::writef(getStream(), kMsgDMouseWheel1_0, yDelta);
}
void
CClientProxy1_0::gameDeviceButtons(GameDeviceID, GameDeviceButton)
{
// ignore -- not supported in protocol 1.0
LOG((CLOG_DEBUG "gameDeviceButtons not supported"));
}
void
CClientProxy1_0::gameDeviceSticks(GameDeviceID, SInt16, SInt16, SInt16, SInt16)
{
// ignore -- not supported in protocol 1.0
LOG((CLOG_DEBUG "gameDeviceSticks not supported"));
}
void
CClientProxy1_0::gameDeviceTriggers(GameDeviceID, UInt8, UInt8)
{
// ignore -- not supported in protocol 1.0
LOG((CLOG_DEBUG "gameDeviceTriggers not supported"));
}
void
CClientProxy1_0::gameDeviceTimingReq()
{
// ignore -- not supported in protocol 1.0
LOG((CLOG_DEBUG "gameDeviceTimingReq not supported"));
}
void
CClientProxy1_0::screensaver(bool on)
{
LOG((CLOG_DEBUG1 "send screen saver to \"%s\" on=%d", getName().c_str(), on ? 1 : 0));
CProtocolUtil::writef(getStream(), kMsgCScreenSaver, on ? 1 : 0);
}
void
CClientProxy1_0::resetOptions()
{
LOG((CLOG_DEBUG1 "send reset options to \"%s\"", getName().c_str()));
CProtocolUtil::writef(getStream(), kMsgCResetOptions);
// reset heart rate and death
resetHeartbeatRate();
removeHeartbeatTimer();
addHeartbeatTimer();
}
void
CClientProxy1_0::setOptions(const COptionsList& options)
{
LOG((CLOG_DEBUG1 "send set options to \"%s\" size=%d", getName().c_str(), options.size()));
CProtocolUtil::writef(getStream(), kMsgDSetOptions, &options);
// check options
for (UInt32 i = 0, n = (UInt32)options.size(); i < n; i += 2) {
if (options[i] == kOptionHeartbeat) {
double rate = 1.0e-3 * static_cast<double>(options[i + 1]);
if (rate <= 0.0) {
rate = -1.0;
}
setHeartbeatRate(rate, rate * kHeartBeatsUntilDeath);
removeHeartbeatTimer();
addHeartbeatTimer();
}
}
}
bool
CClientProxy1_0::recvInfo()
{
// parse the message
SInt16 x, y, w, h, dummy1, mx, my;
if (!CProtocolUtil::readf(getStream(), kMsgDInfo + 4,
&x, &y, &w, &h, &dummy1, &mx, &my)) {
return false;
}
LOG((CLOG_DEBUG "received client \"%s\" info shape=%d,%d %dx%d at %d,%d", getName().c_str(), x, y, w, h, mx, my));
// validate
if (w <= 0 || h <= 0) {
return false;
}
if (mx < x || mx >= x + w || my < y || my >= y + h) {
mx = x + w / 2;
my = y + h / 2;
}
// save
m_info.m_x = x;
m_info.m_y = y;
m_info.m_w = w;
m_info.m_h = h;
m_info.m_mx = mx;
m_info.m_my = my;
// acknowledge receipt
LOG((CLOG_DEBUG1 "send info ack to \"%s\"", getName().c_str()));
CProtocolUtil::writef(getStream(), kMsgCInfoAck);
return true;
}
bool
CClientProxy1_0::recvClipboard()
{
// parse message
ClipboardID id;
UInt32 seqNum;
CString data;
if (!CProtocolUtil::readf(getStream(),
kMsgDClipboard + 4, &id, &seqNum, &data)) {
return false;
}
LOG((CLOG_DEBUG "received client \"%s\" clipboard %d seqnum=%d, size=%d", getName().c_str(), id, seqNum, data.size()));
// validate
if (id >= kClipboardEnd) {
return false;
}
// save clipboard
m_clipboard[id].m_clipboard.unmarshall(data, 0);
m_clipboard[id].m_sequenceNumber = seqNum;
// notify
CClipboardInfo* info = new CClipboardInfo;
info->m_id = id;
info->m_sequenceNumber = seqNum;
EVENTQUEUE->addEvent(CEvent(getClipboardChangedEvent(),
getEventTarget(), info));
return true;
}
bool
CClientProxy1_0::recvGrabClipboard()
{
// parse message
ClipboardID id;
UInt32 seqNum;
if (!CProtocolUtil::readf(getStream(), kMsgCClipboard + 4, &id, &seqNum)) {
return false;
}
LOG((CLOG_DEBUG "received client \"%s\" grabbed clipboard %d seqnum=%d", getName().c_str(), id, seqNum));
// validate
if (id >= kClipboardEnd) {
return false;
}
// notify
CClipboardInfo* info = new CClipboardInfo;
info->m_id = id;
info->m_sequenceNumber = seqNum;
EVENTQUEUE->addEvent(CEvent(getClipboardGrabbedEvent(),
getEventTarget(), info));
return true;
}
//
// CClientProxy1_0::CClientClipboard
//
CClientProxy1_0::CClientClipboard::CClientClipboard() :
m_clipboard(),
m_sequenceNumber(0),
m_dirty(true)
{
// do nothing
}

View File

@@ -0,0 +1,107 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CCLIENTPROXY1_0_H
#define CCLIENTPROXY1_0_H
#include "CClientProxy.h"
#include "CClipboard.h"
#include "ProtocolTypes.h"
class CEvent;
class CEventQueueTimer;
//! Proxy for client implementing protocol version 1.0
class CClientProxy1_0 : public CClientProxy {
public:
CClientProxy1_0(const CString& name, IStream* adoptedStream);
~CClientProxy1_0();
// IScreen
virtual bool getClipboard(ClipboardID id, IClipboard*) const;
virtual void getShape(SInt32& x, SInt32& y,
SInt32& width, SInt32& height) const;
virtual void getCursorPos(SInt32& x, SInt32& y) const;
// IClient overrides
virtual void enter(SInt32 xAbs, SInt32 yAbs,
UInt32 seqNum, KeyModifierMask mask,
bool forScreensaver);
virtual bool leave();
virtual void setClipboard(ClipboardID, const IClipboard*);
virtual void grabClipboard(ClipboardID);
virtual void setClipboardDirty(ClipboardID, bool);
virtual void keyDown(KeyID, KeyModifierMask, KeyButton);
virtual void keyRepeat(KeyID, KeyModifierMask,
SInt32 count, KeyButton);
virtual void keyUp(KeyID, KeyModifierMask, KeyButton);
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 xDelta, SInt32 yDelta);
virtual void screensaver(bool activate);
virtual void resetOptions();
virtual void setOptions(const COptionsList& options);
virtual void gameDeviceButtons(GameDeviceID id, GameDeviceButton buttons);
virtual void gameDeviceSticks(GameDeviceID id, SInt16 x1, SInt16 y1, SInt16 x2, SInt16 y2);
virtual void gameDeviceTriggers(GameDeviceID id, UInt8 t1, UInt8 t2);
virtual void gameDeviceTimingReq();
protected:
virtual bool parseHandshakeMessage(const UInt8* code);
virtual bool parseMessage(const UInt8* code);
virtual void resetHeartbeatRate();
virtual void setHeartbeatRate(double rate, double alarm);
virtual void resetHeartbeatTimer();
virtual void addHeartbeatTimer();
virtual void removeHeartbeatTimer();
private:
void disconnect();
void removeHandlers();
void handleData(const CEvent&, void*);
void handleDisconnect(const CEvent&, void*);
void handleWriteError(const CEvent&, void*);
void handleFlatline(const CEvent&, void*);
bool recvInfo();
bool recvClipboard();
bool recvGrabClipboard();
private:
typedef bool (CClientProxy1_0::*MessageParser)(const UInt8*);
struct CClientClipboard {
public:
CClientClipboard();
public:
CClipboard m_clipboard;
UInt32 m_sequenceNumber;
bool m_dirty;
};
CClientInfo m_info;
CClientClipboard m_clipboard[kClipboardEnd];
double m_heartbeatAlarm;
CEventQueueTimer* m_heartbeatTimer;
MessageParser m_parser;
};
#endif

View File

@@ -0,0 +1,58 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "CClientProxy1_1.h"
#include "CProtocolUtil.h"
#include "CLog.h"
#include <cstring>
//
// CClientProxy1_1
//
CClientProxy1_1::CClientProxy1_1(const CString& name, IStream* stream) :
CClientProxy1_0(name, stream)
{
// do nothing
}
CClientProxy1_1::~CClientProxy1_1()
{
// do nothing
}
void
CClientProxy1_1::keyDown(KeyID key, KeyModifierMask mask, KeyButton button)
{
LOG((CLOG_DEBUG1 "send key down to \"%s\" id=%d, mask=0x%04x, button=0x%04x", getName().c_str(), key, mask, button));
CProtocolUtil::writef(getStream(), kMsgDKeyDown, key, mask, button);
}
void
CClientProxy1_1::keyRepeat(KeyID key, KeyModifierMask mask,
SInt32 count, KeyButton button)
{
LOG((CLOG_DEBUG1 "send key repeat to \"%s\" id=%d, mask=0x%04x, count=%d, button=0x%04x", getName().c_str(), key, mask, count, button));
CProtocolUtil::writef(getStream(), kMsgDKeyRepeat, key, mask, count, button);
}
void
CClientProxy1_1::keyUp(KeyID key, KeyModifierMask mask, KeyButton button)
{
LOG((CLOG_DEBUG1 "send key up to \"%s\" id=%d, mask=0x%04x, button=0x%04x", getName().c_str(), key, mask, button));
CProtocolUtil::writef(getStream(), kMsgDKeyUp, key, mask, button);
}

View File

@@ -0,0 +1,36 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CCLIENTPROXY1_1_H
#define CCLIENTPROXY1_1_H
#include "CClientProxy1_0.h"
//! Proxy for client implementing protocol version 1.1
class CClientProxy1_1 : public CClientProxy1_0 {
public:
CClientProxy1_1(const CString& name, IStream* adoptedStream);
~CClientProxy1_1();
// IClient overrides
virtual void keyDown(KeyID, KeyModifierMask, KeyButton);
virtual void keyRepeat(KeyID, KeyModifierMask,
SInt32 count, KeyButton);
virtual void keyUp(KeyID, KeyModifierMask, KeyButton);
};
#endif

View File

@@ -0,0 +1,42 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "CClientProxy1_2.h"
#include "CProtocolUtil.h"
#include "CLog.h"
//
// CClientProxy1_1
//
CClientProxy1_2::CClientProxy1_2(const CString& name, IStream* stream) :
CClientProxy1_1(name, stream)
{
// do nothing
}
CClientProxy1_2::~CClientProxy1_2()
{
// do nothing
}
void
CClientProxy1_2::mouseRelativeMove(SInt32 xRel, SInt32 yRel)
{
LOG((CLOG_DEBUG2 "send mouse relative move to \"%s\" %d,%d", getName().c_str(), xRel, yRel));
CProtocolUtil::writef(getStream(), kMsgDMouseRelMove, xRel, yRel);
}

View File

@@ -0,0 +1,33 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2004 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CCLIENTPROXY1_2_H
#define CCLIENTPROXY1_2_H
#include "CClientProxy1_1.h"
//! Proxy for client implementing protocol version 1.2
class CClientProxy1_2 : public CClientProxy1_1 {
public:
CClientProxy1_2(const CString& name, IStream* adoptedStream);
~CClientProxy1_2();
// IClient overrides
virtual void mouseRelativeMove(SInt32 xRel, SInt32 yRel);
};
#endif

View File

@@ -0,0 +1,119 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2006 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "CClientProxy1_3.h"
#include "CProtocolUtil.h"
#include "CLog.h"
#include "IEventQueue.h"
#include "TMethodEventJob.h"
#include <cstring>
#include <memory>
//
// CClientProxy1_3
//
CClientProxy1_3::CClientProxy1_3(const CString& name, IStream* stream) :
CClientProxy1_2(name, stream),
m_keepAliveRate(kKeepAliveRate),
m_keepAliveTimer(NULL)
{
setHeartbeatRate(kKeepAliveRate, kKeepAliveRate * kKeepAlivesUntilDeath);
}
CClientProxy1_3::~CClientProxy1_3()
{
// cannot do this in superclass or our override wouldn't get called
removeHeartbeatTimer();
}
void
CClientProxy1_3::mouseWheel(SInt32 xDelta, SInt32 yDelta)
{
LOG((CLOG_DEBUG2 "send mouse wheel to \"%s\" %+d,%+d", getName().c_str(), xDelta, yDelta));
CProtocolUtil::writef(getStream(), kMsgDMouseWheel, xDelta, yDelta);
}
bool
CClientProxy1_3::parseMessage(const UInt8* code)
{
// process message
if (memcmp(code, kMsgCKeepAlive, 4) == 0) {
// reset alarm
resetHeartbeatTimer();
return true;
}
else {
return CClientProxy1_2::parseMessage(code);
}
}
void
CClientProxy1_3::resetHeartbeatRate()
{
setHeartbeatRate(kKeepAliveRate, kKeepAliveRate * kKeepAlivesUntilDeath);
}
void
CClientProxy1_3::setHeartbeatRate(double rate, double)
{
m_keepAliveRate = rate;
CClientProxy1_2::setHeartbeatRate(rate, rate * kKeepAlivesUntilDeath);
}
void
CClientProxy1_3::resetHeartbeatTimer()
{
// reset the alarm but not the keep alive timer
CClientProxy1_2::removeHeartbeatTimer();
CClientProxy1_2::addHeartbeatTimer();
}
void
CClientProxy1_3::addHeartbeatTimer()
{
// create and install a timer to periodically send keep alives
if (m_keepAliveRate > 0.0) {
m_keepAliveTimer = EVENTQUEUE->newTimer(m_keepAliveRate, NULL);
EVENTQUEUE->adoptHandler(CEvent::kTimer, m_keepAliveTimer,
new TMethodEventJob<CClientProxy1_3>(this,
&CClientProxy1_3::handleKeepAlive, NULL));
}
// superclass does the alarm
CClientProxy1_2::addHeartbeatTimer();
}
void
CClientProxy1_3::removeHeartbeatTimer()
{
// remove the timer that sends keep alives periodically
if (m_keepAliveTimer != NULL) {
EVENTQUEUE->removeHandler(CEvent::kTimer, m_keepAliveTimer);
EVENTQUEUE->deleteTimer(m_keepAliveTimer);
m_keepAliveTimer = NULL;
}
// superclass does the alarm
CClientProxy1_2::removeHeartbeatTimer();
}
void
CClientProxy1_3::handleKeepAlive(const CEvent&, void*)
{
CProtocolUtil::writef(getStream(), kMsgCKeepAlive);
}

View File

@@ -0,0 +1,50 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2006 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CCLIENTPROXY1_3_H
#define CCLIENTPROXY1_3_H
#include "CClientProxy1_2.h"
//! Proxy for client implementing protocol version 1.3
class CClientProxy1_3 : public CClientProxy1_2 {
public:
CClientProxy1_3(const CString& name, IStream* adoptedStream);
~CClientProxy1_3();
// IClient overrides
virtual void mouseWheel(SInt32 xDelta, SInt32 yDelta);
protected:
// CClientProxy overrides
virtual bool parseMessage(const UInt8* code);
virtual void resetHeartbeatRate();
virtual void setHeartbeatRate(double rate, double alarm);
virtual void resetHeartbeatTimer();
virtual void addHeartbeatTimer();
virtual void removeHeartbeatTimer();
private:
void handleKeepAlive(const CEvent&, void*);
private:
double m_keepAliveRate;
CEventQueueTimer* m_keepAliveTimer;
};
#endif

View File

@@ -0,0 +1,111 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2011 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "CClientProxy1_4.h"
#include "CProtocolUtil.h"
#include "CLog.h"
#include "IEventQueue.h"
#include "TMethodEventJob.h"
#include <cstring>
#include <memory>
#include "CServer.h"
//
// CClientProxy1_4
//
CClientProxy1_4::CClientProxy1_4(const CString& name, IStream* stream, CServer* server) :
CClientProxy1_3(name, stream), m_server(server)
{
assert(m_server != NULL);
}
CClientProxy1_4::~CClientProxy1_4()
{
}
void
CClientProxy1_4::gameDeviceButtons(GameDeviceID id, GameDeviceButton buttons)
{
LOG((CLOG_DEBUG2 "send game device buttons to \"%s\" id=%d buttons=%d", getName().c_str(), id, buttons));
CProtocolUtil::writef(getStream(), kMsgDGameButtons, id, buttons);
}
void
CClientProxy1_4::gameDeviceSticks(GameDeviceID id, SInt16 x1, SInt16 y1, SInt16 x2, SInt16 y2)
{
LOG((CLOG_DEBUG2 "send game device sticks to \"%s\" id=%d s1=%+d,%+d s2=%+d,%+d", getName().c_str(), id, x1, y1, x2, y2));
CProtocolUtil::writef(getStream(), kMsgDGameSticks, id, x1, y1, x2, y2);
}
void
CClientProxy1_4::gameDeviceTriggers(GameDeviceID id, UInt8 t1, UInt8 t2)
{
LOG((CLOG_DEBUG2 "send game device triggers to \"%s\" id=%d t1=%d t2=%d", getName().c_str(), id, t1, t2));
CProtocolUtil::writef(getStream(), kMsgDGameTriggers, id, t1, t2);
}
void
CClientProxy1_4::gameDeviceTimingReq()
{
LOG((CLOG_DEBUG2 "send game device timing request to \"%s\"", getName().c_str()));
CProtocolUtil::writef(getStream(), kMsgCGameTimingReq);
}
bool
CClientProxy1_4::parseMessage(const UInt8* code)
{
// process message
if (memcmp(code, kMsgCGameTimingResp, 4) == 0) {
gameDeviceTimingResp();
}
else if (memcmp(code, kMsgDGameFeedback, 4) == 0) {
gameDeviceFeedback();
}
else {
return CClientProxy1_3::parseMessage(code);
}
return true;
}
void
CClientProxy1_4::gameDeviceFeedback()
{
// parse
GameDeviceID id;
UInt16 m1, m2;
CProtocolUtil::readf(getStream(), kMsgDGameFeedback + 4, &id, &m1, &m2);
LOG((CLOG_DEBUG2 "recv game device feedback id=%d m1=%d m2=%d", id, m1, m2));
// forward
m_server->gameDeviceFeedback(id, m1, m2);
}
void
CClientProxy1_4::gameDeviceTimingResp()
{
// parse
UInt16 freq;
CProtocolUtil::readf(getStream(), kMsgCGameTimingResp + 4, &freq);
LOG((CLOG_DEBUG2 "recv game device timing response freq=%dms", freq));
// forward
m_server->gameDeviceTimingResp(freq);
}

View File

@@ -0,0 +1,47 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2011 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "CClientProxy1_3.h"
#include "GameDeviceTypes.h"
class CServer;
//! Proxy for client implementing protocol version 1.4
class CClientProxy1_4 : public CClientProxy1_3 {
public:
CClientProxy1_4(const CString& name, IStream* adoptedStream, CServer* server);
~CClientProxy1_4();
// IClient overrides
virtual void gameDeviceButtons(GameDeviceID id, GameDeviceButton buttons);
virtual void gameDeviceSticks(GameDeviceID id, SInt16 x1, SInt16 y1, SInt16 x2, SInt16 y2);
virtual void gameDeviceTriggers(GameDeviceID id, UInt8 t1, UInt8 t2);
virtual void gameDeviceTimingReq();
protected:
// CClientProxy overrides
virtual bool parseMessage(const UInt8* code);
private:
// message handlers
void gameDeviceTimingResp();
void gameDeviceFeedback();
CServer* m_server;
};

View File

@@ -0,0 +1,299 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2004 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "CClientProxyUnknown.h"
#include "CClientProxy1_0.h"
#include "CClientProxy1_1.h"
#include "CClientProxy1_2.h"
#include "CClientProxy1_3.h"
#include "CClientProxy1_4.h"
#include "ProtocolTypes.h"
#include "CProtocolUtil.h"
#include "XSynergy.h"
#include "IStream.h"
#include "XIO.h"
#include "CLog.h"
#include "CString.h"
#include "IEventQueue.h"
#include "TMethodEventJob.h"
#include "CServer.h"
//
// CClientProxyUnknown
//
CEvent::Type CClientProxyUnknown::s_successEvent = CEvent::kUnknown;
CEvent::Type CClientProxyUnknown::s_failureEvent = CEvent::kUnknown;
CClientProxyUnknown::CClientProxyUnknown(IStream* stream, double timeout, CServer* server) :
m_stream(stream),
m_proxy(NULL),
m_ready(false),
m_server(server)
{
assert(m_server != NULL);
EVENTQUEUE->adoptHandler(CEvent::kTimer, this,
new TMethodEventJob<CClientProxyUnknown>(this,
&CClientProxyUnknown::handleTimeout, NULL));
m_timer = EVENTQUEUE->newOneShotTimer(timeout, this);
addStreamHandlers();
LOG((CLOG_DEBUG1 "saying hello"));
CProtocolUtil::writef(m_stream, kMsgHello,
kProtocolMajorVersion,
kProtocolMinorVersion);
}
CClientProxyUnknown::~CClientProxyUnknown()
{
removeHandlers();
removeTimer();
delete m_stream;
delete m_proxy;
}
CClientProxy*
CClientProxyUnknown::orphanClientProxy()
{
if (m_ready) {
removeHandlers();
CClientProxy* proxy = m_proxy;
m_proxy = NULL;
return proxy;
}
else {
return NULL;
}
}
CEvent::Type
CClientProxyUnknown::getSuccessEvent()
{
return EVENTQUEUE->registerTypeOnce(s_successEvent,
"CClientProxy::success");
}
CEvent::Type
CClientProxyUnknown::getFailureEvent()
{
return EVENTQUEUE->registerTypeOnce(s_failureEvent,
"CClientProxy::failure");
}
void
CClientProxyUnknown::sendSuccess()
{
m_ready = true;
removeTimer();
EVENTQUEUE->addEvent(CEvent(getSuccessEvent(), this));
}
void
CClientProxyUnknown::sendFailure()
{
delete m_proxy;
m_proxy = NULL;
m_ready = false;
removeHandlers();
removeTimer();
EVENTQUEUE->addEvent(CEvent(getFailureEvent(), this));
}
void
CClientProxyUnknown::addStreamHandlers()
{
assert(m_stream != NULL);
EVENTQUEUE->adoptHandler(m_stream->getInputReadyEvent(),
m_stream->getEventTarget(),
new TMethodEventJob<CClientProxyUnknown>(this,
&CClientProxyUnknown::handleData));
EVENTQUEUE->adoptHandler(m_stream->getOutputErrorEvent(),
m_stream->getEventTarget(),
new TMethodEventJob<CClientProxyUnknown>(this,
&CClientProxyUnknown::handleWriteError));
EVENTQUEUE->adoptHandler(m_stream->getInputShutdownEvent(),
m_stream->getEventTarget(),
new TMethodEventJob<CClientProxyUnknown>(this,
&CClientProxyUnknown::handleDisconnect));
EVENTQUEUE->adoptHandler(m_stream->getOutputShutdownEvent(),
m_stream->getEventTarget(),
new TMethodEventJob<CClientProxyUnknown>(this,
&CClientProxyUnknown::handleWriteError));
}
void
CClientProxyUnknown::addProxyHandlers()
{
assert(m_proxy != NULL);
EVENTQUEUE->adoptHandler(CClientProxy::getReadyEvent(),
m_proxy,
new TMethodEventJob<CClientProxyUnknown>(this,
&CClientProxyUnknown::handleReady));
EVENTQUEUE->adoptHandler(CClientProxy::getDisconnectedEvent(),
m_proxy,
new TMethodEventJob<CClientProxyUnknown>(this,
&CClientProxyUnknown::handleDisconnect));
}
void
CClientProxyUnknown::removeHandlers()
{
if (m_stream != NULL) {
EVENTQUEUE->removeHandler(m_stream->getInputReadyEvent(),
m_stream->getEventTarget());
EVENTQUEUE->removeHandler(m_stream->getOutputErrorEvent(),
m_stream->getEventTarget());
EVENTQUEUE->removeHandler(m_stream->getInputShutdownEvent(),
m_stream->getEventTarget());
EVENTQUEUE->removeHandler(m_stream->getOutputShutdownEvent(),
m_stream->getEventTarget());
}
if (m_proxy != NULL) {
EVENTQUEUE->removeHandler(CClientProxy::getReadyEvent(),
m_proxy);
EVENTQUEUE->removeHandler(CClientProxy::getDisconnectedEvent(),
m_proxy);
}
}
void
CClientProxyUnknown::removeTimer()
{
if (m_timer != NULL) {
EVENTQUEUE->deleteTimer(m_timer);
EVENTQUEUE->removeHandler(CEvent::kTimer, this);
m_timer = NULL;
}
}
void
CClientProxyUnknown::handleData(const CEvent&, void*)
{
LOG((CLOG_DEBUG1 "parsing hello reply"));
CString name("<unknown>");
try {
// limit the maximum length of the hello
UInt32 n = m_stream->getSize();
if (n > kMaxHelloLength) {
LOG((CLOG_DEBUG1 "hello reply too long"));
throw XBadClient();
}
// parse the reply to hello
SInt16 major, minor;
if (!CProtocolUtil::readf(m_stream, kMsgHelloBack,
&major, &minor, &name)) {
throw XBadClient();
}
// disallow invalid version numbers
if (major <= 0 || minor < 0) {
throw XIncompatibleClient(major, minor);
}
// remove stream event handlers. the proxy we're about to create
// may install its own handlers and we don't want to accidentally
// remove those later.
removeHandlers();
// create client proxy for highest version supported by the client
if (major == 1) {
switch (minor) {
case 0:
m_proxy = new CClientProxy1_0(name, m_stream);
break;
case 1:
m_proxy = new CClientProxy1_1(name, m_stream);
break;
case 2:
m_proxy = new CClientProxy1_2(name, m_stream);
break;
case 3:
m_proxy = new CClientProxy1_3(name, m_stream);
break;
case 4:
m_proxy = new CClientProxy1_4(name, m_stream, m_server);
break;
}
}
// hangup (with error) if version isn't supported
if (m_proxy == NULL) {
throw XIncompatibleClient(major, minor);
}
// the proxy is created and now proxy now owns the stream
LOG((CLOG_DEBUG1 "created proxy for client \"%s\" version %d.%d", name.c_str(), major, minor));
m_stream = NULL;
// wait until the proxy signals that it's ready or has disconnected
addProxyHandlers();
return;
}
catch (XIncompatibleClient& e) {
// client is incompatible
LOG((CLOG_WARN "client \"%s\" has incompatible version %d.%d)", name.c_str(), e.getMajor(), e.getMinor()));
CProtocolUtil::writef(m_stream,
kMsgEIncompatible,
kProtocolMajorVersion, kProtocolMinorVersion);
}
catch (XBadClient&) {
// client not behaving
LOG((CLOG_WARN "protocol error from client \"%s\"", name.c_str()));
CProtocolUtil::writef(m_stream, kMsgEBad);
}
catch (XBase& e) {
// misc error
LOG((CLOG_WARN "error communicating with client \"%s\": %s", name.c_str(), e.what()));
}
sendFailure();
}
void
CClientProxyUnknown::handleWriteError(const CEvent&, void*)
{
LOG((CLOG_NOTE "error communicating with new client"));
sendFailure();
}
void
CClientProxyUnknown::handleTimeout(const CEvent&, void*)
{
LOG((CLOG_NOTE "new client is unresponsive"));
sendFailure();
}
void
CClientProxyUnknown::handleDisconnect(const CEvent&, void*)
{
LOG((CLOG_NOTE "new client disconnected"));
sendFailure();
}
void
CClientProxyUnknown::handleReady(const CEvent&, void*)
{
sendSuccess();
}

View File

@@ -0,0 +1,88 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2004 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CCLIENTPROXYUNKNOWN_H
#define CCLIENTPROXYUNKNOWN_H
#include "CEvent.h"
class CClientProxy;
class CEventQueueTimer;
class IStream;
class CServer;
class CClientProxyUnknown {
public:
CClientProxyUnknown(IStream* stream, double timeout, CServer* server);
~CClientProxyUnknown();
//! @name manipulators
//@{
//! Get the client proxy
/*!
Returns the client proxy created after a successful handshake
(i.e. when this object sends a success event). Returns NULL
if the handshake is unsuccessful or incomplete.
*/
CClientProxy* orphanClientProxy();
//@}
//! @name accessors
//@{
//! Get success event type
/*!
Returns the success event type. This is sent when the client has
correctly responded to the hello message. The target is this.
*/
static CEvent::Type getSuccessEvent();
//! Get failure event type
/*!
Returns the failure event type. This is sent when a client fails
to correctly respond to the hello message. The target is this.
*/
static CEvent::Type getFailureEvent();
//@}
private:
void sendSuccess();
void sendFailure();
void addStreamHandlers();
void addProxyHandlers();
void removeHandlers();
void removeTimer();
void handleData(const CEvent&, void*);
void handleWriteError(const CEvent&, void*);
void handleTimeout(const CEvent&, void*);
void handleDisconnect(const CEvent&, void*);
void handleReady(const CEvent&, void*);
private:
IStream* m_stream;
CEventQueueTimer* m_timer;
CClientProxy* m_proxy;
bool m_ready;
static CEvent::Type s_successEvent;
static CEvent::Type s_failureEvent;
CServer* m_server;
};
#endif

2323
src/lib/server/CConfig.cpp Normal file

File diff suppressed because it is too large Load Diff

539
src/lib/server/CConfig.h Normal file
View File

@@ -0,0 +1,539 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CCONFIG_H
#define CCONFIG_H
#include "OptionTypes.h"
#include "ProtocolTypes.h"
#include "CNetworkAddress.h"
#include "CStringUtil.h"
#include "CInputFilter.h"
#include "XBase.h"
#include "stdmap.h"
#include "stdset.h"
#include "IPlatformScreen.h"
#include <iosfwd>
class CConfig;
class CConfigReadContext;
namespace std {
template <>
struct iterator_traits<CConfig> {
typedef CString value_type;
typedef ptrdiff_t difference_type;
typedef bidirectional_iterator_tag iterator_category;
typedef CString* pointer;
typedef CString& reference;
};
};
//! Server configuration
/*!
This class holds server configuration information. That includes
the names of screens and their aliases, the links between them,
and network addresses.
Note that case is preserved in screen names but is ignored when
comparing names. Screen names and their aliases share a
namespace and must be unique.
*/
class CConfig {
public:
typedef std::map<OptionID, OptionValue> CScreenOptions;
typedef std::pair<float, float> CInterval;
class CCellEdge {
public:
CCellEdge(EDirection side, float position);
CCellEdge(EDirection side, const CInterval&);
CCellEdge(const CString& name, EDirection side, const CInterval&);
~CCellEdge();
CInterval getInterval() const;
void setName(const CString& newName);
CString getName() const;
EDirection getSide() const;
bool overlaps(const CCellEdge&) const;
bool isInside(float x) const;
// transform position to [0,1]
float transform(float x) const;
// transform [0,1] to position
float inverseTransform(float x) const;
// compares side and start of interval
bool operator<(const CCellEdge&) const;
// compares side and interval
bool operator==(const CCellEdge&) const;
bool operator!=(const CCellEdge&) const;
private:
void init(const CString& name, EDirection side,
const CInterval&);
private:
CString m_name;
EDirection m_side;
CInterval m_interval;
};
private:
class CName {
public:
CName(CConfig*, const CString& name);
bool operator==(const CString& name) const;
private:
CConfig* m_config;
CString m_name;
};
class CCell {
private:
typedef std::map<CCellEdge, CCellEdge> CEdgeLinks;
public:
typedef CEdgeLinks::const_iterator const_iterator;
bool add(const CCellEdge& src, const CCellEdge& dst);
void remove(EDirection side);
void remove(EDirection side, float position);
void remove(const CName& destinationName);
void rename(const CName& oldName, const CString& newName);
bool hasEdge(const CCellEdge&) const;
bool overlaps(const CCellEdge&) const;
bool getLink(EDirection side, float position,
const CCellEdge*& src, const CCellEdge*& dst) const;
bool operator==(const CCell&) const;
bool operator!=(const CCell&) const;
const_iterator begin() const;
const_iterator end() const;
private:
CEdgeLinks m_neighbors;
public:
CScreenOptions m_options;
};
typedef std::map<CString, CCell, CStringUtil::CaselessCmp> CCellMap;
typedef std::map<CString, CString, CStringUtil::CaselessCmp> CNameMap;
public:
typedef CCell::const_iterator link_const_iterator;
typedef CCellMap::const_iterator internal_const_iterator;
typedef CNameMap::const_iterator all_const_iterator;
class const_iterator : std::iterator_traits<CConfig> {
public:
explicit const_iterator() : m_i() { }
explicit const_iterator(const internal_const_iterator& i) : m_i(i) { }
const_iterator& operator=(const const_iterator& i) {
m_i = i.m_i;
return *this;
}
CString operator*() { return m_i->first; }
const CString* operator->() { return &(m_i->first); }
const_iterator& operator++() { ++m_i; return *this; }
const_iterator operator++(int) { return const_iterator(m_i++); }
const_iterator& operator--() { --m_i; return *this; }
const_iterator operator--(int) { return const_iterator(m_i--); }
bool operator==(const const_iterator& i) const {
return (m_i == i.m_i);
}
bool operator!=(const const_iterator& i) const {
return (m_i != i.m_i);
}
private:
internal_const_iterator m_i;
};
CConfig();
virtual ~CConfig();
//! @name manipulators
//@{
//! Add screen
/*!
Adds a screen, returning true iff successful. If a screen or
alias with the given name exists then it fails.
*/
bool addScreen(const CString& name);
//! Rename screen
/*!
Renames a screen. All references to the name are updated.
Returns true iff successful.
*/
bool renameScreen(const CString& oldName,
const CString& newName);
//! Remove screen
/*!
Removes a screen. This also removes aliases for the screen and
disconnects any connections to the screen. \c name may be an
alias.
*/
void removeScreen(const CString& name);
//! Remove all screens
/*!
Removes all screens, aliases, and connections.
*/
void removeAllScreens();
//! Add alias
/*!
Adds an alias for a screen name. An alias can be used
any place the canonical screen name can (except addScreen()).
Returns false if the alias name already exists or the canonical
name is unknown, otherwise returns true.
*/
bool addAlias(const CString& canonical,
const CString& alias);
//! Remove alias
/*!
Removes an alias for a screen name. It returns false if the
alias is unknown or a canonical name, otherwise returns true.
*/
bool removeAlias(const CString& alias);
//! Remove aliases
/*!
Removes all aliases for a canonical screen name. It returns false
if the canonical name is unknown, otherwise returns true.
*/
bool removeAliases(const CString& canonical);
//! Remove all aliases
/*!
This removes all aliases but not the screens.
*/
void removeAllAliases();
//! Connect screens
/*!
Establishes a one-way connection between portions of opposite edges
of two screens. Each portion is described by an interval defined
by two numbers, the start and end of the interval half-open on the
end. The numbers range from 0 to 1, inclusive, for the left/top
to the right/bottom. The user will be able to jump from the
\c srcStart to \c srcSend interval of \c srcSide of screen
\c srcName to the opposite side of screen \c dstName in the interval
\c dstStart and \c dstEnd when both screens are connected to the
server and the user isn't locked to a screen. Returns false if
\c srcName is unknown. \c srcStart must be less than or equal to
\c srcEnd and \c dstStart must be less then or equal to \c dstEnd
and all of \c srcStart, \c srcEnd, \c dstStart, or \c dstEnd must
be inside the range [0,1].
*/
bool connect(const CString& srcName,
EDirection srcSide,
float srcStart, float srcEnd,
const CString& dstName,
float dstStart, float dstEnd);
//! Disconnect screens
/*!
Removes all connections created by connect() on side \c srcSide.
Returns false if \c srcName is unknown.
*/
bool disconnect(const CString& srcName,
EDirection srcSide);
//! Disconnect screens
/*!
Removes the connections created by connect() on side \c srcSide
covering position \c position. Returns false if \c srcName is
unknown.
*/
bool disconnect(const CString& srcName,
EDirection srcSide, float position);
//! Set server address
/*!
Set the synergy listen addresses. There is no default address so
this must be called to run a server using this configuration.
*/
void setSynergyAddress(const CNetworkAddress&);
//! Add a screen option
/*!
Adds an option and its value to the named screen. Replaces the
existing option's value if there is one. Returns true iff \c name
is a known screen.
*/
bool addOption(const CString& name,
OptionID option, OptionValue value);
//! Remove a screen option
/*!
Removes an option and its value from the named screen. Does
nothing if the option doesn't exist on the screen. Returns true
iff \c name is a known screen.
*/
bool removeOption(const CString& name, OptionID option);
//! Remove a screen options
/*!
Removes all options and values from the named screen. Returns true
iff \c name is a known screen.
*/
bool removeOptions(const CString& name);
//! Get the hot key input filter
/*!
Returns the hot key input filter. Clients can modify hotkeys using
that object.
*/
CInputFilter* getInputFilter();
//@}
//! @name accessors
//@{
//! Test screen name validity
/*!
Returns true iff \c name is a valid screen name.
*/
bool isValidScreenName(const CString& name) const;
//! Get beginning (canonical) screen name iterator
const_iterator begin() const;
//! Get ending (canonical) screen name iterator
const_iterator end() const;
//! Get beginning screen name iterator
all_const_iterator beginAll() const;
//! Get ending screen name iterator
all_const_iterator endAll() const;
//! Test for screen name
/*!
Returns true iff \c name names a screen.
*/
bool isScreen(const CString& name) const;
//! Test for canonical screen name
/*!
Returns true iff \c name is the canonical name of a screen.
*/
bool isCanonicalName(const CString& name) const;
//! Get canonical name
/*!
Returns the canonical name of a screen or the empty string if
the name is unknown. Returns the canonical name if one is given.
*/
CString getCanonicalName(const CString& name) const;
//! Get neighbor
/*!
Returns the canonical screen name of the neighbor in the given
direction (set through connect()) at position \c position. Returns
the empty string if there is no neighbor in that direction, otherwise
saves the position on the neighbor in \c positionOut if it's not
\c NULL.
*/
CString getNeighbor(const CString&, EDirection,
float position, float* positionOut) const;
//! Check for neighbor
/*!
Returns \c true if the screen has a neighbor anywhere along the edge
given by the direction.
*/
bool hasNeighbor(const CString&, EDirection) const;
//! Check for neighbor
/*!
Returns \c true if the screen has a neighbor in the given range along
the edge given by the direction.
*/
bool hasNeighbor(const CString&, EDirection,
float start, float end) const;
//! Get beginning neighbor iterator
link_const_iterator beginNeighbor(const CString&) const;
//! Get ending neighbor iterator
link_const_iterator endNeighbor(const CString&) const;
//! Get the server address
const CNetworkAddress& getSynergyAddress() const;
//! Get the screen options
/*!
Returns all the added options for the named screen. Returns NULL
if the screen is unknown and an empty collection if there are no
options.
*/
const CScreenOptions* getOptions(const CString& name) const;
//! Check for lock to screen action
/*!
Returns \c true if this configuration has a lock to screen action.
This is for backwards compatible support of ScrollLock locking.
*/
bool hasLockToScreenAction() const;
//! Compare configurations
bool operator==(const CConfig&) const;
//! Compare configurations
bool operator!=(const CConfig&) const;
//! Read configuration
/*!
Reads a configuration from a context. Throws XConfigRead on error
and context is unchanged.
*/
void read(CConfigReadContext& context);
//! Read configuration
/*!
Reads a configuration from a stream. Throws XConfigRead on error.
*/
friend std::istream& operator>>(std::istream&, CConfig&);
//! Write configuration
/*!
Writes a configuration to a stream.
*/
friend std::ostream& operator<<(std::ostream&, const CConfig&);
//! Get direction name
/*!
Returns the name of a direction (for debugging).
*/
static const char* dirName(EDirection);
//! Get interval as string
/*!
Returns an interval as a parseable string.
*/
static CString formatInterval(const CInterval&);
//@}
private:
void readSection(CConfigReadContext&);
void readSectionOptions(CConfigReadContext&);
void readSectionScreens(CConfigReadContext&);
void readSectionLinks(CConfigReadContext&);
void readSectionAliases(CConfigReadContext&);
CInputFilter::CCondition*
parseCondition(CConfigReadContext&,
const CString& condition,
const std::vector<CString>& args);
void parseAction(CConfigReadContext&,
const CString& action,
const std::vector<CString>& args,
CInputFilter::CRule&, bool activate);
void parseScreens(CConfigReadContext&, const CString&,
std::set<CString>& screens) const;
static const char* getOptionName(OptionID);
static CString getOptionValue(OptionID, OptionValue);
private:
CCellMap m_map;
CNameMap m_nameToCanonicalName;
CNetworkAddress m_synergyAddress;
CScreenOptions m_globalOptions;
CInputFilter m_inputFilter;
bool m_hasLockToScreenAction;
};
//! Configuration read context
/*!
Maintains a context when reading a configuration from a stream.
*/
class CConfigReadContext {
public:
typedef std::vector<CString> ArgList;
CConfigReadContext(std::istream&, SInt32 firstLine = 1);
~CConfigReadContext();
bool readLine(CString&);
UInt32 getLineNumber() const;
operator void*() const;
bool operator!() const;
OptionValue parseBoolean(const CString&) const;
OptionValue parseInt(const CString&) const;
OptionValue parseModifierKey(const CString&) const;
OptionValue parseCorner(const CString&) const;
OptionValue parseCorners(const CString&) const;
CConfig::CInterval
parseInterval(const ArgList& args) const;
void parseNameWithArgs(
const CString& type, const CString& line,
const CString& delim, CString::size_type& index,
CString& name, ArgList& args) const;
IPlatformScreen::CKeyInfo*
parseKeystroke(const CString& keystroke) const;
IPlatformScreen::CKeyInfo*
parseKeystroke(const CString& keystroke,
const std::set<CString>& screens) const;
IPlatformScreen::CButtonInfo*
parseMouse(const CString& mouse) const;
KeyModifierMask parseModifier(const CString& modifiers) const;
private:
// not implemented
CConfigReadContext& operator=(const CConfigReadContext&);
static CString concatArgs(const ArgList& args);
private:
std::istream& m_stream;
SInt32 m_line;
};
//! Configuration stream read exception
/*!
Thrown when a configuration stream cannot be parsed.
*/
class XConfigRead : public XBase {
public:
XConfigRead(const CConfigReadContext& context, const CString&);
XConfigRead(const CConfigReadContext& context,
const char* errorFmt, const CString& arg);
~XConfigRead();
protected:
// XBase overrides
virtual CString getWhat() const throw();
private:
CString m_error;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,347 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2005 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CINPUTFILTER_H
#define CINPUTFILTER_H
#include "KeyTypes.h"
#include "MouseTypes.h"
#include "ProtocolTypes.h"
#include "IPlatformScreen.h"
#include "CString.h"
#include "stdmap.h"
#include "stdset.h"
class CPrimaryClient;
class CEvent;
class CInputFilter {
public:
// -------------------------------------------------------------------------
// Input Filter Condition Classes
// -------------------------------------------------------------------------
enum EFilterStatus {
kNoMatch,
kActivate,
kDeactivate
};
class CCondition {
public:
CCondition();
virtual ~CCondition();
virtual CCondition* clone() const = 0;
virtual CString format() const = 0;
virtual EFilterStatus match(const CEvent&) = 0;
virtual void enablePrimary(CPrimaryClient*);
virtual void disablePrimary(CPrimaryClient*);
};
// CKeystrokeCondition
class CKeystrokeCondition : public CCondition {
public:
CKeystrokeCondition(IPlatformScreen::CKeyInfo*);
CKeystrokeCondition(KeyID key, KeyModifierMask mask);
virtual ~CKeystrokeCondition();
KeyID getKey() const;
KeyModifierMask getMask() const;
// CCondition overrides
virtual CCondition* clone() const;
virtual CString format() const;
virtual EFilterStatus match(const CEvent&);
virtual void enablePrimary(CPrimaryClient*);
virtual void disablePrimary(CPrimaryClient*);
private:
UInt32 m_id;
KeyID m_key;
KeyModifierMask m_mask;
};
// CMouseButtonCondition
class CMouseButtonCondition : public CCondition {
public:
CMouseButtonCondition(IPlatformScreen::CButtonInfo*);
CMouseButtonCondition(ButtonID, KeyModifierMask mask);
virtual ~CMouseButtonCondition();
ButtonID getButton() const;
KeyModifierMask getMask() const;
// CCondition overrides
virtual CCondition* clone() const;
virtual CString format() const;
virtual EFilterStatus match(const CEvent&);
private:
ButtonID m_button;
KeyModifierMask m_mask;
};
// CScreenConnectedCondition
class CScreenConnectedCondition : public CCondition {
public:
CScreenConnectedCondition(const CString& screen);
virtual ~CScreenConnectedCondition();
// CCondition overrides
virtual CCondition* clone() const;
virtual CString format() const;
virtual EFilterStatus match(const CEvent&);
private:
CString m_screen;
};
// -------------------------------------------------------------------------
// Input Filter Action Classes
// -------------------------------------------------------------------------
class CAction {
public:
CAction();
virtual ~CAction();
virtual CAction* clone() const = 0;
virtual CString format() const = 0;
virtual void perform(const CEvent&) = 0;
};
// CLockCursorToScreenAction
class CLockCursorToScreenAction : public CAction {
public:
enum Mode { kOff, kOn, kToggle };
CLockCursorToScreenAction(Mode = kToggle);
Mode getMode() const;
// CAction overrides
virtual CAction* clone() const;
virtual CString format() const;
virtual void perform(const CEvent&);
private:
Mode m_mode;
};
// CSwitchToScreenAction
class CSwitchToScreenAction : public CAction {
public:
CSwitchToScreenAction(const CString& screen);
CString getScreen() const;
// CAction overrides
virtual CAction* clone() const;
virtual CString format() const;
virtual void perform(const CEvent&);
private:
CString m_screen;
};
// CSwitchInDirectionAction
class CSwitchInDirectionAction : public CAction {
public:
CSwitchInDirectionAction(EDirection);
EDirection getDirection() const;
// CAction overrides
virtual CAction* clone() const;
virtual CString format() const;
virtual void perform(const CEvent&);
private:
EDirection m_direction;
};
// CKeyboardBroadcastAction
class CKeyboardBroadcastAction : public CAction {
public:
enum Mode { kOff, kOn, kToggle };
CKeyboardBroadcastAction(Mode = kToggle);
CKeyboardBroadcastAction(Mode, const std::set<CString>& screens);
Mode getMode() const;
std::set<CString> getScreens() const;
// CAction overrides
virtual CAction* clone() const;
virtual CString format() const;
virtual void perform(const CEvent&);
private:
Mode m_mode;
CString m_screens;
};
// CKeystrokeAction
class CKeystrokeAction : public CAction {
public:
CKeystrokeAction(IPlatformScreen::CKeyInfo* adoptedInfo, bool press);
~CKeystrokeAction();
void adoptInfo(IPlatformScreen::CKeyInfo*);
const IPlatformScreen::CKeyInfo*
getInfo() const;
bool isOnPress() const;
// CAction overrides
virtual CAction* clone() const;
virtual CString format() const;
virtual void perform(const CEvent&);
protected:
virtual const char* formatName() const;
private:
IPlatformScreen::CKeyInfo* m_keyInfo;
bool m_press;
};
// CMouseButtonAction -- modifier combinations not implemented yet
class CMouseButtonAction : public CAction {
public:
CMouseButtonAction(IPlatformScreen::CButtonInfo* adoptedInfo,
bool press);
~CMouseButtonAction();
const IPlatformScreen::CButtonInfo*
getInfo() const;
bool isOnPress() const;
// CAction overrides
virtual CAction* clone() const;
virtual CString format() const;
virtual void perform(const CEvent&);
protected:
virtual const char* formatName() const;
private:
IPlatformScreen::CButtonInfo* m_buttonInfo;
bool m_press;
};
class CRule {
public:
CRule();
CRule(CCondition* adopted);
CRule(const CRule&);
~CRule();
CRule& operator=(const CRule&);
// replace the condition
void setCondition(CCondition* adopted);
// add an action to the rule
void adoptAction(CAction*, bool onActivation);
// remove an action from the rule
void removeAction(bool onActivation, UInt32 index);
// replace an action in the rule
void replaceAction(CAction* adopted,
bool onActivation, UInt32 index);
// enable/disable
void enable(CPrimaryClient*);
void disable(CPrimaryClient*);
// event handling
bool handleEvent(const CEvent&);
// convert rule to a string
CString format() const;
// get the rule's condition
const CCondition*
getCondition() const;
// get number of actions
UInt32 getNumActions(bool onActivation) const;
// get action by index
const CAction& getAction(bool onActivation, UInt32 index) const;
private:
void clear();
void copy(const CRule&);
private:
typedef std::vector<CAction*> CActionList;
CCondition* m_condition;
CActionList m_activateActions;
CActionList m_deactivateActions;
};
// -------------------------------------------------------------------------
// Input Filter Class
// -------------------------------------------------------------------------
typedef std::vector<CRule> CRuleList;
CInputFilter();
CInputFilter(const CInputFilter&);
virtual ~CInputFilter();
CInputFilter& operator=(const CInputFilter&);
// add rule, adopting the condition and the actions
void addFilterRule(const CRule& rule);
// remove a rule
void removeFilterRule(UInt32 index);
// get rule by index
CRule& getRule(UInt32 index);
// enable event filtering using the given primary client. disable
// if client is NULL.
void setPrimaryClient(CPrimaryClient* client);
// convert rules to a string
CString format(const CString& linePrefix) const;
// get number of rules
UInt32 getNumRules() const;
//! Compare filters
bool operator==(const CInputFilter&) const;
//! Compare filters
bool operator!=(const CInputFilter&) const;
private:
// event handling
void handleEvent(const CEvent&, void*);
private:
CRuleList m_ruleList;
CPrimaryClient* m_primaryClient;
};
#endif

View File

@@ -0,0 +1,79 @@
# synergy -- mouse and keyboard sharing utility
# Copyright (C) 2009 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file COPYING that should have accompanied this file.
#
# This package is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
set(inc
CBaseClientProxy.h
CClientListener.h
CClientProxy.h
CClientProxy1_0.h
CClientProxy1_1.h
CClientProxy1_2.h
CClientProxy1_3.h
CClientProxy1_4.h
CClientProxyUnknown.h
CConfig.h
CInputFilter.h
CPrimaryClient.h
CServer.h
)
set(src
CBaseClientProxy.cpp
CClientListener.cpp
CClientProxy.cpp
CClientProxy1_0.cpp
CClientProxy1_1.cpp
CClientProxy1_2.cpp
CClientProxy1_3.cpp
CClientProxy1_4.cpp
CClientProxyUnknown.cpp
CConfig.cpp
CInputFilter.cpp
CPrimaryClient.cpp
CServer.cpp
)
if (WIN32)
list(APPEND src ${inc})
endif()
set(inc
../arch
../base
../common
../io
../mt
../net
../synergy
)
if (UNIX)
list(APPEND inc
../../..
)
endif()
include_directories(${inc})
add_library(server STATIC ${src})
if (WIN32)
if (GAME_DEVICE_SUPPORT)
include_directories($ENV{DXSDK_DIR}/Include)
endif()
endif()
if (UNIX)
target_link_libraries(server synergy)
endif()

View File

@@ -0,0 +1,284 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "CPrimaryClient.h"
#include "CScreen.h"
#include "CClipboard.h"
#include "CLog.h"
//
// CPrimaryClient
//
CPrimaryClient::CPrimaryClient(const CString& name, CScreen* screen) :
CBaseClientProxy(name),
m_screen(screen),
m_fakeInputCount(0)
{
// all clipboards are clean
for (UInt32 i = 0; i < kClipboardEnd; ++i) {
m_clipboardDirty[i] = false;
}
}
CPrimaryClient::~CPrimaryClient()
{
// do nothing
}
void
CPrimaryClient::reconfigure(UInt32 activeSides)
{
m_screen->reconfigure(activeSides);
}
UInt32
CPrimaryClient::registerHotKey(KeyID key, KeyModifierMask mask)
{
return m_screen->registerHotKey(key, mask);
}
void
CPrimaryClient::unregisterHotKey(UInt32 id)
{
m_screen->unregisterHotKey(id);
}
void
CPrimaryClient::fakeInputBegin()
{
if (++m_fakeInputCount == 1) {
m_screen->fakeInputBegin();
}
}
void
CPrimaryClient::fakeInputEnd()
{
if (--m_fakeInputCount == 0) {
m_screen->fakeInputEnd();
}
}
SInt32
CPrimaryClient::getJumpZoneSize() const
{
return m_screen->getJumpZoneSize();
}
void
CPrimaryClient::getCursorCenter(SInt32& x, SInt32& y) const
{
m_screen->getCursorCenter(x, y);
}
KeyModifierMask
CPrimaryClient::getToggleMask() const
{
return m_screen->pollActiveModifiers();
}
bool
CPrimaryClient::isLockedToScreen() const
{
return m_screen->isLockedToScreen();
}
void*
CPrimaryClient::getEventTarget() const
{
return m_screen->getEventTarget();
}
bool
CPrimaryClient::getClipboard(ClipboardID id, IClipboard* clipboard) const
{
return m_screen->getClipboard(id, clipboard);
}
void
CPrimaryClient::getShape(SInt32& x, SInt32& y,
SInt32& width, SInt32& height) const
{
m_screen->getShape(x, y, width, height);
}
void
CPrimaryClient::getCursorPos(SInt32& x, SInt32& y) const
{
m_screen->getCursorPos(x, y);
}
void
CPrimaryClient::enable()
{
m_screen->enable();
}
void
CPrimaryClient::disable()
{
m_screen->disable();
}
void
CPrimaryClient::enter(SInt32 xAbs, SInt32 yAbs,
UInt32 seqNum, KeyModifierMask mask, bool screensaver)
{
m_screen->setSequenceNumber(seqNum);
if (!screensaver) {
m_screen->warpCursor(xAbs, yAbs);
}
m_screen->enter(mask);
}
bool
CPrimaryClient::leave()
{
return m_screen->leave();
}
void
CPrimaryClient::setClipboard(ClipboardID id, const IClipboard* clipboard)
{
// ignore if this clipboard is already clean
if (m_clipboardDirty[id]) {
// this clipboard is now clean
m_clipboardDirty[id] = false;
// set clipboard
m_screen->setClipboard(id, clipboard);
}
}
void
CPrimaryClient::grabClipboard(ClipboardID id)
{
// grab clipboard
m_screen->grabClipboard(id);
// clipboard is dirty (because someone else owns it now)
m_clipboardDirty[id] = true;
}
void
CPrimaryClient::setClipboardDirty(ClipboardID id, bool dirty)
{
m_clipboardDirty[id] = dirty;
}
void
CPrimaryClient::keyDown(KeyID key, KeyModifierMask mask, KeyButton button)
{
if (m_fakeInputCount > 0) {
// XXX -- don't forward keystrokes to primary screen for now
(void)key;
(void)mask;
(void)button;
// m_screen->keyDown(key, mask, button);
}
}
void
CPrimaryClient::keyRepeat(KeyID, KeyModifierMask, SInt32, KeyButton)
{
// ignore
}
void
CPrimaryClient::keyUp(KeyID key, KeyModifierMask mask, KeyButton button)
{
if (m_fakeInputCount > 0) {
// XXX -- don't forward keystrokes to primary screen for now
(void)key;
(void)mask;
(void)button;
// m_screen->keyUp(key, mask, button);
}
}
void
CPrimaryClient::mouseDown(ButtonID)
{
// ignore
}
void
CPrimaryClient::mouseUp(ButtonID)
{
// ignore
}
void
CPrimaryClient::mouseMove(SInt32 x, SInt32 y)
{
m_screen->warpCursor(x, y);
}
void
CPrimaryClient::mouseRelativeMove(SInt32, SInt32)
{
// ignore
}
void
CPrimaryClient::mouseWheel(SInt32, SInt32)
{
// ignore
}
void
CPrimaryClient::gameDeviceButtons(GameDeviceID, GameDeviceButton)
{
// ignore
}
void
CPrimaryClient::gameDeviceSticks(GameDeviceID, SInt16, SInt16, SInt16, SInt16)
{
// ignore
}
void
CPrimaryClient::gameDeviceTriggers(GameDeviceID, UInt8, UInt8)
{
// ignore
}
void
CPrimaryClient::gameDeviceTimingReq()
{
// ignore
}
void
CPrimaryClient::screensaver(bool)
{
// ignore
}
void
CPrimaryClient::resetOptions()
{
m_screen->resetOptions();
}
void
CPrimaryClient::setOptions(const COptionsList& options)
{
m_screen->setOptions(options);
}

View File

@@ -0,0 +1,152 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CPRIMARYCLIENT_H
#define CPRIMARYCLIENT_H
#include "CBaseClientProxy.h"
#include "ProtocolTypes.h"
class CScreen;
//! Primary screen as pseudo-client
/*!
The primary screen does not have a client associated with it. This
class provides a pseudo-client to allow the primary screen to be
treated as if it was a client.
*/
class CPrimaryClient : public CBaseClientProxy {
public:
/*!
\c name is the name of the server and \p screen is primary screen.
*/
CPrimaryClient(const CString& name, CScreen* screen);
~CPrimaryClient();
//! @name manipulators
//@{
//! Update configuration
/*!
Handles reconfiguration of jump zones.
*/
void reconfigure(UInt32 activeSides);
//! Register a system hotkey
/*!
Registers a system-wide hotkey for key \p key with modifiers \p mask.
Returns an id used to unregister the hotkey.
*/
UInt32 registerHotKey(KeyID key, KeyModifierMask mask);
//! Unregister a system hotkey
/*!
Unregisters a previously registered hot key.
*/
void unregisterHotKey(UInt32 id);
//! Prepare to synthesize input on primary screen
/*!
Prepares the primary screen to receive synthesized input. We do not
want to receive this synthesized input as user input so this method
ensures that we ignore it. Calls to \c fakeInputBegin() and
\c fakeInputEnd() may be nested; only the outermost have an effect.
*/
void fakeInputBegin();
//! Done synthesizing input on primary screen
/*!
Undoes whatever \c fakeInputBegin() did.
*/
void fakeInputEnd();
//@}
//! @name accessors
//@{
//! Get jump zone size
/*!
Return the jump zone size, the size of the regions on the edges of
the screen that cause the cursor to jump to another screen.
*/
SInt32 getJumpZoneSize() const;
//! Get cursor center position
/*!
Return the cursor center position which is where we park the
cursor to compute cursor motion deltas and should be far from
the edges of the screen, typically the center.
*/
void getCursorCenter(SInt32& x, SInt32& y) const;
//! Get toggle key state
/*!
Returns the primary screen's current toggle modifier key state.
*/
KeyModifierMask getToggleMask() const;
//! Get screen lock state
/*!
Returns true if the user is locked to the screen.
*/
bool isLockedToScreen() const;
//@}
// FIXME -- these probably belong on IScreen
virtual void enable();
virtual void disable();
// IScreen overrides
virtual void* getEventTarget() const;
virtual bool getClipboard(ClipboardID id, IClipboard*) const;
virtual void getShape(SInt32& x, SInt32& y,
SInt32& width, SInt32& height) const;
virtual void getCursorPos(SInt32& x, SInt32& y) const;
// IClient overrides
virtual void enter(SInt32 xAbs, SInt32 yAbs,
UInt32 seqNum, KeyModifierMask mask,
bool forScreensaver);
virtual bool leave();
virtual void setClipboard(ClipboardID, const IClipboard*);
virtual void grabClipboard(ClipboardID);
virtual void setClipboardDirty(ClipboardID, bool);
virtual void keyDown(KeyID, KeyModifierMask, KeyButton);
virtual void keyRepeat(KeyID, KeyModifierMask,
SInt32 count, KeyButton);
virtual void keyUp(KeyID, KeyModifierMask, KeyButton);
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 xDelta, SInt32 yDelta);
virtual void gameDeviceButtons(GameDeviceID id, GameDeviceButton buttons);
virtual void gameDeviceSticks(GameDeviceID id, SInt16 x1, SInt16 y1, SInt16 x2, SInt16 y2);
virtual void gameDeviceTriggers(GameDeviceID id, UInt8 t1, UInt8 t2);
virtual void gameDeviceTimingReq();
virtual void screensaver(bool activate);
virtual void resetOptions();
virtual void setOptions(const COptionsList& options);
private:
CScreen* m_screen;
bool m_clipboardDirty[kClipboardEnd];
SInt32 m_fakeInputCount;
};
#endif

2300
src/lib/server/CServer.cpp Normal file

File diff suppressed because it is too large Load Diff

498
src/lib/server/CServer.h Normal file
View File

@@ -0,0 +1,498 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CSERVER_H
#define CSERVER_H
#include "CConfig.h"
#include "CClipboard.h"
#include "ClipboardTypes.h"
#include "KeyTypes.h"
#include "MouseTypes.h"
#include "CEvent.h"
#include "CStopwatch.h"
#include "stdmap.h"
#include "stdset.h"
#include "stdvector.h"
#include "INode.h"
class CBaseClientProxy;
class CEventQueueTimer;
class CPrimaryClient;
class CInputFilter;
class CScreen;
//! Synergy server
/*!
This class implements the top-level server algorithms for synergy.
*/
class CServer : public INode {
public:
//! Lock cursor to screen data
class CLockCursorToScreenInfo {
public:
enum State { kOff, kOn, kToggle };
static CLockCursorToScreenInfo* alloc(State state = kToggle);
public:
State m_state;
};
//! Switch to screen data
class CSwitchToScreenInfo {
public:
static CSwitchToScreenInfo* alloc(const CString& screen);
public:
// this is a C-string; this type is a variable size structure
char m_screen[1];
};
//! Switch in direction data
class CSwitchInDirectionInfo {
public:
static CSwitchInDirectionInfo* alloc(EDirection direction);
public:
EDirection m_direction;
};
//! Screen connected data
class CScreenConnectedInfo {
public:
CScreenConnectedInfo(CString screen) : m_screen(screen) { }
public:
CString m_screen; // was char[1]
};
//! Keyboard broadcast data
class CKeyboardBroadcastInfo {
public:
enum State { kOff, kOn, kToggle };
static CKeyboardBroadcastInfo* alloc(State state = kToggle);
static CKeyboardBroadcastInfo* alloc(State state,
const CString& screens);
public:
State m_state;
char m_screens[1];
};
/*!
Start the server with the configuration \p config and the primary
client (local screen) \p primaryClient. The client retains
ownership of \p primaryClient.
*/
CServer(const CConfig& config, CPrimaryClient* primaryClient, CScreen* screen);
~CServer();
//! @name manipulators
//@{
//! Set configuration
/*!
Change the server's configuration. Returns true iff the new
configuration was accepted (it must include the server's name).
This will disconnect any clients no longer in the configuration.
*/
bool setConfig(const CConfig&);
//! Add a client
/*!
Adds \p client to the server. The client is adopted and will be
destroyed when the client disconnects or is disconnected.
*/
void adoptClient(CBaseClientProxy* client);
//! Disconnect clients
/*!
Disconnect clients. This tells them to disconnect but does not wait
for them to actually do so. The server sends the disconnected event
when they're all disconnected (or immediately if none are connected).
The caller can also just destroy this object to force the disconnection.
*/
void disconnect();
//! Notify of game device timing response
void gameDeviceTimingResp(UInt16 freq);
//! Notify of game device feedback
void gameDeviceFeedback(GameDeviceID id, UInt16 m1, UInt16 m2);
//@}
//! @name accessors
//@{
//! Get number of connected clients
/*!
Returns the number of connected clients, including the server itself.
*/
UInt32 getNumClients() const;
//! Get the list of connected clients
/*!
Set the \c list to the names of the currently connected clients.
*/
void getClients(std::vector<CString>& list) const;
//! Get error event type
/*!
Returns the error event type. This is sent when the server fails
for some reason.
*/
static CEvent::Type getErrorEvent();
//! Get connected event type
/*!
Returns the connected event type. This is sent when a client screen
has connected. The event data is a \c CScreenConnectedInfo* that
indicates the connected screen.
*/
static CEvent::Type getConnectedEvent();
//! Get disconnected event type
/*!
Returns the disconnected event type. This is sent when all the
clients have disconnected.
*/
static CEvent::Type getDisconnectedEvent();
//! Get switch to screen event type
/*!
Returns the switch to screen event type. The server responds to this
by switching screens. The event data is a \c CSwitchToScreenInfo*
that indicates the target screen.
*/
static CEvent::Type getSwitchToScreenEvent();
//! Get switch in direction event type
/*!
Returns the switch in direction event type. The server responds to this
by switching screens. The event data is a \c CSwitchInDirectionInfo*
that indicates the target direction.
*/
static CEvent::Type getSwitchInDirectionEvent();
//! Get keyboard broadcast event type
/*!
Returns the keyboard broadcast event type. The server responds
to this by turning on keyboard broadcasting or turning it off. The
event data is a \c CKeyboardBroadcastInfo*.
*/
static CEvent::Type getKeyboardBroadcastEvent();
//! Get lock cursor event type
/*!
Returns the lock cursor event type. The server responds to this
by locking the cursor to the active screen or unlocking it. The
event data is a \c CLockCursorToScreenInfo*.
*/
static CEvent::Type getLockCursorToScreenEvent();
//! Get screen switched event type
/*!
Returns the screen switched event type. This is raised when the
screen has been switched to a client.
*/
static CEvent::Type getScreenSwitchedEvent();
//@}
private:
// get canonical name of client
CString getName(const CBaseClientProxy*) const;
// get the sides of the primary screen that have neighbors
UInt32 getActivePrimarySides() const;
// returns true iff mouse should be locked to the current screen
// according to this object only, ignoring what the primary client
// says.
bool isLockedToScreenServer() const;
// returns true iff mouse should be locked to the current screen
// according to this object or the primary client.
bool isLockedToScreen() const;
// returns the jump zone of the client
SInt32 getJumpZoneSize(CBaseClientProxy*) const;
// change the active screen
void switchScreen(CBaseClientProxy*,
SInt32 x, SInt32 y, bool forScreenSaver);
// jump to screen
void jumpToScreen(CBaseClientProxy*);
// convert pixel position to fraction, using x or y depending on the
// direction.
float mapToFraction(CBaseClientProxy*, EDirection,
SInt32 x, SInt32 y) const;
// convert fraction to pixel position, writing only x or y depending
// on the direction.
void mapToPixel(CBaseClientProxy*, EDirection, float f,
SInt32& x, SInt32& y) const;
// returns true if the client has a neighbor anywhere along the edge
// indicated by the direction.
bool hasAnyNeighbor(CBaseClientProxy*, EDirection) const;
// lookup neighboring screen, mapping the coordinate independent of
// the direction to the neighbor's coordinate space.
CBaseClientProxy* getNeighbor(CBaseClientProxy*, EDirection,
SInt32& x, SInt32& y) const;
// lookup neighboring screen. given a position relative to the
// source screen, find the screen we should move onto and where.
// if the position is sufficiently far from the source then we
// cross multiple screens. if there is no suitable screen then
// return NULL and x,y are not modified.
CBaseClientProxy* mapToNeighbor(CBaseClientProxy*, EDirection,
SInt32& x, SInt32& y) const;
// adjusts x and y or neither to avoid ending up in a jump zone
// after entering the client in the given direction.
void avoidJumpZone(CBaseClientProxy*, EDirection,
SInt32& x, SInt32& y) const;
// test if a switch is permitted. this includes testing user
// options like switch delay and tracking any state required to
// implement them. returns true iff a switch is permitted.
bool isSwitchOkay(CBaseClientProxy* dst, EDirection,
SInt32 x, SInt32 y, SInt32 xActive, SInt32 yActive);
// update switch state due to a mouse move at \p x, \p y that
// doesn't switch screens.
void noSwitch(SInt32 x, SInt32 y);
// stop switch timers
void stopSwitch();
// start two tap switch timer
void startSwitchTwoTap();
// arm the two tap switch timer if \p x, \p y is outside the tap zone
void armSwitchTwoTap(SInt32 x, SInt32 y);
// stop the two tap switch timer
void stopSwitchTwoTap();
// returns true iff the two tap switch timer is started
bool isSwitchTwoTapStarted() const;
// returns true iff should switch because of two tap
bool shouldSwitchTwoTap() const;
// start delay switch timer
void startSwitchWait(SInt32 x, SInt32 y);
// stop delay switch timer
void stopSwitchWait();
// returns true iff the delay switch timer is started
bool isSwitchWaitStarted() const;
// returns the corner (EScreenSwitchCornerMasks) where x,y is on the
// given client. corners have the given size.
UInt32 getCorner(CBaseClientProxy*,
SInt32 x, SInt32 y, SInt32 size) const;
// stop relative mouse moves
void stopRelativeMoves();
// send screen options to \c client
void sendOptions(CBaseClientProxy* client) const;
// process options from configuration
void processOptions();
// event handlers
void handleShapeChanged(const CEvent&, void*);
void handleClipboardGrabbed(const CEvent&, void*);
void handleClipboardChanged(const CEvent&, void*);
void handleKeyDownEvent(const CEvent&, void*);
void handleKeyUpEvent(const CEvent&, void*);
void handleKeyRepeatEvent(const CEvent&, void*);
void handleButtonDownEvent(const CEvent&, void*);
void handleButtonUpEvent(const CEvent&, void*);
void handleMotionPrimaryEvent(const CEvent&, void*);
void handleMotionSecondaryEvent(const CEvent&, void*);
void handleWheelEvent(const CEvent&, void*);
void handleGameDeviceButtons(const CEvent&, void*);
void handleGameDeviceSticks(const CEvent&, void*);
void handleGameDeviceTriggers(const CEvent&, void*);
void handleGameDeviceTimingReq(const CEvent&, void*);
void handleScreensaverActivatedEvent(const CEvent&, void*);
void handleScreensaverDeactivatedEvent(const CEvent&, void*);
void handleSwitchWaitTimeout(const CEvent&, void*);
void handleClientDisconnected(const CEvent&, void*);
void handleClientCloseTimeout(const CEvent&, void*);
void handleSwitchToScreenEvent(const CEvent&, void*);
void handleSwitchInDirectionEvent(const CEvent&, void*);
void handleKeyboardBroadcastEvent(const CEvent&,void*);
void handleLockCursorToScreenEvent(const CEvent&, void*);
void handleFakeInputBeginEvent(const CEvent&, void*);
void handleFakeInputEndEvent(const CEvent&, void*);
// event processing
void onClipboardChanged(CBaseClientProxy* sender,
ClipboardID id, UInt32 seqNum);
void onScreensaver(bool activated);
void onKeyDown(KeyID, KeyModifierMask, KeyButton,
const char* screens);
void onKeyUp(KeyID, KeyModifierMask, KeyButton,
const char* screens);
void onKeyRepeat(KeyID, KeyModifierMask, SInt32, KeyButton);
void onMouseDown(ButtonID);
void onMouseUp(ButtonID);
bool onMouseMovePrimary(SInt32 x, SInt32 y);
void onMouseMoveSecondary(SInt32 dx, SInt32 dy);
void onMouseWheel(SInt32 xDelta, SInt32 yDelta);
void onGameDeviceButtons(GameDeviceID id, GameDeviceButton buttons);
void onGameDeviceSticks(GameDeviceID id, SInt16 x1, SInt16 y1, SInt16 x2, SInt16 y2);
void onGameDeviceTriggers(GameDeviceID id, UInt8 t1, UInt8 t2);
void onGameDeviceTimingReq();
// add client to list and attach event handlers for client
bool addClient(CBaseClientProxy*);
// remove client from list and detach event handlers for client
bool removeClient(CBaseClientProxy*);
// close a client
void closeClient(CBaseClientProxy*, const char* msg);
// close clients not in \p config
void closeClients(const CConfig& config);
// close all clients whether they've completed the handshake or not,
// except the primary client
void closeAllClients();
// remove clients from internal state
void removeActiveClient(CBaseClientProxy*);
void removeOldClient(CBaseClientProxy*);
// force the cursor off of \p client
void forceLeaveClient(CBaseClientProxy* client);
private:
class CClipboardInfo {
public:
CClipboardInfo();
public:
CClipboard m_clipboard;
CString m_clipboardData;
CString m_clipboardOwner;
UInt32 m_clipboardSeqNum;
};
// the primary screen client
CPrimaryClient* m_primaryClient;
// all clients (including the primary client) indexed by name
typedef std::map<CString, CBaseClientProxy*> CClientList;
typedef std::set<CBaseClientProxy*> CClientSet;
CClientList m_clients;
CClientSet m_clientSet;
// all old connections that we're waiting to hangup
typedef std::map<CBaseClientProxy*, CEventQueueTimer*> COldClients;
COldClients m_oldClients;
// the client with focus
CBaseClientProxy* m_active;
// the sequence number of enter messages
UInt32 m_seqNum;
// current mouse position (in absolute screen coordinates) on
// whichever screen is active
SInt32 m_x, m_y;
// last mouse deltas. this is needed to smooth out double tap
// on win32 which reports bogus mouse motion at the edge of
// the screen when using low level hooks, synthesizing motion
// in the opposite direction the mouse actually moved.
SInt32 m_xDelta, m_yDelta;
SInt32 m_xDelta2, m_yDelta2;
// current configuration
CConfig m_config;
// input filter (from m_config);
CInputFilter* m_inputFilter;
// clipboard cache
CClipboardInfo m_clipboards[kClipboardEnd];
// state saved when screen saver activates
CBaseClientProxy* m_activeSaver;
SInt32 m_xSaver, m_ySaver;
// common state for screen switch tests. all tests are always
// trying to reach the same screen in the same direction.
EDirection m_switchDir;
CBaseClientProxy* m_switchScreen;
// state for delayed screen switching
double m_switchWaitDelay;
CEventQueueTimer* m_switchWaitTimer;
SInt32 m_switchWaitX, m_switchWaitY;
// state for double-tap screen switching
double m_switchTwoTapDelay;
CStopwatch m_switchTwoTapTimer;
bool m_switchTwoTapEngaged;
bool m_switchTwoTapArmed;
SInt32 m_switchTwoTapZone;
// modifiers needed before switching
bool m_switchNeedsShift;
bool m_switchNeedsControl;
bool m_switchNeedsAlt;
// relative mouse move option
bool m_relativeMoves;
// flag whether or not we have broadcasting enabled and the screens to
// which we should send broadcasted keys.
bool m_keyboardBroadcasting;
CString m_keyboardBroadcastingScreens;
// screen locking (former scroll lock)
bool m_lockedToScreen;
// server screen
CScreen* m_screen;
static CEvent::Type s_errorEvent;
static CEvent::Type s_connectedEvent;
static CEvent::Type s_disconnectedEvent;
static CEvent::Type s_switchToScreen;
static CEvent::Type s_switchInDirection;
static CEvent::Type s_keyboardBroadcast;
static CEvent::Type s_lockCursorToScreen;
static CEvent::Type s_screenSwitched;
};
#endif