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_events(events),
m_cryptoStream(NULL),
m_crypto(crypto)
m_crypto(crypto),
m_sendFileThread(NULL)
{
assert(m_socketFactory != NULL);
assert(m_screen != NULL);
@ -108,6 +109,7 @@ CClient::~CClient()
cleanupConnection();
delete m_socketFactory;
delete m_streamFilterFactory;
delete m_sendFileThread;
}
void
@ -790,7 +792,7 @@ CClient::isReceivedFileSizeValid()
void
CClient::sendFileToServer(const char* filename)
{
CThread* thread = new CThread(
m_sendFileThread = new CThread(
new TMethodJob<CClient>(
this, &CClient::sendFileThread,
reinterpret_cast<void*>(const_cast<char*>(filename))));
@ -806,4 +808,13 @@ CClient::sendFileThread(void* filename)
catch (std::runtime_error error) {
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 IEventQueue;
class CCryptoStream;
class CThread;
//! Synergy client
/*!
@ -111,6 +112,9 @@ public:
//! Set file transder destination
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
//@{
@ -229,6 +233,7 @@ private:
CString m_fileTransferDes;
CDragFileList m_dragFileList;
CString m_dragFileExt;
CThread* m_sendFileThread;
};
#endif

View File

@ -28,7 +28,6 @@
#include "TMethodEventJob.h"
#include "XBase.h"
#include <memory>
#include <cstring>
#include "CCryptoStream.h"
//
@ -946,3 +945,9 @@ CServerProxy::fileChunkSending(UInt8 mark, char* data, size_t dataSize)
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 "CEvent.h"
#include "CStopwatch.h"
#include "CString.h"
class CClient;
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);
// sending dragging information to server
void draggingInfoSending(UInt32 fileCount, CString fileList, size_t size);
#ifdef TEST_ENV
void handleDataForTest() { handleData(CEvent(), NULL); }
#endif

View File

@ -1835,3 +1835,9 @@ CMSWindowsScreen::CHotKeyItem::operator<(const CHotKeyItem& x) const
return (m_keycode < x.m_keycode ||
(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 setSequenceNumber(UInt32);
virtual bool isPrimary() const;
virtual void fakeDraggingFiles(CString str);
protected:
// IPlatformScreen overrides

View File

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

View File

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

View File

@ -34,6 +34,9 @@
#include "XArch.h"
#include "COSXDragSimulator.h"
#include "COSXPasteboardPeeker.h"
#include "CClientApp.h"
#include "CServerApp.h"
#include "CClient.h"
#include <math.h>
@ -98,6 +101,7 @@ COSXScreen::COSXScreen(IEventQueue* events, bool isPrimary, bool autoShowHideCur
m_eventTapRLSR(nullptr),
m_eventTapPort(nullptr),
m_pmRootPort(0),
m_draggingStarted(false),
m_fakeDraggingStarted(false),
m_getDropTargetThread(NULL)
{
@ -593,6 +597,7 @@ COSXScreen::fakeMouseButton(ButtonID id, bool press)
}
m_fakeDraggingStarted = false;
m_draggingStarted = false;
}
}
@ -638,6 +643,11 @@ COSXScreen::fakeMouseMove(SInt32 x, SInt32 y)
fakeKeyDown(kKeyControl_L, 8194, 29);
}
// index 0 means left mouse button
if (m_buttonState.test(0)) {
m_draggingStarted = true;
}
// synthesize event
CGPoint pos;
pos.x = x;
@ -890,6 +900,24 @@ COSXScreen::leave()
{
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) {
// warp to center
//warpCursor(m_xCenter, m_yCenter);

View File

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

View File

@ -76,6 +76,9 @@ CClientProxy1_5::parseMessage(const UInt8* code)
if (memcmp(code, kMsgDFileTransfer, 4) == 0) {
fileChunkReceived();
}
else if (memcmp(code, kMsgDDragInfo, 4) == 0) {
dragInfoReceived();
}
else {
return CClientProxy1_4::parseMessage(code);
}
@ -133,3 +136,14 @@ CClientProxy1_5::fileChunkReceived()
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 bool parseMessage(const UInt8* code);
void fileChunkReceived();
void dragInfoReceived();
private:
IEventQueue* m_events;

View File

@ -37,7 +37,6 @@
#include "CThread.h"
#include "TMethodJob.h"
#include "CFileChunker.h"
#include "CDragInformation.h"
#include <cstring>
#include <cstdlib>
#include <sstream>
@ -75,7 +74,8 @@ CServer::CServer(CConfig& config, CPrimaryClient* primaryClient, CScreen* screen
m_relativeMoves(false),
m_keyboardBroadcasting(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
assert(m_primaryClient != NULL);
@ -243,6 +243,8 @@ CServer::~CServer()
// disable and disconnect primary client
m_primaryClient->disable();
removeClient(m_primaryClient);
delete m_sendFileThread;
}
bool
@ -1950,9 +1952,11 @@ void
CServer::onFileRecieveCompleted()
{
if (isReceivedFileSizeValid()) {
if (!m_fileTransferDes.empty()) {
if (!m_fileTransferDes.empty() && m_dragFileList.size() > 0) {
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()) {
// TODO: file open failed
}
@ -1960,6 +1964,9 @@ CServer::onFileRecieveCompleted()
file.write(m_receivedFileData.c_str(), m_receivedFileData.size());
file.close();
}
else {
LOG((CLOG_ERR "drop file failed: drop target is empty"));
}
}
}
@ -2262,7 +2269,7 @@ CServer::isReceivedFileSizeValid()
void
CServer::sendFileToClient(const char* filename)
{
CThread* thread = new CThread(
m_sendFileThread = new CThread(
new TMethodJob<CServer>(
this, &CServer::sendFileThread,
reinterpret_cast<void*>(const_cast<char*>(filename))));
@ -2279,4 +2286,23 @@ CServer::sendFileThread(void* filename)
catch (std::runtime_error error) {
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 "INode.h"
#include "CEventTypes.h"
#include "CDragInformation.h"
class CBaseClientProxy;
class CEventQueueTimer;
@ -38,6 +39,7 @@ class CPrimaryClient;
class CInputFilter;
class CScreen;
class IEventQueue;
class CThread;
//! Synergy server
/*!
@ -153,6 +155,9 @@ public:
//! Create a new thread and use it to send file to client
void sendFileToClient(const char* filename);
//! Received dragging information from client
void dragInfoReceived(UInt32 fileNum, CString content);
//@}
//! @name accessors
//@{
@ -456,6 +461,8 @@ private:
CString m_receivedFileData;
CString m_fileTransferSrc;
CString m_fileTransferDes;
CDragFileList m_dragFileList;
CThread* m_sendFileThread;
};
#endif

View File

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

View File

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

View File

@ -47,6 +47,10 @@
#include "COSXScreen.h"
#endif
#if defined(__APPLE__)
#include "COSXDragSimulator.h"
#endif
#include <iostream>
#include <stdio.h>
#include <fstream>
@ -782,7 +786,17 @@ CServerApp::mainLoop()
// later. the timer installed by startServer() will take care of
// that.
DAEMON_RUNNING(true);
#if defined(__APPLE__)
CThread thread(
new TMethodJob<CServerApp>(
this, &CServerApp::runEventsLoop,
NULL));
runCocoaApp();
#else
m_events->loop();
#endif
DAEMON_RUNNING(false);
// close down
@ -901,3 +915,10 @@ CServerApp::startNode()
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(); }
CServer* getServerPtr() { return s_server; }
// TODO: change s_ to m_
CServer* s_server;
EServerState s_serverState;
@ -124,6 +126,7 @@ public:
private:
virtual bool parseArg(const int& argc, const char* const* argv, int& i);
void handleScreenSwitched(const CEvent&, void* data);
void runEventsLoop(void*);
};
// configuration file name