added 4 changesets to branch 'refs/remotes/jessicah-github/synergy' old head: e0b88faae29e4f09ce24b8c16182d4a0a739b518 new head: 81423a30f7034de7790bb5ae451a6cb2434be37f overview: https://github.com/jessicah/haiku/compare/e0b88fa...81423a3 ---------------------------------------------------------------------------- bd3ce77: synergy: handle CBYE command * this enables the client to reconnect to the server after it has been shutdown and later restarted; this fixes an issue where Haiku would lose the connection to a Windows server when the screen is locked accad32: synergy: correct line endings to LF fded361: synergy: don't leak the BNotification and BBitmap objects 81423a3: synergy: major cleanup/refactor [ Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx> ] ---------------------------------------------------------------------------- 4 files changed, 902 insertions(+), 911 deletions(-) .../devices/synergy/haiku-usynergy.cpp | 420 +++--- .../devices/synergy/haiku-usynergy.h | 107 +- .../input_server/devices/synergy/uSynergy.c | 1279 +++++++++--------- .../input_server/devices/synergy/uSynergy.h | 7 +- ############################################################################ Commit: bd3ce7761d1230db334c0860b9cb093293315d73 Author: Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx> Date: Wed Oct 1 05:57:12 2014 UTC synergy: handle CBYE command * this enables the client to reconnect to the server after it has been shutdown and later restarted; this fixes an issue where Haiku would lose the connection to a Windows server when the screen is locked ---------------------------------------------------------------------------- diff --git a/src/add-ons/input_server/devices/synergy/uSynergy.c b/src/add-ons/input_server/devices/synergy/uSynergy.c index 8ebbd46..7b0eb56 100644 --- a/src/add-ons/input_server/devices/synergy/uSynergy.c +++ b/src/add-ons/input_server/devices/synergy/uSynergy.c @@ -167,6 +167,19 @@ static void sSendMouseCallback(uSynergyContext *context) /** +@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 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) @@ -428,6 +441,13 @@ static void sProcessMessage(uSynergyContext *context, const uint8_t *message) parse_msg += size; } } + else if (USYNERGY_IS_PACKET("CBYE")) + { + // Server is closing connection + sSetDisconnected(context); + sTrace(context, "Server has quit"); + return; + } else { // Unknown packet, could be any of these @@ -456,19 +476,6 @@ static void sProcessMessage(uSynergyContext *context, const uint8_t *message) -/** -@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 ############################################################################ Commit: accad320891683c860b596775e454c5417d95319 Author: Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx> Date: Wed Oct 1 05:59:31 2014 UTC synergy: correct line endings to LF ---------------------------------------------------------------------------- diff --git a/src/add-ons/input_server/devices/synergy/uSynergy.c b/src/add-ons/input_server/devices/synergy/uSynergy.c index 7b0eb56..d745258 100644 --- a/src/add-ons/input_server/devices/synergy/uSynergy.c +++ b/src/add-ons/input_server/devices/synergy/uSynergy.c @@ -1,643 +1,643 @@ -/* -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 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 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 if (USYNERGY_IS_PACKET("CBYE")) - { - // Server is closing connection - sSetDisconnected(context); - sTrace(context, "Server has quit"); - return; - } - 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 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); -} +/* +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 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 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 if (USYNERGY_IS_PACKET("CBYE")) + { + // Server is closing connection + sSetDisconnected(context); + sTrace(context, "Server has quit"); + return; + } + 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 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); +} ############################################################################ Commit: fded36137d2ccdf30f756a48a42ea17dd41b11ad Author: Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx> Date: Wed Oct 1 06:47:27 2014 UTC synergy: don't leak the BNotification and BBitmap objects ---------------------------------------------------------------------------- diff --git a/src/add-ons/input_server/devices/synergy/haiku-usynergy.cpp b/src/add-ons/input_server/devices/synergy/haiku-usynergy.cpp index 69d3da6..6b0a3cf 100644 --- a/src/add-ons/input_server/devices/synergy/haiku-usynergy.cpp +++ b/src/add-ons/input_server/devices/synergy/haiku-usynergy.cpp @@ -1,6 +1,7 @@ #include <Application.h> #include <Autolock.h> +#include <Bitmap.h> #include <Clipboard.h> #include <FindDirectory.h> #include <Mime.h> @@ -385,18 +386,19 @@ uSynergyGetTimeHaiku() void uSynergyTraceHaiku(uSynergyCookie cookie, const char *text) { - BNotification *notify = new BNotification(B_INFORMATION_NOTIFICATION); + BNotification notify(B_INFORMATION_NOTIFICATION); BString group("Synergy"); BString content(text); - notify->SetGroup(group); - notify->SetContent(content); + notify.SetGroup(group); + notify.SetContent(content); BBitmap* bitmap = BTranslationUtils::GetBitmap("/boot/home/config/non-packaged/data/synergy-32.png"); if (bitmap != NULL) - notify->SetIcon(bitmap); + notify.SetIcon(bitmap); else TRACE("synergy: couldn't load bitmap\n"); - notify->Send(); + notify.Send(); + delete bitmap; } void ############################################################################ Commit: 81423a30f7034de7790bb5ae451a6cb2434be37f Author: Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx> Date: Wed Oct 1 10:47:19 2014 UTC synergy: major cleanup/refactor ---------------------------------------------------------------------------- diff --git a/src/add-ons/input_server/devices/synergy/haiku-usynergy.cpp b/src/add-ons/input_server/devices/synergy/haiku-usynergy.cpp index 6b0a3cf..591df07 100644 --- a/src/add-ons/input_server/devices/synergy/haiku-usynergy.cpp +++ b/src/add-ons/input_server/devices/synergy/haiku-usynergy.cpp @@ -1,4 +1,20 @@ - +/* + * Copyright (c) + * 2014 Ed Robbins <edd.robbins@xxxxxxxxx> + * 2014 Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ #include <Application.h> #include <Autolock.h> #include <Bitmap.h> @@ -31,60 +47,88 @@ #include "haiku-usynergy.h" -#define FILE_UPDATED 'fiUp' - #define TRACE_SYNERGY_DEVICE #ifdef TRACE_SYNERGY_DEVICE - -# define CALLED(x...) \ - debug_printf("%s:%s\n", "SynergyDevice", __FUNCTION__) # define TRACE(x...) \ do { debug_printf(x); } while (0) -# define LOG_EVENT(text...) debug_printf(text) -# define LOG_ERR(text...) TRACE(text) #else # define TRACE(x...) do {} while (0) -# define CALLED(x...) TRACE(x) -# define LOG_ERR(text...) debug_printf(text) -# define LOG_EVENT(text...) TRACE(x) #endif +#define FILE_UPDATED 'fiUp' + const static uint32 kSynergyThreadPriority = B_FIRST_REAL_TIME_PRIORITY + 4; +#define _U uSynergyInputServerDevice +static bool uConnect(_U* device) { + return device->Connect(); +} +static bool uSend(_U* device, const uint8* buffer, int length) { + return device->Send(buffer, length); +} +static bool uReceive(_U* device, uint8* buffer, int maxLength, int* outLength) { + return device->Receive(buffer, maxLength, outLength); +} +static void uSleep(void* unused, int milliseconds) { + snooze(milliseconds * 1000); +} +static uint32_t uGetTime() { + return system_time() / 1000; +} +static void uTrace(_U* device, const char* text) { + device->Trace(text); +} +static void uScreenActive(_U* device, bool active) { + device->ScreenActive(active); +} +static void uMouseCallback(_U* device, uint16 x, uint16 y, int16 wheelX, int16 wheelY, bool buttonLeft, bool buttonRight, bool buttonMiddle) { + device->MouseCallback(x, y, wheelX, wheelY, buttonLeft, buttonRight, buttonMiddle); +} +static void uKeyboardCallback(_U* device, uint16 key, uint16 modifiers, bool isKeyDown, bool isKeyRepeat) { + device->KeyboardCallback(key, modifiers, isKeyDown, isKeyRepeat); +} +static void uJoystickCallback(_U* device, uint8_t joyNum, uint16_t buttons, int8_t leftStickX, int8_t leftStickY, int8_t rightStickX, int8_t rightStickY) { + device->JoystickCallback(joyNum, buttons, leftStickX, leftStickY, rightStickX, rightStickY); +} +static void uClipboardCallback(_U* device, enum uSynergyClipboardFormat format, const uint8_t* data, uint32_t size) { + device->ClipboardCallback(format, data, size); +} +#undef _U + + uSynergyInputServerDevice::uSynergyInputServerDevice() : BHandler("uSynergy Handler"), threadActive(false), - uSynergyHaikuContext(NULL), - synergyServerSocket(-1), + fContext(NULL), + fSocket(-1), fEnableSynergy(false), fServerAddress(NULL), fUpdateSettings(false), fKeymapLock("synergy keymap lock") { - CALLED(); - uSynergyHaikuContext = (uSynergyContext*)malloc(sizeof(uSynergyContext)); - uSynergyInit(uSynergyHaikuContext); - - uSynergyHaikuContext->m_connectFunc = uSynergyConnectHaiku; - uSynergyHaikuContext->m_receiveFunc = uSynergyReceiveHaiku; - uSynergyHaikuContext->m_sendFunc = uSynergySendHaiku; - uSynergyHaikuContext->m_getTimeFunc = uSynergyGetTimeHaiku; - uSynergyHaikuContext->m_screenActiveCallback = uSynergyScreenActiveCallbackHaiku; - uSynergyHaikuContext->m_mouseCallback = uSynergyMouseCallbackHaiku; - uSynergyHaikuContext->m_keyboardCallback = uSynergyKeyboardCallbackHaiku; - uSynergyHaikuContext->m_sleepFunc = uSynergySleepHaiku; - uSynergyHaikuContext->m_traceFunc = uSynergyTraceHaiku; - uSynergyHaikuContext->m_joystickCallback = uSynergyJoystickCallbackHaiku; - uSynergyHaikuContext->m_clipboardCallback = uSynergyClipboardCallbackHaiku; - uSynergyHaikuContext->m_clientName = "haiku"; - uSynergyHaikuContext->m_cookie = (uSynergyCookie)this; + fContext = (uSynergyContext*)malloc(sizeof(uSynergyContext)); + uSynergyInit(fContext); + + fContext->m_connectFunc = &uConnect; + fContext->m_receiveFunc = &uReceive; + fContext->m_sendFunc = &uSend; + fContext->m_getTimeFunc = &uGetTime; + fContext->m_screenActiveCallback = &uScreenActive; + fContext->m_mouseCallback = &uMouseCallback; + fContext->m_keyboardCallback = &uKeyboardCallback; + fContext->m_sleepFunc = &uSleep; + fContext->m_traceFunc = &uTrace; + fContext->m_joystickCallback = &uJoystickCallback; + fContext->m_clipboardCallback = &uClipboardCallback; + fContext->m_clientName = "haiku"; + fContext->m_cookie = (uSynergyCookie)this; BRect screenRect = BScreen().Frame(); - uSynergyHaikuContext->m_clientWidth = (uint16_t)screenRect.Width() + 1; - uSynergyHaikuContext->m_clientHeight = (uint16_t)screenRect.Height() + 1; + fContext->m_clientWidth = (uint16_t)screenRect.Width() + 1; + fContext->m_clientHeight = (uint16_t)screenRect.Height() + 1; if (be_app->Lock()) { be_app->AddHandler(this); @@ -93,7 +137,7 @@ uSynergyInputServerDevice::uSynergyInputServerDevice() BPath path; if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) - path.Append("kernel/drivers/synergy"); + path.Append("synergy_settings"); fFilename = new char[strlen(path.Path()) + 1]; strcpy(fFilename, path.Path()); @@ -103,19 +147,23 @@ uSynergyInputServerDevice::uSynergyInputServerDevice() BPrivate::BPathMonitor::StartWatching(fFilename, B_WATCH_STAT | B_WATCH_FILES_ONLY, this); _UpdateSettings(); - - TRACE("synergy: monitoring settings file at '%s'\n", fFilename); } + uSynergyInputServerDevice::~uSynergyInputServerDevice() { - free(uSynergyHaikuContext); + if (be_app->Lock()) { + be_app->RemoveHandler(this); + be_app->Unlock(); + } + + free(fContext); } + status_t uSynergyInputServerDevice::InitCheck() { - CALLED(); input_device_ref *devices[3]; input_device_ref mouse = { "uSynergy Mouse", B_POINTING_DEVICE, (void *)this }; @@ -130,10 +178,10 @@ uSynergyInputServerDevice::InitCheck() return B_OK; } + void uSynergyInputServerDevice::MessageReceived(BMessage* message) { - CALLED(); switch (message->what) { case B_PATH_MONITOR: { @@ -165,7 +213,7 @@ uSynergyInputServerDevice::MessageReceived(BMessage* message) be_clipboard->Unlock(); } if (len > 0 && text != NULL) { - uSynergySendClipboard(this->uSynergyHaikuContext, text); + uSynergySendClipboard(fContext, text); TRACE("synergy: data added to clipboard\n"); } else TRACE("synergy: couldn't add data to clipboard\n"); @@ -175,12 +223,14 @@ uSynergyInputServerDevice::MessageReceived(BMessage* message) } } + status_t uSynergyInputServerDevice::Start(const char* name, void* cookie) { - CALLED(); - if (fServerAddress == NULL || fEnableSynergy == false) + if (fServerAddress.Length() == 0 || fEnableSynergy == false) { + TRACE("synergy: not enabled, or no server specified\n"); return B_NO_ERROR; + } status_t status = B_OK; char threadName[B_OS_NAME_LENGTH]; @@ -189,11 +239,11 @@ uSynergyInputServerDevice::Start(const char* name, void* cookie) TRACE("synergy: thread active = %d\n", threadActive); if ((atomic_get_and_set((int32*)&threadActive, true) & true) == true) { - TRACE("synergy: skipping thread spawn\n"); - goto clean; + TRACE("synergy: main thread already running\n"); + return B_OK; } - uSynergyThread = spawn_thread(uSynergyThreadLoop, threadName, kSynergyThreadPriority, (void*)this->uSynergyHaikuContext); + uSynergyThread = spawn_thread(_MainLoop, threadName, kSynergyThreadPriority, (void*)this); if (uSynergyThread < 0) { threadActive = false; @@ -202,34 +252,31 @@ uSynergyInputServerDevice::Start(const char* name, void* cookie) } else { be_clipboard->StartWatching(this); status = resume_thread(uSynergyThread); - TRACE("synergy: spawned uSynergyThreadLoop!\n"); } -clean: + return status; } + status_t uSynergyInputServerDevice::Stop(const char* name, void* cookie) { - CALLED(); threadActive = false; // this will stop the thread as soon as it reads the next packet be_clipboard->StopWatching(this); if (uSynergyThread >= 0) { // unblock the thread, which might wait on a semaphore. - TRACE("synergy: asking thread to stop...\n"); suspend_thread(uSynergyThread); resume_thread(uSynergyThread); status_t dummy; wait_for_thread(uSynergyThread, &dummy); - uSynergyThread = -1; - TRACE("synergy: all stopped\n"); } return B_OK; } + status_t uSynergyInputServerDevice::SystemShuttingDown() { @@ -238,6 +285,7 @@ uSynergyInputServerDevice::SystemShuttingDown() return B_OK; } + status_t uSynergyInputServerDevice::Control(const char* name, void* cookie, uint32 command, BMessage* message) { @@ -249,24 +297,28 @@ uSynergyInputServerDevice::Control(const char* name, void* cookie, uint32 comman return B_BAD_VALUE; } -BMessage* -uSynergyInputServerDevice::_BuildMouseMessage(uint32 what, uint64 when, uint32 buttons, float x, float y) const + +status_t +uSynergyInputServerDevice::_MainLoop(void* arg) { - BMessage* message = new BMessage(what); - if (message == NULL) - return NULL; + uSynergyInputServerDevice *inputDevice = (uSynergyInputServerDevice*)arg; - if (message->AddInt64("when", when) < B_OK - || message->AddInt32("buttons", buttons) < B_OK - || message->AddFloat("x", x) < B_OK - || message->AddFloat("y", y) < B_OK) { - delete message; - return NULL; + while (inputDevice->threadActive) { + uSynergyUpdate(inputDevice->fContext); + + if (inputDevice->fUpdateSettings) { + inputDevice->_UpdateSettings(); + inputDevice->fUpdateSettings = false; + } } - return message; + close(inputDevice->fSocket); + inputDevice->fSocket = -1; + + return B_OK; } + void uSynergyInputServerDevice::_UpdateSettings() { @@ -276,115 +328,71 @@ uSynergyInputServerDevice::_UpdateSettings() fControlKey = fKeymap.KeyForModifier(B_LEFT_CONTROL_KEY); fCommandKey = fKeymap.KeyForModifier(B_LEFT_COMMAND_KEY); - void* handle = load_driver_settings("synergy"); + void* handle = load_driver_settings(fFilename); if (handle == NULL) return; fEnableSynergy = get_driver_boolean_parameter(handle, "enable", false, false); - const char *server = get_driver_parameter(handle, "server", NULL, NULL); - TRACE("synergy: settings: enable = %s, server = %s\n", fEnableSynergy ? "yes" : "no", server == NULL ? "(null)" : server); - if (server != NULL) - fServerAddress.SetTo(server); + fServerAddress = get_driver_parameter(handle, "server", NULL, NULL); unload_driver_settings(handle); } -status_t -uSynergyInputServerDevice::uSynergyThreadLoop(void* arg) -{ - uSynergyContext *uSynergyHaikuContext = (uSynergyContext*)arg; - uSynergyInputServerDevice *inputDevice = (uSynergyInputServerDevice*)uSynergyHaikuContext->m_cookie; - - while (inputDevice->threadActive) { - uSynergyUpdate(uSynergyHaikuContext); - if (inputDevice->fUpdateSettings) { - inputDevice->_UpdateSettings(); - inputDevice->fUpdateSettings = false; - } - } - - TRACE("synergy: exiting thread loop\n"); - - close(inputDevice->synergyServerSocket); - inputDevice->synergyServerSocket = -1; - - return B_OK; -} - - -uSynergyBool -uSynergyConnectHaiku(uSynergyCookie cookie) +bool +uSynergyInputServerDevice::Connect() { - CALLED(); - uSynergyInputServerDevice *inputDevice = (uSynergyInputServerDevice*)cookie; - - if (inputDevice->fServerAddress.Length() == 0 || inputDevice->fEnableSynergy == false) + if (fServerAddress.Length() == 0 || fEnableSynergy == false) goto exit; struct sockaddr_in server; server.sin_family = AF_INET; server.sin_port = htons(24800); - inet_aton(inputDevice->fServerAddress.String(), &server.sin_addr); - TRACE("synergy: connecting to %s:%d\n", inputDevice->fServerAddress.String(), 24800); + inet_aton(fServerAddress.String(), &server.sin_addr); - inputDevice->synergyServerSocket = socket(PF_INET, SOCK_STREAM, 0); + TRACE("synergy: connecting to %s:%d\n", fServerAddress.String(), 24800); - if (inputDevice->synergyServerSocket < 0) { + fSocket = socket(PF_INET, SOCK_STREAM, 0); + if (fSocket < 0) { TRACE("synergy: socket couldn't be created\n"); goto exit; } - if (connect(inputDevice->synergyServerSocket, (struct sockaddr*)&server, sizeof(struct sockaddr)) < 0 ) { - TRACE("synergy: %s: %d\n", "failed to connect to remote host", errno); - close(inputDevice->synergyServerSocket); - inputDevice->synergyServerSocket = -1; + if (connect(fSocket, (struct sockaddr*)&server, sizeof(struct sockaddr)) < 0 ) { + TRACE("synergy: %s: %x\n", "failed to connect to remote host", errno); + close(fSocket); + fSocket = -1; goto exit; } - else { - TRACE("synergy: connected to remote host!!!\n"); - return USYNERGY_TRUE; - } + else + return true; exit: snooze(1000000); - return USYNERGY_FALSE; + return false; } -uSynergyBool -uSynergySendHaiku(uSynergyCookie cookie, const uint8_t *buffer, int length) -{ - uSynergyInputServerDevice *inputDevice = (uSynergyInputServerDevice*)cookie; - - if (send(inputDevice->synergyServerSocket, buffer, length, 0) != length) - return USYNERGY_FALSE; - return USYNERGY_TRUE; -} -uSynergyBool -uSynergyReceiveHaiku(uSynergyCookie cookie, uint8_t *buffer, int maxLength, int* outLength) +bool +uSynergyInputServerDevice::Send(const uint8_t* buffer, int32_t length) { - uSynergyInputServerDevice *inputDevice = (uSynergyInputServerDevice*)cookie; - - if ((*outLength = recv(inputDevice->synergyServerSocket, buffer, maxLength, 0)) == -1) - return USYNERGY_FALSE; - return USYNERGY_TRUE; + if (send(fSocket, buffer, length, 0) != length) + return false; + return true; } -void -uSynergySleepHaiku(uSynergyCookie cookie, int timeMs) -{ - snooze(timeMs * 1000); -} -uint32_t -uSynergyGetTimeHaiku() +bool +uSynergyInputServerDevice::Receive(uint8_t *buffer, int maxLength, int* outLength) { - return system_time() / 1000; // return milliseconds, not microseconds + if ((*outLength = recv(fSocket, buffer, maxLength, 0)) == -1) + return false; + return true; } + void -uSynergyTraceHaiku(uSynergyCookie cookie, const char *text) +uSynergyInputServerDevice::Trace(const char *text) { BNotification notify(B_INFORMATION_NOTIFICATION); BString group("Synergy"); @@ -395,29 +403,46 @@ uSynergyTraceHaiku(uSynergyCookie cookie, const char *text) BBitmap* bitmap = BTranslationUtils::GetBitmap("/boot/home/config/non-packaged/data/synergy-32.png"); if (bitmap != NULL) notify.SetIcon(bitmap); - else - TRACE("synergy: couldn't load bitmap\n"); notify.Send(); delete bitmap; } + void -uSynergyScreenActiveCallbackHaiku(uSynergyCookie cookie, uSynergyBool active) +uSynergyInputServerDevice::ScreenActive(bool active) +{ +} + + +BMessage* +uSynergyInputServerDevice::_BuildMouseMessage(uint32 what, uint64 when, uint32 buttons, float x, float y) const { + BMessage* message = new BMessage(what); + if (message == NULL) + return NULL; + if (message->AddInt64("when", when) < B_OK + || message->AddInt32("buttons", buttons) < B_OK + || message->AddFloat("x", x) < B_OK + || message->AddFloat("y", y) < B_OK) { + delete message; + return NULL; + } + + return message; } + void -uSynergyMouseCallbackHaiku(uSynergyCookie cookie, uint16_t x, uint16_t y, int16_t wheelX, int16_t wheelY, uSynergyBool buttonLeft, uSynergyBool buttonRight, uSynergyBool buttonMiddle) +uSynergyInputServerDevice::MouseCallback(uint16_t x, uint16_t y, int16_t wheelX, int16_t wheelY, uSynergyBool buttonLeft, uSynergyBool buttonRight, uSynergyBool buttonMiddle) { - uSynergyInputServerDevice *inputDevice = (uSynergyInputServerDevice*)cookie; static uint32_t oldButtons = 0, oldPressedButtons = 0; uint32_t buttons = 0; static uint16_t oldX = 0, oldY = 0, clicks = 0; static int16_t oldWheelX = 0, oldWheelY = 0; static uint64 oldWhen = system_time(); - float xVal = (float)x / (float)inputDevice->uSynergyHaikuContext->m_clientWidth; - float yVal = (float)y / (float)inputDevice->uSynergyHaikuContext->m_clientHeight; + float xVal = (float)x / (float)fContext->m_clientWidth; + float yVal = (float)y / (float)fContext->m_clientHeight; int64 timestamp = system_time(); @@ -433,7 +458,7 @@ uSynergyMouseCallbackHaiku(uSynergyCookie cookie, uint16_t x, uint16_t y, int16_ if (buttons != oldButtons) { bool pressedButton = buttons > 0; - BMessage* message = inputDevice->_BuildMouseMessage(pressedButton ? B_MOUSE_DOWN : B_MOUSE_UP, timestamp, buttons, xVal, yVal); + BMessage* message = _BuildMouseMessage(pressedButton ? B_MOUSE_DOWN : B_MOUSE_UP, timestamp, buttons, xVal, yVal); if (pressedButton) { if ((buttons == oldPressedButtons) && ((timestamp - oldWhen) < 500000)) clicks++; @@ -447,15 +472,15 @@ uSynergyMouseCallbackHaiku(uSynergyCookie cookie, uint16_t x, uint16_t y, int16_ clicks = 1; if (message != NULL) - inputDevice->EnqueueMessage(message); + EnqueueMessage(message); oldButtons = buttons; } if ((x != oldX) || (y != oldY)) { - BMessage* message = inputDevice->_BuildMouseMessage(B_MOUSE_MOVED, timestamp, buttons, xVal, yVal); + BMessage* message = _BuildMouseMessage(B_MOUSE_MOVED, timestamp, buttons, xVal, yVal); if (message != NULL) - inputDevice->EnqueueMessage(message); + EnqueueMessage(message); oldX = x; oldY = y; } @@ -466,7 +491,7 @@ uSynergyMouseCallbackHaiku(uSynergyCookie cookie, uint16_t x, uint16_t y, int16_ if (message->AddInt64("when", timestamp) == B_OK && message->AddFloat("be:wheel_delta_x", (oldWheelX - wheelX) / 120) == B_OK && message->AddFloat("be:wheel_delta_y", (oldWheelY - wheelY) / 120) == B_OK) - inputDevice->EnqueueMessage(message); + EnqueueMessage(message); else delete message; } @@ -475,36 +500,16 @@ uSynergyMouseCallbackHaiku(uSynergyCookie cookie, uint16_t x, uint16_t y, int16_ } } -/* Synergy modifier definitions */ -#define SYNERGY_SHIFT 0x0001 -#define SYNERGY_CONTROL 0x0002 -#define SYNERGY_ALT 0x0004 -#define SYNERGY_META 0x0008 -#define SYNERGY_SUPER 0x0010 -#define SYNERGY_ALTGR 0x0020 -#define SYNERGY_LEVEL5LOCK 0x0040 -#define SYNERGY_CAPSLOCK 0x1000 -#define SYNERGY_NUMLOCK 0x2000 -#define SYNERGY_SCROLLLOCK 0x4000 -#define EXTENDED_KEY 0xe000 void -uSynergyInputServerDevice::_ProcessKeyboard(uint16_t scancode, uint16_t _modifiers, bool isKeyDown, bool isKeyRepeat) +uSynergyInputServerDevice::KeyboardCallback(uint16_t scancode, uint16_t _modifiers, bool isKeyDown, bool isKeyRepeat) { static uint32 lastScanCode = 0; static uint32 repeatCount = 1; static uint8 states[16]; - bool isExtended = false; - - if (scancode & EXTENDED_KEY != 0) { - isExtended = true; - TRACE("synergy: extended key\n"); - } - int64 timestamp = system_time(); - TRACE("synergy: scancode = 0x%02x\n", scancode); uint32_t keycode = 0; if (scancode > 0 && scancode < sizeof(kATKeycodeMap)/sizeof(uint32)) keycode = kATKeycodeMap[scancode - 1]; @@ -513,7 +518,8 @@ uSynergyInputServerDevice::_ProcessKeyboard(uint16_t scancode, uint16_t _modifie if (scancode > 0 && scancode < sizeof(kATKeycodeMap)/sizeof(uint32)) keycode = kATKeycodeMap[scancode - 1]; } - TRACE("synergy: keycode = 0x%x\n", keycode); + + TRACE("synergy: scancode = 0x%02x, keycode = 0x%x\n", scancode, keycode); if (keycode < 256) { if (isKeyDown) @@ -522,45 +528,34 @@ uSynergyInputServerDevice::_ProcessKeyboard(uint16_t scancode, uint16_t _modifie states[(keycode) >> 3] &= (!(1 << (7 - (keycode & 0x7)))); } +#if false if (isKeyDown && keycode == 0x34 // DELETE KEY && (states[fCommandKey >> 3] & (1 << (7 - (fCommandKey & 0x7)))) && (states[fControlKey >> 3] & (1 << (7 - (fControlKey & 0x7))))) { TRACE("synergy: TeamMonitor called\n"); } +#endif uint32 modifiers = 0; - //TRACE("synergy: modifiers: "); - if (_modifiers & SYNERGY_SHIFT) { - // TRACE("SHIFT "); + + if (_modifiers & USYNERGY_MODIFIER_SHIFT) modifiers |= B_SHIFT_KEY | B_LEFT_SHIFT_KEY; - } - if (_modifiers & SYNERGY_CONTROL) { - // TRACE("CONTROL "); + if (_modifiers & USYNERGY_MODIFIER_CTRL) modifiers |= B_CONTROL_KEY | B_LEFT_CONTROL_KEY; - } - if (_modifiers & SYNERGY_ALT) { - // TRACE("COMMAND(ALT) "); + if (_modifiers & USYNERGY_MODIFIER_ALT) modifiers |= B_COMMAND_KEY | B_LEFT_COMMAND_KEY; - } - if (_modifiers & SYNERGY_META) { - // TRACE("MENU(META) "); + if (_modifiers & USYNERGY_MODIFIER_META) modifiers |= B_MENU_KEY; - } - if (_modifiers & SYNERGY_SUPER) { - // TRACE("OPTION(SUPER) "); + if (_modifiers & USYNERGY_MODIFIER_WIN) modifiers |= B_OPTION_KEY | B_LEFT_OPTION_KEY; - } - if (_modifiers & SYNERGY_ALTGR) { - // TRACE("RIGHT_OPTION(ALTGR) "); + if (_modifiers & USYNERGY_MODIFIER_ALT_GR) modifiers |= B_RIGHT_OPTION_KEY | B_OPTION_KEY; - } - if (_modifiers & SYNERGY_CAPSLOCK) + if (_modifiers & USYNERGY_MODIFIER_CAPSLOCK) modifiers |= B_CAPS_LOCK; - if (_modifiers & SYNERGY_NUMLOCK) + if (_modifiers & USYNERGY_MODIFIER_NUMLOCK) modifiers |= B_NUM_LOCK; - if (_modifiers & SYNERGY_SCROLLLOCK) + if (_modifiers & USYNERGY_MODIFIER_SCROLLOCK) modifiers |= B_SCROLL_LOCK; - //TRACE("\n"); //bool isLock // = (modifiers & (B_CAPS_LOCK | B_NUM_LOCK | B_SCROLL_LOCK)) != 0; @@ -591,10 +586,8 @@ uSynergyInputServerDevice::_ProcessKeyboard(uint16_t scancode, uint16_t _modifie } } - if (scancode == 0 || scancode == EXTENDED_KEY) { - TRACE("empty scancode\n"); + if (scancode == 0) return; - } BMessage* msg = new BMessage; if (msg == NULL) @@ -649,30 +642,26 @@ uSynergyInputServerDevice::_ProcessKeyboard(uint16_t scancode, uint16_t _modifie lastScanCode = isKeyDown ? scancode : 0; } -void -uSynergyKeyboardCallbackHaiku(uSynergyCookie cookie, uint16_t key, uint16_t modifiers, uSynergyBool down, uSynergyBool repeat) -{ - ((uSynergyInputServerDevice*)cookie)->_ProcessKeyboard(key, modifiers, down, repeat); -} void -uSynergyJoystickCallbackHaiku(uSynergyCookie cookie, uint8_t joyNum, uint16_t buttons, int8_t leftStickX, int8_t leftStickY, int8_t rightStickX, int8_t rightStickY) +uSynergyInputServerDevice::JoystickCallback(uint8_t joyNum, uint16_t buttons, int8_t leftStickX, int8_t leftStickY, int8_t rightStickX, int8_t rightStickY) { - } + void -uSynergyInputServerDevice::_PostClipboard(const BString &mimetype, const uint8_t *data, uint32_t size) +uSynergyInputServerDevice::ClipboardCallback(enum uSynergyClipboardFormat format, const uint8_t *data, uint32_t size) { + if (format != USYNERGY_CLIPBOARD_FORMAT_TEXT) + return; + if (be_clipboard->Lock()) { be_clipboard->Clear(); BMessage *clip = be_clipboard->Data(); - clip->AddData(mimetype, B_MIME_TYPE, data, size); + clip->AddData("text/plain", B_MIME_TYPE, data, size); status_t result = be_clipboard->Commit(); - if (result != B_OK) { + if (result != B_OK) TRACE("synergy: failed to commit data to clipboard\n"); - } else - TRACE("synergy: received clipboard data\n"); be_clipboard->Unlock(); } else { @@ -680,13 +669,6 @@ uSynergyInputServerDevice::_PostClipboard(const BString &mimetype, const uint8_t } } -void -uSynergyClipboardCallbackHaiku(uSynergyCookie cookie, enum uSynergyClipboardFormat format, const uint8_t *data, uint32_t size) -{ - if (format == USYNERGY_CLIPBOARD_FORMAT_TEXT) - ((uSynergyInputServerDevice*)cookie)->_PostClipboard("text/plain", data, size); -} - extern "C" BInputServerDevice* instantiate_input_device() diff --git a/src/add-ons/input_server/devices/synergy/haiku-usynergy.h b/src/add-ons/input_server/devices/synergy/haiku-usynergy.h index cd33342..bfc8fe5 100644 --- a/src/add-ons/input_server/devices/synergy/haiku-usynergy.h +++ b/src/add-ons/input_server/devices/synergy/haiku-usynergy.h @@ -1,10 +1,24 @@ /* - * Copyright 2004-2008, Haiku. - * Distributed under the terms of the MIT License. + * Copyright (c) + * 2014 Ed Robbins <edd.robbins@xxxxxxxxx> + * 2014 Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx> * - * Authors: - * Stefano Ceccherini + * Based on MouseInputDevice.h by + * Stefano Ceccherini Copyright 2004-2008, Haiku + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + #ifndef USYNERGY_H #define USYNERGY_H @@ -18,72 +32,53 @@ #include "uSynergy.h" -uSynergyBool uSynergyConnectHaiku(uSynergyCookie cookie); -uSynergyBool uSynergySendHaiku(uSynergyCookie cookie, const uint8_t *buffer, int length); -uSynergyBool uSynergyReceiveHaiku(uSynergyCookie cookie, uint8_t *buffer, int maxLength, int* outLength); -void uSynergySleepHaiku(uSynergyCookie cookie, int timeMs); -uint32_t uSynergyGetTimeHaiku(); -void uSynergyTraceHaiku(uSynergyCookie cookie, const char *text); -void uSynergyScreenActiveCallbackHaiku(uSynergyCookie cookie, uSynergyBool active); -void uSynergyMouseCallbackHaiku(uSynergyCookie cookie, uint16_t x, uint16_t y, int16_t wheelX, int16_t wheelY, uSynergyBool buttonLeft, uSynergyBool buttonRight, uSynergyBool buttonMiddle); -void uSynergyKeyboardCallbackHaiku(uSynergyCookie cookie, uint16_t key, uint16_t modifiers, uSynergyBool down, uSynergyBool repeat); -void uSynergyJoystickCallbackHaiku(uSynergyCookie cookie, uint8_t joyNum, uint16_t buttons, int8_t leftStickX, int8_t leftStickY, int8_t rightStickX, int8_t rightStickY); -void uSynergyClipboardCallbackHaiku(uSynergyCookie cookie, enum uSynergyClipboardFormat format, const uint8_t *data, uint32_t size); - class uSynergyInputServerDevice : public BHandler, public BInputServerDevice { public: - uSynergyInputServerDevice(); - virtual ~uSynergyInputServerDevice(); + uSynergyInputServerDevice(); + virtual ~uSynergyInputServerDevice(); - virtual status_t InitCheck(); + virtual status_t InitCheck(); - virtual void MessageReceived(BMessage* message); - virtual status_t Start(const char* name, void* cookie); - virtual status_t Stop(const char* name, void* cookie); - virtual status_t SystemShuttingDown(); + virtual status_t Control(const char* name, void* cookie, uint32 command, BMessage* message); + virtual status_t Start(const char* name, void* cookie); + virtual status_t Stop(const char* name, void* cookie); + virtual status_t SystemShuttingDown(); + virtual void MessageReceived(BMessage* message); + + // Synergy Hooks + bool Connect(); + bool Send(const uint8_t* buffer, int32_t length); + bool Receive(uint8_t* buffer, int maxLength, int* outLength); + void Trace(const char* text); + void ScreenActive(bool active); + void MouseCallback(uint16_t x, uint16_t y, int16_t wheelX, int16_t wheelY, bool buttonLeft, bool buttonRight, bool buttonMiddle); + void KeyboardCallback(uint16_t key, uint16_t modifiers, bool isKeyDown, bool isKeyRepeat); + void JoystickCallback(uint8_t joyNum, uint16_t buttons, int8_t leftStickX, int8_t leftStickY, int8_t rightStickX, int8_t rightStickY); + void ClipboardCallback(enum uSynergyClipboardFormat format, const uint8_t* data, uint32_t size); - virtual status_t Control(const char* name, void* cookie, uint32 command, BMessage* message); private: - bool threadActive; - thread_id uSynergyThread; - uSynergyContext *uSynergyHaikuContext; BMessage* _BuildMouseMessage(uint32 what, uint64 when, uint32 buttons, float x, float y) const; - void _ProcessKeyboard(uint16_t scancode, uint16_t modifiers, bool isKeyDown, bool isKeyRepeat); void _UpdateSettings(); - void _PostClipboard(const BString &mimetype, const uint8_t *data, uint32_t size); - public: - struct sockaddr_in synergyServerData; - int synergyServerSocket; - private: - static status_t uSynergyThreadLoop(void* arg); + static status_t _MainLoop(void* arg); - uint32 fModifiers; - uint32 fCommandKey; - uint32 fControlKey; - char* fFilename; - bool fEnableSynergy; - BString fServerAddress; + bool threadActive; + thread_id uSynergyThread; + uSynergyContext* fContext; + int fSocket; - volatile bool fUpdateSettings; + uint32 fModifiers; + uint32 fCommandKey; + uint32 fControlKey; + char* fFilename; + bool fEnableSynergy; + BString fServerAddress; - Keymap fKeymap; - BLocker fKeymapLock; + volatile bool fUpdateSettings; - public: - /* callbacks for uSynergy */ - friend uSynergyBool uSynergyConnectHaiku(uSynergyCookie cookie); - friend uSynergyBool uSynergySendHaiku(uSynergyCookie cookie, const uint8_t *buffer, int length); - friend uSynergyBool uSynergyReceiveHaiku(uSynergyCookie cookie, uint8_t *buffer, int maxLength, int* outLength); - friend void uSynergySleepHaiku(uSynergyCookie cookie, int timeMs); - friend uint32_t uSynergyGetTimeHaiku(); - friend void uSynergyTraceHaiku(uSynergyCookie cookie, const char *text); - friend void uSynergyScreenActiveCallbackHaiku(uSynergyCookie cookie, uSynergyBool active); - friend void uSynergyMouseCallbackHaiku(uSynergyCookie cookie, uint16_t x, uint16_t y, int16_t wheelX, int16_t wheelY, uSynergyBool buttonLeft, uSynergyBool buttonRight, uSynergyBool buttonMiddle); - friend void uSynergyKeyboardCallbackHaiku(uSynergyCookie cookie, uint16_t key, uint16_t modifiers, uSynergyBool down, uSynergyBool repeat); - friend void uSynergyJoystickCallbackHaiku(uSynergyCookie cookie, uint8_t joyNum, uint16_t buttons, int8_t leftStickX, int8_t leftStickY, int8_t rightStickX, int8_t rightStickY); - friend void uSynergyClipboardCallbackHaiku(uSynergyCookie cookie, enum uSynergyClipboardFormat format, const uint8_t *data, uint32_t size); + Keymap fKeymap; + BLocker fKeymapLock; }; diff --git a/src/add-ons/input_server/devices/synergy/uSynergy.h b/src/add-ons/input_server/devices/synergy/uSynergy.h index 7d3b9a9..b8d58dc 100644 --- a/src/add-ons/input_server/devices/synergy/uSynergy.h +++ b/src/add-ons/input_server/devices/synergy/uSynergy.h @@ -68,10 +68,15 @@ extern "C" { /** @brief Boolean type **/ +#if defined(__cplusplus) +typedef bool uSynergyBool; +#define USYNERGY_FALSE false +#define USYNERGY_TRUE true +#else typedef int uSynergyBool; #define USYNERGY_FALSE 0 /* False value */ #define USYNERGY_TRUE 1 /* True value */ - +#endif /** @brief User context type