mirror of
https://github.com/debauchee/barrier.git
synced 2026-11-03 14:04:19 +08:00
Reorganized source tree. Moved client.cpp into cmd/synergy as
synergy.cpp and server.cpp into cmd/synergyd as synergyd.cpp. Moved and renamed related files. Moved remaining source files into lib/.... Modified and added makefiles as appropriate. Result is that library files are under lib with each library in its own directory and program files are under cmd with each command in its own directory.
This commit is contained in:
629
lib/client/CClient.cpp
Normal file
629
lib/client/CClient.cpp
Normal file
@@ -0,0 +1,629 @@
|
||||
#include "CClient.h"
|
||||
#include "CServerProxy.h"
|
||||
#include "CClipboard.h"
|
||||
#include "CInputPacketStream.h"
|
||||
#include "COutputPacketStream.h"
|
||||
#include "CProtocolUtil.h"
|
||||
#include "CSecondaryScreen.h"
|
||||
#include "IServer.h"
|
||||
#include "ProtocolTypes.h"
|
||||
#include "XScreen.h"
|
||||
#include "XSynergy.h"
|
||||
#include "XSocket.h"
|
||||
#include "CLock.h"
|
||||
#include "CThread.h"
|
||||
#include "CTimerThread.h"
|
||||
#include "XThread.h"
|
||||
#include "CLog.h"
|
||||
#include "CStopwatch.h"
|
||||
#include "TMethodJob.h"
|
||||
|
||||
//
|
||||
// CClient
|
||||
//
|
||||
|
||||
CClient::CClient(const CString& clientName) :
|
||||
m_name(clientName),
|
||||
m_screen(NULL),
|
||||
m_server(NULL),
|
||||
m_camp(false),
|
||||
m_session(NULL),
|
||||
m_active(false),
|
||||
m_rejected(true)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
CClient::~CClient()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void
|
||||
CClient::camp(bool on)
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
m_camp = on;
|
||||
}
|
||||
|
||||
void
|
||||
CClient::setAddress(const CNetworkAddress& serverAddress)
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
m_serverAddress = serverAddress;
|
||||
}
|
||||
|
||||
void
|
||||
CClient::exitMainLoop()
|
||||
{
|
||||
m_screen->exitMainLoop();
|
||||
}
|
||||
|
||||
bool
|
||||
CClient::wasRejected() const
|
||||
{
|
||||
return m_rejected;
|
||||
}
|
||||
|
||||
void
|
||||
CClient::onError()
|
||||
{
|
||||
// close down session but don't wait too long
|
||||
deleteSession(3.0);
|
||||
}
|
||||
|
||||
void
|
||||
CClient::onInfoChanged(const CClientInfo& info)
|
||||
{
|
||||
log((CLOG_DEBUG "resolution changed"));
|
||||
|
||||
CLock lock(&m_mutex);
|
||||
if (m_server != NULL) {
|
||||
m_server->onInfoChanged(info);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CClient::onGrabClipboard(ClipboardID id)
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
if (m_server == NULL) {
|
||||
// m_server can be NULL if the screen calls this method
|
||||
// before we've gotten around to connecting to the server.
|
||||
// we simply ignore the clipboard change in that case.
|
||||
return false;
|
||||
}
|
||||
|
||||
// grab ownership
|
||||
m_server->onGrabClipboard(id);
|
||||
|
||||
// we now own the clipboard and it has not been sent to the server
|
||||
m_ownClipboard[id] = true;
|
||||
m_timeClipboard[id] = 0;
|
||||
|
||||
// if we're not the active screen then send the clipboard now,
|
||||
// otherwise we'll wait until we leave.
|
||||
if (!m_active) {
|
||||
sendClipboard(id);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CClient::onClipboardChanged(ClipboardID, const CString&)
|
||||
{
|
||||
// ignore -- we'll check the clipboard when we leave
|
||||
}
|
||||
|
||||
bool
|
||||
CClient::open()
|
||||
{
|
||||
// open the screen
|
||||
try {
|
||||
log((CLOG_INFO "opening screen"));
|
||||
openSecondaryScreen();
|
||||
return true;
|
||||
}
|
||||
catch (XScreenOpenFailure&) {
|
||||
// can't open screen yet. wait a few seconds to retry.
|
||||
log((CLOG_INFO "failed to open screen"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CClient::mainLoop()
|
||||
{
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
|
||||
// check preconditions
|
||||
assert(m_screen != NULL);
|
||||
assert(m_server == NULL);
|
||||
|
||||
// connection starts as unsuccessful
|
||||
m_rejected = true;
|
||||
}
|
||||
|
||||
try {
|
||||
log((CLOG_NOTE "starting client \"%s\"", m_name.c_str()));
|
||||
|
||||
// start server interactions
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
m_session = new CThread(new TMethodJob<CClient>(
|
||||
this, &CClient::runSession));
|
||||
}
|
||||
|
||||
// handle events
|
||||
m_screen->mainLoop();
|
||||
|
||||
// clean up
|
||||
deleteSession();
|
||||
log((CLOG_NOTE "stopping client \"%s\"", m_name.c_str()));
|
||||
}
|
||||
catch (XBase& e) {
|
||||
log((CLOG_ERR "client error: %s", e.what()));
|
||||
|
||||
// clean up
|
||||
deleteSession();
|
||||
log((CLOG_NOTE "stopping client \"%s\"", m_name.c_str()));
|
||||
CLock lock(&m_mutex);
|
||||
m_rejected = false;
|
||||
}
|
||||
catch (XThread&) {
|
||||
// clean up
|
||||
deleteSession();
|
||||
log((CLOG_NOTE "stopping client \"%s\"", m_name.c_str()));
|
||||
throw;
|
||||
}
|
||||
catch (...) {
|
||||
log((CLOG_DEBUG "unknown client error"));
|
||||
|
||||
// clean up
|
||||
deleteSession();
|
||||
log((CLOG_NOTE "stopping client \"%s\"", m_name.c_str()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CClient::close()
|
||||
{
|
||||
closeSecondaryScreen();
|
||||
log((CLOG_INFO "closed screen"));
|
||||
}
|
||||
|
||||
void
|
||||
CClient::enter(SInt32 xAbs, SInt32 yAbs, UInt32, KeyModifierMask mask, bool)
|
||||
{
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
m_active = true;
|
||||
}
|
||||
|
||||
m_screen->enter(xAbs, yAbs, mask);
|
||||
}
|
||||
|
||||
bool
|
||||
CClient::leave()
|
||||
{
|
||||
m_screen->leave();
|
||||
|
||||
CLock lock(&m_mutex);
|
||||
m_active = false;
|
||||
|
||||
// send clipboards that we own and that have changed
|
||||
for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
|
||||
if (m_ownClipboard[id]) {
|
||||
sendClipboard(id);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CClient::setClipboard(ClipboardID id, const CString& data)
|
||||
{
|
||||
// unmarshall
|
||||
CClipboard clipboard;
|
||||
clipboard.unmarshall(data, 0);
|
||||
|
||||
// set screen's clipboard
|
||||
m_screen->setClipboard(id, &clipboard);
|
||||
}
|
||||
|
||||
void
|
||||
CClient::grabClipboard(ClipboardID id)
|
||||
{
|
||||
// we no longer own the clipboard
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
m_ownClipboard[id] = false;
|
||||
}
|
||||
|
||||
m_screen->grabClipboard(id);
|
||||
}
|
||||
|
||||
void
|
||||
CClient::setClipboardDirty(ClipboardID, bool)
|
||||
{
|
||||
assert(0 && "shouldn't be called");
|
||||
}
|
||||
|
||||
void
|
||||
CClient::keyDown(KeyID id, KeyModifierMask mask)
|
||||
{
|
||||
m_screen->keyDown(id, mask);
|
||||
}
|
||||
|
||||
void
|
||||
CClient::keyRepeat(KeyID id, KeyModifierMask mask, SInt32 count)
|
||||
{
|
||||
m_screen->keyRepeat(id, mask, count);
|
||||
}
|
||||
|
||||
void
|
||||
CClient::keyUp(KeyID id, KeyModifierMask mask)
|
||||
{
|
||||
m_screen->keyUp(id, mask);
|
||||
}
|
||||
|
||||
void
|
||||
CClient::mouseDown(ButtonID id)
|
||||
{
|
||||
m_screen->mouseDown(id);
|
||||
}
|
||||
|
||||
void
|
||||
CClient::mouseUp(ButtonID id)
|
||||
{
|
||||
m_screen->mouseUp(id);
|
||||
}
|
||||
|
||||
void
|
||||
CClient::mouseMove(SInt32 x, SInt32 y)
|
||||
{
|
||||
m_screen->mouseMove(x, y);
|
||||
}
|
||||
|
||||
void
|
||||
CClient::mouseWheel(SInt32 delta)
|
||||
{
|
||||
m_screen->mouseWheel(delta);
|
||||
}
|
||||
|
||||
void
|
||||
CClient::screensaver(bool activate)
|
||||
{
|
||||
m_screen->screensaver(activate);
|
||||
}
|
||||
|
||||
CString
|
||||
CClient::getName() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
SInt32
|
||||
CClient::getJumpZoneSize() const
|
||||
{
|
||||
return m_screen->getJumpZoneSize();
|
||||
}
|
||||
|
||||
void
|
||||
CClient::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const
|
||||
{
|
||||
m_screen->getShape(x, y, w, h);
|
||||
}
|
||||
|
||||
void
|
||||
CClient::getCursorPos(SInt32& x, SInt32& y) const
|
||||
{
|
||||
m_screen->getCursorPos(x, y);
|
||||
}
|
||||
|
||||
void
|
||||
CClient::getCursorCenter(SInt32&, SInt32&) const
|
||||
{
|
||||
assert(0 && "shouldn't be called");
|
||||
}
|
||||
|
||||
// FIXME -- use factory to create screen
|
||||
#if WINDOWS_LIKE
|
||||
#include "CMSWindowsSecondaryScreen.h"
|
||||
#elif UNIX_LIKE
|
||||
#include "CXWindowsSecondaryScreen.h"
|
||||
#endif
|
||||
void
|
||||
CClient::openSecondaryScreen()
|
||||
{
|
||||
assert(m_screen == NULL);
|
||||
|
||||
// not active
|
||||
m_active = false;
|
||||
|
||||
// reset clipboard state
|
||||
for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
|
||||
m_ownClipboard[id] = false;
|
||||
m_timeClipboard[id] = 0;
|
||||
}
|
||||
|
||||
// open screen
|
||||
log((CLOG_DEBUG1 "creating secondary screen"));
|
||||
#if WINDOWS_LIKE
|
||||
m_screen = new CMSWindowsSecondaryScreen(this);
|
||||
#elif UNIX_LIKE
|
||||
m_screen = new CXWindowsSecondaryScreen(this);
|
||||
#endif
|
||||
log((CLOG_DEBUG1 "opening secondary screen"));
|
||||
try {
|
||||
m_screen->open();
|
||||
}
|
||||
catch (...) {
|
||||
log((CLOG_DEBUG1 "destroying secondary screen"));
|
||||
delete m_screen;
|
||||
m_screen = NULL;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CClient::closeSecondaryScreen()
|
||||
{
|
||||
assert(m_screen != NULL);
|
||||
|
||||
// close the secondary screen
|
||||
try {
|
||||
log((CLOG_DEBUG1 "closing secondary screen"));
|
||||
m_screen->close();
|
||||
}
|
||||
catch (...) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
// clean up
|
||||
log((CLOG_DEBUG1 "destroying secondary screen"));
|
||||
delete m_screen;
|
||||
m_screen = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
CClient::sendClipboard(ClipboardID id)
|
||||
{
|
||||
// note -- m_mutex must be locked on entry
|
||||
assert(m_screen != NULL);
|
||||
assert(m_server != NULL);
|
||||
|
||||
// get clipboard data. set the clipboard time to the last
|
||||
// clipboard time before getting the data from the screen
|
||||
// as the screen may detect an unchanged clipboard and
|
||||
// avoid copying the data.
|
||||
CClipboard clipboard;
|
||||
if (clipboard.open(m_timeClipboard[id])) {
|
||||
clipboard.close();
|
||||
}
|
||||
m_screen->getClipboard(id, &clipboard);
|
||||
|
||||
// check time
|
||||
if (m_timeClipboard[id] == 0 ||
|
||||
clipboard.getTime() != m_timeClipboard[id]) {
|
||||
// save new time
|
||||
m_timeClipboard[id] = clipboard.getTime();
|
||||
|
||||
// marshall the data
|
||||
CString data = clipboard.marshall();
|
||||
|
||||
// save and send data if different
|
||||
if (data != m_dataClipboard[id]) {
|
||||
m_dataClipboard[id] = data;
|
||||
m_server->onClipboardChanged(id, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CClient::runSession(void*)
|
||||
{
|
||||
try {
|
||||
log((CLOG_DEBUG "starting server proxy"));
|
||||
runServer();
|
||||
m_screen->exitMainLoop();
|
||||
log((CLOG_DEBUG "stopping server proxy"));
|
||||
}
|
||||
catch (...) {
|
||||
m_screen->exitMainLoop();
|
||||
log((CLOG_DEBUG "stopping server proxy"));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CClient::deleteSession(double timeout)
|
||||
{
|
||||
// get session thread object
|
||||
CThread* thread;
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
thread = m_session;
|
||||
m_session = NULL;
|
||||
}
|
||||
|
||||
// shut it down
|
||||
if (thread != NULL) {
|
||||
thread->cancel();
|
||||
thread->wait(timeout);
|
||||
delete thread;
|
||||
}
|
||||
}
|
||||
|
||||
#include "CTCPSocket.h" // FIXME
|
||||
void
|
||||
CClient::runServer()
|
||||
{
|
||||
IDataSocket* socket = NULL;
|
||||
CServerProxy* proxy = NULL;
|
||||
try {
|
||||
for (;;) {
|
||||
try {
|
||||
// allow connect this much time to succeed
|
||||
// FIXME -- timeout in member
|
||||
CTimerThread timer(m_camp ? -1.0 : 30.0);
|
||||
|
||||
// create socket and attempt to connect to server
|
||||
log((CLOG_DEBUG1 "connecting to server"));
|
||||
socket = new CTCPSocket; // FIXME -- use factory
|
||||
socket->connect(m_serverAddress);
|
||||
log((CLOG_INFO "connected to server"));
|
||||
break;
|
||||
}
|
||||
catch (XSocketConnect& e) {
|
||||
log((CLOG_DEBUG1 "failed to connect to server: %s", e.getErrstr()));
|
||||
|
||||
// failed to connect. if not camping then rethrow.
|
||||
if (!m_camp) {
|
||||
throw;
|
||||
}
|
||||
|
||||
// we're camping. wait a bit before retrying
|
||||
CThread::sleep(5.0);
|
||||
}
|
||||
}
|
||||
|
||||
// create proxy
|
||||
log((CLOG_DEBUG1 "negotiating with server"));
|
||||
proxy = handshakeServer(socket);
|
||||
CLock lock(&m_mutex);
|
||||
m_server = proxy;
|
||||
}
|
||||
catch (XThread&) {
|
||||
log((CLOG_ERR "connection timed out"));
|
||||
delete socket;
|
||||
throw;
|
||||
}
|
||||
catch (XBase& e) {
|
||||
log((CLOG_ERR "connection failed: %s", e.what()));
|
||||
log((CLOG_DEBUG "disconnecting from server"));
|
||||
delete socket;
|
||||
return;
|
||||
}
|
||||
catch (...) {
|
||||
log((CLOG_ERR "connection failed: <unknown error>"));
|
||||
log((CLOG_DEBUG "disconnecting from server"));
|
||||
delete socket;
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// process messages
|
||||
bool rejected = true;
|
||||
if (proxy != NULL) {
|
||||
log((CLOG_DEBUG1 "communicating with server"));
|
||||
rejected = !proxy->mainLoop();
|
||||
}
|
||||
|
||||
// clean up
|
||||
CLock lock(&m_mutex);
|
||||
m_rejected = rejected;
|
||||
m_server = NULL;
|
||||
delete proxy;
|
||||
log((CLOG_DEBUG "disconnecting from server"));
|
||||
socket->close();
|
||||
delete socket;
|
||||
}
|
||||
catch (...) {
|
||||
CLock lock(&m_mutex);
|
||||
m_rejected = false;
|
||||
m_server = NULL;
|
||||
delete proxy;
|
||||
log((CLOG_DEBUG "disconnecting from server"));
|
||||
socket->close();
|
||||
delete socket;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
CServerProxy*
|
||||
CClient::handshakeServer(IDataSocket* socket)
|
||||
{
|
||||
// get the input and output streams
|
||||
IInputStream* input = socket->getInputStream();
|
||||
IOutputStream* output = socket->getOutputStream();
|
||||
bool own = false;
|
||||
|
||||
// attach the encryption layer
|
||||
/* FIXME -- implement ISecurityFactory
|
||||
if (m_securityFactory != NULL) {
|
||||
input = m_securityFactory->createInputFilter(input, own);
|
||||
output = m_securityFactory->createOutputFilter(output, own);
|
||||
own = true;
|
||||
}
|
||||
*/
|
||||
|
||||
// attach the packetizing filters
|
||||
input = new CInputPacketStream(input, own);
|
||||
output = new COutputPacketStream(output, own);
|
||||
own = true;
|
||||
|
||||
CServerProxy* proxy = NULL;
|
||||
try {
|
||||
// give handshake some time
|
||||
CTimerThread timer(30.0);
|
||||
|
||||
// wait for hello from server
|
||||
log((CLOG_DEBUG1 "wait for hello"));
|
||||
SInt16 major, minor;
|
||||
CProtocolUtil::readf(input, "Synergy%2i%2i", &major, &minor);
|
||||
|
||||
// check versions
|
||||
log((CLOG_DEBUG1 "got hello version %d.%d", major, minor));
|
||||
if (major < kProtocolMajorVersion ||
|
||||
(major == kProtocolMajorVersion && minor < kProtocolMinorVersion)) {
|
||||
throw XIncompatibleClient(major, minor);
|
||||
}
|
||||
|
||||
// say hello back
|
||||
log((CLOG_DEBUG1 "say hello version %d.%d", kProtocolMajorVersion, kProtocolMinorVersion));
|
||||
CProtocolUtil::writef(output, "Synergy%2i%2i%s",
|
||||
kProtocolMajorVersion,
|
||||
kProtocolMinorVersion, &m_name);
|
||||
|
||||
// create server proxy
|
||||
proxy = new CServerProxy(this, input, output);
|
||||
|
||||
// negotiate
|
||||
// FIXME
|
||||
|
||||
return proxy;
|
||||
}
|
||||
catch (XIncompatibleClient& e) {
|
||||
log((CLOG_ERR "server has incompatible version %d.%d", e.getMajor(), e.getMinor()));
|
||||
}
|
||||
catch (XBase& e) {
|
||||
log((CLOG_WARN "error communicating with server: %s", e.what()));
|
||||
}
|
||||
catch (...) {
|
||||
// probably timed out
|
||||
if (proxy != NULL) {
|
||||
delete proxy;
|
||||
}
|
||||
else if (own) {
|
||||
delete input;
|
||||
delete output;
|
||||
}
|
||||
throw;
|
||||
}
|
||||
|
||||
// failed
|
||||
if (proxy != NULL) {
|
||||
delete proxy;
|
||||
}
|
||||
else if (own) {
|
||||
delete input;
|
||||
delete output;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
128
lib/client/CClient.h
Normal file
128
lib/client/CClient.h
Normal file
@@ -0,0 +1,128 @@
|
||||
#ifndef CCLIENT_H
|
||||
#define CCLIENT_H
|
||||
|
||||
#include "IScreenReceiver.h"
|
||||
#include "IClient.h"
|
||||
#include "IClipboard.h"
|
||||
#include "CNetworkAddress.h"
|
||||
#include "CMutex.h"
|
||||
|
||||
class CSecondaryScreen;
|
||||
class CServerProxy;
|
||||
class CThread;
|
||||
class IDataSocket;
|
||||
class IScreenReceiver;
|
||||
|
||||
//! Synergy client
|
||||
/*!
|
||||
This class implements the top-level client algorithms for synergy.
|
||||
*/
|
||||
class CClient : public IScreenReceiver, public IClient {
|
||||
public:
|
||||
/*!
|
||||
This client will attempt to connect the server using \c clientName
|
||||
as its name.
|
||||
*/
|
||||
CClient(const CString& clientName);
|
||||
~CClient();
|
||||
|
||||
//! @name manipulators
|
||||
//@{
|
||||
|
||||
//! Set camping state
|
||||
/*!
|
||||
Turns camping on or off. When camping the client will keep
|
||||
trying to connect to the server until it succeeds. This
|
||||
is useful if the client may start before the server. Do
|
||||
not call this while in mainLoop().
|
||||
*/
|
||||
void camp(bool on);
|
||||
|
||||
//! Set server address
|
||||
/*!
|
||||
Sets the server's address that the client should connect to.
|
||||
*/
|
||||
void setAddress(const CNetworkAddress& serverAddress);
|
||||
|
||||
//! Exit event loop
|
||||
/*!
|
||||
Force mainLoop() to return. This call can return before
|
||||
mainLoop() does (i.e. asynchronously). This may only be
|
||||
called between a successful open() and close().
|
||||
*/
|
||||
void exitMainLoop();
|
||||
|
||||
//@}
|
||||
//! @name accessors
|
||||
//@{
|
||||
|
||||
//!
|
||||
/*!
|
||||
Returns true if the server rejected our connection.
|
||||
*/
|
||||
bool wasRejected() const;
|
||||
|
||||
//@}
|
||||
|
||||
// IScreenReceiver overrides
|
||||
virtual void onError();
|
||||
virtual void onInfoChanged(const CClientInfo&);
|
||||
virtual bool onGrabClipboard(ClipboardID);
|
||||
virtual void onClipboardChanged(ClipboardID, const CString&);
|
||||
|
||||
// IClient overrides
|
||||
virtual bool open();
|
||||
virtual void mainLoop();
|
||||
virtual void close();
|
||||
virtual void enter(SInt32 xAbs, SInt32 yAbs,
|
||||
UInt32 seqNum, KeyModifierMask mask,
|
||||
bool forScreensaver);
|
||||
virtual bool leave();
|
||||
virtual void setClipboard(ClipboardID, const CString&);
|
||||
virtual void grabClipboard(ClipboardID);
|
||||
virtual void setClipboardDirty(ClipboardID, bool dirty);
|
||||
virtual void keyDown(KeyID, KeyModifierMask);
|
||||
virtual void keyRepeat(KeyID, KeyModifierMask, SInt32 count);
|
||||
virtual void keyUp(KeyID, KeyModifierMask);
|
||||
virtual void mouseDown(ButtonID);
|
||||
virtual void mouseUp(ButtonID);
|
||||
virtual void mouseMove(SInt32 xAbs, SInt32 yAbs);
|
||||
virtual void mouseWheel(SInt32 delta);
|
||||
virtual void screensaver(bool activate);
|
||||
virtual CString getName() const;
|
||||
virtual SInt32 getJumpZoneSize() const;
|
||||
virtual void getShape(SInt32& x, SInt32& y,
|
||||
SInt32& width, SInt32& height) const;
|
||||
virtual void getCursorPos(SInt32& x, SInt32& y) const;
|
||||
virtual void getCursorCenter(SInt32& x, SInt32& y) const;
|
||||
|
||||
private:
|
||||
// open/close the secondary screen
|
||||
void openSecondaryScreen();
|
||||
void closeSecondaryScreen();
|
||||
|
||||
// send the clipboard to the server
|
||||
void sendClipboard(ClipboardID);
|
||||
|
||||
// handle server messaging
|
||||
void runSession(void*);
|
||||
void deleteSession(double timeout = -1.0);
|
||||
void runServer();
|
||||
CServerProxy* handshakeServer(IDataSocket*);
|
||||
|
||||
private:
|
||||
CMutex m_mutex;
|
||||
CString m_name;
|
||||
CSecondaryScreen* m_screen;
|
||||
IScreenReceiver* m_server;
|
||||
CNetworkAddress m_serverAddress;
|
||||
bool m_camp;
|
||||
CThread* m_session;
|
||||
bool m_active;
|
||||
bool m_rejected;
|
||||
bool m_ownClipboard[kClipboardEnd];
|
||||
IClipboard::Time m_timeClipboard[kClipboardEnd];
|
||||
CString m_dataClipboard[kClipboardEnd];
|
||||
};
|
||||
|
||||
#endif
|
||||
1069
lib/client/CMSWindowsSecondaryScreen.cpp
Normal file
1069
lib/client/CMSWindowsSecondaryScreen.cpp
Normal file
File diff suppressed because it is too large
Load Diff
107
lib/client/CMSWindowsSecondaryScreen.h
Normal file
107
lib/client/CMSWindowsSecondaryScreen.h
Normal file
@@ -0,0 +1,107 @@
|
||||
#ifndef CMSWINDOWSSECONDARYSCREEN_H
|
||||
#define CMSWINDOWSSECONDARYSCREEN_H
|
||||
|
||||
// ensure that we get SendInput()
|
||||
#if _WIN32_WINNT <= 0x400
|
||||
#undef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x401
|
||||
#endif
|
||||
|
||||
#include "CSecondaryScreen.h"
|
||||
#include "IMSWindowsScreenEventHandler.h"
|
||||
#include "CMutex.h"
|
||||
#include "CString.h"
|
||||
#include "stdvector.h"
|
||||
|
||||
class CMSWindowsScreen;
|
||||
class IScreenReceiver;
|
||||
|
||||
//! Microsoft windows secondary screen implementation
|
||||
class CMSWindowsSecondaryScreen :
|
||||
public CSecondaryScreen, public IMSWindowsScreenEventHandler {
|
||||
public:
|
||||
CMSWindowsSecondaryScreen(IScreenReceiver*);
|
||||
virtual ~CMSWindowsSecondaryScreen();
|
||||
|
||||
// CSecondaryScreen overrides
|
||||
virtual void keyDown(KeyID, KeyModifierMask);
|
||||
virtual void keyRepeat(KeyID, KeyModifierMask, SInt32 count);
|
||||
virtual void keyUp(KeyID, KeyModifierMask);
|
||||
virtual void mouseDown(ButtonID);
|
||||
virtual void mouseUp(ButtonID);
|
||||
virtual void mouseMove(SInt32 xAbsolute, SInt32 yAbsolute);
|
||||
virtual void mouseWheel(SInt32 delta);
|
||||
virtual IScreen* getScreen() const;
|
||||
|
||||
// IMSWindowsScreenEventHandler overrides
|
||||
virtual void onScreensaver(bool activated);
|
||||
virtual bool onPreDispatch(const CEvent* event);
|
||||
virtual bool onEvent(CEvent* event);
|
||||
virtual SInt32 getJumpZoneSize() const;
|
||||
virtual void postCreateWindow(HWND);
|
||||
virtual void preDestroyWindow(HWND);
|
||||
|
||||
protected:
|
||||
// CSecondaryScreen overrides
|
||||
virtual void onPreMainLoop();
|
||||
virtual void onPreOpen();
|
||||
virtual void onPreEnter();
|
||||
virtual void onPreLeave();
|
||||
virtual void createWindow();
|
||||
virtual void destroyWindow();
|
||||
virtual void showWindow();
|
||||
virtual void hideWindow();
|
||||
virtual void warpCursor(SInt32 x, SInt32 y);
|
||||
virtual void updateKeys();
|
||||
virtual void setToggleState(KeyModifierMask);
|
||||
|
||||
private:
|
||||
enum EKeyAction { kPress, kRelease, kRepeat };
|
||||
class Keystroke {
|
||||
public:
|
||||
UINT m_virtualKey;
|
||||
bool m_press;
|
||||
bool m_repeat;
|
||||
};
|
||||
typedef std::vector<Keystroke> Keystrokes;
|
||||
|
||||
// open/close desktop (for windows 95/98/me)
|
||||
bool openDesktop();
|
||||
void closeDesktop();
|
||||
|
||||
// make desk the thread desktop (for windows NT/2000/XP)
|
||||
bool switchDesktop(HDESK desk);
|
||||
|
||||
// returns true iff there appear to be multiple monitors
|
||||
bool isMultimon() const;
|
||||
|
||||
// key and button queries and operations
|
||||
DWORD mapButton(ButtonID button, bool press) const;
|
||||
KeyModifierMask mapKey(Keystrokes&, UINT& virtualKey, KeyID,
|
||||
KeyModifierMask, EKeyAction) const;
|
||||
void doKeystrokes(const Keystrokes&, SInt32 count);
|
||||
|
||||
void releaseKeys();
|
||||
void toggleKey(UINT virtualKey, KeyModifierMask mask);
|
||||
UINT virtualKeyToScanCode(UINT& virtualKey);
|
||||
bool isExtendedKey(UINT virtualKey);
|
||||
void sendKeyEvent(UINT virtualKey, bool press);
|
||||
|
||||
private:
|
||||
CMutex m_mutex;
|
||||
CMSWindowsScreen* m_screen;
|
||||
|
||||
// true if windows 95/98/me
|
||||
bool m_is95Family;
|
||||
|
||||
// our window
|
||||
HWND m_window;
|
||||
|
||||
// virtual key states
|
||||
BYTE m_keys[256];
|
||||
|
||||
// current active modifiers
|
||||
KeyModifierMask m_mask;
|
||||
};
|
||||
|
||||
#endif
|
||||
260
lib/client/CSecondaryScreen.cpp
Normal file
260
lib/client/CSecondaryScreen.cpp
Normal file
@@ -0,0 +1,260 @@
|
||||
#include "CSecondaryScreen.h"
|
||||
#include "IScreen.h"
|
||||
#include "CLock.h"
|
||||
#include "CThread.h"
|
||||
#include "CLog.h"
|
||||
|
||||
//
|
||||
// CSecondaryScreen
|
||||
//
|
||||
|
||||
CSecondaryScreen::CSecondaryScreen()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
CSecondaryScreen::~CSecondaryScreen()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void
|
||||
CSecondaryScreen::mainLoop()
|
||||
{
|
||||
// change our priority
|
||||
CThread::getCurrentThread().setPriority(-7);
|
||||
|
||||
// run event loop
|
||||
try {
|
||||
log((CLOG_DEBUG "entering event loop"));
|
||||
onPreMainLoop();
|
||||
getScreen()->mainLoop();
|
||||
onPostMainLoop();
|
||||
log((CLOG_DEBUG "exiting event loop"));
|
||||
}
|
||||
catch (...) {
|
||||
onPostMainLoop();
|
||||
log((CLOG_DEBUG "exiting event loop"));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CSecondaryScreen::exitMainLoop()
|
||||
{
|
||||
getScreen()->exitMainLoop();
|
||||
}
|
||||
|
||||
void
|
||||
CSecondaryScreen::open()
|
||||
{
|
||||
try {
|
||||
// subclass hook
|
||||
onPreOpen();
|
||||
|
||||
// open the screen
|
||||
getScreen()->open();
|
||||
|
||||
// create and prepare our window
|
||||
createWindow();
|
||||
|
||||
// assume primary has all clipboards
|
||||
for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
|
||||
grabClipboard(id);
|
||||
}
|
||||
|
||||
// update keyboard state
|
||||
updateKeys();
|
||||
|
||||
// disable the screen saver
|
||||
getScreen()->openScreensaver(false);
|
||||
|
||||
// subclass hook
|
||||
onPostOpen();
|
||||
}
|
||||
catch (...) {
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
|
||||
// hide the cursor
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
m_active = true;
|
||||
}
|
||||
leave();
|
||||
}
|
||||
|
||||
void
|
||||
CSecondaryScreen::close()
|
||||
{
|
||||
onPreClose();
|
||||
getScreen()->closeScreensaver();
|
||||
destroyWindow();
|
||||
getScreen()->close();
|
||||
onPostClose();
|
||||
}
|
||||
|
||||
void
|
||||
CSecondaryScreen::enter(SInt32 x, SInt32 y, KeyModifierMask mask)
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
assert(m_active == false);
|
||||
|
||||
log((CLOG_INFO "entering screen at %d,%d mask=%04x", x, y, mask));
|
||||
|
||||
getScreen()->syncDesktop();
|
||||
|
||||
// now active
|
||||
m_active = true;
|
||||
|
||||
// subclass hook
|
||||
onPreEnter();
|
||||
|
||||
// update our keyboard state to reflect the local state
|
||||
updateKeys();
|
||||
|
||||
// toggle modifiers that don't match the desired state
|
||||
setToggleState(mask);
|
||||
|
||||
// warp to requested location
|
||||
warpCursor(x, y);
|
||||
|
||||
// show mouse
|
||||
hideWindow();
|
||||
|
||||
// subclass hook
|
||||
onPostEnter();
|
||||
}
|
||||
|
||||
void
|
||||
CSecondaryScreen::leave()
|
||||
{
|
||||
log((CLOG_INFO "leaving screen"));
|
||||
CLock lock(&m_mutex);
|
||||
assert(m_active == true);
|
||||
|
||||
getScreen()->syncDesktop();
|
||||
|
||||
// subclass hook
|
||||
onPreLeave();
|
||||
|
||||
// hide mouse
|
||||
showWindow();
|
||||
|
||||
// subclass hook
|
||||
onPostLeave();
|
||||
|
||||
// not active anymore
|
||||
m_active = false;
|
||||
|
||||
// make sure our idea of clipboard ownership is correct
|
||||
getScreen()->checkClipboards();
|
||||
}
|
||||
|
||||
void
|
||||
CSecondaryScreen::setClipboard(ClipboardID id,
|
||||
const IClipboard* clipboard)
|
||||
{
|
||||
getScreen()->setClipboard(id, clipboard);
|
||||
}
|
||||
|
||||
void
|
||||
CSecondaryScreen::grabClipboard(ClipboardID id)
|
||||
{
|
||||
getScreen()->setClipboard(id, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
CSecondaryScreen::screensaver(bool activate)
|
||||
{
|
||||
getScreen()->screensaver(activate);
|
||||
}
|
||||
|
||||
bool
|
||||
CSecondaryScreen::isActive() const
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
return m_active;
|
||||
}
|
||||
|
||||
void
|
||||
CSecondaryScreen::getClipboard(ClipboardID id,
|
||||
IClipboard* clipboard) const
|
||||
{
|
||||
getScreen()->getClipboard(id, clipboard);
|
||||
}
|
||||
|
||||
void
|
||||
CSecondaryScreen::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const
|
||||
{
|
||||
getScreen()->syncDesktop();
|
||||
getScreen()->getShape(x, y, w, h);
|
||||
}
|
||||
|
||||
void
|
||||
CSecondaryScreen::getCursorPos(SInt32& x, SInt32& y) const
|
||||
{
|
||||
getScreen()->syncDesktop();
|
||||
getScreen()->getCursorPos(x, y);
|
||||
}
|
||||
|
||||
void
|
||||
CSecondaryScreen::onPreMainLoop()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void
|
||||
CSecondaryScreen::onPostMainLoop()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void
|
||||
CSecondaryScreen::onPreOpen()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void
|
||||
CSecondaryScreen::onPostOpen()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void
|
||||
CSecondaryScreen::onPreClose()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void
|
||||
CSecondaryScreen::onPostClose()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void
|
||||
CSecondaryScreen::onPreEnter()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void
|
||||
CSecondaryScreen::onPostEnter()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void
|
||||
CSecondaryScreen::onPreLeave()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void
|
||||
CSecondaryScreen::onPostLeave()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
320
lib/client/CSecondaryScreen.h
Normal file
320
lib/client/CSecondaryScreen.h
Normal file
@@ -0,0 +1,320 @@
|
||||
#ifndef CSECONDARYSCREEN_H
|
||||
#define CSECONDARYSCREEN_H
|
||||
|
||||
#include "ClipboardTypes.h"
|
||||
#include "KeyTypes.h"
|
||||
#include "MouseTypes.h"
|
||||
#include "CMutex.h"
|
||||
|
||||
class IClipboard;
|
||||
class IScreen;
|
||||
|
||||
//! Generic client-side screen
|
||||
/*!
|
||||
This is a platform independent base class for secondary screen
|
||||
implementations. A secondary screen is a client-side screen.
|
||||
Each platform will derive a class from CSecondaryScreen to handle
|
||||
platform dependent operations.
|
||||
*/
|
||||
class CSecondaryScreen {
|
||||
public:
|
||||
CSecondaryScreen();
|
||||
virtual ~CSecondaryScreen();
|
||||
|
||||
//! @name manipulators
|
||||
//@{
|
||||
|
||||
//! Open screen
|
||||
/*!
|
||||
Opens the screen. This includes initializing the screen,
|
||||
hiding the cursor, and disabling the screen saver. It also causes
|
||||
events to the reported to an IScreenReceiver (which is set through
|
||||
some other interface). Calls close() before returning (rethrowing)
|
||||
if it fails for any reason.
|
||||
*/
|
||||
void open();
|
||||
|
||||
//! Run event loop
|
||||
/*!
|
||||
Run the screen's event loop. This returns when it detects
|
||||
the application should terminate or when exitMainLoop() is called.
|
||||
mainLoop() may only be called between open() and close().
|
||||
*/
|
||||
void mainLoop();
|
||||
|
||||
//! Exit event loop
|
||||
/*!
|
||||
Force mainLoop() to return. This call can return before
|
||||
mainLoop() does (i.e. asynchronously).
|
||||
*/
|
||||
void exitMainLoop();
|
||||
|
||||
//! Close screen
|
||||
/*!
|
||||
Closes the screen. This restores the screen saver, shows the cursor
|
||||
and closes the screen. It also synthesizes key up events for any
|
||||
keys that are logically down; without this the client will leave
|
||||
its keyboard in the wrong logical state.
|
||||
*/
|
||||
void close();
|
||||
|
||||
//! Enter screen
|
||||
/*!
|
||||
Called when the user navigates to this secondary screen. Warps
|
||||
the cursor to the absolute coordinates \c x,y and unhides
|
||||
it. Also prepares to synthesize input events.
|
||||
*/
|
||||
void enter(SInt32 x, SInt32 y, KeyModifierMask mask);
|
||||
|
||||
//! Leave screen
|
||||
/*!
|
||||
Called when the user navigates off the secondary screen. Cleans
|
||||
up input event synthesis and hides the cursor.
|
||||
*/
|
||||
void leave();
|
||||
|
||||
//! Set clipboard
|
||||
/*!
|
||||
Sets the system's clipboard contents. This is usually called
|
||||
soon after an enter().
|
||||
*/
|
||||
void setClipboard(ClipboardID, const IClipboard*);
|
||||
|
||||
//! Grab clipboard
|
||||
/*!
|
||||
Grabs (i.e. take ownership of) the system clipboard.
|
||||
*/
|
||||
void grabClipboard(ClipboardID);
|
||||
|
||||
//! Activate/deactivate screen saver
|
||||
/*!
|
||||
Forcibly activates the screen saver if \c activate is true otherwise
|
||||
forcibly deactivates it.
|
||||
*/
|
||||
void screensaver(bool activate);
|
||||
|
||||
//! Notify of key press
|
||||
/*!
|
||||
Synthesize key events to generate a press of key \c id. If possible
|
||||
match the given modifier mask.
|
||||
*/
|
||||
virtual void keyDown(KeyID id, KeyModifierMask) = 0;
|
||||
|
||||
//! Notify of key repeat
|
||||
/*!
|
||||
Synthesize key events to generate a press and release of key \c id
|
||||
\c count times. If possible match the given modifier mask.
|
||||
*/
|
||||
virtual void keyRepeat(KeyID id, KeyModifierMask, SInt32 count) = 0;
|
||||
|
||||
//! Notify of key release
|
||||
/*!
|
||||
Synthesize key events to generate a release of key \c id. If possible
|
||||
match the given modifier mask.
|
||||
*/
|
||||
virtual void keyUp(KeyID id, KeyModifierMask) = 0;
|
||||
|
||||
//! Notify of mouse press
|
||||
/*!
|
||||
Synthesize mouse events to generate a press of mouse button \c id.
|
||||
*/
|
||||
virtual void mouseDown(ButtonID id) = 0;
|
||||
|
||||
//! Notify of mouse release
|
||||
/*!
|
||||
Synthesize mouse events to generate a release of mouse button \c id.
|
||||
*/
|
||||
virtual void mouseUp(ButtonID id) = 0;
|
||||
|
||||
//! Notify of mouse motion
|
||||
/*!
|
||||
Synthesize mouse events to generate mouse motion to the absolute
|
||||
screen position \c xAbs,yAbs.
|
||||
*/
|
||||
virtual void mouseMove(SInt32 xAbs, SInt32 yAbs) = 0;
|
||||
|
||||
//! Notify of mouse wheel motion
|
||||
/*!
|
||||
Synthesize mouse events to generate mouse wheel motion of \c delta.
|
||||
\c delta is positive for motion away from the user and negative for
|
||||
motion towards the user. Each wheel click should generate a delta
|
||||
of +/-120.
|
||||
*/
|
||||
virtual void mouseWheel(SInt32 delta) = 0;
|
||||
|
||||
//@}
|
||||
//! @name accessors
|
||||
//@{
|
||||
|
||||
//! Test if active
|
||||
/*!
|
||||
Returns true iff the screen is active (i.e. the user has entered
|
||||
the screen). Note this is the reverse of a primary screen.
|
||||
*/
|
||||
bool isActive() const;
|
||||
|
||||
//! Get clipboard
|
||||
/*!
|
||||
Saves the contents of the system clipboard indicated by \c id.
|
||||
*/
|
||||
void getClipboard(ClipboardID id, IClipboard*) const;
|
||||
|
||||
//! 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.
|
||||
*/
|
||||
virtual SInt32 getJumpZoneSize() const = 0;
|
||||
|
||||
//! Get screen shape
|
||||
/*!
|
||||
Return the position of the upper-left corner of the screen in \c x and
|
||||
\c y and the size of the screen in \c width and \c height.
|
||||
*/
|
||||
virtual void getShape(SInt32& x, SInt32& y,
|
||||
SInt32& width, SInt32& height) const;
|
||||
|
||||
//! Get cursor position
|
||||
/*!
|
||||
Return the current position of the cursor in \c x,y.
|
||||
*/
|
||||
virtual void getCursorPos(SInt32& x, SInt32& y) const;
|
||||
|
||||
//! Get screen
|
||||
/*!
|
||||
Return the platform dependent screen.
|
||||
*/
|
||||
virtual IScreen* getScreen() const = 0;
|
||||
|
||||
//@}
|
||||
|
||||
protected:
|
||||
//! Pre-mainLoop() hook
|
||||
/*!
|
||||
Called on entry to mainLoop(). Override to perform platform specific
|
||||
operations. Default does nothing. May throw.
|
||||
*/
|
||||
virtual void onPreMainLoop();
|
||||
|
||||
//! Post-mainLoop() hook
|
||||
/*!
|
||||
Called on exit from mainLoop(). Override to perform platform specific
|
||||
operations. Default does nothing. May \b not throw.
|
||||
*/
|
||||
virtual void onPostMainLoop();
|
||||
|
||||
//! Pre-open() hook
|
||||
/*!
|
||||
Called on entry to open(). Override to perform platform specific
|
||||
operations. Default does nothing. May throw.
|
||||
*/
|
||||
virtual void onPreOpen();
|
||||
|
||||
//! Post-open() hook
|
||||
/*!
|
||||
Called on exit from open() iff the open was successful. Default
|
||||
does nothing. May throw.
|
||||
*/
|
||||
virtual void onPostOpen();
|
||||
|
||||
//! Pre-close() hook
|
||||
/*!
|
||||
Called on entry to close(). Override to perform platform specific
|
||||
operations. Default does nothing. May \b not throw.
|
||||
*/
|
||||
virtual void onPreClose();
|
||||
|
||||
//! Post-close() hook
|
||||
/*!
|
||||
Called on exit from close(). Override to perform platform specific
|
||||
operations. Default does nothing. May \b not throw.
|
||||
*/
|
||||
virtual void onPostClose();
|
||||
|
||||
//! Pre-enter() hook
|
||||
/*!
|
||||
Called on entry to enter() after desktop synchronization. Override
|
||||
to perform platform specific operations. Default does nothing. May
|
||||
\b not throw.
|
||||
*/
|
||||
virtual void onPreEnter();
|
||||
|
||||
//! Post-enter() hook
|
||||
/*!
|
||||
Called on exit from enter(). Override to perform platform specific
|
||||
operations. Default does nothing. May \b not throw.
|
||||
*/
|
||||
virtual void onPostEnter();
|
||||
|
||||
//! Pre-leave() hook
|
||||
/*!
|
||||
Called on entry to leave() after desktop synchronization. Override
|
||||
to perform platform specific operations. Default does nothing. May
|
||||
\b not throw.
|
||||
*/
|
||||
virtual void onPreLeave();
|
||||
|
||||
//! Post-leave() hook
|
||||
/*!
|
||||
Called on exit from leave(). Override to perform platform specific
|
||||
operations. Default does nothing. May \b not throw.
|
||||
*/
|
||||
virtual void onPostLeave();
|
||||
|
||||
//! Create window
|
||||
/*!
|
||||
Called to create the window. This window is generally used to
|
||||
receive events and hide the cursor.
|
||||
*/
|
||||
virtual void createWindow() = 0;
|
||||
|
||||
//! Destroy window
|
||||
/*!
|
||||
Called to destroy the window created by createWindow().
|
||||
*/
|
||||
virtual void destroyWindow() = 0;
|
||||
|
||||
//! Show window
|
||||
/*!
|
||||
Called when the user navigates off this secondary screen. It needn't
|
||||
actually show the window created by createWindow() but it must hide
|
||||
the cursor and clean up event synthesis.
|
||||
*/
|
||||
virtual void showWindow() = 0;
|
||||
|
||||
//! Hide window
|
||||
/*!
|
||||
Called when the user navigates to this secondary screen. It should
|
||||
hide the window (if shown), show the cursor, and prepare to synthesize
|
||||
input events.
|
||||
*/
|
||||
virtual void hideWindow() = 0;
|
||||
|
||||
//! Warp cursor
|
||||
/*!
|
||||
Warp the cursor to the absolute coordinates \c x,y.
|
||||
*/
|
||||
virtual void warpCursor(SInt32 x, SInt32 y) = 0;
|
||||
|
||||
//! Synchronize key state
|
||||
/*!
|
||||
Check the current keyboard state. Normally a screen will save
|
||||
the keyboard state in this method and use this shadow state
|
||||
when synthesizing events.
|
||||
*/
|
||||
virtual void updateKeys() = 0;
|
||||
|
||||
//! Synchronize toggle key state
|
||||
/*!
|
||||
Toggle modifiers that don't match the given state so that they do.
|
||||
*/
|
||||
virtual void setToggleState(KeyModifierMask) = 0;
|
||||
|
||||
private:
|
||||
CMutex m_mutex;
|
||||
|
||||
// m_active is true if this screen has been entered
|
||||
bool m_active;
|
||||
};
|
||||
|
||||
#endif
|
||||
527
lib/client/CServerProxy.cpp
Normal file
527
lib/client/CServerProxy.cpp
Normal file
@@ -0,0 +1,527 @@
|
||||
#include "CServerProxy.h"
|
||||
#include "CProtocolUtil.h"
|
||||
#include "IClient.h"
|
||||
#include "ProtocolTypes.h"
|
||||
#include "IInputStream.h"
|
||||
#include "IOutputStream.h"
|
||||
#include "CLock.h"
|
||||
#include "CLog.h"
|
||||
#include "CStopwatch.h"
|
||||
#include "XBase.h"
|
||||
#include <memory>
|
||||
|
||||
//
|
||||
// CServerProxy
|
||||
//
|
||||
|
||||
CServerProxy::CServerProxy(IClient* client,
|
||||
IInputStream* adoptedInput, IOutputStream* adoptedOutput) :
|
||||
m_client(client),
|
||||
m_input(adoptedInput),
|
||||
m_output(adoptedOutput),
|
||||
m_seqNum(0)
|
||||
{
|
||||
assert(m_client != NULL);
|
||||
assert(m_input != NULL);
|
||||
assert(m_output != NULL);
|
||||
}
|
||||
|
||||
CServerProxy::~CServerProxy()
|
||||
{
|
||||
delete m_input;
|
||||
delete m_output;
|
||||
}
|
||||
|
||||
bool
|
||||
CServerProxy::mainLoop()
|
||||
{
|
||||
bool failedToConnect = false;
|
||||
try {
|
||||
// no compressed mouse motion yet
|
||||
m_compressMouse = false;
|
||||
|
||||
// not ignoring mouse motions
|
||||
m_ignoreMouse = false;
|
||||
|
||||
// reset sequence number
|
||||
m_seqNum = 0;
|
||||
|
||||
// handle messages from server
|
||||
CStopwatch heartbeat;
|
||||
for (;;) {
|
||||
// if no input is pending then flush compressed mouse motion
|
||||
if (getInputStream()->getSize() == 0) {
|
||||
flushCompressedMouse();
|
||||
}
|
||||
|
||||
// wait for a message
|
||||
log((CLOG_DEBUG2 "waiting for message"));
|
||||
UInt8 code[4];
|
||||
UInt32 n = getInputStream()->read(code, 4, kHeartRate);
|
||||
|
||||
// check if server hungup
|
||||
if (n == 0) {
|
||||
log((CLOG_NOTE "server disconnected"));
|
||||
break;
|
||||
}
|
||||
|
||||
// check for time out
|
||||
if (n == (UInt32)-1 || heartbeat.getTime() > kHeartRate) {
|
||||
// send heartbeat
|
||||
CLock lock(&m_mutex);
|
||||
CProtocolUtil::writef(getOutputStream(), kMsgCNoop);
|
||||
heartbeat.reset();
|
||||
if (n == (UInt32)-1) {
|
||||
// no message to process
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// verify we got an entire code
|
||||
if (n != 4) {
|
||||
// client sent an incomplete message
|
||||
log((CLOG_ERR "incomplete message from server"));
|
||||
break;
|
||||
}
|
||||
|
||||
// parse message
|
||||
log((CLOG_DEBUG2 "msg from server: %c%c%c%c", code[0], code[1], code[2], code[3]));
|
||||
if (memcmp(code, kMsgDMouseMove, 4) == 0) {
|
||||
mouseMove();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgDMouseWheel, 4) == 0) {
|
||||
mouseWheel();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgDKeyDown, 4) == 0) {
|
||||
keyDown();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgDKeyUp, 4) == 0) {
|
||||
keyUp();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgDMouseDown, 4) == 0) {
|
||||
mouseDown();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgDMouseUp, 4) == 0) {
|
||||
mouseUp();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgDKeyRepeat, 4) == 0) {
|
||||
keyRepeat();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgCNoop, 4) == 0) {
|
||||
// accept and discard no-op
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgCEnter, 4) == 0) {
|
||||
enter();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgCLeave, 4) == 0) {
|
||||
leave();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgCClipboard, 4) == 0) {
|
||||
grabClipboard();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgCScreenSaver, 4) == 0) {
|
||||
screensaver();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgQInfo, 4) == 0) {
|
||||
queryInfo();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgCInfoAck, 4) == 0) {
|
||||
infoAcknowledgment();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgDClipboard, 4) == 0) {
|
||||
setClipboard();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgCClose, 4) == 0) {
|
||||
// server wants us to hangup
|
||||
log((CLOG_DEBUG1 "recv close"));
|
||||
break;
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgEIncompatible, 4) == 0) {
|
||||
SInt32 major, minor;
|
||||
CProtocolUtil::readf(getInputStream(),
|
||||
kMsgEIncompatible + 4, &major, &minor);
|
||||
log((CLOG_ERR "server has incompatible version %d.%d", major, minor));
|
||||
failedToConnect = true;
|
||||
break;
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgEBusy, 4) == 0) {
|
||||
log((CLOG_ERR "server already has a connected client with name \"%s\"", getName().c_str()));
|
||||
failedToConnect = true;
|
||||
break;
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgEUnknown, 4) == 0) {
|
||||
log((CLOG_ERR "server refused client with name \"%s\"", getName().c_str()));
|
||||
failedToConnect = true;
|
||||
break;
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgEBad, 4) == 0) {
|
||||
log((CLOG_ERR "server disconnected due to a protocol error"));
|
||||
failedToConnect = true;
|
||||
break;
|
||||
}
|
||||
|
||||
else {
|
||||
// unknown message
|
||||
log((CLOG_ERR "unknown message from server"));
|
||||
failedToConnect = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (XBase& e) {
|
||||
log((CLOG_ERR "error: %s", e.what()));
|
||||
}
|
||||
catch (...) {
|
||||
throw;
|
||||
}
|
||||
|
||||
return !failedToConnect;
|
||||
}
|
||||
|
||||
IClient*
|
||||
CServerProxy::getClient() const
|
||||
{
|
||||
return m_client;
|
||||
}
|
||||
|
||||
CString
|
||||
CServerProxy::getName() const
|
||||
{
|
||||
return m_client->getName();
|
||||
}
|
||||
|
||||
IInputStream*
|
||||
CServerProxy::getInputStream() const
|
||||
{
|
||||
return m_input;
|
||||
}
|
||||
|
||||
IOutputStream*
|
||||
CServerProxy::getOutputStream() const
|
||||
{
|
||||
return m_output;
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::onError()
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::onInfoChanged(const CClientInfo& info)
|
||||
{
|
||||
// ignore mouse motion until we receive acknowledgment of our info
|
||||
// change message.
|
||||
CLock lock(&m_mutex);
|
||||
m_ignoreMouse = true;
|
||||
|
||||
// send info update
|
||||
sendInfo(info);
|
||||
}
|
||||
|
||||
bool
|
||||
CServerProxy::onGrabClipboard(ClipboardID id)
|
||||
{
|
||||
log((CLOG_DEBUG1 "sending clipboard %d changed", id));
|
||||
CLock lock(&m_mutex);
|
||||
CProtocolUtil::writef(getOutputStream(), kMsgCClipboard, id, m_seqNum);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::onClipboardChanged(ClipboardID id, const CString& data)
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
log((CLOG_DEBUG1 "sending clipboard %d seqnum=%d, size=%d", id, m_seqNum, data.size()));
|
||||
CProtocolUtil::writef(getOutputStream(), kMsgDClipboard, id, m_seqNum, &data);
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::flushCompressedMouse()
|
||||
{
|
||||
bool send = false;
|
||||
SInt32 x = 0, y = 0;
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
if (m_compressMouse) {
|
||||
m_compressMouse = false;
|
||||
x = m_xMouse;
|
||||
y = m_yMouse;
|
||||
send = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (send) {
|
||||
getClient()->mouseMove(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::sendInfo(const CClientInfo& info)
|
||||
{
|
||||
// note -- m_mutex should be locked on entry
|
||||
log((CLOG_DEBUG1 "sending info shape=%d,%d %dx%d zone=%d pos=%d,%d", info.m_x, info.m_y, info.m_w, info.m_h, info.m_zoneSize, info.m_mx, info.m_my));
|
||||
CProtocolUtil::writef(getOutputStream(), kMsgDInfo,
|
||||
info.m_x, info.m_y,
|
||||
info.m_w, info.m_h,
|
||||
info.m_zoneSize,
|
||||
info.m_mx, info.m_my);
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::enter()
|
||||
{
|
||||
// parse
|
||||
SInt16 x, y;
|
||||
UInt16 mask;
|
||||
UInt32 seqNum;
|
||||
CProtocolUtil::readf(getInputStream(),
|
||||
kMsgCEnter + 4, &x, &y, &seqNum, &mask);
|
||||
log((CLOG_DEBUG1 "recv enter, %d,%d %d %04x", x, y, seqNum, mask));
|
||||
|
||||
// discard old compressed mouse motion, if any
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
m_compressMouse = false;
|
||||
m_seqNum = seqNum;
|
||||
}
|
||||
|
||||
// forward
|
||||
getClient()->enter(x, y, seqNum, static_cast<KeyModifierMask>(mask), false);
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::leave()
|
||||
{
|
||||
// parse
|
||||
log((CLOG_DEBUG1 "recv leave"));
|
||||
|
||||
// send last mouse motion
|
||||
flushCompressedMouse();
|
||||
|
||||
// forward
|
||||
getClient()->leave();
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::setClipboard()
|
||||
{
|
||||
// parse
|
||||
ClipboardID id;
|
||||
UInt32 seqNum;
|
||||
CString data;
|
||||
CProtocolUtil::readf(getInputStream(),
|
||||
kMsgDClipboard + 4, &id, &seqNum, &data);
|
||||
log((CLOG_DEBUG "recv clipboard %d size=%d", id, data.size()));
|
||||
|
||||
// validate
|
||||
if (id >= kClipboardEnd) {
|
||||
return;
|
||||
}
|
||||
|
||||
// forward
|
||||
getClient()->setClipboard(id, data);
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::grabClipboard()
|
||||
{
|
||||
// parse
|
||||
ClipboardID id;
|
||||
UInt32 seqNum;
|
||||
CProtocolUtil::readf(getInputStream(), kMsgCClipboard + 4, &id, &seqNum);
|
||||
log((CLOG_DEBUG "recv grab clipboard %d", id));
|
||||
|
||||
// validate
|
||||
if (id >= kClipboardEnd) {
|
||||
return;
|
||||
}
|
||||
|
||||
// forward
|
||||
getClient()->grabClipboard(id);
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::keyDown()
|
||||
{
|
||||
// get mouse up to date
|
||||
flushCompressedMouse();
|
||||
|
||||
// parse
|
||||
UInt16 id, mask;
|
||||
CProtocolUtil::readf(getInputStream(), kMsgDKeyDown + 4, &id, &mask);
|
||||
log((CLOG_DEBUG1 "recv key down id=%d, mask=0x%04x", id, mask));
|
||||
|
||||
// forward
|
||||
getClient()->keyDown(static_cast<KeyID>(id),
|
||||
static_cast<KeyModifierMask>(mask));
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::keyRepeat()
|
||||
{
|
||||
// get mouse up to date
|
||||
flushCompressedMouse();
|
||||
|
||||
// parse
|
||||
UInt16 id, mask, count;
|
||||
CProtocolUtil::readf(getInputStream(),
|
||||
kMsgDKeyRepeat + 4, &id, &mask, &count);
|
||||
log((CLOG_DEBUG1 "recv key repeat id=%d, mask=0x%04x, count=%d", id, mask, count));
|
||||
|
||||
// forward
|
||||
getClient()->keyRepeat(static_cast<KeyID>(id),
|
||||
static_cast<KeyModifierMask>(mask),
|
||||
count);
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::keyUp()
|
||||
{
|
||||
// get mouse up to date
|
||||
flushCompressedMouse();
|
||||
|
||||
// parse
|
||||
UInt16 id, mask;
|
||||
CProtocolUtil::readf(getInputStream(), kMsgDKeyUp + 4, &id, &mask);
|
||||
log((CLOG_DEBUG1 "recv key up id=%d, mask=0x%04x", id, mask));
|
||||
|
||||
// forward
|
||||
getClient()->keyUp(static_cast<KeyID>(id),
|
||||
static_cast<KeyModifierMask>(mask));
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::mouseDown()
|
||||
{
|
||||
// get mouse up to date
|
||||
flushCompressedMouse();
|
||||
|
||||
// parse
|
||||
SInt8 id;
|
||||
CProtocolUtil::readf(getInputStream(), kMsgDMouseDown + 4, &id);
|
||||
log((CLOG_DEBUG1 "recv mouse down id=%d", id));
|
||||
|
||||
// forward
|
||||
getClient()->mouseDown(static_cast<ButtonID>(id));
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::mouseUp()
|
||||
{
|
||||
// get mouse up to date
|
||||
flushCompressedMouse();
|
||||
|
||||
// parse
|
||||
SInt8 id;
|
||||
CProtocolUtil::readf(getInputStream(), kMsgDMouseUp + 4, &id);
|
||||
log((CLOG_DEBUG1 "recv mouse up id=%d", id));
|
||||
|
||||
// forward
|
||||
getClient()->mouseUp(static_cast<ButtonID>(id));
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::mouseMove()
|
||||
{
|
||||
// parse
|
||||
bool ignore;
|
||||
SInt16 x, y;
|
||||
CProtocolUtil::readf(getInputStream(), kMsgDMouseMove + 4, &x, &y);
|
||||
|
||||
{
|
||||
// note if we should ignore the move
|
||||
CLock lock(&m_mutex);
|
||||
ignore = m_ignoreMouse;
|
||||
|
||||
// compress mouse motion events if more input follows
|
||||
if (!ignore && !m_compressMouse && getInputStream()->getSize() > 0) {
|
||||
m_compressMouse = true;
|
||||
}
|
||||
|
||||
// if compressing then ignore the motion but record it
|
||||
if (m_compressMouse) {
|
||||
ignore = true;
|
||||
m_xMouse = x;
|
||||
m_yMouse = y;
|
||||
}
|
||||
}
|
||||
log((CLOG_DEBUG2 "recv mouse move %d,%d", x, y));
|
||||
|
||||
// forward
|
||||
if (!ignore) {
|
||||
getClient()->mouseMove(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::mouseWheel()
|
||||
{
|
||||
// get mouse up to date
|
||||
flushCompressedMouse();
|
||||
|
||||
// parse
|
||||
SInt16 delta;
|
||||
CProtocolUtil::readf(getInputStream(), kMsgDMouseWheel + 4, &delta);
|
||||
log((CLOG_DEBUG2 "recv mouse wheel %+d", delta));
|
||||
|
||||
// forward
|
||||
getClient()->mouseWheel(delta);
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::screensaver()
|
||||
{
|
||||
// parse
|
||||
SInt8 on;
|
||||
CProtocolUtil::readf(getInputStream(), kMsgCScreenSaver + 4, &on);
|
||||
log((CLOG_DEBUG1 "recv screen saver on=%d", on));
|
||||
|
||||
// forward
|
||||
getClient()->screensaver(on != 0);
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::queryInfo()
|
||||
{
|
||||
// get current info
|
||||
CClientInfo info;
|
||||
getClient()->getShape(info.m_x, info.m_y, info.m_w, info.m_h);
|
||||
getClient()->getCursorPos(info.m_mx, info.m_my);
|
||||
info.m_zoneSize = getClient()->getJumpZoneSize();
|
||||
|
||||
// send it
|
||||
CLock lock(&m_mutex);
|
||||
sendInfo(info);
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::infoAcknowledgment()
|
||||
{
|
||||
// parse
|
||||
log((CLOG_DEBUG1 "recv info acknowledgment"));
|
||||
|
||||
// now allow mouse motion
|
||||
CLock lock(&m_mutex);
|
||||
m_ignoreMouse = false;
|
||||
}
|
||||
112
lib/client/CServerProxy.h
Normal file
112
lib/client/CServerProxy.h
Normal file
@@ -0,0 +1,112 @@
|
||||
#ifndef CSERVERPROXY_H
|
||||
#define CSERVERPROXY_H
|
||||
|
||||
#include "IScreenReceiver.h"
|
||||
#include "CMutex.h"
|
||||
|
||||
class IClient;
|
||||
class IInputStream;
|
||||
class IOutputStream;
|
||||
|
||||
//! Proxy for server
|
||||
/*!
|
||||
This class acts a proxy for the server, converting calls into messages
|
||||
to the server and messages from the server to calls on the client.
|
||||
*/
|
||||
class CServerProxy : public IScreenReceiver {
|
||||
public:
|
||||
/*! \c adoptedInput is the stream from the server and
|
||||
\c adoptedOutput is the stream to the server. This object
|
||||
takes ownership of both and destroys them in the d'tor.
|
||||
Messages from the server are converted to calls on \c client.
|
||||
*/
|
||||
CServerProxy(IClient* client,
|
||||
IInputStream* adoptedInput,
|
||||
IOutputStream* adoptedOutput);
|
||||
~CServerProxy();
|
||||
|
||||
//! @name manipulators
|
||||
//@{
|
||||
|
||||
//! Run event loop
|
||||
/*!
|
||||
Run the event loop and return when the server disconnects or
|
||||
requests the client to disconnect. Return true iff the server
|
||||
didn't reject our connection.
|
||||
|
||||
(cancellation point)
|
||||
*/
|
||||
bool mainLoop();
|
||||
|
||||
//@}
|
||||
//! @name accessors
|
||||
//@{
|
||||
|
||||
//! Get client
|
||||
/*!
|
||||
Returns the client passed to the c'tor.
|
||||
*/
|
||||
IClient* getClient() const;
|
||||
|
||||
//! Get input stream
|
||||
/*!
|
||||
Return the input stream passed to the c'tor.
|
||||
*/
|
||||
IInputStream* getInputStream() const;
|
||||
|
||||
//! Get output stream
|
||||
/*!
|
||||
Return the output stream passed to the c'tor.
|
||||
*/
|
||||
IOutputStream* getOutputStream() const;
|
||||
|
||||
//@}
|
||||
|
||||
// IScreenReceiver overrides
|
||||
virtual void onError();
|
||||
virtual void onInfoChanged(const CClientInfo&);
|
||||
virtual bool onGrabClipboard(ClipboardID);
|
||||
virtual void onClipboardChanged(ClipboardID, const CString& data);
|
||||
|
||||
private:
|
||||
|
||||
// get the client name (from the client)
|
||||
CString getName() const;
|
||||
|
||||
// if compressing mouse motion then send the last motion now
|
||||
void flushCompressedMouse();
|
||||
|
||||
void sendInfo(const CClientInfo&);
|
||||
|
||||
// message handlers
|
||||
void enter();
|
||||
void leave();
|
||||
void setClipboard();
|
||||
void grabClipboard();
|
||||
void keyDown();
|
||||
void keyRepeat();
|
||||
void keyUp();
|
||||
void mouseDown();
|
||||
void mouseUp();
|
||||
void mouseMove();
|
||||
void mouseWheel();
|
||||
void screensaver();
|
||||
void queryInfo();
|
||||
void infoAcknowledgment();
|
||||
|
||||
private:
|
||||
CMutex m_mutex;
|
||||
|
||||
IClient* m_client;
|
||||
IInputStream* m_input;
|
||||
IOutputStream* m_output;
|
||||
|
||||
UInt32 m_seqNum;
|
||||
|
||||
bool m_compressMouse;
|
||||
SInt32 m_xMouse, m_yMouse;
|
||||
|
||||
bool m_ignoreMouse;
|
||||
};
|
||||
|
||||
#endif
|
||||
1024
lib/client/CXWindowsSecondaryScreen.cpp
Normal file
1024
lib/client/CXWindowsSecondaryScreen.cpp
Normal file
File diff suppressed because it is too large
Load Diff
128
lib/client/CXWindowsSecondaryScreen.h
Normal file
128
lib/client/CXWindowsSecondaryScreen.h
Normal file
@@ -0,0 +1,128 @@
|
||||
#ifndef CXWINDOWSSECONDARYSCREEN_H
|
||||
#define CXWINDOWSSECONDARYSCREEN_H
|
||||
|
||||
#include "CSecondaryScreen.h"
|
||||
#include "IScreenEventHandler.h"
|
||||
#include "stdmap.h"
|
||||
#include "stdvector.h"
|
||||
#if defined(X_DISPLAY_MISSING)
|
||||
# error X11 is required to build synergy
|
||||
#else
|
||||
# include <X11/Xlib.h>
|
||||
#endif
|
||||
|
||||
class CXWindowsScreen;
|
||||
class IScreenReceiver;
|
||||
|
||||
//! X11 secondary screen implementation
|
||||
class CXWindowsSecondaryScreen :
|
||||
public CSecondaryScreen, public IScreenEventHandler {
|
||||
public:
|
||||
CXWindowsSecondaryScreen(IScreenReceiver*);
|
||||
virtual ~CXWindowsSecondaryScreen();
|
||||
|
||||
// CSecondaryScreen overrides
|
||||
virtual void keyDown(KeyID, KeyModifierMask);
|
||||
virtual void keyRepeat(KeyID, KeyModifierMask, SInt32 count);
|
||||
virtual void keyUp(KeyID, KeyModifierMask);
|
||||
virtual void mouseDown(ButtonID);
|
||||
virtual void mouseUp(ButtonID);
|
||||
virtual void mouseMove(SInt32 x, SInt32 y);
|
||||
virtual void mouseWheel(SInt32 delta);
|
||||
virtual IScreen* getScreen() const;
|
||||
|
||||
// IScreenEventHandler overrides
|
||||
virtual void onScreensaver(bool activated);
|
||||
virtual bool onPreDispatch(const CEvent* event);
|
||||
virtual bool onEvent(CEvent* event);
|
||||
virtual SInt32 getJumpZoneSize() const;
|
||||
|
||||
protected:
|
||||
// CSecondaryScreen overrides
|
||||
virtual void onPreMainLoop();
|
||||
virtual void onPreOpen();
|
||||
virtual void onPostOpen();
|
||||
virtual void onPreEnter();
|
||||
virtual void onPreLeave();
|
||||
virtual void createWindow();
|
||||
virtual void destroyWindow();
|
||||
virtual void showWindow();
|
||||
virtual void hideWindow();
|
||||
virtual void warpCursor(SInt32 x, SInt32 y);
|
||||
virtual void updateKeys();
|
||||
virtual void setToggleState(KeyModifierMask);
|
||||
|
||||
private:
|
||||
enum EKeyAction { kPress, kRelease, kRepeat };
|
||||
class KeyCodeMask {
|
||||
public:
|
||||
KeyCode m_keycode;
|
||||
unsigned int m_keyMask;
|
||||
unsigned int m_keyMaskMask;
|
||||
};
|
||||
class Keystroke {
|
||||
public:
|
||||
KeyCode m_keycode;
|
||||
Bool m_press;
|
||||
bool m_repeat;
|
||||
};
|
||||
typedef std::vector<Keystroke> Keystrokes;
|
||||
typedef std::vector<KeyCode> KeyCodes;
|
||||
typedef std::map<KeyID, KeyCodeMask> KeyCodeMap;
|
||||
typedef std::map<KeyCode, unsigned int> ModifierMap;
|
||||
|
||||
unsigned int mapButton(ButtonID button) const;
|
||||
|
||||
unsigned int mapKey(Keystrokes&, KeyCode&, KeyID,
|
||||
KeyModifierMask, EKeyAction) const;
|
||||
bool findKeyCode(KeyCode&, unsigned int&,
|
||||
KeyID id, unsigned int) const;
|
||||
void doKeystrokes(const Keystrokes&, SInt32 count);
|
||||
unsigned int maskToX(KeyModifierMask) const;
|
||||
|
||||
void releaseKeys(Display*);
|
||||
void updateKeycodeMap(Display* display);
|
||||
void updateModifiers(Display* display);
|
||||
void updateModifierMap(Display* display);
|
||||
void toggleKey(Display*, KeySym, unsigned int mask);
|
||||
static bool isToggleKeysym(KeySym);
|
||||
|
||||
private:
|
||||
CXWindowsScreen* m_screen;
|
||||
Window m_window;
|
||||
|
||||
// note toggle keys that toggles on up/down (false) or on
|
||||
// transition (true)
|
||||
bool m_numLockHalfDuplex;
|
||||
bool m_capsLockHalfDuplex;
|
||||
|
||||
// set entries indicate keys that are pressed. indexed by keycode.
|
||||
bool m_keys[256];
|
||||
|
||||
// current active modifiers (X key masks)
|
||||
unsigned int m_mask;
|
||||
|
||||
// maps key IDs to X keycodes and the X modifier key mask needed
|
||||
// to generate the right keysym
|
||||
KeyCodeMap m_keycodeMap;
|
||||
|
||||
// the modifiers that have keys bound to them
|
||||
unsigned int m_modifierMask;
|
||||
|
||||
// set bits indicate modifiers that toggle (e.g. caps-lock)
|
||||
unsigned int m_toggleModifierMask;
|
||||
|
||||
// masks that indicate which modifier bits are for toggle keys
|
||||
unsigned int m_numLockMask;
|
||||
unsigned int m_capsLockMask;
|
||||
unsigned int m_scrollLockMask;
|
||||
|
||||
// map X modifier key indices to the key codes bound to them
|
||||
unsigned int m_keysPerModifier;
|
||||
KeyCodes m_modifierToKeycode;
|
||||
|
||||
// maps keycodes to modifier indices
|
||||
ModifierMap m_keycodeToModifier;
|
||||
};
|
||||
|
||||
#endif
|
||||
23
lib/client/Makefile.am
Normal file
23
lib/client/Makefile.am
Normal file
@@ -0,0 +1,23 @@
|
||||
## Process this file with automake to produce Makefile.in
|
||||
NULL =
|
||||
DEPTH = ../..
|
||||
|
||||
noinst_LIBRARIES = libclient.a
|
||||
libclient_a_SOURCES = \
|
||||
CClient.cpp \
|
||||
CSecondaryScreen.cpp \
|
||||
CServerProxy.cpp \
|
||||
CXWindowsSecondaryScreen.cpp \
|
||||
CClient.h \
|
||||
CSecondaryScreen.h \
|
||||
CServerProxy.h \
|
||||
CXWindowsSecondaryScreen.h \
|
||||
$(NULL)
|
||||
INCLUDES = \
|
||||
-I$(DEPTH)/lib/base \
|
||||
-I$(DEPTH)/lib/mt \
|
||||
-I$(DEPTH)/lib/io \
|
||||
-I$(DEPTH)/lib/net \
|
||||
-I$(DEPTH)/lib/synergy \
|
||||
-I$(DEPTH)/lib/platform \
|
||||
$(NULL)
|
||||
Reference in New Issue
Block a user