2
* synergy -- mouse and keyboard sharing utility
3
* Copyright (C) 2002 Chris Schoeneman
5
* This package is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU General Public License
7
* found in the file COPYING that should have accompanied this file.
9
* This package is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
15
#include "CClientProxy1_0.h"
17
#include "CClipboard.h"
18
#include "CProtocolUtil.h"
20
#include "IInputStream.h"
21
#include "IOutputStream.h"
25
#include "CStopwatch.h"
32
CClientProxy1_0::CClientProxy1_0(IServer* server, const CString& name,
33
IInputStream* input, IOutputStream* output) :
34
CClientProxy(server, name, input, output),
35
m_heartRate(kHeartRate),
36
m_heartDeath(kHeartRate * kHeartBeatsUntilDeath)
38
for (UInt32 i = 0; i < kClipboardEnd; ++i) {
39
m_clipboardDirty[i] = true;
43
CClientProxy1_0::~CClientProxy1_0()
49
CClientProxy1_0::open()
52
LOG((CLOG_DEBUG1 "querying client \"%s\" info", getName().c_str()));
53
CProtocolUtil::writef(getOutputStream(), kMsgQInfo);
54
getOutputStream()->flush();
56
// wait for and verify reply
59
UInt32 n = getInputStream()->read(code, 4, -1.0);
61
if (memcmp(code, kMsgCNoop, 4) == 0) {
65
if (memcmp(code, kMsgDInfo, 4) == 0) {
77
CClientProxy1_0::mainLoop()
79
// handle messages until the client hangs up or stops sending heartbeats
80
CStopwatch heartTimer;
82
CThread::testCancel();
86
UInt32 n = getInputStream()->read(code, 4, m_heartRate);
87
CThread::testCancel();
89
// check if client hungup
91
LOG((CLOG_NOTE "client \"%s\" disconnected", getName().c_str()));
95
// check if client has stopped sending heartbeats
96
if (n == (UInt32)-1) {
97
if (m_heartDeath >= 0.0 && heartTimer.getTime() > m_heartDeath) {
98
LOG((CLOG_NOTE "client \"%s\" is dead", getName().c_str()));
104
// got a message so reset heartbeat monitor
107
// verify we got an entire code
109
LOG((CLOG_ERR "incomplete message from \"%s\": %d bytes", getName().c_str(), n));
111
// client sent an incomplete message
116
LOG((CLOG_DEBUG2 "msg from \"%s\": %c%c%c%c", getName().c_str(), code[0], code[1], code[2], code[3]));
117
if (memcmp(code, kMsgDInfo, 4) == 0) {
120
else if (memcmp(code, kMsgCNoop, 4) == 0) {
122
LOG((CLOG_DEBUG2 "no-op from", getName().c_str()));
125
else if (memcmp(code, kMsgCClipboard, 4) == 0) {
128
else if (memcmp(code, kMsgDClipboard, 4) == 0) {
131
// note -- more message handlers go here
133
LOG((CLOG_ERR "invalid message from client \"%s\"", getName().c_str()));
142
CClientProxy1_0::close()
144
LOG((CLOG_DEBUG1 "send close to \"%s\"", getName().c_str()));
145
CProtocolUtil::writef(getOutputStream(), kMsgCClose);
147
// force the close to be sent before we return
148
getOutputStream()->flush();
152
CClientProxy1_0::enter(SInt32 xAbs, SInt32 yAbs,
153
UInt32 seqNum, KeyModifierMask mask, bool)
155
LOG((CLOG_DEBUG1 "send enter to \"%s\", %d,%d %d %04x", getName().c_str(), xAbs, yAbs, seqNum, mask));
156
CProtocolUtil::writef(getOutputStream(), kMsgCEnter,
157
xAbs, yAbs, seqNum, mask);
161
CClientProxy1_0::leave()
163
LOG((CLOG_DEBUG1 "send leave to \"%s\"", getName().c_str()));
164
CProtocolUtil::writef(getOutputStream(), kMsgCLeave);
166
// we can never prevent the user from leaving
171
CClientProxy1_0::setClipboard(ClipboardID id, const CString& data)
173
// ignore if this clipboard is already clean
174
CLock lock(getMutex());
175
if (m_clipboardDirty[id]) {
176
// this clipboard is now clean
177
m_clipboardDirty[id] = false;
179
LOG((CLOG_DEBUG "send clipboard %d to \"%s\" size=%d", id, getName().c_str(), data.size()));
180
CProtocolUtil::writef(getOutputStream(), kMsgDClipboard, id, 0, &data);
185
CClientProxy1_0::grabClipboard(ClipboardID id)
187
LOG((CLOG_DEBUG "send grab clipboard %d to \"%s\"", id, getName().c_str()));
188
CProtocolUtil::writef(getOutputStream(), kMsgCClipboard, id, 0);
190
// this clipboard is now dirty
191
CLock lock(getMutex());
192
m_clipboardDirty[id] = true;
196
CClientProxy1_0::setClipboardDirty(ClipboardID id, bool dirty)
198
CLock lock(getMutex());
199
m_clipboardDirty[id] = dirty;
203
CClientProxy1_0::keyDown(KeyID key, KeyModifierMask mask, KeyButton)
205
LOG((CLOG_DEBUG1 "send key down to \"%s\" id=%d, mask=0x%04x", getName().c_str(), key, mask));
206
CProtocolUtil::writef(getOutputStream(), kMsgDKeyDown1_0, key, mask);
210
CClientProxy1_0::keyRepeat(KeyID key, KeyModifierMask mask,
211
SInt32 count, KeyButton)
213
LOG((CLOG_DEBUG1 "send key repeat to \"%s\" id=%d, mask=0x%04x, count=%d", getName().c_str(), key, mask, count));
214
CProtocolUtil::writef(getOutputStream(), kMsgDKeyRepeat1_0, key, mask, count);
218
CClientProxy1_0::keyUp(KeyID key, KeyModifierMask mask, KeyButton)
220
LOG((CLOG_DEBUG1 "send key up to \"%s\" id=%d, mask=0x%04x", getName().c_str(), key, mask));
221
CProtocolUtil::writef(getOutputStream(), kMsgDKeyUp1_0, key, mask);
225
CClientProxy1_0::mouseDown(ButtonID button)
227
LOG((CLOG_DEBUG1 "send mouse down to \"%s\" id=%d", getName().c_str(), button));
228
CProtocolUtil::writef(getOutputStream(), kMsgDMouseDown, button);
232
CClientProxy1_0::mouseUp(ButtonID button)
234
LOG((CLOG_DEBUG1 "send mouse up to \"%s\" id=%d", getName().c_str(), button));
235
CProtocolUtil::writef(getOutputStream(), kMsgDMouseUp, button);
239
CClientProxy1_0::mouseMove(SInt32 xAbs, SInt32 yAbs)
241
LOG((CLOG_DEBUG2 "send mouse move to \"%s\" %d,%d", getName().c_str(), xAbs, yAbs));
242
CProtocolUtil::writef(getOutputStream(), kMsgDMouseMove, xAbs, yAbs);
246
CClientProxy1_0::mouseWheel(SInt32 delta)
248
LOG((CLOG_DEBUG2 "send mouse wheel to \"%s\" %+d", getName().c_str(), delta));
249
CProtocolUtil::writef(getOutputStream(), kMsgDMouseWheel, delta);
253
CClientProxy1_0::screensaver(bool on)
255
LOG((CLOG_DEBUG1 "send screen saver to \"%s\" on=%d", getName().c_str(), on ? 1 : 0));
256
CProtocolUtil::writef(getOutputStream(), kMsgCScreenSaver, on ? 1 : 0);
260
CClientProxy1_0::resetOptions()
262
LOG((CLOG_DEBUG1 "send reset options to \"%s\"", getName().c_str()));
263
CProtocolUtil::writef(getOutputStream(), kMsgCResetOptions);
265
// reset heart rate and death
266
CLock lock(getMutex());
267
m_heartRate = kHeartRate;
268
m_heartDeath = kHeartRate * kHeartBeatsUntilDeath;
272
CClientProxy1_0::setOptions(const COptionsList& options)
274
LOG((CLOG_DEBUG1 "send set options to \"%s\" size=%d", getName().c_str(), options.size()));
275
CProtocolUtil::writef(getOutputStream(), kMsgDSetOptions, &options);
278
CLock lock(getMutex());
279
for (UInt32 i = 0, n = options.size(); i < n; i += 2) {
280
if (options[i] == kOptionHeartbeat) {
281
m_heartRate = 1.0e-3 * static_cast<double>(options[i + 1]);
282
if (m_heartRate <= 0.0) {
285
m_heartDeath = m_heartRate * kHeartBeatsUntilDeath;
291
CClientProxy1_0::getJumpZoneSize() const
293
CLock lock(getMutex());
294
return m_info.m_zoneSize;
298
CClientProxy1_0::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const
300
CLock lock(getMutex());
308
CClientProxy1_0::getCursorPos(SInt32&, SInt32&) const
310
assert(0 && "shouldn't be called");
314
CClientProxy1_0::getCursorCenter(SInt32& x, SInt32& y) const
316
CLock lock(getMutex());
322
CClientProxy1_0::recvInfo(bool notify)
325
CLock lock(getMutex());
328
SInt16 x, y, w, h, zoneSize, mx, my;
329
CProtocolUtil::readf(getInputStream(), kMsgDInfo + 4,
330
&x, &y, &w, &h, &zoneSize, &mx, &my);
331
LOG((CLOG_DEBUG "received client \"%s\" info shape=%d,%d %dx%d, zone=%d, pos=%d,%d", getName().c_str(), x, y, w, h, zoneSize, mx, my));
334
if (w <= 0 || h <= 0 || zoneSize < 0) {
337
if (mx < x || my < y || mx >= x + w || my >= y + h) {
346
m_info.m_zoneSize = zoneSize;
351
// tell server of change
353
getServer()->onInfoChanged(getName(), m_info);
356
// acknowledge receipt
357
LOG((CLOG_DEBUG1 "send info ack to \"%s\"", getName().c_str()));
358
CProtocolUtil::writef(getOutputStream(), kMsgCInfoAck);
362
CClientProxy1_0::recvClipboard()
368
CProtocolUtil::readf(getInputStream(), kMsgDClipboard + 4, &id, &seqNum, &data);
369
LOG((CLOG_DEBUG "received client \"%s\" clipboard %d seqnum=%d, size=%d", getName().c_str(), id, seqNum, data.size()));
372
if (id >= kClipboardEnd) {
376
// send update. this calls us back to reset our clipboard dirty flag
377
// so don't hold a lock during the call.
378
getServer()->onClipboardChanged(id, seqNum, data);
382
CClientProxy1_0::recvGrabClipboard()
387
CProtocolUtil::readf(getInputStream(), kMsgCClipboard + 4, &id, &seqNum);
388
LOG((CLOG_DEBUG "received client \"%s\" grabbed clipboard %d seqnum=%d", getName().c_str(), id, seqNum));
391
if (id >= kClipboardEnd) {
395
// send update. this calls us back to reset our clipboard dirty flag
396
// so don't hold a lock during the call.
397
getServer()->onGrabClipboard(getName(), id, seqNum);