diff options
| author | grm <grm@eyesin.space> | 2024-06-05 19:04:25 +0300 | 
|---|---|---|
| committer | grm <grm@eyesin.space> | 2024-06-05 19:04:25 +0300 | 
| commit | 181edce08e0b914b7274571b7feb1ea8b1f341d8 (patch) | |
| tree | 1a442e6095abf160e36baa31a319858774cd1178 /lib/imgui-1.90.7/examples/libs/usynergy | |
| parent | 294e3409d007c29f17c6551acbc9f9199a044b0c (diff) | |
| download | cgame-181edce08e0b914b7274571b7feb1ea8b1f341d8.tar.gz cgame-181edce08e0b914b7274571b7feb1ea8b1f341d8.tar.bz2 cgame-181edce08e0b914b7274571b7feb1ea8b1f341d8.zip  | |
more vks, stupid mutlistep build, and imgui
Diffstat (limited to 'lib/imgui-1.90.7/examples/libs/usynergy')
| -rw-r--r-- | lib/imgui-1.90.7/examples/libs/usynergy/README.txt | 8 | ||||
| -rw-r--r-- | lib/imgui-1.90.7/examples/libs/usynergy/uSynergy.c | 636 | ||||
| -rw-r--r-- | lib/imgui-1.90.7/examples/libs/usynergy/uSynergy.h | 420 | 
3 files changed, 1064 insertions, 0 deletions
diff --git a/lib/imgui-1.90.7/examples/libs/usynergy/README.txt b/lib/imgui-1.90.7/examples/libs/usynergy/README.txt new file mode 100644 index 0000000..c86b909 --- /dev/null +++ b/lib/imgui-1.90.7/examples/libs/usynergy/README.txt @@ -0,0 +1,8 @@ + +uSynergy client -- Implementation for the embedded Synergy client library +version 1.0.0, July 7th, 2012 +Copyright (c) 2012 Alex Evans + +This is a copy of the files once found at: +  https://github.com/symless/synergy-core/tree/790d108a56ada9caad8e56ff777d444485a69da9/src/micro + diff --git a/lib/imgui-1.90.7/examples/libs/usynergy/uSynergy.c b/lib/imgui-1.90.7/examples/libs/usynergy/uSynergy.c new file mode 100644 index 0000000..8dce47b --- /dev/null +++ b/lib/imgui-1.90.7/examples/libs/usynergy/uSynergy.c @@ -0,0 +1,636 @@ +/* +uSynergy client -- Implementation for the embedded Synergy client library +  version 1.0.0, July 7th, 2012 + +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 "uSynergy.h" +#include <stdio.h> +#include <string.h> + + + +//--------------------------------------------------------------------------------------------------------------------- +//	Internal helpers +//--------------------------------------------------------------------------------------------------------------------- + + + +/** +@brief Read 16 bit integer in network byte order and convert to native byte order +**/ +static int16_t sNetToNative16(const unsigned char *value) +{ +#ifdef USYNERGY_LITTLE_ENDIAN +	return value[1] | (value[0] << 8); +#else +	return value[0] | (value[1] << 8); +#endif +} + + + +/** +@brief Read 32 bit integer in network byte order and convert to native byte order +**/ +static int32_t sNetToNative32(const unsigned char *value) +{ +#ifdef USYNERGY_LITTLE_ENDIAN +	return value[3] | (value[2] << 8) | (value[1] << 16) | (value[0] << 24); +#else +	return value[0] | (value[1] << 8) | (value[2] << 16) | (value[3] << 24); +#endif +} + + + +/** +@brief Trace text to client +**/ +static void sTrace(uSynergyContext *context, const char* text) +{ +	// Don't trace if we don't have a trace function +	if (context->m_traceFunc != 0L) +		context->m_traceFunc(context->m_cookie, text); +} + + + +/** +@brief Add string to reply packet +**/ +static void sAddString(uSynergyContext *context, const char *string) +{ +	size_t len = strlen(string); +	memcpy(context->m_replyCur, string, len); +	context->m_replyCur += len; +} + + + +/** +@brief Add uint8 to reply packet +**/ +static void sAddUInt8(uSynergyContext *context, uint8_t value) +{ +	*context->m_replyCur++ = value; +} + + + +/** +@brief Add uint16 to reply packet +**/ +static void sAddUInt16(uSynergyContext *context, uint16_t value) +{ +	uint8_t *reply = context->m_replyCur; +	*reply++ = (uint8_t)(value >> 8); +	*reply++ = (uint8_t)value; +	context->m_replyCur = reply; +} + + + +/** +@brief Add uint32 to reply packet +**/ +static void sAddUInt32(uSynergyContext *context, uint32_t value) +{ +	uint8_t *reply = context->m_replyCur; +	*reply++ = (uint8_t)(value >> 24); +	*reply++ = (uint8_t)(value >> 16); +	*reply++ = (uint8_t)(value >> 8); +	*reply++ = (uint8_t)value; +	context->m_replyCur = reply; +} + + + +/** +@brief Send reply packet +**/ +static uSynergyBool sSendReply(uSynergyContext *context) +{ +	// Set header size +	uint8_t		*reply_buf	= context->m_replyBuffer; +	uint32_t	reply_len	= (uint32_t)(context->m_replyCur - reply_buf);				/* Total size of reply */ +	uint32_t	body_len	= reply_len - 4;											/* Size of body */ +	uSynergyBool ret; +	reply_buf[0] = (uint8_t)(body_len >> 24); +	reply_buf[1] = (uint8_t)(body_len >> 16); +	reply_buf[2] = (uint8_t)(body_len >> 8); +	reply_buf[3] = (uint8_t)body_len; + +	// Send reply +	ret = context->m_sendFunc(context->m_cookie, context->m_replyBuffer, reply_len); + +	// Reset reply buffer write pointer +	context->m_replyCur = context->m_replyBuffer+4; +	return ret; +} + + + +/** +@brief Call mouse callback after a mouse event +**/ +static void sSendMouseCallback(uSynergyContext *context) +{ +	// Skip if no callback is installed +	if (context->m_mouseCallback == 0L) +		return; + +	// Send callback +	context->m_mouseCallback(context->m_cookie, context->m_mouseX, context->m_mouseY, context->m_mouseWheelX, +		context->m_mouseWheelY, context->m_mouseButtonLeft, context->m_mouseButtonRight, context->m_mouseButtonMiddle); +} + + + +/** +@brief Send keyboard callback when a key has been pressed or released +**/ +static void sSendKeyboardCallback(uSynergyContext *context, uint16_t key, uint16_t modifiers, uSynergyBool down, uSynergyBool repeat) +{ +	// Skip if no callback is installed +	if (context->m_keyboardCallback == 0L) +		return; + +	// Send callback +	context->m_keyboardCallback(context->m_cookie, key, modifiers, down, repeat); +} + + + +/** +@brief Send joystick callback +**/ +static void sSendJoystickCallback(uSynergyContext *context, uint8_t joyNum) +{ +	int8_t *sticks; + +	// Skip if no callback is installed +	if (context->m_joystickCallback == 0L) +		return; + +	// Send callback +	sticks = context->m_joystickSticks[joyNum]; +	context->m_joystickCallback(context->m_cookie, joyNum, context->m_joystickButtons[joyNum], sticks[0], sticks[1], sticks[2], sticks[3]); +} + + + +/** +@brief Parse a single client message, update state, send callbacks and send replies +**/ +#define USYNERGY_IS_PACKET(pkt_id)	memcmp(message+4, pkt_id, 4)==0 +static void sProcessMessage(uSynergyContext *context, const uint8_t *message) +{ +	// We have a packet! +	if (memcmp(message+4, "Synergy", 7)==0) +	{ +		// Welcome message +		//		kMsgHello			= "Synergy%2i%2i" +		//		kMsgHelloBack		= "Synergy%2i%2i%s" +		sAddString(context, "Synergy"); +		sAddUInt16(context, USYNERGY_PROTOCOL_MAJOR); +		sAddUInt16(context, USYNERGY_PROTOCOL_MINOR); +		sAddUInt32(context, (uint32_t)strlen(context->m_clientName)); +		sAddString(context, context->m_clientName); +		if (!sSendReply(context)) +		{ +			// Send reply failed, let's try to reconnect +			sTrace(context, "SendReply failed, trying to reconnect in a second"); +			context->m_connected = USYNERGY_FALSE; +			context->m_sleepFunc(context->m_cookie, 1000); +		} +		else +		{ +			// Let's assume we're connected +			char buffer[256+1]; +			sprintf(buffer, "Connected as client \"%s\"", context->m_clientName); +			sTrace(context, buffer); +			context->m_hasReceivedHello = USYNERGY_TRUE; +		} +		return; +	} +	else if (USYNERGY_IS_PACKET("QINF")) +	{ +		// Screen info. Reply with DINF +		//		kMsgQInfo			= "QINF" +		//		kMsgDInfo			= "DINF%2i%2i%2i%2i%2i%2i%2i" +		uint16_t x = 0, y = 0, warp = 0; +		sAddString(context, "DINF"); +		sAddUInt16(context, x); +		sAddUInt16(context, y); +		sAddUInt16(context, context->m_clientWidth); +		sAddUInt16(context, context->m_clientHeight); +		sAddUInt16(context, warp); +		sAddUInt16(context, 0);		// mx? +		sAddUInt16(context, 0);		// my? +		sSendReply(context); +		return; +	} +	else if (USYNERGY_IS_PACKET("CIAK")) +	{ +		// Do nothing? +		//		kMsgCInfoAck		= "CIAK" +		return; +	} +	else if (USYNERGY_IS_PACKET("CROP")) +	{ +		// Do nothing? +		//		kMsgCResetOptions	= "CROP" +		return; +	} +	else if (USYNERGY_IS_PACKET("CINN")) +	{ +		// Screen enter. Reply with CNOP +		//		kMsgCEnter 			= "CINN%2i%2i%4i%2i" + +		// Obtain the Synergy sequence number +		context->m_sequenceNumber = sNetToNative32(message + 12); +		context->m_isCaptured = USYNERGY_TRUE; + +		// Call callback +		if (context->m_screenActiveCallback != 0L) +			context->m_screenActiveCallback(context->m_cookie, USYNERGY_TRUE); +	} +	else if (USYNERGY_IS_PACKET("COUT")) +	{ +		// Screen leave +		//		kMsgCLeave 			= "COUT" +		context->m_isCaptured = USYNERGY_FALSE; + +		// Call callback +		if (context->m_screenActiveCallback != 0L) +			context->m_screenActiveCallback(context->m_cookie, USYNERGY_FALSE); +	} +	else if (USYNERGY_IS_PACKET("DMDN")) +	{ +		// Mouse down +		//		kMsgDMouseDown		= "DMDN%1i" +		char btn = message[8]-1; +		if (btn==2) +			context->m_mouseButtonRight		= USYNERGY_TRUE; +		else if (btn==1) +			context->m_mouseButtonMiddle	= USYNERGY_TRUE; +		else +			context->m_mouseButtonLeft		= USYNERGY_TRUE; +		sSendMouseCallback(context); +	} +	else if (USYNERGY_IS_PACKET("DMUP")) +	{ +		// Mouse up +		//		kMsgDMouseUp		= "DMUP%1i" +		char btn = message[8]-1; +		if (btn==2) +			context->m_mouseButtonRight		= USYNERGY_FALSE; +		else if (btn==1) +			context->m_mouseButtonMiddle	= USYNERGY_FALSE; +		else +			context->m_mouseButtonLeft		= USYNERGY_FALSE; +		sSendMouseCallback(context); +	} +	else if (USYNERGY_IS_PACKET("DMMV")) +	{ +		// Mouse move. Reply with CNOP +		//		kMsgDMouseMove		= "DMMV%2i%2i" +		context->m_mouseX = sNetToNative16(message+8); +		context->m_mouseY = sNetToNative16(message+10); +		sSendMouseCallback(context); +	} +	else if (USYNERGY_IS_PACKET("DMWM")) +	{ +		// Mouse wheel +		//		kMsgDMouseWheel		= "DMWM%2i%2i" +		//		kMsgDMouseWheel1_0	= "DMWM%2i" +		context->m_mouseWheelX += sNetToNative16(message+8); +		context->m_mouseWheelY += sNetToNative16(message+10); +		sSendMouseCallback(context); +	} +	else if (USYNERGY_IS_PACKET("DKDN")) +	{ +		// Key down +		//		kMsgDKeyDown		= "DKDN%2i%2i%2i" +		//		kMsgDKeyDown1_0		= "DKDN%2i%2i" +		//uint16_t id = sNetToNative16(message+8); +		uint16_t mod = sNetToNative16(message+10); +		uint16_t key = sNetToNative16(message+12); +		sSendKeyboardCallback(context, key, mod, USYNERGY_TRUE, USYNERGY_FALSE); +	} +	else if (USYNERGY_IS_PACKET("DKRP")) +	{ +		// Key repeat +		//		kMsgDKeyRepeat		= "DKRP%2i%2i%2i%2i" +		//		kMsgDKeyRepeat1_0	= "DKRP%2i%2i%2i" +		uint16_t mod = sNetToNative16(message+10); +//		uint16_t count = sNetToNative16(message+12); +		uint16_t key = sNetToNative16(message+14); +		sSendKeyboardCallback(context, key, mod, USYNERGY_TRUE, USYNERGY_TRUE); +	} +	else if (USYNERGY_IS_PACKET("DKUP")) +	{ +		// Key up +		//		kMsgDKeyUp			= "DKUP%2i%2i%2i" +		//		kMsgDKeyUp1_0		= "DKUP%2i%2i" +		//uint16 id=Endian::sNetToNative(sbuf[4]); +		uint16_t mod = sNetToNative16(message+10); +		uint16_t key = sNetToNative16(message+12); +		sSendKeyboardCallback(context, key, mod, USYNERGY_FALSE, USYNERGY_FALSE); +	} +	else if (USYNERGY_IS_PACKET("DGBT")) +	{ +		// Joystick buttons +		//		kMsgDGameButtons	= "DGBT%1i%2i"; +		uint8_t	joy_num = message[8]; +		if (joy_num<USYNERGY_NUM_JOYSTICKS) +		{ +			// Copy button state, then send callback +			context->m_joystickButtons[joy_num] = (message[9] << 8) | message[10]; +			sSendJoystickCallback(context, joy_num); +		} +	} +	else if (USYNERGY_IS_PACKET("DGST")) +	{ +		// Joystick sticks +		//		kMsgDGameSticks		= "DGST%1i%1i%1i%1i%1i"; +		uint8_t	joy_num = message[8]; +		if (joy_num<USYNERGY_NUM_JOYSTICKS) +		{ +			// Copy stick state, then send callback +			memcpy(context->m_joystickSticks[joy_num], message+9, 4); +			sSendJoystickCallback(context, joy_num); +		} +	} +	else if (USYNERGY_IS_PACKET("DSOP")) +	{ +		// Set options +		//		kMsgDSetOptions		= "DSOP%4I" +	} +	else if (USYNERGY_IS_PACKET("CALV")) +	{ +		// Keepalive, reply with CALV and then CNOP +		//		kMsgCKeepAlive		= "CALV" +		sAddString(context, "CALV"); +		sSendReply(context); +		// now reply with CNOP +	} +	else if (USYNERGY_IS_PACKET("DCLP")) +	{ +		// Clipboard message +		//		kMsgDClipboard		= "DCLP%1i%4i%s" +		// +		// The clipboard message contains: +		//		1 uint32:	The size of the message +		//		4 chars: 	The identifier ("DCLP") +		//		1 uint8: 	The clipboard index +		//		1 uint32:	The sequence number. It's zero, because this message is always coming from the server? +		//		1 uint32:	The total size of the remaining 'string' (as per the Synergy %s string format (which is 1 uint32 for size followed by a char buffer (not necessarily null terminated)). +		//		1 uint32:	The number of formats present in the message +		// And then 'number of formats' times the following: +		//		1 uint32:	The format of the clipboard data +		//		1 uint32:	The size n of the clipboard data +		//		n uint8:	The clipboard data +		const uint8_t *	parse_msg	= message+17; +		uint32_t		num_formats = sNetToNative32(parse_msg); +		parse_msg += 4; +		for (; num_formats; num_formats--) +		{ +			// Parse clipboard format header +			uint32_t format	= sNetToNative32(parse_msg); +			uint32_t size	= sNetToNative32(parse_msg+4); +			parse_msg += 8; +			 +			// Call callback +			if (context->m_clipboardCallback) +				context->m_clipboardCallback(context->m_cookie, format, parse_msg, size); + +			parse_msg += size; +		} +	} +	else +	{ +		// Unknown packet, could be any of these +		//		kMsgCNoop 			= "CNOP" +		//		kMsgCClose 			= "CBYE" +		//		kMsgCClipboard 		= "CCLP%1i%4i" +		//		kMsgCScreenSaver 	= "CSEC%1i" +		//		kMsgDKeyRepeat		= "DKRP%2i%2i%2i%2i" +		//		kMsgDKeyRepeat1_0	= "DKRP%2i%2i%2i" +		//		kMsgDMouseRelMove	= "DMRM%2i%2i" +		//		kMsgEIncompatible	= "EICV%2i%2i" +		//		kMsgEBusy 			= "EBSY" +		//		kMsgEUnknown		= "EUNK" +		//		kMsgEBad			= "EBAD" +		char buffer[64]; +		sprintf(buffer, "Unknown packet '%c%c%c%c'", message[4], message[5], message[6], message[7]); +		sTrace(context, buffer); +		return; +	} + +	// Reply with CNOP maybe? +	sAddString(context, "CNOP"); +	sSendReply(context); +} +#undef USYNERGY_IS_PACKET + + + +/** +@brief Mark context as being disconnected +**/ +static void sSetDisconnected(uSynergyContext *context) +{ +	context->m_connected		= USYNERGY_FALSE; +	context->m_hasReceivedHello = USYNERGY_FALSE; +	context->m_isCaptured		= USYNERGY_FALSE; +	context->m_replyCur			= context->m_replyBuffer + 4; +	context->m_sequenceNumber	= 0; +} + + + +/** +@brief Update a connected context +**/ +static void sUpdateContext(uSynergyContext *context) +{ +	/* Receive data (blocking) */ +	int receive_size = USYNERGY_RECEIVE_BUFFER_SIZE - context->m_receiveOfs; +	int num_received = 0; +	int packlen = 0; +	if (context->m_receiveFunc(context->m_cookie, context->m_receiveBuffer + context->m_receiveOfs, receive_size, &num_received) == USYNERGY_FALSE) +	{ +		/* Receive failed, let's try to reconnect */ +		char buffer[128]; +		sprintf(buffer, "Receive failed (%d bytes asked, %d bytes received), trying to reconnect in a second", receive_size, num_received); +		sTrace(context, buffer); +		sSetDisconnected(context); +		context->m_sleepFunc(context->m_cookie, 1000); +		return; +	} +	context->m_receiveOfs += num_received; + +	/*	If we didn't receive any data then we're probably still polling to get connected and +		therefore not getting any data back. To avoid overloading the system with a Synergy +		thread that would hammer on polling, we let it rest for a bit if there's no data. */ +	if (num_received == 0) +		context->m_sleepFunc(context->m_cookie, 500); + +	/* Check for timeouts */ +	if (context->m_hasReceivedHello) +	{ +		uint32_t cur_time = context->m_getTimeFunc(); +		if (num_received == 0) +		{ +			/* Timeout after 2 secs of inactivity (we received no CALV) */ +			if ((cur_time - context->m_lastMessageTime) > USYNERGY_IDLE_TIMEOUT) +				sSetDisconnected(context); +		} +		else +			context->m_lastMessageTime = cur_time; +	} + +	/* Eat packets */ +	for (;;) +	{ +		/* Grab packet length and bail out if the packet goes beyond the end of the buffer */ +		packlen = sNetToNative32(context->m_receiveBuffer); +		if (packlen+4 > context->m_receiveOfs) +			break; + +		/* Process message */ +		sProcessMessage(context, context->m_receiveBuffer); + +		/* Move packet to front of buffer */ +		memmove(context->m_receiveBuffer, context->m_receiveBuffer+packlen+4, context->m_receiveOfs-packlen-4); +		context->m_receiveOfs -= packlen+4; +	} + +	/* Throw away over-sized packets */ +	if (packlen > USYNERGY_RECEIVE_BUFFER_SIZE) +	{ +		/* Oversized packet, ditch tail end */ +		char buffer[128]; +		sprintf(buffer, "Oversized packet: '%c%c%c%c' (length %d)", context->m_receiveBuffer[4], context->m_receiveBuffer[5], context->m_receiveBuffer[6], context->m_receiveBuffer[7], packlen); +		sTrace(context, buffer); +		num_received = context->m_receiveOfs-4; // 4 bytes for the size field +		while (num_received != packlen) +		{ +			int buffer_left = packlen - num_received; +			int to_receive = buffer_left < USYNERGY_RECEIVE_BUFFER_SIZE ? buffer_left : USYNERGY_RECEIVE_BUFFER_SIZE; +			int ditch_received = 0; +			if (context->m_receiveFunc(context->m_cookie, context->m_receiveBuffer, to_receive, &ditch_received) == USYNERGY_FALSE) +			{ +				/* Receive failed, let's try to reconnect */ +				sTrace(context, "Receive failed, trying to reconnect in a second"); +				sSetDisconnected(context); +				context->m_sleepFunc(context->m_cookie, 1000); +				break; +			} +			else +			{ +				num_received += ditch_received; +			} +		} +		context->m_receiveOfs = 0; +	} +} + + +//--------------------------------------------------------------------------------------------------------------------- +//	Public interface +//--------------------------------------------------------------------------------------------------------------------- + + + +/** +@brief Initialize uSynergy context +**/ +void uSynergyInit(uSynergyContext *context) +{ +	/* Zero memory */ +	memset(context, 0, sizeof(uSynergyContext)); + +	/* Initialize to default state */ +	sSetDisconnected(context); +} + + +/** +@brief Update uSynergy +**/ +void uSynergyUpdate(uSynergyContext *context) +{ +	if (context->m_connected) +	{ +		/* Update context, receive data, call callbacks */ +		sUpdateContext(context); +	} +	else +	{ +		/* Try to connect */ +		if (context->m_connectFunc(context->m_cookie)) +			context->m_connected = USYNERGY_TRUE; +	} +} + + + +/** +@brief Send clipboard data +**/ +void uSynergySendClipboard(uSynergyContext *context, const char *text) +{ +	// Calculate maximum size that will fit in a reply packet +	uint32_t overhead_size =	4 +					/* Message size */ +								4 +					/* Message ID */ +								1 +					/* Clipboard index */ +								4 +					/* Sequence number */ +								4 +					/* Rest of message size (because it's a Synergy string from here on) */ +								4 +					/* Number of clipboard formats */ +								4 +					/* Clipboard format */ +								4;					/* Clipboard data length */ +	uint32_t max_length = USYNERGY_REPLY_BUFFER_SIZE - overhead_size; +	 +	// Clip text to max length +	uint32_t text_length = (uint32_t)strlen(text); +	if (text_length > max_length) +	{ +		char buffer[128]; +		sprintf(buffer, "Clipboard buffer too small, clipboard truncated at %d characters", max_length); +		sTrace(context, buffer); +		text_length = max_length; +	} + +	// Assemble packet +	sAddString(context, "DCLP"); +	sAddUInt8(context, 0);							/* Clipboard index */ +	sAddUInt32(context, context->m_sequenceNumber); +	sAddUInt32(context, 4+4+4+text_length);			/* Rest of message size: numFormats, format, length, data */ +	sAddUInt32(context, 1);							/* Number of formats (only text for now) */ +	sAddUInt32(context, USYNERGY_CLIPBOARD_FORMAT_TEXT); +	sAddUInt32(context, text_length); +	sAddString(context, text); +	sSendReply(context); +} diff --git a/lib/imgui-1.90.7/examples/libs/usynergy/uSynergy.h b/lib/imgui-1.90.7/examples/libs/usynergy/uSynergy.h new file mode 100644 index 0000000..2d7f9fa --- /dev/null +++ b/lib/imgui-1.90.7/examples/libs/usynergy/uSynergy.h @@ -0,0 +1,420 @@ +/* +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 occurred. 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  | 
