421 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			421 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
| uSynergy client -- Interface for the embedded Synergy client library
 | |
|   version 1.0.0, July 7th, 2012
 | |
| 
 | |
| Copyright (C) 2012 Synergy Si Ltd.
 | |
| Copyright (c) 2012 Alex Evans
 | |
| 
 | |
| This software is provided 'as-is', without any express or implied
 | |
| warranty. In no event will the authors be held liable for any damages
 | |
| arising from the use of this software.
 | |
| 
 | |
| Permission is granted to anyone to use this software for any purpose,
 | |
| including commercial applications, and to alter it and redistribute it
 | |
| freely, subject to the following restrictions:
 | |
| 
 | |
|    1. The origin of this software must not be misrepresented; you must not
 | |
|    claim that you wrote the original software. If you use this software
 | |
|    in a product, an acknowledgment in the product documentation would be
 | |
|    appreciated but is not required.
 | |
| 
 | |
|    2. Altered source versions must be plainly marked as such, and must not be
 | |
|    misrepresented as being the original software.
 | |
| 
 | |
|    3. This notice may not be removed or altered from any source
 | |
|    distribution.
 | |
| */
 | |
| #include <stdint.h>
 | |
| 
 | |
| #ifdef __cplusplus
 | |
| extern "C" {
 | |
| #endif
 | |
| 
 | |
| 
 | |
| 
 | |
| //---------------------------------------------------------------------------------------------------------------------
 | |
| //	Configuration
 | |
| //---------------------------------------------------------------------------------------------------------------------
 | |
| 
 | |
| 
 | |
| 
 | |
| /**
 | |
| @brief Determine endianness
 | |
| **/
 | |
| #if defined(USYNERGY_LITTLE_ENDIAN) && defined(USYNERGY_BIG_ENDIAN)
 | |
| 	/* Ambiguous: both endians specified */
 | |
| 	#error "Can't define both USYNERGY_LITTLE_ENDIAN and USYNERGY_BIG_ENDIAN"
 | |
| #elif !defined(USYNERGY_LITTLE_ENDIAN) && !defined(USYNERGY_BIG_ENDIAN)
 | |
| 	/* Attempt to auto detect */
 | |
| 	#if defined(__LITTLE_ENDIAN__) || defined(LITTLE_ENDIAN) || (_BYTE_ORDER == _LITTLE_ENDIAN)
 | |
| 		#define USYNERGY_LITTLE_ENDIAN
 | |
| 	#elif defined(__BIG_ENDIAN__) || defined(BIG_ENDIAN) || (_BYTE_ORDER == _BIG_ENDIAN)
 | |
| 		#define USYNERGY_BIG_ENDIAN
 | |
| 	#else
 | |
| 		#error "Can't detect endian-nes, please defined either USYNERGY_LITTLE_ENDIAN or USYNERGY_BIG_ENDIAN";
 | |
| 	#endif
 | |
| #else
 | |
| 	/* User-specified endian-nes, nothing to do for us */
 | |
| #endif
 | |
| 
 | |
| 
 | |
| 
 | |
| //---------------------------------------------------------------------------------------------------------------------
 | |
| //	Types and Constants
 | |
| //---------------------------------------------------------------------------------------------------------------------
 | |
| 
 | |
| 
 | |
| 
 | |
| /**
 | |
| @brief Boolean type
 | |
| **/
 | |
| typedef int			uSynergyBool;
 | |
| #define				USYNERGY_FALSE					0				/* False value */
 | |
| #define				USYNERGY_TRUE					1				/* True value */
 | |
| 
 | |
| 
 | |
| /**
 | |
| @brief User context type
 | |
| 
 | |
| The uSynergyCookie type is an opaque type that is used by uSynergy to communicate to the client. It is passed along to
 | |
| callback functions as context.
 | |
| **/
 | |
| typedef struct { int ignored; } *					uSynergyCookie;
 | |
| 
 | |
| 
 | |
| 
 | |
| /**
 | |
| @brief Clipboard types
 | |
| **/
 | |
| enum uSynergyClipboardFormat
 | |
| {
 | |
| 	USYNERGY_CLIPBOARD_FORMAT_TEXT					= 0,			/* Text format, UTF-8, newline is LF */
 | |
| 	USYNERGY_CLIPBOARD_FORMAT_BITMAP				= 1,			/* Bitmap format, BMP 24/32bpp, BI_RGB */
 | |
| 	USYNERGY_CLIPBOARD_FORMAT_HTML					= 2,			/* HTML format, HTML fragment, UTF-8, newline is LF */
 | |
| };
 | |
| 
 | |
| 
 | |
| 
 | |
| /**
 | |
| @brief Constants and limits
 | |
| **/
 | |
| #define				USYNERGY_NUM_JOYSTICKS			4				/* Maximum number of supported joysticks */
 | |
| 
 | |
| #define				USYNERGY_PROTOCOL_MAJOR			1				/* Major protocol version */
 | |
| #define				USYNERGY_PROTOCOL_MINOR			4				/* Minor protocol version */
 | |
| 
 | |
| #define				USYNERGY_IDLE_TIMEOUT			2000			/* Timeout in milliseconds before reconnecting */
 | |
| 
 | |
| #define				USYNERGY_TRACE_BUFFER_SIZE		1024			/* Maximum length of traced message */
 | |
| #define				USYNERGY_REPLY_BUFFER_SIZE		1024			/* Maximum size of a reply packet */
 | |
| #define				USYNERGY_RECEIVE_BUFFER_SIZE	4096			/* Maximum size of an incoming packet */
 | |
| 
 | |
| 
 | |
| 
 | |
| /**
 | |
| @brief Keyboard constants
 | |
| **/
 | |
| #define				USYNERGY_MODIFIER_SHIFT			0x0001			/* Shift key modifier */
 | |
| #define				USYNERGY_MODIFIER_CTRL			0x0002			/* Ctrl key modifier */
 | |
| #define				USYNERGY_MODIFIER_ALT			0x0004			/* Alt key modifier */
 | |
| #define				USYNERGY_MODIFIER_META			0x0008			/* Meta key modifier */
 | |
| #define				USYNERGY_MODIFIER_WIN			0x0010			/* Windows key modifier */
 | |
| #define				USYNERGY_MODIFIER_ALT_GR		0x0020			/* AltGr key modifier */
 | |
| #define				USYNERGY_MODIFIER_LEVEL5LOCK	0x0040			/* Level5Lock key modifier */
 | |
| #define				USYNERGY_MODIFIER_CAPSLOCK		0x1000			/* CapsLock key modifier */
 | |
| #define				USYNERGY_MODIFIER_NUMLOCK		0x2000			/* NumLock key modifier */
 | |
| #define				USYNERGY_MODIFIER_SCROLLOCK		0x4000			/* ScrollLock key modifier */
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| //---------------------------------------------------------------------------------------------------------------------
 | |
| //	Functions and Callbacks
 | |
| //---------------------------------------------------------------------------------------------------------------------
 | |
| 
 | |
| 
 | |
| 
 | |
| /**
 | |
| @brief Connect function
 | |
| 
 | |
| This function is called when uSynergy needs to connect to the host. It doesn't imply a network implementation or
 | |
| destination address, that must all be handled on the user side. The function should return USYNERGY_TRUE if a
 | |
| connection was established or USYNERGY_FALSE if it could not connect.
 | |
| 
 | |
| When network errors occur (e.g. uSynergySend or uSynergyReceive fail) then the connect call will be called again
 | |
| so the implementation of the function must close any old connections and clean up resources before retrying.
 | |
| 
 | |
| @param cookie		Cookie supplied in the Synergy context
 | |
| **/
 | |
| typedef uSynergyBool (*uSynergyConnectFunc)(uSynergyCookie cookie);
 | |
| 
 | |
| 
 | |
| 
 | |
| /**
 | |
| @brief Send function
 | |
| 
 | |
| This function is called when uSynergy needs to send something over the default connection. It should return
 | |
| USYNERGY_TRUE if sending succeeded and USYNERGY_FALSE otherwise. This function should block until the send
 | |
| operation is completed.
 | |
| 
 | |
| @param cookie		Cookie supplied in the Synergy context
 | |
| @param buffer		Address of buffer to send
 | |
| @param length		Length of buffer to send
 | |
| **/
 | |
| typedef uSynergyBool (*uSynergySendFunc)(uSynergyCookie cookie, const uint8_t *buffer, int length);
 | |
| 
 | |
| 
 | |
| 
 | |
| /**
 | |
| @brief Receive function
 | |
| 
 | |
| This function is called when uSynergy needs to receive data from the default connection. It should return
 | |
| USYNERGY_TRUE if receiving data succeeded and USYNERGY_FALSE otherwise. This function should block until data
 | |
| has been received and wait for data to become available. If @a outLength is set to 0 upon completion it is
 | |
| assumed that the connection is alive, but still in a connecting state and needs time to settle.
 | |
| 
 | |
| @param cookie		Cookie supplied in the Synergy context
 | |
| @param buffer		Address of buffer to receive data into
 | |
| @param maxLength	Maximum amount of bytes to write into the receive buffer
 | |
| @param outLength	Address of integer that receives the actual amount of bytes written into @a buffer
 | |
| **/
 | |
| typedef uSynergyBool (*uSynergyReceiveFunc)(uSynergyCookie cookie, uint8_t *buffer, int maxLength, int* outLength);
 | |
| 
 | |
| 
 | |
| 
 | |
| /**
 | |
| @brief Thread sleep function
 | |
| 
 | |
| This function is called when uSynergy wants to suspend operation for a while before retrying an operation. It
 | |
| is mostly used when a socket times out or disconnect occurs to prevent uSynergy from continuously hammering a
 | |
| network connection in case the network is down.
 | |
| 
 | |
| @param cookie		Cookie supplied in the Synergy context
 | |
| @param timeMs		Time to sleep the current thread (in milliseconds)
 | |
| **/
 | |
| typedef void		(*uSynergySleepFunc)(uSynergyCookie cookie, int timeMs);
 | |
| 
 | |
| 
 | |
| 
 | |
| /**
 | |
| @brief Get time function
 | |
| 
 | |
| This function is called when uSynergy needs to know the current time. This is used to determine when timeouts
 | |
| have occured. The time base should be a cyclic millisecond time value.
 | |
| 
 | |
| @returns			Time value in milliseconds
 | |
| **/
 | |
| typedef uint32_t	(*uSynergyGetTimeFunc)();
 | |
| 
 | |
| 
 | |
| 
 | |
| /**
 | |
| @brief Trace function
 | |
| 
 | |
| This function is called when uSynergy wants to trace something. It is optional to show these messages, but they
 | |
| are often useful when debugging. uSynergy only traces major events like connecting and disconnecting. Usually
 | |
| only a single trace is shown when the connection is established and no more trace are called.
 | |
| 
 | |
| @param cookie		Cookie supplied in the Synergy context
 | |
| @param text			Text to be traced
 | |
| **/
 | |
| typedef void		(*uSynergyTraceFunc)(uSynergyCookie cookie, const char *text);
 | |
| 
 | |
| 
 | |
| 
 | |
| /**
 | |
| @brief Screen active callback
 | |
| 
 | |
| This callback is called when Synergy makes the screen active or inactive. This
 | |
| callback is usually sent when the mouse enters or leaves the screen.
 | |
| 
 | |
| @param cookie		Cookie supplied in the Synergy context
 | |
| @param active		Activation flag, 1 if the screen has become active, 0 if the screen has become inactive
 | |
| **/
 | |
| typedef void		(*uSynergyScreenActiveCallback)(uSynergyCookie cookie, uSynergyBool active);
 | |
| 
 | |
| 
 | |
| 
 | |
| /**
 | |
| @brief Mouse callback
 | |
| 
 | |
| This callback is called when a mouse events happens. The mouse X and Y position,
 | |
| wheel and button state is communicated in the message. It's up to the user to
 | |
| interpret if this is a mouse up, down, double-click or other message.
 | |
| 
 | |
| @param cookie		Cookie supplied in the Synergy context
 | |
| @param x			Mouse X position
 | |
| @param y			Mouse Y position
 | |
| @param wheelX		Mouse wheel X position
 | |
| @param wheelY		Mouse wheel Y position
 | |
| @param buttonLeft	Left button pressed status, 0 for released, 1 for pressed
 | |
| @param buttonMiddle	Middle button pressed status, 0 for released, 1 for pressed
 | |
| @param buttonRight	Right button pressed status, 0 for released, 1 for pressed
 | |
| **/
 | |
| typedef void		(*uSynergyMouseCallback)(uSynergyCookie cookie, uint16_t x, uint16_t y, int16_t wheelX, int16_t wheelY, uSynergyBool buttonLeft, uSynergyBool buttonRight, uSynergyBool buttonMiddle);
 | |
| 
 | |
| 
 | |
| 
 | |
| /**
 | |
| @brief Key event callback
 | |
| 
 | |
| This callback is called when a key is pressed or released.
 | |
| 
 | |
| @param cookie		Cookie supplied in the Synergy context
 | |
| @param key			Key code of key that was pressed or released
 | |
| @param modifiers	Status of modifier keys (alt, shift, etc.)
 | |
| @param down			Down or up status, 1 is key is pressed down, 0 if key is released (up)
 | |
| @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
 | |
| **/
 | |
| typedef void		(*uSynergyKeyboardCallback)(uSynergyCookie cookie, uint16_t key, uint16_t modifiers, uSynergyBool down, uSynergyBool repeat);
 | |
| 
 | |
| 
 | |
| 
 | |
| /**
 | |
| @brief Joystick event callback
 | |
| 
 | |
| This callback is called when a joystick stick or button changes. It is possible that multiple callbacks are
 | |
| fired when different sticks or buttons change as these are individual messages in the packet stream. Each
 | |
| callback will contain all the valid state for the different axes and buttons. The last callback received will
 | |
| represent the most current joystick state.
 | |
| 
 | |
| @param cookie		Cookie supplied in the Synergy context
 | |
| @param joyNum		Joystick number, always in the range [0 ... USYNERGY_NUM_JOYSTICKS>
 | |
| @param buttons		Button pressed mask
 | |
| @param leftStickX	Left stick X position, in range [-127 ... 127]
 | |
| @param leftStickY	Left stick Y position, in range [-127 ... 127]
 | |
| @param rightStickX	Right stick X position, in range [-127 ... 127]
 | |
| @param rightStickY	Right stick Y position, in range [-127 ... 127]
 | |
| **/
 | |
| typedef void		(*uSynergyJoystickCallback)(uSynergyCookie cookie, uint8_t joyNum, uint16_t buttons, int8_t leftStickX, int8_t leftStickY, int8_t rightStickX, int8_t rightStickY);
 | |
| 
 | |
| 
 | |
| 
 | |
| /**
 | |
| @brief Clipboard event callback
 | |
| 
 | |
| This callback is called when something is placed on the clipboard. Multiple callbacks may be fired for
 | |
| multiple clipboard formats if they are supported. The data provided is read-only and may not be modified
 | |
| by the application.
 | |
| 
 | |
| @param cookie		Cookie supplied in the Synergy context
 | |
| @param format		Clipboard format
 | |
| @param data			Memory area containing the clipboard raw data
 | |
| @param size			Size of clipboard data
 | |
| **/
 | |
| typedef void		(*uSynergyClipboardCallback)(uSynergyCookie cookie, enum uSynergyClipboardFormat format, const uint8_t *data, uint32_t size);
 | |
| 
 | |
| 
 | |
| 
 | |
| //---------------------------------------------------------------------------------------------------------------------
 | |
| //	Context
 | |
| //---------------------------------------------------------------------------------------------------------------------
 | |
| 
 | |
| 
 | |
| 
 | |
| /**
 | |
| @brief uSynergy context
 | |
| **/
 | |
| typedef struct
 | |
| {
 | |
| 	/* Mandatory configuration data, filled in by client */
 | |
| 	uSynergyConnectFunc				m_connectFunc;									/* Connect function */
 | |
| 	uSynergySendFunc				m_sendFunc;										/* Send data function */
 | |
| 	uSynergyReceiveFunc				m_receiveFunc;									/* Receive data function */
 | |
| 	uSynergySleepFunc				m_sleepFunc;									/* Thread sleep function */
 | |
| 	uSynergyGetTimeFunc				m_getTimeFunc;									/* Get current time function */
 | |
| 	const char*						m_clientName;									/* Name of Synergy Screen / Client */
 | |
| 	uint16_t						m_clientWidth;									/* Width of screen */
 | |
| 	uint16_t						m_clientHeight;									/* Height of screen */
 | |
| 
 | |
| 	/* Optional configuration data, filled in by client */
 | |
| 	uSynergyCookie					m_cookie;										/* Cookie pointer passed to callback functions (can be NULL) */
 | |
| 	uSynergyTraceFunc				m_traceFunc;									/* Function for tracing status (can be NULL) */
 | |
| 	uSynergyScreenActiveCallback	m_screenActiveCallback;							/* Callback for entering and leaving screen */
 | |
| 	uSynergyMouseCallback			m_mouseCallback;								/* Callback for mouse events */
 | |
| 	uSynergyKeyboardCallback		m_keyboardCallback;								/* Callback for keyboard events */
 | |
| 	uSynergyJoystickCallback		m_joystickCallback;								/* Callback for joystick events */
 | |
| 	uSynergyClipboardCallback		m_clipboardCallback;							/* Callback for clipboard events */
 | |
| 
 | |
| 	/* State data, used internall by client, initialized by uSynergyInit() */
 | |
| 	uSynergyBool					m_connected;									/* Is our socket connected? */
 | |
| 	uSynergyBool					m_hasReceivedHello;								/* Have we received a 'Hello' from the server? */
 | |
| 	uSynergyBool					m_isCaptured;									/* Is Synergy active (i.e. this client is receiving input messages?) */
 | |
| 	uint32_t						m_lastMessageTime;								/* Time at which last message was received */
 | |
| 	uint32_t						m_sequenceNumber;								/* Packet sequence number */
 | |
| 	uint8_t							m_receiveBuffer[USYNERGY_RECEIVE_BUFFER_SIZE];	/* Receive buffer */
 | |
| 	int								m_receiveOfs;									/* Receive buffer offset */
 | |
| 	uint8_t							m_replyBuffer[USYNERGY_REPLY_BUFFER_SIZE];		/* Reply buffer */
 | |
| 	uint8_t*						m_replyCur;										/* Write offset into reply buffer */
 | |
| 	uint16_t						m_mouseX;										/* Mouse X position */
 | |
| 	uint16_t						m_mouseY;										/* Mouse Y position */
 | |
| 	int16_t							m_mouseWheelX;									/* Mouse wheel X position */
 | |
| 	int16_t							m_mouseWheelY;									/* Mouse wheel Y position */
 | |
| 	uSynergyBool					m_mouseButtonLeft;								/* Mouse left button */
 | |
| 	uSynergyBool					m_mouseButtonRight;								/* Mouse right button */
 | |
| 	uSynergyBool					m_mouseButtonMiddle;							/* Mouse middle button */
 | |
| 	int8_t							m_joystickSticks[USYNERGY_NUM_JOYSTICKS][4];	/* Joystick stick position in 2 axes for 2 sticks */
 | |
| 	uint16_t						m_joystickButtons[USYNERGY_NUM_JOYSTICKS];		/* Joystick button state */
 | |
| } uSynergyContext;
 | |
| 
 | |
| 
 | |
| 
 | |
| //---------------------------------------------------------------------------------------------------------------------
 | |
| //	Interface
 | |
| //---------------------------------------------------------------------------------------------------------------------
 | |
| 
 | |
| 
 | |
| 
 | |
| /**
 | |
| @brief Initialize uSynergy context
 | |
| 
 | |
| This function initializes @a context for use. Call this function directly after
 | |
| creating the context, before filling in any configuration data in it. Not calling
 | |
| this function will cause undefined behavior.
 | |
| 
 | |
| @param context	Context to be initialized
 | |
| **/
 | |
| extern void		uSynergyInit(uSynergyContext *context);
 | |
| 
 | |
| 
 | |
| 
 | |
| /**
 | |
| @brief Update uSynergy
 | |
| 
 | |
| This function updates uSynergy and does the bulk of the work. It does connection management,
 | |
| receiving data, reconnecting after errors or timeouts and so on. It assumes that networking
 | |
| operations are blocking and it can suspend the current thread if it needs to wait. It is
 | |
| best practice to call uSynergyUpdate from a background thread so it is responsive.
 | |
| 
 | |
| Because uSynergy relies mostly on blocking calls it will mostly stay in thread sleep state
 | |
| waiting for system mutexes and won't eat much memory.
 | |
| 
 | |
| uSynergyUpdate doesn't do any memory allocations or have any side effects beyond those of
 | |
| the callbacks it calls.
 | |
| 
 | |
| @param context	Context to be updated
 | |
| **/
 | |
| extern void		uSynergyUpdate(uSynergyContext *context);
 | |
| 
 | |
| 
 | |
| 
 | |
| /**
 | |
| @brief Send clipboard data
 | |
| 
 | |
| This function sets new clipboard data and sends it to the server. Use this function if
 | |
| your client cuts or copies data onto the clipboard that it needs to share with the
 | |
| server.
 | |
| 
 | |
| Currently there is only support for plaintext, but HTML and image data could be
 | |
| supported with some effort.
 | |
| 
 | |
| @param context	Context to send clipboard data to
 | |
| @param text		Text to set to the clipboard
 | |
| **/
 | |
| extern void		uSynergySendClipboard(uSynergyContext *context, const char *text);
 | |
| 
 | |
| 
 | |
| 
 | |
| #ifdef __cplusplus
 | |
| };
 | |
| #endif
 |