1 /* 2 uSynergy client -- Interface for the embedded Synergy client library 3 version 1.0.0, July 7th, 2012 4 5 Copyright (C) 2012 Synergy Si Ltd. 6 Copyright (c) 2012 Alex Evans 7 8 This software is provided 'as-is', without any express or implied 9 warranty. In no event will the authors be held liable for any damages 10 arising from the use of this software. 11 12 Permission is granted to anyone to use this software for any purpose, 13 including commercial applications, and to alter it and redistribute it 14 freely, subject to the following restrictions: 15 16 1. The origin of this software must not be misrepresented; you must not 17 claim that you wrote the original software. If you use this software 18 in a product, an acknowledgment in the product documentation would be 19 appreciated but is not required. 20 21 2. Altered source versions must be plainly marked as such, and must not be 22 misrepresented as being the original software. 23 24 3. This notice may not be removed or altered from any source 25 distribution. 26 */ 27 #include <stdint.h> 28 29 #ifdef __cplusplus 30 extern "C" { 31 #endif 32 33 34 35 //--------------------------------------------------------------------------------------------------------------------- 36 // Configuration 37 //--------------------------------------------------------------------------------------------------------------------- 38 39 40 41 /** 42 @brief Determine endianness 43 **/ 44 #if defined(USYNERGY_LITTLE_ENDIAN) && defined(USYNERGY_BIG_ENDIAN) 45 /* Ambiguous: both endians specified */ 46 #error "Can't define both USYNERGY_LITTLE_ENDIAN and USYNERGY_BIG_ENDIAN" 47 #elif !defined(USYNERGY_LITTLE_ENDIAN) && !defined(USYNERGY_BIG_ENDIAN) 48 /* Attempt to auto detect */ 49 #if defined(__LITTLE_ENDIAN__) || defined(LITTLE_ENDIAN) || (_BYTE_ORDER == _LITTLE_ENDIAN) 50 #define USYNERGY_LITTLE_ENDIAN 51 #elif defined(__BIG_ENDIAN__) || defined(BIG_ENDIAN) || (_BYTE_ORDER == _BIG_ENDIAN) 52 #define USYNERGY_BIG_ENDIAN 53 #else 54 #error "Can't detect endian-nes, please defined either USYNERGY_LITTLE_ENDIAN or USYNERGY_BIG_ENDIAN"; 55 #endif 56 #else 57 /* User-specified endian-nes, nothing to do for us */ 58 #endif 59 60 61 62 //--------------------------------------------------------------------------------------------------------------------- 63 // Types and Constants 64 //--------------------------------------------------------------------------------------------------------------------- 65 66 67 68 /** 69 @brief Boolean type 70 **/ 71 typedef int uSynergyBool; 72 #define USYNERGY_FALSE 0 /* False value */ 73 #define USYNERGY_TRUE 1 /* True value */ 74 75 76 /** 77 @brief User context type 78 79 The uSynergyCookie type is an opaque type that is used by uSynergy to communicate to the client. It is passed along to 80 callback functions as context. 81 **/ 82 typedef struct { int ignored; } * uSynergyCookie; 83 84 85 86 /** 87 @brief Clipboard types 88 **/ 89 enum uSynergyClipboardFormat 90 { 91 USYNERGY_CLIPBOARD_FORMAT_TEXT = 0, /* Text format, UTF-8, newline is LF */ 92 USYNERGY_CLIPBOARD_FORMAT_BITMAP = 1, /* Bitmap format, BMP 24/32bpp, BI_RGB */ 93 USYNERGY_CLIPBOARD_FORMAT_HTML = 2, /* HTML format, HTML fragment, UTF-8, newline is LF */ 94 }; 95 96 97 98 /** 99 @brief Constants and limits 100 **/ 101 #define USYNERGY_NUM_JOYSTICKS 4 /* Maximum number of supported joysticks */ 102 103 #define USYNERGY_PROTOCOL_MAJOR 1 /* Major protocol version */ 104 #define USYNERGY_PROTOCOL_MINOR 4 /* Minor protocol version */ 105 106 #define USYNERGY_IDLE_TIMEOUT 2000 /* Timeout in milliseconds before reconnecting */ 107 108 #define USYNERGY_TRACE_BUFFER_SIZE 1024 /* Maximum length of traced message */ 109 #define USYNERGY_REPLY_BUFFER_SIZE 1024 /* Maximum size of a reply packet */ 110 #define USYNERGY_RECEIVE_BUFFER_SIZE 4096 /* Maximum size of an incoming packet */ 111 112 113 114 /** 115 @brief Keyboard constants 116 **/ 117 #define USYNERGY_MODIFIER_SHIFT 0x0001 /* Shift key modifier */ 118 #define USYNERGY_MODIFIER_CTRL 0x0002 /* Ctrl key modifier */ 119 #define USYNERGY_MODIFIER_ALT 0x0004 /* Alt key modifier */ 120 #define USYNERGY_MODIFIER_META 0x0008 /* Meta key modifier */ 121 #define USYNERGY_MODIFIER_WIN 0x0010 /* Windows key modifier */ 122 #define USYNERGY_MODIFIER_ALT_GR 0x0020 /* AltGr key modifier */ 123 #define USYNERGY_MODIFIER_LEVEL5LOCK 0x0040 /* Level5Lock key modifier */ 124 #define USYNERGY_MODIFIER_CAPSLOCK 0x1000 /* CapsLock key modifier */ 125 #define USYNERGY_MODIFIER_NUMLOCK 0x2000 /* NumLock key modifier */ 126 #define USYNERGY_MODIFIER_SCROLLOCK 0x4000 /* ScrollLock key modifier */ 127 128 129 130 131 //--------------------------------------------------------------------------------------------------------------------- 132 // Functions and Callbacks 133 //--------------------------------------------------------------------------------------------------------------------- 134 135 136 137 /** 138 @brief Connect function 139 140 This function is called when uSynergy needs to connect to the host. It doesn't imply a network implementation or 141 destination address, that must all be handled on the user side. The function should return USYNERGY_TRUE if a 142 connection was established or USYNERGY_FALSE if it could not connect. 143 144 When network errors occur (e.g. uSynergySend or uSynergyReceive fail) then the connect call will be called again 145 so the implementation of the function must close any old connections and clean up resources before retrying. 146 147 @param cookie Cookie supplied in the Synergy context 148 **/ 149 typedef uSynergyBool (*uSynergyConnectFunc)(uSynergyCookie cookie); 150 151 152 153 /** 154 @brief Send function 155 156 This function is called when uSynergy needs to send something over the default connection. It should return 157 USYNERGY_TRUE if sending succeeded and USYNERGY_FALSE otherwise. This function should block until the send 158 operation is completed. 159 160 @param cookie Cookie supplied in the Synergy context 161 @param buffer Address of buffer to send 162 @param length Length of buffer to send 163 **/ 164 typedef uSynergyBool (*uSynergySendFunc)(uSynergyCookie cookie, const uint8_t *buffer, int length); 165 166 167 168 /** 169 @brief Receive function 170 171 This function is called when uSynergy needs to receive data from the default connection. It should return 172 USYNERGY_TRUE if receiving data succeeded and USYNERGY_FALSE otherwise. This function should block until data 173 has been received and wait for data to become available. If @a outLength is set to 0 upon completion it is 174 assumed that the connection is alive, but still in a connecting state and needs time to settle. 175 176 @param cookie Cookie supplied in the Synergy context 177 @param buffer Address of buffer to receive data into 178 @param maxLength Maximum amount of bytes to write into the receive buffer 179 @param outLength Address of integer that receives the actual amount of bytes written into @a buffer 180 **/ 181 typedef uSynergyBool (*uSynergyReceiveFunc)(uSynergyCookie cookie, uint8_t *buffer, int maxLength, int* outLength); 182 183 184 185 /** 186 @brief Thread sleep function 187 188 This function is called when uSynergy wants to suspend operation for a while before retrying an operation. It 189 is mostly used when a socket times out or disconnect occurs to prevent uSynergy from continuously hammering a 190 network connection in case the network is down. 191 192 @param cookie Cookie supplied in the Synergy context 193 @param timeMs Time to sleep the current thread (in milliseconds) 194 **/ 195 typedef void (*uSynergySleepFunc)(uSynergyCookie cookie, int timeMs); 196 197 198 199 /** 200 @brief Get time function 201 202 This function is called when uSynergy needs to know the current time. This is used to determine when timeouts 203 have occured. The time base should be a cyclic millisecond time value. 204 205 @returns Time value in milliseconds 206 **/ 207 typedef uint32_t (*uSynergyGetTimeFunc)(); 208 209 210 211 /** 212 @brief Trace function 213 214 This function is called when uSynergy wants to trace something. It is optional to show these messages, but they 215 are often useful when debugging. uSynergy only traces major events like connecting and disconnecting. Usually 216 only a single trace is shown when the connection is established and no more trace are called. 217 218 @param cookie Cookie supplied in the Synergy context 219 @param text Text to be traced 220 **/ 221 typedef void (*uSynergyTraceFunc)(uSynergyCookie cookie, const char *text); 222 223 224 225 /** 226 @brief Screen active callback 227 228 This callback is called when Synergy makes the screen active or inactive. This 229 callback is usually sent when the mouse enters or leaves the screen. 230 231 @param cookie Cookie supplied in the Synergy context 232 @param active Activation flag, 1 if the screen has become active, 0 if the screen has become inactive 233 **/ 234 typedef void (*uSynergyScreenActiveCallback)(uSynergyCookie cookie, uSynergyBool active); 235 236 237 238 /** 239 @brief Mouse callback 240 241 This callback is called when a mouse events happens. The mouse X and Y position, 242 wheel and button state is communicated in the message. It's up to the user to 243 interpret if this is a mouse up, down, double-click or other message. 244 245 @param cookie Cookie supplied in the Synergy context 246 @param x Mouse X position 247 @param y Mouse Y position 248 @param wheelX Mouse wheel X position 249 @param wheelY Mouse wheel Y position 250 @param buttonLeft Left button pressed status, 0 for released, 1 for pressed 251 @param buttonMiddle Middle button pressed status, 0 for released, 1 for pressed 252 @param buttonRight Right button pressed status, 0 for released, 1 for pressed 253 **/ 254 typedef void (*uSynergyMouseCallback)(uSynergyCookie cookie, uint16_t x, uint16_t y, int16_t wheelX, int16_t wheelY, uSynergyBool buttonLeft, uSynergyBool buttonRight, uSynergyBool buttonMiddle); 255 256 257 258 /** 259 @brief Key event callback 260 261 This callback is called when a key is pressed or released. 262 263 @param cookie Cookie supplied in the Synergy context 264 @param key Key code of key that was pressed or released 265 @param modifiers Status of modifier keys (alt, shift, etc.) 266 @param down Down or up status, 1 is key is pressed down, 0 if key is released (up) 267 @param repeat Repeat flag, 1 if the key is down because the key is repeating, 0 if the key is initially pressed by the user 268 **/ 269 typedef void (*uSynergyKeyboardCallback)(uSynergyCookie cookie, uint16_t key, uint16_t modifiers, uSynergyBool down, uSynergyBool repeat); 270 271 272 273 /** 274 @brief Joystick event callback 275 276 This callback is called when a joystick stick or button changes. It is possible that multiple callbacks are 277 fired when different sticks or buttons change as these are individual messages in the packet stream. Each 278 callback will contain all the valid state for the different axes and buttons. The last callback received will 279 represent the most current joystick state. 280 281 @param cookie Cookie supplied in the Synergy context 282 @param joyNum Joystick number, always in the range [0 ... USYNERGY_NUM_JOYSTICKS> 283 @param buttons Button pressed mask 284 @param leftStickX Left stick X position, in range [-127 ... 127] 285 @param leftStickY Left stick Y position, in range [-127 ... 127] 286 @param rightStickX Right stick X position, in range [-127 ... 127] 287 @param rightStickY Right stick Y position, in range [-127 ... 127] 288 **/ 289 typedef void (*uSynergyJoystickCallback)(uSynergyCookie cookie, uint8_t joyNum, uint16_t buttons, int8_t leftStickX, int8_t leftStickY, int8_t rightStickX, int8_t rightStickY); 290 291 292 293 /** 294 @brief Clipboard event callback 295 296 This callback is called when something is placed on the clipboard. Multiple callbacks may be fired for 297 multiple clipboard formats if they are supported. The data provided is read-only and may not be modified 298 by the application. 299 300 @param cookie Cookie supplied in the Synergy context 301 @param format Clipboard format 302 @param data Memory area containing the clipboard raw data 303 @param size Size of clipboard data 304 **/ 305 typedef void (*uSynergyClipboardCallback)(uSynergyCookie cookie, enum uSynergyClipboardFormat format, const uint8_t *data, uint32_t size); 306 307 308 309 //--------------------------------------------------------------------------------------------------------------------- 310 // Context 311 //--------------------------------------------------------------------------------------------------------------------- 312 313 314 315 /** 316 @brief uSynergy context 317 **/ 318 typedef struct 319 { 320 /* Mandatory configuration data, filled in by client */ 321 uSynergyConnectFunc m_connectFunc; /* Connect function */ 322 uSynergySendFunc m_sendFunc; /* Send data function */ 323 uSynergyReceiveFunc m_receiveFunc; /* Receive data function */ 324 uSynergySleepFunc m_sleepFunc; /* Thread sleep function */ 325 uSynergyGetTimeFunc m_getTimeFunc; /* Get current time function */ 326 const char* m_clientName; /* Name of Synergy Screen / Client */ 327 uint16_t m_clientWidth; /* Width of screen */ 328 uint16_t m_clientHeight; /* Height of screen */ 329 330 /* Optional configuration data, filled in by client */ 331 uSynergyCookie m_cookie; /* Cookie pointer passed to callback functions (can be NULL) */ 332 uSynergyTraceFunc m_traceFunc; /* Function for tracing status (can be NULL) */ 333 uSynergyScreenActiveCallback m_screenActiveCallback; /* Callback for entering and leaving screen */ 334 uSynergyMouseCallback m_mouseCallback; /* Callback for mouse events */ 335 uSynergyKeyboardCallback m_keyboardCallback; /* Callback for keyboard events */ 336 uSynergyJoystickCallback m_joystickCallback; /* Callback for joystick events */ 337 uSynergyClipboardCallback m_clipboardCallback; /* Callback for clipboard events */ 338 339 /* State data, used internall by client, initialized by uSynergyInit() */ 340 uSynergyBool m_connected; /* Is our socket connected? */ 341 uSynergyBool m_hasReceivedHello; /* Have we received a 'Hello' from the server? */ 342 uSynergyBool m_isCaptured; /* Is Synergy active (i.e. this client is receiving input messages?) */ 343 uint32_t m_lastMessageTime; /* Time at which last message was received */ 344 uint32_t m_sequenceNumber; /* Packet sequence number */ 345 uint8_t m_receiveBuffer[USYNERGY_RECEIVE_BUFFER_SIZE]; /* Receive buffer */ 346 int m_receiveOfs; /* Receive buffer offset */ 347 uint8_t m_replyBuffer[USYNERGY_REPLY_BUFFER_SIZE]; /* Reply buffer */ 348 uint8_t* m_replyCur; /* Write offset into reply buffer */ 349 uint16_t m_mouseX; /* Mouse X position */ 350 uint16_t m_mouseY; /* Mouse Y position */ 351 int16_t m_mouseWheelX; /* Mouse wheel X position */ 352 int16_t m_mouseWheelY; /* Mouse wheel Y position */ 353 uSynergyBool m_mouseButtonLeft; /* Mouse left button */ 354 uSynergyBool m_mouseButtonRight; /* Mouse right button */ 355 uSynergyBool m_mouseButtonMiddle; /* Mouse middle button */ 356 int8_t m_joystickSticks[USYNERGY_NUM_JOYSTICKS][4]; /* Joystick stick position in 2 axes for 2 sticks */ 357 uint16_t m_joystickButtons[USYNERGY_NUM_JOYSTICKS]; /* Joystick button state */ 358 } uSynergyContext; 359 360 361 362 //--------------------------------------------------------------------------------------------------------------------- 363 // Interface 364 //--------------------------------------------------------------------------------------------------------------------- 365 366 367 368 /** 369 @brief Initialize uSynergy context 370 371 This function initializes @a context for use. Call this function directly after 372 creating the context, before filling in any configuration data in it. Not calling 373 this function will cause undefined behavior. 374 375 @param context Context to be initialized 376 **/ 377 extern void uSynergyInit(uSynergyContext *context); 378 379 380 381 /** 382 @brief Update uSynergy 383 384 This function updates uSynergy and does the bulk of the work. It does connection management, 385 receiving data, reconnecting after errors or timeouts and so on. It assumes that networking 386 operations are blocking and it can suspend the current thread if it needs to wait. It is 387 best practice to call uSynergyUpdate from a background thread so it is responsive. 388 389 Because uSynergy relies mostly on blocking calls it will mostly stay in thread sleep state 390 waiting for system mutexes and won't eat much memory. 391 392 uSynergyUpdate doesn't do any memory allocations or have any side effects beyond those of 393 the callbacks it calls. 394 395 @param context Context to be updated 396 **/ 397 extern void uSynergyUpdate(uSynergyContext *context); 398 399 400 401 /** 402 @brief Send clipboard data 403 404 This function sets new clipboard data and sends it to the server. Use this function if 405 your client cuts or copies data onto the clipboard that it needs to share with the 406 server. 407 408 Currently there is only support for plaintext, but HTML and image data could be 409 supported with some effort. 410 411 @param context Context to send clipboard data to 412 @param text Text to set to the clipboard 413 **/ 414 extern void uSynergySendClipboard(uSynergyContext *context, const char *text); 415 416 417 418 #ifdef __cplusplus 419 }; 420 #endif 421