Feature to drag a file from Windows to Mac:

- On Mac client main thread is used for cocoa application in order to simulate drag.
- Send dragging file dir from Windows server to Mac client while dragging after switching screen.
- Dragging information sending is immature now (need to support multi files dragging in the future).
- Used Cocoa function to monitor dragg pasteboard.
- Changed Mac client to use another thread for event queue instead of the main thread.
- Change fileRecieveComplete to fileRecieveCompleted.
This commit is contained in:
jerry 2013-08-30 14:38:43 +00:00
parent 031a84ca84
commit ce1b62db14
52 changed files with 875 additions and 184 deletions

View File

@ -594,3 +594,9 @@ CEventQueue::CTimer::operator<(const CTimer& t) const
{ {
return m_time < t.m_time; return m_time < t.m_time;
} }
void
CEventQueue::cacheCurrentEventQueueRef()
{
m_buffer->cacheCurrentEventQueueRef();
}

View File

@ -61,6 +61,8 @@ public:
getRegisteredType(const CString& name) const; getRegisteredType(const CString& name) const;
void* getSystemTarget(); void* getSystemTarget();
void cacheCurrentEventQueueRef();
private: private:
UInt32 saveEvent(const CEvent& event); UInt32 saveEvent(const CEvent& event);
CEvent removeEvent(UInt32 eventID); CEvent removeEvent(UInt32 eventID);

View File

@ -177,7 +177,7 @@ REGISTER_EVENT(IScreen, clipboardGrabbed)
REGISTER_EVENT(IScreen, suspend) REGISTER_EVENT(IScreen, suspend)
REGISTER_EVENT(IScreen, resume) REGISTER_EVENT(IScreen, resume)
REGISTER_EVENT(IScreen, fileChunkSending) REGISTER_EVENT(IScreen, fileChunkSending)
REGISTER_EVENT(IScreen, fileRecieveComplete) REGISTER_EVENT(IScreen, fileRecieveCompleted)
// //
// CIpcServer // CIpcServer

View File

@ -629,7 +629,7 @@ public:
m_suspend(CEvent::kUnknown), m_suspend(CEvent::kUnknown),
m_resume(CEvent::kUnknown), m_resume(CEvent::kUnknown),
m_fileChunkSending(CEvent::kUnknown), m_fileChunkSending(CEvent::kUnknown),
m_fileRecieveComplete(CEvent::kUnknown) { } m_fileRecieveCompleted(CEvent::kUnknown) { }
//! @name accessors //! @name accessors
//@{ //@{
@ -674,7 +674,7 @@ public:
CEvent::Type fileChunkSending(); CEvent::Type fileChunkSending();
//! Completed receiving a file //! Completed receiving a file
CEvent::Type fileRecieveComplete(); CEvent::Type fileRecieveCompleted();
//@} //@}
@ -685,5 +685,5 @@ private:
CEvent::Type m_suspend; CEvent::Type m_suspend;
CEvent::Type m_resume; CEvent::Type m_resume;
CEvent::Type m_fileChunkSending; CEvent::Type m_fileChunkSending;
CEvent::Type m_fileRecieveComplete; CEvent::Type m_fileRecieveCompleted;
}; };

View File

@ -40,6 +40,7 @@ public:
virtual CEventQueueTimer* virtual CEventQueueTimer*
newTimer(double duration, bool oneShot) const; newTimer(double duration, bool oneShot) const;
virtual void deleteTimer(CEventQueueTimer*) const; virtual void deleteTimer(CEventQueueTimer*) const;
void cacheCurrentEventQueueRef() { }
private: private:
typedef std::deque<UInt32> CEventDeque; typedef std::deque<UInt32> CEventDeque;

View File

@ -177,6 +177,8 @@ public:
registerTypeOnce(CEvent::Type& type, registerTypeOnce(CEvent::Type& type,
const char* name) = 0; const char* name) = 0;
virtual void cacheCurrentEventQueueRef() = 0;
//@} //@}
//! @name accessors //! @name accessors
//@{ //@{

View File

@ -67,6 +67,8 @@ public:
*/ */
virtual bool addEvent(UInt32 dataID) = 0; virtual bool addEvent(UInt32 dataID) = 0;
virtual void cacheCurrentEventQueueRef() = 0;
//@} //@}
//! @name accessors //! @name accessors
//@{ //@{

View File

@ -85,10 +85,10 @@ CClient::CClient(IEventQueue* events,
this, this,
new TMethodEventJob<CClient>(this, new TMethodEventJob<CClient>(this,
&CClient::handleFileChunkSending)); &CClient::handleFileChunkSending));
m_events->adoptHandler(m_events->forIScreen().fileRecieveComplete(), m_events->adoptHandler(m_events->forIScreen().fileRecieveCompleted(),
this, this,
new TMethodEventJob<CClient>(this, new TMethodEventJob<CClient>(this,
&CClient::handleFileRecieveComplete)); &CClient::handleFileRecieveCompleted));
} }
CClient::~CClient() CClient::~CClient()
@ -711,17 +711,19 @@ CClient::handleFileChunkSending(const CEvent& event, void*)
} }
void void
CClient::handleFileRecieveComplete(const CEvent& event, void*) CClient::handleFileRecieveCompleted(const CEvent& event, void*)
{ {
onFileRecieveComplete(); onFileRecieveCompleted();
} }
void void
CClient::onFileRecieveComplete() CClient::onFileRecieveCompleted()
{ {
if (isReceivedFileSizeValid()) { if (isReceivedFileSizeValid()) {
m_fileTransferDes = m_screen->getDropTarget();
if (!m_fileTransferDes.empty()) { if (!m_fileTransferDes.empty()) {
std::fstream file; std::fstream file;
m_fileTransferDes.append("/").append(m_dragFileList.at(0));
file.open(m_fileTransferDes.c_str(), std::ios::out | std::ios::binary); file.open(m_fileTransferDes.c_str(), std::ios::out | std::ios::binary);
if (!file.is_open()) { if (!file.is_open()) {
// TODO: file open failed // TODO: file open failed
@ -730,6 +732,9 @@ CClient::onFileRecieveComplete()
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"));
}
} }
} }
@ -752,6 +757,30 @@ CClient::fileChunkReceived(CString data)
m_receivedFileData += data; m_receivedFileData += data;
} }
void
CClient::dragInfoReceived(UInt32 fileNum, CString data)
{
CDragInformation::parseDragInfo(m_dragFileList, fileNum, data);
LOG((CLOG_DEBUG "drag information received"));
LOG((CLOG_DEBUG "total drag file number: %i", m_dragFileList.size()));
for(int i = 0; i < m_dragFileList.size(); ++i) {
LOG((CLOG_DEBUG2 "dragging file %i name: %s", i + 1, m_dragFileList.at(i).c_str()));
}
if (m_dragFileList.size() == 1) {
m_dragFileExt = CDragInformation::getDragFileExtension(m_dragFileList.at(0));
}
else if (m_dragFileList.size() > 1) {
m_dragFileExt.clear();
}
else {
return;
}
m_screen->startDraggingFiles(m_dragFileExt);
}
bool bool
CClient::isReceivedFileSizeValid() CClient::isReceivedFileSizeValid()
{ {

View File

@ -25,6 +25,7 @@
#include "INode.h" #include "INode.h"
#include "CCryptoOptions.h" #include "CCryptoOptions.h"
#include "CEventTypes.h" #include "CEventTypes.h"
#include "CDragInformation.h"
class CEventQueueTimer; class CEventQueueTimer;
class CScreen; class CScreen;
@ -101,6 +102,9 @@ public:
//! Received a chunk of file data //! Received a chunk of file data
void fileChunkReceived(CString data); void fileChunkReceived(CString data);
//! Received drag information
void dragInfoReceived(UInt32 fileNum, CString data);
//! Create a new thread and use it to send file to Server //! Create a new thread and use it to send file to Server
void sendFileToServer(const char* filename); void sendFileToServer(const char* filename);
@ -193,8 +197,8 @@ private:
void handleSuspend(const CEvent& event, void*); void handleSuspend(const CEvent& event, void*);
void handleResume(const CEvent& event, void*); void handleResume(const CEvent& event, void*);
void handleFileChunkSending(const CEvent&, void*); void handleFileChunkSending(const CEvent&, void*);
void handleFileRecieveComplete(const CEvent&, void*); void handleFileRecieveCompleted(const CEvent&, void*);
void onFileRecieveComplete(); void onFileRecieveCompleted();
public: public:
bool m_mock; bool m_mock;
@ -223,6 +227,8 @@ private:
CString m_receivedFileData; CString m_receivedFileData;
CString m_fileTransferSrc; CString m_fileTransferSrc;
CString m_fileTransferDes; CString m_fileTransferDes;
CDragFileList m_dragFileList;
CString m_dragFileExt;
}; };
#endif #endif

View File

@ -301,6 +301,9 @@ CServerProxy::parseMessage(const UInt8* code)
else if (memcmp(code, kMsgDFileTransfer, 4) == 0) { else if (memcmp(code, kMsgDFileTransfer, 4) == 0) {
fileChunkReceived(); fileChunkReceived();
} }
else if (memcmp(code, kMsgDDragInfo, 4) == 0) {
dragInfoReceived();
}
else if (memcmp(code, kMsgCClose, 4) == 0) { else if (memcmp(code, kMsgCClose, 4) == 0) {
// server wants us to hangup // server wants us to hangup
@ -865,7 +868,7 @@ void
CServerProxy::fileChunkReceived() CServerProxy::fileChunkReceived()
{ {
// parse // parse
UInt8 mark; UInt8 mark = 0;
CString content; CString content;
CProtocolUtil::readf(m_stream, kMsgDFileTransfer + 4, &mark, &content); CProtocolUtil::readf(m_stream, kMsgDFileTransfer + 4, &mark, &content);
@ -898,7 +901,7 @@ CServerProxy::fileChunkReceived()
break; break;
case kFileEnd: case kFileEnd:
m_events->addEvent(CEvent(m_events->forIScreen().fileRecieveComplete(), m_client)); m_events->addEvent(CEvent(m_events->forIScreen().fileRecieveCompleted(), m_client));
if (CLOG->getFilter() >= kDEBUG2) { if (CLOG->getFilter() >= kDEBUG2) {
LOG((CLOG_DEBUG2 "file data transfer finished")); LOG((CLOG_DEBUG2 "file data transfer finished"));
m_elapsedTime += m_stopwatch.getTime(); m_elapsedTime += m_stopwatch.getTime();
@ -911,6 +914,17 @@ CServerProxy::fileChunkReceived()
} }
} }
void
CServerProxy::dragInfoReceived()
{
// parse
UInt32 fileNum = 0;
CString content;
CProtocolUtil::readf(m_stream, kMsgDDragInfo + 4, &fileNum, &content);
m_client->dragInfoReceived(fileNum, content);
}
void void
CServerProxy::fileChunkSending(UInt8 mark, char* data, size_t dataSize) CServerProxy::fileChunkSending(UInt8 mark, char* data, size_t dataSize)
{ {

View File

@ -103,6 +103,7 @@ private:
void queryInfo(); void queryInfo();
void infoAcknowledgment(); void infoAcknowledgment();
void fileChunkReceived(); void fileChunkReceived();
void dragInfoReceived();
private: private:
typedef EResult (CServerProxy::*MessageParser)(const UInt8*); typedef EResult (CServerProxy::*MessageParser)(const UInt8*);

View File

@ -40,6 +40,8 @@ public:
newTimer(double duration, bool oneShot) const; newTimer(double duration, bool oneShot) const;
virtual void deleteTimer(CEventQueueTimer*) const; virtual void deleteTimer(CEventQueueTimer*) const;
virtual void cacheCurrentEventQueueRef() {}
private: private:
DWORD m_thread; DWORD m_thread;
UINT m_userEvent; UINT m_userEvent;

View File

@ -699,7 +699,7 @@ CMSWindowsScreen::fakeMouseButton(ButtonID id, bool press)
} }
void void
CMSWindowsScreen::fakeMouseMove(SInt32 x, SInt32 y) const CMSWindowsScreen::fakeMouseMove(SInt32 x, SInt32 y)
{ {
m_desks->fakeMouseMove(x, y); m_desks->fakeMouseMove(x, y);
} }

View File

@ -88,7 +88,7 @@ public:
// ISecondaryScreen overrides // ISecondaryScreen overrides
virtual void fakeMouseButton(ButtonID id, bool press); virtual void fakeMouseButton(ButtonID id, bool press);
virtual void fakeMouseMove(SInt32 x, SInt32 y) const; virtual void fakeMouseMove(SInt32 x, SInt32 y);
virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const; virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const;
virtual void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const; virtual void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const;

View File

@ -70,6 +70,9 @@ elseif (APPLE)
COSXScreen.cpp COSXScreen.cpp
COSXScreenSaver.cpp COSXScreenSaver.cpp
COSXScreenSaverUtil.m COSXScreenSaverUtil.m
COSXPasteboardPeeker.m
COSXDragSimulator.m
COSXDragView.m
) )
elseif (UNIX) elseif (UNIX)
@ -110,9 +113,20 @@ if (UNIX)
) )
endif() endif()
if (APPLE)
list(APPEND inc
/System/Library/Frameworks
)
endif()
include_directories(${inc}) 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 ${libs})
endif() endif()
if (APPLE)
FIND_LIBRARY(COCOA_LIBRARY Cocoa)
target_link_libraries(platform ${COCOA_LIBRARY})
endif()

View File

@ -0,0 +1,32 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2013 Bolton Software Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "common.h"
#import <CoreFoundation/CoreFoundation.h>
#if defined(__cplusplus)
extern "C" {
#endif
void runCocoaApp();
void fakeDragging(const char* str, int length, int cursorX, int cursorY);
CFStringRef getCocoaDropTarget();
#if defined(__cplusplus)
}
#endif

View File

@ -0,0 +1,64 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2013 Bolton Software Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#import "COSXDragSimulator.h"
#import "COSXDragView.h"
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#import <Cocoa/Cocoa.h>
NSWindow* g_dragWindow = NULL;
COSXDragView* g_dragView = NULL;
void
runCocoaApp()
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
NSApplication* app = [[NSApplication alloc] init];
NSWindow* window = [[NSWindow alloc]
initWithContentRect: NSMakeRect(-100, -100, 100, 100)
styleMask: NSTitledWindowMask | NSMiniaturizableWindowMask
backing: NSBackingStoreBuffered
defer: NO];
[window setTitle: @""];
[window makeKeyAndOrderFront:nil];
COSXDragView* dragView = [[COSXDragView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)];
g_dragWindow = window;
g_dragView = dragView;
[window setContentView: dragView];
[app run];
[pool release];
}
void
fakeDragging(const char* str, int length, int cursorX, int cursorY)
{
dispatch_async(dispatch_get_main_queue(), ^{
NSRect screen = [[NSScreen mainScreen] frame];
NSLog ( @"mouseLocation: %d %d", cursorX, cursorY);
NSRect rect = NSMakeRect(cursorX - 50, screen.size.height - cursorY - 50, 100, 100);
[g_dragWindow setFrame:rect display:YES];
[g_dragWindow makeKeyWindow];
});
}
CFStringRef
getCocoaDropTarget()
{
return [g_dragView getDropTarget];
}

View File

@ -0,0 +1,28 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2013 Bolton Software Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#import <Cocoa/Cocoa.h>
@interface COSXDragView : NSView<NSDraggingSource,NSDraggingInfo>
{
NSMutableString* m_dropTarget;
}
-(CFStringRef)getDropTarget;
-(void)clearDropTarget;
@end

View File

@ -0,0 +1,90 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2013 Bolton Software Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#import "COSXDragView.h"
@implementation COSXDragView
- (id)
initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
m_dropTarget = [[NSMutableString alloc] initWithCapacity:0];
return self;
}
- (void)
drawRect:(NSRect)dirtyRect
{
}
- (BOOL)
acceptsFirstMouse:(NSEvent *)theEvent
{
return YES;
}
- (void)
mouseDown:(NSEvent *)theEvent
{
NSPoint dragPosition;
NSRect imageLocation;
dragPosition = [self convertPoint:[theEvent locationInWindow]
fromView:nil];
dragPosition.x -= 16;
dragPosition.y -= 16;
imageLocation.origin = dragPosition;
imageLocation.size = NSMakeSize(32,32);
[self dragPromisedFilesOfTypes:[NSArray arrayWithObject:@"zip"]
fromRect:imageLocation
source:self
slideBack:NO
event:theEvent];
}
- (NSArray*)
namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropDestination
{
[m_dropTarget setString:@""];
[m_dropTarget appendString:dropDestination.path];
NSLog ( @"cocoa drop target: %@", m_dropTarget);
return nil;
}
-(NSDragOperation)
draggingSourceOperationMaskForLocal:(BOOL)flag
{
return NSDragOperationCopy;
}
-(CFStringRef)
getDropTarget
{
NSMutableString* string;
string = [[NSMutableString alloc] initWithCapacity:0];
[string appendString:m_dropTarget];
return (CFStringRef)string;
}
-(void)
clearDropTarget
{
[m_dropTarget setString:@""];
}
@end

View File

@ -99,7 +99,7 @@ COSXEventQueueBuffer::addEvent(UInt32 dataID)
&event); &event);
if (error == noErr) { if (error == noErr) {
error = PostEventToQueue(GetMainEventQueue(), event, error = PostEventToQueue(m_threadEventQueueRef, event,
kEventPriorityStandard); kEventPriorityStandard);
ReleaseEvent(event); ReleaseEvent(event);
} }
@ -126,3 +126,9 @@ COSXEventQueueBuffer::deleteTimer(CEventQueueTimer* timer) const
{ {
delete timer; delete timer;
} }
void
COSXEventQueueBuffer::cacheCurrentEventQueueRef()
{
m_threadEventQueueRef = GetCurrentEventQueue();
}

View File

@ -38,10 +38,12 @@ public:
virtual CEventQueueTimer* virtual CEventQueueTimer*
newTimer(double duration, bool oneShot) const; newTimer(double duration, bool oneShot) const;
virtual void deleteTimer(CEventQueueTimer*) const; virtual void deleteTimer(CEventQueueTimer*) const;
virtual void cacheCurrentEventQueueRef();
private: private:
EventRef m_event; EventRef m_event;
IEventQueue* m_eventQueue; IEventQueue* m_eventQueue;
EventQueueRef m_threadEventQueueRef;
}; };
#endif #endif

View File

@ -0,0 +1,31 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2013 Bolton Software Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "common.h"
#import <CoreFoundation/CoreFoundation.h>
#if defined(__cplusplus)
extern "C" {
#endif
CFStringRef getDraggedFileURL();
#if defined(__cplusplus)
}
#endif

View File

@ -0,0 +1,35 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2013 Bolton Software Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#import "COSXPasteboardPeeker.h"
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#import <Cocoa/Cocoa.h>
CFStringRef
getDraggedFileURL()
{
NSString* pbName = NSDragPboard;
NSPasteboard* pboard = [NSPasteboard pasteboardWithName:pbName];
NSMutableString* string;
string = [[NSMutableString alloc] initWithCapacity:0];
NSArray* files = [pboard propertyListForType:NSFilenamesPboardType];
for (id file in files) {
[string appendString: (NSString*)file];
}
return (CFStringRef)string;
}

View File

@ -32,6 +32,8 @@
#include "TMethodEventJob.h" #include "TMethodEventJob.h"
#include "TMethodJob.h" #include "TMethodJob.h"
#include "XArch.h" #include "XArch.h"
#include "COSXDragSimulator.h"
#include "COSXPasteboardPeeker.h"
#include <math.h> #include <math.h>
@ -95,7 +97,9 @@ COSXScreen::COSXScreen(IEventQueue* events, bool isPrimary, bool autoShowHideCur
m_autoShowHideCursor(autoShowHideCursor), m_autoShowHideCursor(autoShowHideCursor),
m_eventTapRLSR(nullptr), m_eventTapRLSR(nullptr),
m_eventTapPort(nullptr), m_eventTapPort(nullptr),
m_pmRootPort(0) m_pmRootPort(0),
m_fakeDraggingStarted(false),
m_getDropTargetThread(NULL)
{ {
try { try {
m_displayID = CGMainDisplayID(); m_displayID = CGMainDisplayID();
@ -564,7 +568,7 @@ COSXScreen::fakeMouseButton(ButtonID id, bool press)
MouseButtonState state = press ? kMouseButtonDown : kMouseButtonUp; MouseButtonState state = press ? kMouseButtonDown : kMouseButtonUp;
LOG((CLOG_DEBUG1 "faking mouse button %s", press ? "press" : "release")); LOG((CLOG_DEBUG1 "faking mouse button id: %d press: %s", id, press ? "pressed" : "released"));
MouseButtonEventMapType thisButtonMap = MouseButtonEventMap[index]; MouseButtonEventMapType thisButtonMap = MouseButtonEventMap[index];
CGEventType type = thisButtonMap[state]; CGEventType type = thisButtonMap[state];
@ -580,11 +584,60 @@ COSXScreen::fakeMouseButton(ButtonID id, bool press)
m_lastSingleClickXCursor = m_xCursor; m_lastSingleClickXCursor = m_xCursor;
m_lastSingleClickYCursor = m_yCursor; m_lastSingleClickYCursor = m_yCursor;
} }
if (!press && (id == kButtonLeft)) {
fakeKeyUp(29);
if (m_fakeDraggingStarted) {
m_getDropTargetThread = new CThread(new TMethodJob<COSXScreen>(
this, &COSXScreen::getDropTargetThread));
}
m_fakeDraggingStarted = false;
}
} }
void void
COSXScreen::fakeMouseMove(SInt32 x, SInt32 y) const COSXScreen::getDropTargetThread(void*)
{ {
char* cstr = NULL;
// wait for 5 secs for the drop destinaiton string to be filled.
UInt32 timeout = ARCH->time() + 5;
while (ARCH->time() < timeout) {
CFStringRef cfstr = getCocoaDropTarget();
cstr = CFStringRefToUTF8String(cfstr);
CFRelease(cfstr);
if (cstr != NULL) {
break;
}
ARCH->sleep(.1f);
}
if (cstr != NULL) {
LOG((CLOG_DEBUG "drop target: %s", cstr));
m_dropTarget = cstr;
}
else {
LOG((CLOG_ERR "failed to get drop target"));
m_dropTarget.clear();
}
delete m_getDropTargetThread;
}
void
COSXScreen::fakeMouseMove(SInt32 x, SInt32 y)
{
if (m_fakeDraggingStarted) {
// HACK: for some reason the drag icon
// does not follow the cursor unless a key
// is pressed (except esc key)
// TODO: fake this key down properly
fakeKeyDown(kKeyControl_L, 8194, 29);
}
// synthesize event // synthesize event
CGPoint pos; CGPoint pos;
pos.x = x; pos.x = x;
@ -671,6 +724,12 @@ COSXScreen::showCursor()
} }
m_cursorHidden = false; m_cursorHidden = false;
if (m_fakeDraggingStarted) {
// TODO: use real file extension
fakeDragging("txt", 3, m_xCursor, m_yCursor);
fakeMouseButton(kButtonLeft, true);
}
} }
void void
@ -1848,10 +1907,16 @@ COSXScreen::handleCGInputEvent(CGEventTapProxy proxy,
case kCGEventOtherMouseUp: case kCGEventOtherMouseUp:
screen->onMouseButton(false, CGEventGetIntegerValueField(event, kCGMouseEventButtonNumber) + 1); screen->onMouseButton(false, CGEventGetIntegerValueField(event, kCGMouseEventButtonNumber) + 1);
break; break;
case kCGEventMouseMoved: case kCGEventLeftMouseDragged: {
case kCGEventLeftMouseDragged: CFStringRef dragInfo = getDraggedFileURL();
char* info = CFStringRefToUTF8String(dragInfo);
LOG((CLOG_DEBUG "drag info: %s", info));
CFRelease(dragInfo);
break;
}
case kCGEventRightMouseDragged: case kCGEventRightMouseDragged:
case kCGEventOtherMouseDragged: case kCGEventOtherMouseDragged:
case kCGEventMouseMoved:
pos = CGEventGetLocation(event); pos = CGEventGetLocation(event);
screen->onMouseMove(pos.x, pos.y); screen->onMouseMove(pos.x, pos.y);
@ -1942,3 +2007,27 @@ COSXScreen::CMouseButtonState::getFirstButtonDown() const
} }
return -1; return -1;
} }
char*
COSXScreen::CFStringRefToUTF8String(CFStringRef aString)
{
if (aString == NULL) {
return NULL;
}
CFIndex length = CFStringGetLength(aString);
CFIndex maxSize = CFStringGetMaximumSizeForEncoding(
length,
kCFStringEncodingUTF8);
char* buffer = (char*)malloc(maxSize);
if (CFStringGetCString(aString, buffer, maxSize, kCFStringEncodingUTF8)) {
return buffer;
}
return NULL;
}
void
COSXScreen::fakeDraggingFiles(CString str)
{
m_fakeDraggingStarted = true;
}

View File

@ -79,7 +79,7 @@ public:
// ISecondaryScreen overrides // ISecondaryScreen overrides
virtual void fakeMouseButton(ButtonID id, bool press); virtual void fakeMouseButton(ButtonID id, bool press);
virtual void fakeMouseMove(SInt32 x, SInt32 y) const; virtual void fakeMouseMove(SInt32 x, SInt32 y);
virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const; virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const;
virtual void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const; virtual void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const;
@ -98,6 +98,10 @@ public:
virtual void setSequenceNumber(UInt32); virtual void setSequenceNumber(UInt32);
virtual bool isPrimary() const; virtual bool isPrimary() const;
virtual void fakeDraggingFiles(CString str);
const CString& getDropTarget() const { return m_dropTarget; }
protected: protected:
// IPlatformScreen overrides // IPlatformScreen overrides
virtual void handleSystemEvent(const CEvent&, void*); virtual void handleSystemEvent(const CEvent&, void*);
@ -195,6 +199,12 @@ private:
CGEventType type, CGEventType type,
CGEventRef event, CGEventRef event,
void* refcon); void* refcon);
// convert CFString to char*
static char* CFStringRefToUTF8String(CFStringRef aString);
void getDropTargetThread(void*);
private: private:
struct CHotKeyItem { struct CHotKeyItem {
public: public:
@ -334,6 +344,10 @@ private:
bool m_autoShowHideCursor; bool m_autoShowHideCursor;
IEventQueue* m_events; IEventQueue* m_events;
bool m_fakeDraggingStarted;
CThread* m_getDropTargetThread;
CString m_dropTarget;
}; };
#endif #endif

View File

@ -45,6 +45,8 @@ public:
newTimer(double duration, bool oneShot) const; newTimer(double duration, bool oneShot) const;
virtual void deleteTimer(CEventQueueTimer*) const; virtual void deleteTimer(CEventQueueTimer*) const;
virtual void cacheCurrentEventQueueRef() {}
private: private:
void flush(); void flush();

View File

@ -832,7 +832,7 @@ CXWindowsScreen::fakeMouseButton(ButtonID button, bool press)
} }
void void
CXWindowsScreen::fakeMouseMove(SInt32 x, SInt32 y) const CXWindowsScreen::fakeMouseMove(SInt32 x, SInt32 y)
{ {
if (m_xinerama && m_xtestIsXineramaUnaware) { if (m_xinerama && m_xtestIsXineramaUnaware) {
XWarpPointer(m_display, None, m_root, 0, 0, 0, 0, x, y); XWarpPointer(m_display, None, m_root, 0, 0, 0, 0, x, y);

View File

@ -66,7 +66,7 @@ public:
// ISecondaryScreen overrides // ISecondaryScreen overrides
virtual void fakeMouseButton(ButtonID id, bool press); virtual void fakeMouseButton(ButtonID id, bool press);
virtual void fakeMouseMove(SInt32 x, SInt32 y) const; virtual void fakeMouseMove(SInt32 x, SInt32 y);
virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const; virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const;
virtual void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const; virtual void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const;

View File

@ -79,6 +79,7 @@ public:
virtual void screensaver(bool activate) = 0; virtual void screensaver(bool activate) = 0;
virtual void resetOptions() = 0; virtual void resetOptions() = 0;
virtual void setOptions(const COptionsList& options) = 0; virtual void setOptions(const COptionsList& options) = 0;
virtual void draggingInfoSending(UInt32 fileCount, const char* data, size_t dataSize) = 0;
virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize) = 0; virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize) = 0;
virtual CString getName() const; virtual CString getName() const;

View File

@ -85,6 +85,7 @@ public:
virtual void resetOptions() = 0; virtual void resetOptions() = 0;
virtual void setOptions(const COptionsList& options) = 0; virtual void setOptions(const COptionsList& options) = 0;
virtual void cryptoIv(const UInt8* iv) = 0; virtual void cryptoIv(const UInt8* iv) = 0;
virtual void draggingInfoSending(UInt32 fileCount, const char* data, size_t dataSize) = 0;
virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize) = 0; virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize) = 0;
private: private:

View File

@ -365,6 +365,13 @@ CClientProxy1_0::cryptoIv(const UInt8* iv)
LOG((CLOG_DEBUG "cryptoIv not supported")); LOG((CLOG_DEBUG "cryptoIv not supported"));
} }
void
CClientProxy1_0::draggingInfoSending(UInt32 fileCount, const char* data, size_t dataSize)
{
// ignore -- not supported in protocol 1.0
LOG((CLOG_DEBUG "draggingInfoSending not supported"));
}
void void
CClientProxy1_0::fileChunkSending(UInt8 mark, char* data, size_t dataSize) CClientProxy1_0::fileChunkSending(UInt8 mark, char* data, size_t dataSize)
{ {

View File

@ -60,6 +60,7 @@ public:
virtual void resetOptions(); virtual void resetOptions();
virtual void setOptions(const COptionsList& options); virtual void setOptions(const COptionsList& options);
virtual void cryptoIv(const UInt8* iv); virtual void cryptoIv(const UInt8* iv);
virtual void draggingInfoSending(UInt32 fileCount, const char* data, size_t dataSize);
virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize); virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize);
protected: protected:

View File

@ -40,6 +40,14 @@ CClientProxy1_5::~CClientProxy1_5()
{ {
} }
void
CClientProxy1_5::draggingInfoSending(UInt32 fileCount, const char* data, size_t dataSize)
{
CString info(data, dataSize);
CProtocolUtil::writef(getStream(), kMsgDDragInfo, fileCount, &info);
}
void void
CClientProxy1_5::fileChunkSending(UInt8 mark, char* data, size_t dataSize) CClientProxy1_5::fileChunkSending(UInt8 mark, char* data, size_t dataSize)
{ {
@ -79,7 +87,7 @@ void
CClientProxy1_5::fileChunkReceived() CClientProxy1_5::fileChunkReceived()
{ {
// parse // parse
UInt8 mark; UInt8 mark = 0;
CString content; CString content;
CProtocolUtil::readf(getStream(), kMsgDFileTransfer + 4, &mark, &content); CProtocolUtil::readf(getStream(), kMsgDFileTransfer + 4, &mark, &content);
@ -113,7 +121,7 @@ CClientProxy1_5::fileChunkReceived()
break; break;
case kFileEnd: case kFileEnd:
m_events->addEvent(CEvent(m_events->forIScreen().fileRecieveComplete(), server)); m_events->addEvent(CEvent(m_events->forIScreen().fileRecieveCompleted(), server));
if (CLOG->getFilter() >= kDEBUG2) { if (CLOG->getFilter() >= kDEBUG2) {
LOG((CLOG_DEBUG2 "file data transfer finished")); LOG((CLOG_DEBUG2 "file data transfer finished"));
m_elapsedTime += m_stopwatch.getTime(); m_elapsedTime += m_stopwatch.getTime();

View File

@ -29,6 +29,7 @@ public:
CClientProxy1_5(const CString& name, synergy::IStream* adoptedStream, CServer* server, IEventQueue* events); CClientProxy1_5(const CString& name, synergy::IStream* adoptedStream, CServer* server, IEventQueue* events);
~CClientProxy1_5(); ~CClientProxy1_5();
virtual void draggingInfoSending(UInt32 fileCount, const char* data, size_t dataSize);
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();

View File

@ -249,6 +249,12 @@ CPrimaryClient::screensaver(bool)
// ignore // ignore
} }
void
CPrimaryClient::draggingInfoSending(UInt32 fileCount, const char* data, size_t dataSize)
{
// ignore
}
void void
CPrimaryClient::fileChunkSending(UInt8 mark, char* data, size_t dataSize) CPrimaryClient::fileChunkSending(UInt8 mark, char* data, size_t dataSize)
{ {

View File

@ -144,6 +144,7 @@ public:
virtual void screensaver(bool activate); virtual void screensaver(bool activate);
virtual void resetOptions(); virtual void resetOptions();
virtual void setOptions(const COptionsList& options); virtual void setOptions(const COptionsList& options);
virtual void draggingInfoSending(UInt32 fileCount, const char* data, size_t dataSize);
virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize); virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize);
private: private:

View File

@ -37,6 +37,7 @@
#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>
@ -167,10 +168,10 @@ CServer::CServer(CConfig& config, CPrimaryClient* primaryClient, CScreen* screen
this, this,
new TMethodEventJob<CServer>(this, new TMethodEventJob<CServer>(this,
&CServer::handleFileChunkSendingEvent)); &CServer::handleFileChunkSendingEvent));
m_events->adoptHandler(m_events->forIScreen().fileRecieveComplete(), m_events->adoptHandler(m_events->forIScreen().fileRecieveCompleted(),
this, this,
new TMethodEventJob<CServer>(this, new TMethodEventJob<CServer>(this,
&CServer::handleFileRecieveCompleteEvent)); &CServer::handleFileRecieveCompletedEvent));
// add connection // add connection
addClient(m_primaryClient); addClient(m_primaryClient);
@ -1472,9 +1473,9 @@ CServer::handleFileChunkSendingEvent(const CEvent& event, void*)
} }
void void
CServer::handleFileRecieveCompleteEvent(const CEvent& event, void*) CServer::handleFileRecieveCompletedEvent(const CEvent& event, void*)
{ {
onFileRecieveComplete(); onFileRecieveCompleted();
} }
void void
@ -1737,8 +1738,24 @@ CServer::onMouseMovePrimary(SInt32 x, SInt32 y)
// should we switch or not? // should we switch or not?
if (isSwitchOkay(newScreen, dir, x, y, xc, yc)) { if (isSwitchOkay(newScreen, dir, x, y, xc, yc)) {
if (m_screen->getDraggingStarted() && m_active != newScreen) {
CString& dragFileList = m_screen->getDraggingFileDir();
size_t size = dragFileList.size() + 1;
char* fileList = new char[size];
memcpy(fileList, dragFileList.c_str(), size);
fileList[size - 1] = '\0';
UInt32 fileCount = 1;
LOG((CLOG_DEBUG2 "sending drag information to client"));
LOG((CLOG_DEBUG3 "dragging file list: %s", fileList));
LOG((CLOG_DEBUG3 "dragging file list string size: %i", size));
newScreen->draggingInfoSending(fileCount, fileList, size);
m_screen->setDraggingStarted(false);
}
// switch screen // switch screen
switchScreen(newScreen, x, y, false); switchScreen(newScreen, x, y, false);
return true; return true;
} }
else { else {
@ -1930,7 +1947,7 @@ CServer::onFileChunkSending(const void* data)
} }
void void
CServer::onFileRecieveComplete() CServer::onFileRecieveCompleted()
{ {
if (isReceivedFileSizeValid()) { if (isReceivedFileSizeValid()) {
if (!m_fileTransferDes.empty()) { if (!m_fileTransferDes.empty()) {

View File

@ -310,7 +310,7 @@ private:
void handleFakeInputBeginEvent(const CEvent&, void*); void handleFakeInputBeginEvent(const CEvent&, void*);
void handleFakeInputEndEvent(const CEvent&, void*); void handleFakeInputEndEvent(const CEvent&, void*);
void handleFileChunkSendingEvent(const CEvent&, void*); void handleFileChunkSendingEvent(const CEvent&, void*);
void handleFileRecieveCompleteEvent(const CEvent&, void*); void handleFileRecieveCompletedEvent(const CEvent&, void*);
// event processing // event processing
void onClipboardChanged(CBaseClientProxy* sender, void onClipboardChanged(CBaseClientProxy* sender,
@ -327,7 +327,7 @@ private:
void onMouseMoveSecondary(SInt32 dx, SInt32 dy); void onMouseMoveSecondary(SInt32 dx, SInt32 dy);
void onMouseWheel(SInt32 xDelta, SInt32 yDelta); void onMouseWheel(SInt32 xDelta, SInt32 yDelta);
void onFileChunkSending(const void* data); void onFileChunkSending(const void* data);
void onFileRecieveComplete(); void onFileRecieveCompleted();
// add client to list and attach event handlers for client // add client to list and attach event handlers for client
bool addClient(CBaseClientProxy*); bool addClient(CBaseClientProxy*);

View File

@ -50,6 +50,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>
@ -531,7 +535,17 @@ CClientApp::mainLoop()
// later. the timer installed by startClient() will take care of // later. the timer installed by startClient() will take care of
// that. // that.
DAEMON_RUNNING(true); DAEMON_RUNNING(true);
#if defined(__APPLE__)
CThread thread(
new TMethodJob<CClientApp>(
this, &CClientApp::runEventsLoop,
NULL));
runCocoaApp();
#else
m_events->loop(); m_events->loop();
#endif
DAEMON_RUNNING(false); DAEMON_RUNNING(false);
// close down // close down
@ -612,3 +626,10 @@ CClientApp::startNode()
m_bye(kExitFailed); m_bye(kExitFailed);
} }
} }
void
CClientApp::runEventsLoop(void*)
{
m_events->cacheCurrentEventQueueRef();
m_events->loop();
}

View File

@ -85,6 +85,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 runEventsLoop(void*);
private: private:
CClient* s_client; CClient* s_client;

View File

@ -0,0 +1,57 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2013 Bolton Software Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "CDragInformation.h"
#include "CLog.h"
using namespace std;
void
CDragInformation::parseDragInfo(CDragFileList& dragFileList, UInt32 fileNum, CString data)
{
size_t startPos = 0;
size_t findResult1 = 0;
size_t findResult2 = 0;
dragFileList.clear();
while (fileNum) {
findResult1 = data.find('\0', startPos);
findResult2 = data.find_last_of("\\", findResult1);
if (findResult1 == startPos) {
//TODO: file number does not match, something goes wrong
break;
}
if (findResult1 - findResult2 > 1) {
dragFileList.push_back(data.substr(findResult2 + 1, findResult1 - findResult2));
}
startPos = findResult1 + 1;
--fileNum;
}
}
CString
CDragInformation::getDragFileExtension(CString fileName)
{
size_t findResult = -1;
findResult = fileName.find_last_of(".", fileName.size());
if (findResult != -1) {
return fileName.substr(findResult + 1, fileName.size() - findResult - 1);
}
else {
return "";
}
}

View File

@ -0,0 +1,34 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2013 Bolton Software Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "stdvector.h"
#include "CString.h"
#include "BasicTypes.h"
typedef std::vector<CString> CDragFileList;
class CDragInformation {
public:
CDragInformation() { }
~CDragInformation() { }
static void parseDragInfo(CDragFileList& dragFileList, UInt32 fileNum, CString data);
static CString getDragFileExtension(CString fileName);
};

View File

@ -48,6 +48,7 @@ set(inc
CArgsBase.h CArgsBase.h
IAppUtil.h IAppUtil.h
CFileChunker.h CFileChunker.h
CDragInformation.h
) )
set(src set(src
@ -75,6 +76,7 @@ set(src
CAppUtil.cpp CAppUtil.cpp
CArgsBase.cpp CArgsBase.cpp
CFileChunker.cpp CFileChunker.cpp
CDragInformation.cpp
) )
if (WIN32) if (WIN32)

View File

@ -20,6 +20,7 @@
#define CPLATFORMSCREEN_H #define CPLATFORMSCREEN_H
#include "IPlatformScreen.h" #include "IPlatformScreen.h"
#include <stdexcept>
//! Base screen implementation //! Base screen implementation
/*! /*!
@ -53,7 +54,7 @@ public:
// ISecondaryScreen overrides // ISecondaryScreen overrides
virtual void fakeMouseButton(ButtonID id, bool press) = 0; virtual void fakeMouseButton(ButtonID id, bool press) = 0;
virtual void fakeMouseMove(SInt32 x, SInt32 y) const = 0; virtual void fakeMouseMove(SInt32 x, SInt32 y) = 0;
virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const = 0; virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const = 0;
virtual void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const = 0; virtual void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const = 0;
@ -76,6 +77,8 @@ public:
virtual SInt32 pollActiveGroup() const; virtual SInt32 pollActiveGroup() const;
virtual void pollPressedKeys(KeyButtonSet& pressedKeys) const; virtual void pollPressedKeys(KeyButtonSet& pressedKeys) const;
virtual void setDraggingStarted(bool started) { m_draggingStarted = started; }
virtual bool getDraggingStarted() { return m_draggingStarted; }
virtual CString& getDraggingFileDir() { return m_draggingFileDir; } virtual CString& getDraggingFileDir() { return m_draggingFileDir; }
// IPlatformScreen overrides // IPlatformScreen overrides
@ -93,6 +96,10 @@ public:
virtual void setSequenceNumber(UInt32) = 0; virtual void setSequenceNumber(UInt32) = 0;
virtual bool isPrimary() const = 0; virtual bool isPrimary() const = 0;
virtual void fakeDraggingFiles(CString str) { throw std::runtime_error("fakeDraggingFiles not implemented"); }
virtual const CString&
getDropTarget() const { throw std::runtime_error("getDropTarget not implemented"); }
protected: protected:
//! Update mouse buttons //! Update mouse buttons
/*! /*!

View File

@ -415,12 +415,36 @@ CScreen::pollActiveModifiers() const
return m_screen->pollActiveModifiers(); return m_screen->pollActiveModifiers();
} }
bool
CScreen::getDraggingStarted() const
{
return m_screen->getDraggingStarted();
}
void
CScreen::setDraggingStarted(bool started)
{
m_screen->setDraggingStarted(started);
}
void
CScreen::startDraggingFiles(CString str)
{
m_screen->fakeDraggingFiles(str);
}
CString& CString&
CScreen::getDraggingFileDir() const CScreen::getDraggingFileDir() const
{ {
return m_screen->getDraggingFileDir(); return m_screen->getDraggingFileDir();
} }
const CString&
CScreen::getDropTarget() const
{
return m_screen->getDropTarget();
}
void* void*
CScreen::getEventTarget() const CScreen::getEventTarget() const
{ {

View File

@ -219,6 +219,12 @@ public:
*/ */
void fakeInputEnd(); void fakeInputEnd();
//! Change dragging status
void setDraggingStarted(bool started);
//! Fake a files dragging operation
void startDraggingFiles(CString str);
//@} //@}
//! @name accessors //! @name accessors
//@{ //@{
@ -267,10 +273,18 @@ public:
*/ */
KeyModifierMask pollActiveModifiers() const; KeyModifierMask pollActiveModifiers() const;
//! Check if dragging has started.
bool getDraggingStarted() const;
//! Get dragging file's directory. //! Get dragging file's directory.
CString& getDraggingFileDir() const; CString& getDraggingFileDir() const;
//! Get drop target directory.
const CString& getDropTarget() const;
//@} //@}
// IScreen overrides // IScreen overrides

View File

@ -130,6 +130,9 @@ public:
*/ */
virtual void setSequenceNumber(UInt32) = 0; virtual void setSequenceNumber(UInt32) = 0;
//! Change dragging status
virtual void setDraggingStarted(bool started) = 0;
//@} //@}
//! @name accessors //! @name accessors
//@{ //@{
@ -162,7 +165,7 @@ public:
// ISecondaryScreen overrides // ISecondaryScreen overrides
virtual void fakeMouseButton(ButtonID id, bool press) = 0; virtual void fakeMouseButton(ButtonID id, bool press) = 0;
virtual void fakeMouseMove(SInt32 x, SInt32 y) const = 0; virtual void fakeMouseMove(SInt32 x, SInt32 y) = 0;
virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const = 0; virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const = 0;
virtual void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const = 0; virtual void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const = 0;
@ -186,6 +189,11 @@ public:
virtual void pollPressedKeys(KeyButtonSet& pressedKeys) const = 0; virtual void pollPressedKeys(KeyButtonSet& pressedKeys) const = 0;
virtual CString& getDraggingFileDir() = 0; virtual CString& getDraggingFileDir() = 0;
virtual bool getDraggingStarted() = 0;
virtual void fakeDraggingFiles(CString str) = 0;
virtual const CString&
getDropTarget() const = 0;
protected: protected:
//! Handle system event //! Handle system event

View File

@ -44,7 +44,7 @@ public:
/*! /*!
Synthesize a mouse move to the absolute coordinates \c x,y. Synthesize a mouse move to the absolute coordinates \c x,y.
*/ */
virtual void fakeMouseMove(SInt32 x, SInt32 y) const = 0; virtual void fakeMouseMove(SInt32 x, SInt32 y) = 0;
//! Fake mouse move //! Fake mouse move
/*! /*!

View File

@ -46,6 +46,7 @@ const char* kMsgDInfo = "DINF%2i%2i%2i%2i%2i%2i%2i";
const char* kMsgDSetOptions = "DSOP%4I"; const char* kMsgDSetOptions = "DSOP%4I";
const char* kMsgDCryptoIv = "DCIV%s"; const char* kMsgDCryptoIv = "DCIV%s";
const char* kMsgDFileTransfer = "DFTR%1i%s"; const char* kMsgDFileTransfer = "DFTR%1i%s";
const char* kMsgDDragInfo = "DDRG%2i%s";
const char* kMsgQInfo = "QINF"; const char* kMsgQInfo = "QINF";
const char* kMsgEIncompatible = "EICV%2i%2i"; const char* kMsgEIncompatible = "EICV%2i%2i";
const char* kMsgEBusy = "EBSY"; const char* kMsgEBusy = "EBSY";

View File

@ -263,6 +263,12 @@ extern const char* kMsgDCryptoIv;
// 2 means the file transfer is finished. // 2 means the file transfer is finished.
extern const char* kMsgDFileTransfer; extern const char* kMsgDFileTransfer;
// drag infomation: primary <-> secondary
// transfer drag infomation. The first 2 bytes are used for storing
// the number of dragging objects. Then the following string consists
// of each object's directory.
extern const char* kMsgDDragInfo;
// //
// query codes // query codes
// //

View File

@ -92,16 +92,16 @@ public:
void sendMockData(void* eventTarget); void sendMockData(void* eventTarget);
void sendToClient_mockData_handleClientConnected(const CEvent&, void* vlistener); void sendToClient_mockData_handleClientConnected(const CEvent&, void* vlistener);
void sendToClient_mockData_fileRecieveComplete(const CEvent&, void*); void sendToClient_mockData_fileRecieveCompleted(const CEvent&, void*);
void sendToClient_mockFile_handleClientConnected(const CEvent&, void* vlistener); void sendToClient_mockFile_handleClientConnected(const CEvent&, void* vlistener);
void sendToClient_mockFile_fileRecieveComplete(const CEvent& event, void*); void sendToClient_mockFile_fileRecieveCompleted(const CEvent& event, void*);
void sendToServer_mockData_handleClientConnected(const CEvent&, void* vlistener); void sendToServer_mockData_handleClientConnected(const CEvent&, void* vlistener);
void sendToServer_mockData_fileRecieveComplete(const CEvent& event, void*); void sendToServer_mockData_fileRecieveCompleted(const CEvent& event, void*);
void sendToServer_mockFile_handleClientConnected(const CEvent&, void* vlistener); void sendToServer_mockFile_handleClientConnected(const CEvent&, void* vlistener);
void sendToServer_mockFile_fileRecieveComplete(const CEvent& event, void*); void sendToServer_mockFile_fileRecieveCompleted(const CEvent& event, void*);
public: public:
CTestEventQueue m_events; CTestEventQueue m_events;
@ -159,16 +159,16 @@ TEST_F(NetworkTests, sendToClient_mockData)
CClient client(&m_events, "stub", serverAddress, clientSocketFactory, NULL, &clientScreen, cryptoOptions); CClient client(&m_events, "stub", serverAddress, clientSocketFactory, NULL, &clientScreen, cryptoOptions);
m_events.adoptHandler( m_events.adoptHandler(
m_events.forIScreen().fileRecieveComplete(), &client, m_events.forIScreen().fileRecieveCompleted(), &client,
new TMethodEventJob<NetworkTests>( new TMethodEventJob<NetworkTests>(
this, &NetworkTests::sendToClient_mockData_fileRecieveComplete)); this, &NetworkTests::sendToClient_mockData_fileRecieveCompleted));
client.connect(); client.connect();
m_events.initQuitTimeout(10); m_events.initQuitTimeout(10);
m_events.loop(); m_events.loop();
m_events.removeHandler(m_events.forCClientListener().connected(), &listener); m_events.removeHandler(m_events.forCClientListener().connected(), &listener);
m_events.removeHandler(m_events.forIScreen().fileRecieveComplete(), &client); m_events.removeHandler(m_events.forIScreen().fileRecieveCompleted(), &client);
m_events.cleanupQuitTimeout(); m_events.cleanupQuitTimeout();
} }
@ -220,16 +220,16 @@ TEST_F(NetworkTests, sendToClient_mockFile)
CClient client(&m_events, "stub", serverAddress, clientSocketFactory, NULL, &clientScreen, cryptoOptions); CClient client(&m_events, "stub", serverAddress, clientSocketFactory, NULL, &clientScreen, cryptoOptions);
m_events.adoptHandler( m_events.adoptHandler(
m_events.forIScreen().fileRecieveComplete(), &client, m_events.forIScreen().fileRecieveCompleted(), &client,
new TMethodEventJob<NetworkTests>( new TMethodEventJob<NetworkTests>(
this, &NetworkTests::sendToClient_mockFile_fileRecieveComplete)); this, &NetworkTests::sendToClient_mockFile_fileRecieveCompleted));
client.connect(); client.connect();
m_events.initQuitTimeout(10); m_events.initQuitTimeout(10);
m_events.loop(); m_events.loop();
m_events.removeHandler(m_events.forCClientListener().connected(), &listener); m_events.removeHandler(m_events.forCClientListener().connected(), &listener);
m_events.removeHandler(m_events.forIScreen().fileRecieveComplete(), &client); m_events.removeHandler(m_events.forIScreen().fileRecieveCompleted(), &client);
m_events.cleanupQuitTimeout(); m_events.cleanupQuitTimeout();
} }
@ -281,16 +281,16 @@ TEST_F(NetworkTests, sendToServer_mockData)
this, &NetworkTests::sendToServer_mockData_handleClientConnected, &client)); this, &NetworkTests::sendToServer_mockData_handleClientConnected, &client));
m_events.adoptHandler( m_events.adoptHandler(
m_events.forIScreen().fileRecieveComplete(), &server, m_events.forIScreen().fileRecieveCompleted(), &server,
new TMethodEventJob<NetworkTests>( new TMethodEventJob<NetworkTests>(
this, &NetworkTests::sendToServer_mockData_fileRecieveComplete)); this, &NetworkTests::sendToServer_mockData_fileRecieveCompleted));
client.connect(); client.connect();
m_events.initQuitTimeout(10); m_events.initQuitTimeout(10);
m_events.loop(); m_events.loop();
m_events.removeHandler(m_events.forCClientListener().connected(), &listener); m_events.removeHandler(m_events.forCClientListener().connected(), &listener);
m_events.removeHandler(m_events.forIScreen().fileRecieveComplete(), &server); m_events.removeHandler(m_events.forIScreen().fileRecieveCompleted(), &server);
m_events.cleanupQuitTimeout(); m_events.cleanupQuitTimeout();
} }
@ -342,16 +342,16 @@ TEST_F(NetworkTests, sendToServer_mockFile)
this, &NetworkTests::sendToServer_mockFile_handleClientConnected, &client)); this, &NetworkTests::sendToServer_mockFile_handleClientConnected, &client));
m_events.adoptHandler( m_events.adoptHandler(
m_events.forIScreen().fileRecieveComplete(), &server, m_events.forIScreen().fileRecieveCompleted(), &server,
new TMethodEventJob<NetworkTests>( new TMethodEventJob<NetworkTests>(
this, &NetworkTests::sendToServer_mockFile_fileRecieveComplete)); this, &NetworkTests::sendToServer_mockFile_fileRecieveCompleted));
client.connect(); client.connect();
m_events.initQuitTimeout(10); m_events.initQuitTimeout(10);
m_events.loop(); m_events.loop();
m_events.removeHandler(m_events.forCClientListener().connected(), &listener); m_events.removeHandler(m_events.forCClientListener().connected(), &listener);
m_events.removeHandler(m_events.forIScreen().fileRecieveComplete(), &server); m_events.removeHandler(m_events.forIScreen().fileRecieveCompleted(), &server);
m_events.cleanupQuitTimeout(); m_events.cleanupQuitTimeout();
} }
@ -374,7 +374,7 @@ NetworkTests::sendToClient_mockData_handleClientConnected(const CEvent&, void* v
} }
void void
NetworkTests::sendToClient_mockData_fileRecieveComplete(const CEvent& event, void*) NetworkTests::sendToClient_mockData_fileRecieveCompleted(const CEvent& event, void*)
{ {
CClient* client = reinterpret_cast<CClient*>(event.getTarget()); CClient* client = reinterpret_cast<CClient*>(event.getTarget());
EXPECT_TRUE(client->isReceivedFileSizeValid()); EXPECT_TRUE(client->isReceivedFileSizeValid());
@ -401,7 +401,7 @@ NetworkTests::sendToClient_mockFile_handleClientConnected(const CEvent&, void* v
} }
void void
NetworkTests::sendToClient_mockFile_fileRecieveComplete(const CEvent& event, void*) NetworkTests::sendToClient_mockFile_fileRecieveCompleted(const CEvent& event, void*)
{ {
CClient* client = reinterpret_cast<CClient*>(event.getTarget()); CClient* client = reinterpret_cast<CClient*>(event.getTarget());
EXPECT_TRUE(client->isReceivedFileSizeValid()); EXPECT_TRUE(client->isReceivedFileSizeValid());
@ -417,7 +417,7 @@ NetworkTests::sendToServer_mockData_handleClientConnected(const CEvent&, void* v
} }
void void
NetworkTests::sendToServer_mockData_fileRecieveComplete(const CEvent& event, void*) NetworkTests::sendToServer_mockData_fileRecieveCompleted(const CEvent& event, void*)
{ {
CServer* server = reinterpret_cast<CServer*>(event.getTarget()); CServer* server = reinterpret_cast<CServer*>(event.getTarget());
EXPECT_TRUE(server->isReceivedFileSizeValid()); EXPECT_TRUE(server->isReceivedFileSizeValid());
@ -433,7 +433,7 @@ NetworkTests::sendToServer_mockFile_handleClientConnected(const CEvent&, void* v
} }
void void
NetworkTests::sendToServer_mockFile_fileRecieveComplete(const CEvent& event, void*) NetworkTests::sendToServer_mockFile_fileRecieveCompleted(const CEvent& event, void*)
{ {
CServer* server = reinterpret_cast<CServer*>(event.getTarget()); CServer* server = reinterpret_cast<CServer*>(event.getTarget());
EXPECT_TRUE(server->isReceivedFileSizeValid()); EXPECT_TRUE(server->isReceivedFileSizeValid());

View File

@ -61,6 +61,7 @@ public:
MOCK_METHOD0(forIKeyState, IKeyStateEvents&()); MOCK_METHOD0(forIKeyState, IKeyStateEvents&());
MOCK_METHOD0(forIPrimaryScreen, IPrimaryScreenEvents&()); MOCK_METHOD0(forIPrimaryScreen, IPrimaryScreenEvents&());
MOCK_METHOD0(forIScreen, IScreenEvents&()); MOCK_METHOD0(forIScreen, IScreenEvents&());
MOCK_METHOD0(cacheCurrentEventQueueRef, void());
}; };
#endif #endif