1 /* 2 * synergy -- mouse and keyboard sharing utility 3 * Copyright (C) 2012-2016 Symless Ltd. 4 * Copyright (C) 2002 Chris Schoeneman 5 * 6 * This package is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * found in the file LICENSE that should have accompanied this file. 9 * 10 * This package is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 #pragma once 20 21 #include "server/Config.h" 22 #include "synergy/clipboard_types.h" 23 #include "synergy/Clipboard.h" 24 #include "synergy/key_types.h" 25 #include "synergy/mouse_types.h" 26 #include "synergy/INode.h" 27 #include "synergy/DragInformation.h" 28 #include "synergy/ServerArgs.h" 29 #include "base/Event.h" 30 #include "base/Stopwatch.h" 31 #include "base/EventTypes.h" 32 #include "common/stdmap.h" 33 #include "common/stdset.h" 34 #include "common/stdvector.h" 35 36 class BaseClientProxy; 37 class EventQueueTimer; 38 class PrimaryClient; 39 class InputFilter; 40 namespace synergy { class Screen; } 41 class IEventQueue; 42 class Thread; 43 class ClientListener; 44 45 //! Synergy server 46 /*! 47 This class implements the top-level server algorithms for synergy. 48 */ 49 class Server : public INode { 50 public: 51 //! Lock cursor to screen data 52 class LockCursorToScreenInfo { 53 public: 54 enum State { kOff, kOn, kToggle }; 55 56 static LockCursorToScreenInfo* alloc(State state = kToggle); 57 58 public: 59 State m_state; 60 }; 61 62 //! Switch to screen data 63 class SwitchToScreenInfo { 64 public: 65 static SwitchToScreenInfo* alloc(const String& screen); 66 67 public: 68 // this is a C-string; this type is a variable size structure 69 char m_screen[1]; 70 }; 71 72 //! Switch in direction data 73 class SwitchInDirectionInfo { 74 public: 75 static SwitchInDirectionInfo* alloc(EDirection direction); 76 77 public: 78 EDirection m_direction; 79 }; 80 81 //! Screen connected data 82 class ScreenConnectedInfo { 83 public: ScreenConnectedInfo(String screen)84 ScreenConnectedInfo(String screen) : m_screen(screen) { } 85 86 public: 87 String m_screen; // was char[1] 88 }; 89 90 //! Keyboard broadcast data 91 class KeyboardBroadcastInfo { 92 public: 93 enum State { kOff, kOn, kToggle }; 94 95 static KeyboardBroadcastInfo* alloc(State state = kToggle); 96 static KeyboardBroadcastInfo* alloc(State state, 97 const String& screens); 98 99 public: 100 State m_state; 101 char m_screens[1]; 102 }; 103 104 /*! 105 Start the server with the configuration \p config and the primary 106 client (local screen) \p primaryClient. The client retains 107 ownership of \p primaryClient. 108 */ 109 Server(Config& config, PrimaryClient* primaryClient, 110 synergy::Screen* screen, IEventQueue* events, lib::synergy::ServerArgs const& args); 111 Server(Server const &) =delete; 112 Server(Server &&) =delete; 113 ~Server(); 114 115 Server& operator=(Server const &) =delete; 116 Server& operator=(Server &&) =delete; 117 118 #ifdef TEST_ENV Server()119 Server() : m_mock(true), m_config(NULL) { } setActive(BaseClientProxy * active)120 void setActive(BaseClientProxy* active) { m_active = active; } 121 #endif 122 123 //! @name manipulators 124 //@{ 125 126 //! Set configuration 127 /*! 128 Change the server's configuration. Returns true iff the new 129 configuration was accepted (it must include the server's name). 130 This will disconnect any clients no longer in the configuration. 131 */ 132 bool setConfig(const Config&); 133 134 //! Add a client 135 /*! 136 Adds \p client to the server. The client is adopted and will be 137 destroyed when the client disconnects or is disconnected. 138 */ 139 void adoptClient(BaseClientProxy* client); 140 141 //! Disconnect clients 142 /*! 143 Disconnect clients. This tells them to disconnect but does not wait 144 for them to actually do so. The server sends the disconnected event 145 when they're all disconnected (or immediately if none are connected). 146 The caller can also just destroy this object to force the disconnection. 147 */ 148 void disconnect(); 149 150 //! Create a new thread and use it to send file to client 151 void sendFileToClient(const char* filename); 152 153 //! Received dragging information from client 154 void dragInfoReceived(UInt32 fileNum, String content); 155 156 //! Store ClientListener pointer setListener(ClientListener * p)157 void setListener(ClientListener* p) { m_clientListener = p; } 158 159 //@} 160 //! @name accessors 161 //@{ 162 163 //! Get number of connected clients 164 /*! 165 Returns the number of connected clients, including the server itself. 166 */ 167 UInt32 getNumClients() const; 168 169 //! Get the list of connected clients 170 /*! 171 Set the \c list to the names of the currently connected clients. 172 */ 173 void getClients(std::vector<String>& list) const; 174 175 //! Return true if recieved file size is valid 176 bool isReceivedFileSizeValid(); 177 178 //! Return expected file data size getExpectedFileSize()179 size_t& getExpectedFileSize() { return m_expectedFileSize; } 180 181 //! Return received file data getReceivedFileData()182 String& getReceivedFileData() { return m_receivedFileData; } 183 184 //! Return fake drag file list getFakeDragFileList()185 DragFileList getFakeDragFileList() { return m_fakeDragFileList; } 186 187 //@} 188 189 private: 190 // get canonical name of client 191 String getName(const BaseClientProxy*) const; 192 193 // get the sides of the primary screen that have neighbors 194 UInt32 getActivePrimarySides() const; 195 196 // returns true iff mouse should be locked to the current screen 197 // according to this object only, ignoring what the primary client 198 // says. 199 bool isLockedToScreenServer() const; 200 201 // returns true iff mouse should be locked to the current screen 202 // according to this object or the primary client. 203 bool isLockedToScreen() const; 204 205 // returns the jump zone of the client 206 SInt32 getJumpZoneSize(BaseClientProxy*) const; 207 208 // change the active screen 209 void switchScreen(BaseClientProxy*, 210 SInt32 x, SInt32 y, bool forScreenSaver); 211 212 // jump to screen 213 void jumpToScreen(BaseClientProxy*); 214 215 // convert pixel position to fraction, using x or y depending on the 216 // direction. 217 float mapToFraction(BaseClientProxy*, EDirection, 218 SInt32 x, SInt32 y) const; 219 220 // convert fraction to pixel position, writing only x or y depending 221 // on the direction. 222 void mapToPixel(BaseClientProxy*, EDirection, float f, 223 SInt32& x, SInt32& y) const; 224 225 // returns true if the client has a neighbor anywhere along the edge 226 // indicated by the direction. 227 bool hasAnyNeighbor(BaseClientProxy*, EDirection) const; 228 229 // lookup neighboring screen, mapping the coordinate independent of 230 // the direction to the neighbor's coordinate space. 231 BaseClientProxy* getNeighbor(BaseClientProxy*, EDirection, 232 SInt32& x, SInt32& y) const; 233 234 // lookup neighboring screen. given a position relative to the 235 // source screen, find the screen we should move onto and where. 236 // if the position is sufficiently far from the source then we 237 // cross multiple screens. if there is no suitable screen then 238 // return NULL and x,y are not modified. 239 BaseClientProxy* mapToNeighbor(BaseClientProxy*, EDirection, 240 SInt32& x, SInt32& y) const; 241 242 // adjusts x and y or neither to avoid ending up in a jump zone 243 // after entering the client in the given direction. 244 void avoidJumpZone(BaseClientProxy*, EDirection, 245 SInt32& x, SInt32& y) const; 246 247 // test if a switch is permitted. this includes testing user 248 // options like switch delay and tracking any state required to 249 // implement them. returns true iff a switch is permitted. 250 bool isSwitchOkay(BaseClientProxy* dst, EDirection, 251 SInt32 x, SInt32 y, SInt32 xActive, SInt32 yActive); 252 253 // update switch state due to a mouse move at \p x, \p y that 254 // doesn't switch screens. 255 void noSwitch(SInt32 x, SInt32 y); 256 257 // stop switch timers 258 void stopSwitch(); 259 260 // start two tap switch timer 261 void startSwitchTwoTap(); 262 263 // arm the two tap switch timer if \p x, \p y is outside the tap zone 264 void armSwitchTwoTap(SInt32 x, SInt32 y); 265 266 // stop the two tap switch timer 267 void stopSwitchTwoTap(); 268 269 // returns true iff the two tap switch timer is started 270 bool isSwitchTwoTapStarted() const; 271 272 // returns true iff should switch because of two tap 273 bool shouldSwitchTwoTap() const; 274 275 // start delay switch timer 276 void startSwitchWait(SInt32 x, SInt32 y); 277 278 // stop delay switch timer 279 void stopSwitchWait(); 280 281 // returns true iff the delay switch timer is started 282 bool isSwitchWaitStarted() const; 283 284 // returns the corner (EScreenSwitchCornerMasks) where x,y is on the 285 // given client. corners have the given size. 286 UInt32 getCorner(BaseClientProxy*, 287 SInt32 x, SInt32 y, SInt32 size) const; 288 289 // stop relative mouse moves 290 void stopRelativeMoves(); 291 292 // send screen options to \c client 293 void sendOptions(BaseClientProxy* client) const; 294 295 // process options from configuration 296 void processOptions(); 297 298 // event handlers 299 void handleShapeChanged(const Event&, void*); 300 void handleClipboardGrabbed(const Event&, void*); 301 void handleClipboardChanged(const Event&, void*); 302 void handleKeyDownEvent(const Event&, void*); 303 void handleKeyUpEvent(const Event&, void*); 304 void handleKeyRepeatEvent(const Event&, void*); 305 void handleButtonDownEvent(const Event&, void*); 306 void handleButtonUpEvent(const Event&, void*); 307 void handleMotionPrimaryEvent(const Event&, void*); 308 void handleMotionSecondaryEvent(const Event&, void*); 309 void handleWheelEvent(const Event&, void*); 310 void handleScreensaverActivatedEvent(const Event&, void*); 311 void handleScreensaverDeactivatedEvent(const Event&, void*); 312 void handleSwitchWaitTimeout(const Event&, void*); 313 void handleClientDisconnected(const Event&, void*); 314 void handleClientCloseTimeout(const Event&, void*); 315 void handleSwitchToScreenEvent(const Event&, void*); 316 void handleSwitchInDirectionEvent(const Event&, void*); 317 void handleKeyboardBroadcastEvent(const Event&,void*); 318 void handleLockCursorToScreenEvent(const Event&, void*); 319 void handleFakeInputBeginEvent(const Event&, void*); 320 void handleFakeInputEndEvent(const Event&, void*); 321 void handleFileChunkSendingEvent(const Event&, void*); 322 void handleFileRecieveCompletedEvent(const Event&, void*); 323 324 // event processing 325 void onClipboardChanged(BaseClientProxy* sender, 326 ClipboardID id, UInt32 seqNum); 327 void onScreensaver(bool activated); 328 void onKeyDown(KeyID, KeyModifierMask, KeyButton, 329 const char* screens); 330 void onKeyUp(KeyID, KeyModifierMask, KeyButton, 331 const char* screens); 332 void onKeyRepeat(KeyID, KeyModifierMask, SInt32, KeyButton); 333 void onMouseDown(ButtonID); 334 void onMouseUp(ButtonID); 335 bool onMouseMovePrimary(SInt32 x, SInt32 y); 336 void onMouseMoveSecondary(SInt32 dx, SInt32 dy); 337 void onMouseWheel(SInt32 xDelta, SInt32 yDelta); 338 void onFileChunkSending(const void* data); 339 void onFileRecieveCompleted(); 340 341 // add client to list and attach event handlers for client 342 bool addClient(BaseClientProxy*); 343 344 // remove client from list and detach event handlers for client 345 bool removeClient(BaseClientProxy*); 346 347 // close a client 348 void closeClient(BaseClientProxy*, const char* msg); 349 350 // close clients not in \p config 351 void closeClients(const Config& config); 352 353 // close all clients whether they've completed the handshake or not, 354 // except the primary client 355 void closeAllClients(); 356 357 // remove clients from internal state 358 void removeActiveClient(BaseClientProxy*); 359 void removeOldClient(BaseClientProxy*); 360 361 // force the cursor off of \p client 362 void forceLeaveClient(BaseClientProxy* client); 363 364 // thread funciton for sending file 365 void sendFileThread(void*); 366 367 // thread function for writing file to drop directory 368 void writeToDropDirThread(void*); 369 370 // thread function for sending drag information 371 void sendDragInfoThread(void*); 372 373 // send drag info to new client screen 374 void sendDragInfo(BaseClientProxy* newScreen); 375 376 public: 377 bool m_mock; 378 379 private: 380 class ClipboardInfo { 381 public: 382 ClipboardInfo(); 383 384 public: 385 Clipboard m_clipboard; 386 String m_clipboardData; 387 String m_clipboardOwner; 388 UInt32 m_clipboardSeqNum; 389 }; 390 391 // the primary screen client 392 PrimaryClient* m_primaryClient; 393 394 // all clients (including the primary client) indexed by name 395 typedef std::map<String, BaseClientProxy*> ClientList; 396 typedef std::set<BaseClientProxy*> ClientSet; 397 ClientList m_clients; 398 ClientSet m_clientSet; 399 400 // all old connections that we're waiting to hangup 401 typedef std::map<BaseClientProxy*, EventQueueTimer*> OldClients; 402 OldClients m_oldClients; 403 404 // the client with focus 405 BaseClientProxy* m_active; 406 407 // the sequence number of enter messages 408 UInt32 m_seqNum; 409 410 // current mouse position (in absolute screen coordinates) on 411 // whichever screen is active 412 SInt32 m_x, m_y; 413 414 // last mouse deltas. this is needed to smooth out double tap 415 // on win32 which reports bogus mouse motion at the edge of 416 // the screen when using low level hooks, synthesizing motion 417 // in the opposite direction the mouse actually moved. 418 SInt32 m_xDelta, m_yDelta; 419 SInt32 m_xDelta2, m_yDelta2; 420 421 // current configuration 422 Config* m_config; 423 424 // input filter (from m_config); 425 InputFilter* m_inputFilter; 426 427 // clipboard cache 428 ClipboardInfo m_clipboards[kClipboardEnd]; 429 430 // state saved when screen saver activates 431 BaseClientProxy* m_activeSaver; 432 SInt32 m_xSaver, m_ySaver; 433 434 // common state for screen switch tests. all tests are always 435 // trying to reach the same screen in the same direction. 436 EDirection m_switchDir; 437 BaseClientProxy* m_switchScreen; 438 439 // state for delayed screen switching 440 double m_switchWaitDelay; 441 EventQueueTimer* m_switchWaitTimer; 442 SInt32 m_switchWaitX, m_switchWaitY; 443 444 // state for double-tap screen switching 445 double m_switchTwoTapDelay; 446 Stopwatch m_switchTwoTapTimer; 447 bool m_switchTwoTapEngaged; 448 bool m_switchTwoTapArmed; 449 SInt32 m_switchTwoTapZone; 450 451 // modifiers needed before switching 452 bool m_switchNeedsShift; 453 bool m_switchNeedsControl; 454 bool m_switchNeedsAlt; 455 456 // relative mouse move option 457 bool m_relativeMoves; 458 459 // flag whether or not we have broadcasting enabled and the screens to 460 // which we should send broadcasted keys. 461 bool m_keyboardBroadcasting; 462 String m_keyboardBroadcastingScreens; 463 464 // screen locking (former scroll lock) 465 bool m_lockedToScreen; 466 467 // server screen 468 synergy::Screen* m_screen; 469 470 IEventQueue* m_events; 471 472 // file transfer 473 size_t m_expectedFileSize; 474 String m_receivedFileData; 475 DragFileList m_dragFileList; 476 DragFileList m_fakeDragFileList; 477 Thread* m_sendFileThread; 478 Thread* m_writeToDropDirThread; 479 String m_dragFileExt; 480 bool m_ignoreFileTransfer; 481 bool m_disableLockToScreen; 482 bool m_enableClipboard; 483 size_t m_maximumClipboardSize; 484 485 Thread* m_sendDragInfoThread; 486 bool m_waitDragInfoThread; 487 488 ClientListener* m_clientListener; 489 lib::synergy::ServerArgs m_args; 490 }; 491