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:
parent
af04f8b2ef
commit
43e2535335
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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*);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue