Feature to drag a file from Mac (client) to Windows (server):

- temporarily drop dragging file to desktop (specified by command line arg --filetransfer-des)
- on Mac side, fake an esc key while dragging off the screen does not seem to work
This commit is contained in:
jerry 2013-08-30 19:49:38 +00:00
parent af04f8b2ef
commit 43e2535335
18 changed files with 155 additions and 13 deletions

View File

@ -67,7 +67,8 @@ CClient::CClient(IEventQueue* events,
m_connectOnResume(false), m_connectOnResume(false),
m_events(events), m_events(events),
m_cryptoStream(NULL), m_cryptoStream(NULL),
m_crypto(crypto) m_crypto(crypto),
m_sendFileThread(NULL)
{ {
assert(m_socketFactory != NULL); assert(m_socketFactory != NULL);
assert(m_screen != NULL); assert(m_screen != NULL);
@ -108,6 +109,7 @@ CClient::~CClient()
cleanupConnection(); cleanupConnection();
delete m_socketFactory; delete m_socketFactory;
delete m_streamFilterFactory; delete m_streamFilterFactory;
delete m_sendFileThread;
} }
void void
@ -790,7 +792,7 @@ CClient::isReceivedFileSizeValid()
void void
CClient::sendFileToServer(const char* filename) CClient::sendFileToServer(const char* filename)
{ {
CThread* thread = new CThread( m_sendFileThread = new CThread(
new TMethodJob<CClient>( new TMethodJob<CClient>(
this, &CClient::sendFileThread, this, &CClient::sendFileThread,
reinterpret_cast<void*>(const_cast<char*>(filename)))); reinterpret_cast<void*>(const_cast<char*>(filename))));
@ -806,4 +808,13 @@ CClient::sendFileThread(void* filename)
catch (std::runtime_error error) { catch (std::runtime_error error) {
LOG((CLOG_ERR "failed sending file chunks: %s", error.what())); LOG((CLOG_ERR "failed sending file chunks: %s", error.what()));
} }
delete m_sendFileThread;
m_sendFileThread = NULL;
}
void
CClient::draggingInfoSending(UInt32 fileCount, CString& fileList, size_t size)
{
m_server->draggingInfoSending(fileCount, fileList, size);
} }

View File

@ -36,6 +36,7 @@ namespace synergy { class IStream; }
class IStreamFilterFactory; class IStreamFilterFactory;
class IEventQueue; class IEventQueue;
class CCryptoStream; class CCryptoStream;
class CThread;
//! Synergy client //! Synergy client
/*! /*!
@ -111,6 +112,9 @@ public:
//! Set file transder destination //! Set file transder destination
void setFileTransferDes(CString& des) { m_fileTransferDes = des; } void setFileTransferDes(CString& des) { m_fileTransferDes = des; }
//! Send dragging file information back to server
void draggingInfoSending(UInt32 fileCount, CString& fileList, size_t size);
//@} //@}
//! @name accessors //! @name accessors
//@{ //@{
@ -229,6 +233,7 @@ private:
CString m_fileTransferDes; CString m_fileTransferDes;
CDragFileList m_dragFileList; CDragFileList m_dragFileList;
CString m_dragFileExt; CString m_dragFileExt;
CThread* m_sendFileThread;
}; };
#endif #endif

View File

@ -28,7 +28,6 @@
#include "TMethodEventJob.h" #include "TMethodEventJob.h"
#include "XBase.h" #include "XBase.h"
#include <memory> #include <memory>
#include <cstring>
#include "CCryptoStream.h" #include "CCryptoStream.h"
// //
@ -946,3 +945,9 @@ CServerProxy::fileChunkSending(UInt8 mark, char* data, size_t dataSize)
CProtocolUtil::writef(m_stream, kMsgDFileTransfer, mark, &chunk); CProtocolUtil::writef(m_stream, kMsgDFileTransfer, mark, &chunk);
} }
void
CServerProxy::draggingInfoSending(UInt32 fileCount, CString fileList, size_t size)
{
CProtocolUtil::writef(m_stream, kMsgDDragInfo, fileCount, &fileList);
}

View File

@ -23,6 +23,7 @@
#include "KeyTypes.h" #include "KeyTypes.h"
#include "CEvent.h" #include "CEvent.h"
#include "CStopwatch.h" #include "CStopwatch.h"
#include "CString.h"
class CClient; class CClient;
class CClientInfo; class CClientInfo;
@ -54,9 +55,12 @@ public:
//@} //@}
//! sending file chunk to server // sending file chunk to server
void fileChunkSending(UInt8 mark, char* data, size_t dataSize); void fileChunkSending(UInt8 mark, char* data, size_t dataSize);
// sending dragging information to server
void draggingInfoSending(UInt32 fileCount, CString fileList, size_t size);
#ifdef TEST_ENV #ifdef TEST_ENV
void handleDataForTest() { handleData(CEvent(), NULL); } void handleDataForTest() { handleData(CEvent(), NULL); }
#endif #endif

View File

@ -1835,3 +1835,9 @@ CMSWindowsScreen::CHotKeyItem::operator<(const CHotKeyItem& x) const
return (m_keycode < x.m_keycode || return (m_keycode < x.m_keycode ||
(m_keycode == x.m_keycode && m_mask < x.m_mask)); (m_keycode == x.m_keycode && m_mask < x.m_mask));
} }
void
CMSWindowsScreen::fakeDraggingFiles(CString str)
{
}

View File

@ -115,6 +115,7 @@ public:
virtual void setOptions(const COptionsList& options); virtual void setOptions(const COptionsList& options);
virtual void setSequenceNumber(UInt32); virtual void setSequenceNumber(UInt32);
virtual bool isPrimary() const; virtual bool isPrimary() const;
virtual void fakeDraggingFiles(CString str);
protected: protected:
// IPlatformScreen overrides // IPlatformScreen overrides

View File

@ -103,6 +103,8 @@ set(inc
../ipc ../ipc
../net ../net
../io ../io
../server
../client
../synwinhk ../synwinhk
../synwinxt ../synwinxt
) )
@ -123,7 +125,7 @@ include_directories(${inc})
add_library(platform STATIC ${src}) add_library(platform STATIC ${src})
if (UNIX) if (UNIX)
target_link_libraries(platform io net ipc synergy ${libs}) target_link_libraries(platform io net ipc synergy server client ${libs})
endif() endif()
if (APPLE) if (APPLE)

View File

@ -29,6 +29,7 @@ getDraggedFileURL()
NSArray* files = [pboard propertyListForType:NSFilenamesPboardType]; NSArray* files = [pboard propertyListForType:NSFilenamesPboardType];
for (id file in files) { for (id file in files) {
[string appendString: (NSString*)file]; [string appendString: (NSString*)file];
[string appendString: @"\0"];
} }
return (CFStringRef)string; return (CFStringRef)string;

View File

@ -34,6 +34,9 @@
#include "XArch.h" #include "XArch.h"
#include "COSXDragSimulator.h" #include "COSXDragSimulator.h"
#include "COSXPasteboardPeeker.h" #include "COSXPasteboardPeeker.h"
#include "CClientApp.h"
#include "CServerApp.h"
#include "CClient.h"
#include <math.h> #include <math.h>
@ -98,6 +101,7 @@ COSXScreen::COSXScreen(IEventQueue* events, bool isPrimary, bool autoShowHideCur
m_eventTapRLSR(nullptr), m_eventTapRLSR(nullptr),
m_eventTapPort(nullptr), m_eventTapPort(nullptr),
m_pmRootPort(0), m_pmRootPort(0),
m_draggingStarted(false),
m_fakeDraggingStarted(false), m_fakeDraggingStarted(false),
m_getDropTargetThread(NULL) m_getDropTargetThread(NULL)
{ {
@ -593,6 +597,7 @@ COSXScreen::fakeMouseButton(ButtonID id, bool press)
} }
m_fakeDraggingStarted = false; m_fakeDraggingStarted = false;
m_draggingStarted = false;
} }
} }
@ -638,6 +643,11 @@ COSXScreen::fakeMouseMove(SInt32 x, SInt32 y)
fakeKeyDown(kKeyControl_L, 8194, 29); fakeKeyDown(kKeyControl_L, 8194, 29);
} }
// index 0 means left mouse button
if (m_buttonState.test(0)) {
m_draggingStarted = true;
}
// synthesize event // synthesize event
CGPoint pos; CGPoint pos;
pos.x = x; pos.x = x;
@ -890,6 +900,24 @@ COSXScreen::leave()
{ {
hideCursor(); hideCursor();
if (m_draggingStarted) {
if (!m_isPrimary) {
CFStringRef dragInfo = getDraggedFileURL();
char* dragInfoCStr = CFStringRefToUTF8String(dragInfo);
LOG((CLOG_DEBUG "drag info: %s", dragInfoCStr));
CFRelease(dragInfo);
CString fileList(dragInfoCStr);
size_t size = fileList.size();
CClientApp& app = CClientApp::instance();
CClient* client = app.getClientPtr();
UInt32 fileCount = 1;
client->draggingInfoSending(fileCount, fileList, size);
LOG((CLOG_DEBUG "send dragging file to server"));
client->sendFileToServer(dragInfoCStr);
m_draggingStarted = false;
}
}
if (m_isPrimary) { if (m_isPrimary) {
// warp to center // warp to center
//warpCursor(m_xCenter, m_yCenter); //warpCursor(m_xCenter, m_yCenter);

View File

@ -97,7 +97,6 @@ public:
virtual void setOptions(const COptionsList& options); virtual void setOptions(const COptionsList& options);
virtual void setSequenceNumber(UInt32); virtual void setSequenceNumber(UInt32);
virtual bool isPrimary() const; virtual bool isPrimary() const;
virtual void fakeDraggingFiles(CString str); virtual void fakeDraggingFiles(CString str);
const CString& getDropTarget() const { return m_dropTarget; } const CString& getDropTarget() const { return m_dropTarget; }
@ -345,6 +344,7 @@ private:
IEventQueue* m_events; IEventQueue* m_events;
bool m_draggingStarted;
bool m_fakeDraggingStarted; bool m_fakeDraggingStarted;
CThread* m_getDropTargetThread; CThread* m_getDropTargetThread;
CString m_dropTarget; CString m_dropTarget;

View File

@ -76,6 +76,9 @@ CClientProxy1_5::parseMessage(const UInt8* code)
if (memcmp(code, kMsgDFileTransfer, 4) == 0) { if (memcmp(code, kMsgDFileTransfer, 4) == 0) {
fileChunkReceived(); fileChunkReceived();
} }
else if (memcmp(code, kMsgDDragInfo, 4) == 0) {
dragInfoReceived();
}
else { else {
return CClientProxy1_4::parseMessage(code); return CClientProxy1_4::parseMessage(code);
} }
@ -133,3 +136,14 @@ CClientProxy1_5::fileChunkReceived()
break; break;
} }
} }
void
CClientProxy1_5::dragInfoReceived()
{
// parse
UInt32 fileNum = 0;
CString content;
CProtocolUtil::readf(getStream(), kMsgDDragInfo + 4, &fileNum, &content);
m_server->dragInfoReceived(fileNum, content);
}

View File

@ -33,6 +33,7 @@ public:
virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize); virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize);
virtual bool parseMessage(const UInt8* code); virtual bool parseMessage(const UInt8* code);
void fileChunkReceived(); void fileChunkReceived();
void dragInfoReceived();
private: private:
IEventQueue* m_events; IEventQueue* m_events;

View File

@ -37,7 +37,6 @@
#include "CThread.h" #include "CThread.h"
#include "TMethodJob.h" #include "TMethodJob.h"
#include "CFileChunker.h" #include "CFileChunker.h"
#include "CDragInformation.h"
#include <cstring> #include <cstring>
#include <cstdlib> #include <cstdlib>
#include <sstream> #include <sstream>
@ -75,7 +74,8 @@ CServer::CServer(CConfig& config, CPrimaryClient* primaryClient, CScreen* screen
m_relativeMoves(false), m_relativeMoves(false),
m_keyboardBroadcasting(false), m_keyboardBroadcasting(false),
m_lockedToScreen(false), m_lockedToScreen(false),
m_screen(screen) m_screen(screen),
m_sendFileThread(NULL)
{ {
// must have a primary client and it must have a canonical name // must have a primary client and it must have a canonical name
assert(m_primaryClient != NULL); assert(m_primaryClient != NULL);
@ -243,6 +243,8 @@ CServer::~CServer()
// disable and disconnect primary client // disable and disconnect primary client
m_primaryClient->disable(); m_primaryClient->disable();
removeClient(m_primaryClient); removeClient(m_primaryClient);
delete m_sendFileThread;
} }
bool bool
@ -1950,9 +1952,11 @@ void
CServer::onFileRecieveCompleted() CServer::onFileRecieveCompleted()
{ {
if (isReceivedFileSizeValid()) { if (isReceivedFileSizeValid()) {
if (!m_fileTransferDes.empty()) { if (!m_fileTransferDes.empty() && m_dragFileList.size() > 0) {
std::fstream file; std::fstream file;
file.open(m_fileTransferDes.c_str(), std::ios::out | std::ios::binary); CString dropTarget = m_fileTransferDes;
dropTarget.append("/").append(m_dragFileList.at(0));
file.open(dropTarget.c_str(), std::ios::out | std::ios::binary);
if (!file.is_open()) { if (!file.is_open()) {
// TODO: file open failed // TODO: file open failed
} }
@ -1960,6 +1964,9 @@ CServer::onFileRecieveCompleted()
file.write(m_receivedFileData.c_str(), m_receivedFileData.size()); file.write(m_receivedFileData.c_str(), m_receivedFileData.size());
file.close(); file.close();
} }
else {
LOG((CLOG_ERR "drop file failed: drop target is empty"));
}
} }
} }
@ -2262,7 +2269,7 @@ CServer::isReceivedFileSizeValid()
void void
CServer::sendFileToClient(const char* filename) CServer::sendFileToClient(const char* filename)
{ {
CThread* thread = new CThread( m_sendFileThread = new CThread(
new TMethodJob<CServer>( new TMethodJob<CServer>(
this, &CServer::sendFileThread, this, &CServer::sendFileThread,
reinterpret_cast<void*>(const_cast<char*>(filename)))); reinterpret_cast<void*>(const_cast<char*>(filename))));
@ -2279,4 +2286,23 @@ CServer::sendFileThread(void* filename)
catch (std::runtime_error error) { catch (std::runtime_error error) {
LOG((CLOG_ERR "failed sending file chunks: %s", error.what())); LOG((CLOG_ERR "failed sending file chunks: %s", error.what()));
} }
delete m_sendFileThread;
m_sendFileThread = NULL;
}
void
CServer::dragInfoReceived(UInt32 fileNum, CString content)
{
CDragInformation::parseDragInfo(m_dragFileList, fileNum, content);
LOG((CLOG_INFO "drag information received"));
LOG((CLOG_INFO "total drag file number: %i", m_dragFileList.size()));
for(int i = 0; i < m_dragFileList.size(); ++i) {
LOG((CLOG_INFO "dragging file %i name: %s", i + 1, m_dragFileList.at(i).c_str()));
}
if (m_dragFileList.size() != 0) {
//TODO: fake a dragging operation
}
} }

View File

@ -31,6 +31,7 @@
#include "stdvector.h" #include "stdvector.h"
#include "INode.h" #include "INode.h"
#include "CEventTypes.h" #include "CEventTypes.h"
#include "CDragInformation.h"
class CBaseClientProxy; class CBaseClientProxy;
class CEventQueueTimer; class CEventQueueTimer;
@ -38,6 +39,7 @@ class CPrimaryClient;
class CInputFilter; class CInputFilter;
class CScreen; class CScreen;
class IEventQueue; class IEventQueue;
class CThread;
//! Synergy server //! Synergy server
/*! /*!
@ -153,6 +155,9 @@ public:
//! Create a new thread and use it to send file to client //! Create a new thread and use it to send file to client
void sendFileToClient(const char* filename); void sendFileToClient(const char* filename);
//! Received dragging information from client
void dragInfoReceived(UInt32 fileNum, CString content);
//@} //@}
//! @name accessors //! @name accessors
//@{ //@{
@ -456,6 +461,8 @@ private:
CString m_receivedFileData; CString m_receivedFileData;
CString m_fileTransferSrc; CString m_fileTransferSrc;
CString m_fileTransferDes; CString m_fileTransferDes;
CDragFileList m_dragFileList;
CThread* m_sendFileThread;
}; };
#endif #endif

View File

@ -83,6 +83,8 @@ public:
static CClientApp& instance() { return (CClientApp&)CApp::instance(); } static CClientApp& instance() { return (CClientApp&)CApp::instance(); }
CClient* getClientPtr() { return s_client; }
private: private:
virtual bool parseArg(const int& argc, const char* const* argv, int& i); virtual bool parseArg(const int& argc, const char* const* argv, int& i);
void runEventsLoop(void*); void runEventsLoop(void*);

View File

@ -27,9 +27,14 @@ CDragInformation::parseDragInfo(CDragFileList& dragFileList, UInt32 fileNum, CSt
size_t findResult1 = 0; size_t findResult1 = 0;
size_t findResult2 = 0; size_t findResult2 = 0;
dragFileList.clear(); dragFileList.clear();
CString slash("\\");
if (data.find("/", startPos != -1)) {
slash = "/";
}
while (fileNum) { while (fileNum) {
findResult1 = data.find('\0', startPos); findResult1 = data.find('\0', startPos);
findResult2 = data.find_last_of("\\", findResult1); findResult2 = data.find_last_of(slash, findResult1);
if (findResult1 == startPos) { if (findResult1 == startPos) {
//TODO: file number does not match, something goes wrong //TODO: file number does not match, something goes wrong

View File

@ -47,6 +47,10 @@
#include "COSXScreen.h" #include "COSXScreen.h"
#endif #endif
#if defined(__APPLE__)
#include "COSXDragSimulator.h"
#endif
#include <iostream> #include <iostream>
#include <stdio.h> #include <stdio.h>
#include <fstream> #include <fstream>
@ -782,7 +786,17 @@ CServerApp::mainLoop()
// later. the timer installed by startServer() will take care of // later. the timer installed by startServer() will take care of
// that. // that.
DAEMON_RUNNING(true); DAEMON_RUNNING(true);
#if defined(__APPLE__)
CThread thread(
new TMethodJob<CServerApp>(
this, &CServerApp::runEventsLoop,
NULL));
runCocoaApp();
#else
m_events->loop(); m_events->loop();
#endif
DAEMON_RUNNING(false); DAEMON_RUNNING(false);
// close down // close down
@ -901,3 +915,10 @@ CServerApp::startNode()
m_bye(kExitFailed); m_bye(kExitFailed);
} }
} }
void
CServerApp::runEventsLoop(void*)
{
m_events->cacheCurrentEventQueueRef();
m_events->loop();
}

View File

@ -111,6 +111,8 @@ public:
static CServerApp& instance() { return (CServerApp&)CApp::instance(); } static CServerApp& instance() { return (CServerApp&)CApp::instance(); }
CServer* getServerPtr() { return s_server; }
// TODO: change s_ to m_ // TODO: change s_ to m_
CServer* s_server; CServer* s_server;
EServerState s_serverState; EServerState s_serverState;
@ -124,6 +126,7 @@ public:
private: private:
virtual bool parseArg(const int& argc, const char* const* argv, int& i); virtual bool parseArg(const int& argc, const char* const* argv, int& i);
void handleScreenSwitched(const CEvent&, void* data); void handleScreenSwitched(const CEvent&, void* data);
void runEventsLoop(void*);
}; };
// configuration file name // configuration file name