mirror of
https://github.com/debauchee/barrier.git
synced 2026-07-02 01:47:37 +08:00
moving 1.4 to trunk
This commit is contained in:
55
src/lib/server/CBaseClientProxy.cpp
Normal file
55
src/lib/server/CBaseClientProxy.cpp
Normal 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;
|
||||
}
|
||||
92
src/lib/server/CBaseClientProxy.h
Normal file
92
src/lib/server/CBaseClientProxy.h
Normal 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
|
||||
207
src/lib/server/CClientListener.cpp
Normal file
207
src/lib/server/CClientListener.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
88
src/lib/server/CClientListener.h
Normal file
88
src/lib/server/CClientListener.h
Normal 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
|
||||
93
src/lib/server/CClientProxy.cpp
Normal file
93
src/lib/server/CClientProxy.cpp
Normal 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));
|
||||
}
|
||||
128
src/lib/server/CClientProxy.h
Normal file
128
src/lib/server/CClientProxy.h
Normal 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
|
||||
529
src/lib/server/CClientProxy1_0.cpp
Normal file
529
src/lib/server/CClientProxy1_0.cpp
Normal 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
|
||||
}
|
||||
107
src/lib/server/CClientProxy1_0.h
Normal file
107
src/lib/server/CClientProxy1_0.h
Normal 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
|
||||
58
src/lib/server/CClientProxy1_1.cpp
Normal file
58
src/lib/server/CClientProxy1_1.cpp
Normal 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);
|
||||
}
|
||||
36
src/lib/server/CClientProxy1_1.h
Normal file
36
src/lib/server/CClientProxy1_1.h
Normal 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
|
||||
42
src/lib/server/CClientProxy1_2.cpp
Normal file
42
src/lib/server/CClientProxy1_2.cpp
Normal 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);
|
||||
}
|
||||
33
src/lib/server/CClientProxy1_2.h
Normal file
33
src/lib/server/CClientProxy1_2.h
Normal 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
|
||||
119
src/lib/server/CClientProxy1_3.cpp
Normal file
119
src/lib/server/CClientProxy1_3.cpp
Normal 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);
|
||||
}
|
||||
50
src/lib/server/CClientProxy1_3.h
Normal file
50
src/lib/server/CClientProxy1_3.h
Normal 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
|
||||
111
src/lib/server/CClientProxy1_4.cpp
Normal file
111
src/lib/server/CClientProxy1_4.cpp
Normal 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);
|
||||
}
|
||||
47
src/lib/server/CClientProxy1_4.h
Normal file
47
src/lib/server/CClientProxy1_4.h
Normal 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;
|
||||
};
|
||||
299
src/lib/server/CClientProxyUnknown.cpp
Normal file
299
src/lib/server/CClientProxyUnknown.cpp
Normal 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();
|
||||
}
|
||||
88
src/lib/server/CClientProxyUnknown.h
Normal file
88
src/lib/server/CClientProxyUnknown.h
Normal 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
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
539
src/lib/server/CConfig.h
Normal 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
|
||||
1069
src/lib/server/CInputFilter.cpp
Normal file
1069
src/lib/server/CInputFilter.cpp
Normal file
File diff suppressed because it is too large
Load Diff
347
src/lib/server/CInputFilter.h
Normal file
347
src/lib/server/CInputFilter.h
Normal 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
|
||||
79
src/lib/server/CMakeLists.txt
Normal file
79
src/lib/server/CMakeLists.txt
Normal 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()
|
||||
284
src/lib/server/CPrimaryClient.cpp
Normal file
284
src/lib/server/CPrimaryClient.cpp
Normal 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);
|
||||
}
|
||||
152
src/lib/server/CPrimaryClient.h
Normal file
152
src/lib/server/CPrimaryClient.h
Normal 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
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
498
src/lib/server/CServer.h
Normal 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
|
||||
Reference in New Issue
Block a user