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:
parent
031a84ca84
commit
ce1b62db14
|
@ -594,3 +594,9 @@ CEventQueue::CTimer::operator<(const CTimer& t) const
|
|||
{
|
||||
return m_time < t.m_time;
|
||||
}
|
||||
|
||||
void
|
||||
CEventQueue::cacheCurrentEventQueueRef()
|
||||
{
|
||||
m_buffer->cacheCurrentEventQueueRef();
|
||||
}
|
||||
|
|
|
@ -61,6 +61,8 @@ public:
|
|||
getRegisteredType(const CString& name) const;
|
||||
void* getSystemTarget();
|
||||
|
||||
void cacheCurrentEventQueueRef();
|
||||
|
||||
private:
|
||||
UInt32 saveEvent(const CEvent& event);
|
||||
CEvent removeEvent(UInt32 eventID);
|
||||
|
|
|
@ -177,7 +177,7 @@ REGISTER_EVENT(IScreen, clipboardGrabbed)
|
|||
REGISTER_EVENT(IScreen, suspend)
|
||||
REGISTER_EVENT(IScreen, resume)
|
||||
REGISTER_EVENT(IScreen, fileChunkSending)
|
||||
REGISTER_EVENT(IScreen, fileRecieveComplete)
|
||||
REGISTER_EVENT(IScreen, fileRecieveCompleted)
|
||||
|
||||
//
|
||||
// CIpcServer
|
||||
|
|
|
@ -629,7 +629,7 @@ public:
|
|||
m_suspend(CEvent::kUnknown),
|
||||
m_resume(CEvent::kUnknown),
|
||||
m_fileChunkSending(CEvent::kUnknown),
|
||||
m_fileRecieveComplete(CEvent::kUnknown) { }
|
||||
m_fileRecieveCompleted(CEvent::kUnknown) { }
|
||||
|
||||
//! @name accessors
|
||||
//@{
|
||||
|
@ -674,7 +674,7 @@ public:
|
|||
CEvent::Type fileChunkSending();
|
||||
|
||||
//! Completed receiving a file
|
||||
CEvent::Type fileRecieveComplete();
|
||||
CEvent::Type fileRecieveCompleted();
|
||||
|
||||
//@}
|
||||
|
||||
|
@ -685,5 +685,5 @@ private:
|
|||
CEvent::Type m_suspend;
|
||||
CEvent::Type m_resume;
|
||||
CEvent::Type m_fileChunkSending;
|
||||
CEvent::Type m_fileRecieveComplete;
|
||||
CEvent::Type m_fileRecieveCompleted;
|
||||
};
|
||||
|
|
|
@ -40,6 +40,7 @@ public:
|
|||
virtual CEventQueueTimer*
|
||||
newTimer(double duration, bool oneShot) const;
|
||||
virtual void deleteTimer(CEventQueueTimer*) const;
|
||||
void cacheCurrentEventQueueRef() { }
|
||||
|
||||
private:
|
||||
typedef std::deque<UInt32> CEventDeque;
|
||||
|
|
|
@ -177,6 +177,8 @@ public:
|
|||
registerTypeOnce(CEvent::Type& type,
|
||||
const char* name) = 0;
|
||||
|
||||
virtual void cacheCurrentEventQueueRef() = 0;
|
||||
|
||||
//@}
|
||||
//! @name accessors
|
||||
//@{
|
||||
|
|
|
@ -67,6 +67,8 @@ public:
|
|||
*/
|
||||
virtual bool addEvent(UInt32 dataID) = 0;
|
||||
|
||||
virtual void cacheCurrentEventQueueRef() = 0;
|
||||
|
||||
//@}
|
||||
//! @name accessors
|
||||
//@{
|
||||
|
|
|
@ -85,10 +85,10 @@ CClient::CClient(IEventQueue* events,
|
|||
this,
|
||||
new TMethodEventJob<CClient>(this,
|
||||
&CClient::handleFileChunkSending));
|
||||
m_events->adoptHandler(m_events->forIScreen().fileRecieveComplete(),
|
||||
m_events->adoptHandler(m_events->forIScreen().fileRecieveCompleted(),
|
||||
this,
|
||||
new TMethodEventJob<CClient>(this,
|
||||
&CClient::handleFileRecieveComplete));
|
||||
&CClient::handleFileRecieveCompleted));
|
||||
}
|
||||
|
||||
CClient::~CClient()
|
||||
|
@ -711,17 +711,19 @@ CClient::handleFileChunkSending(const CEvent& event, void*)
|
|||
}
|
||||
|
||||
void
|
||||
CClient::handleFileRecieveComplete(const CEvent& event, void*)
|
||||
CClient::handleFileRecieveCompleted(const CEvent& event, void*)
|
||||
{
|
||||
onFileRecieveComplete();
|
||||
onFileRecieveCompleted();
|
||||
}
|
||||
|
||||
void
|
||||
CClient::onFileRecieveComplete()
|
||||
CClient::onFileRecieveCompleted()
|
||||
{
|
||||
if (isReceivedFileSizeValid()) {
|
||||
m_fileTransferDes = m_screen->getDropTarget();
|
||||
if (!m_fileTransferDes.empty()) {
|
||||
std::fstream file;
|
||||
m_fileTransferDes.append("/").append(m_dragFileList.at(0));
|
||||
file.open(m_fileTransferDes.c_str(), std::ios::out | std::ios::binary);
|
||||
if (!file.is_open()) {
|
||||
// TODO: file open failed
|
||||
|
@ -730,6 +732,9 @@ CClient::onFileRecieveComplete()
|
|||
file.write(m_receivedFileData.c_str(), m_receivedFileData.size());
|
||||
file.close();
|
||||
}
|
||||
else {
|
||||
LOG((CLOG_ERR "drop file failed: drop target is empty"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -752,6 +757,30 @@ CClient::fileChunkReceived(CString 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
|
||||
CClient::isReceivedFileSizeValid()
|
||||
{
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "INode.h"
|
||||
#include "CCryptoOptions.h"
|
||||
#include "CEventTypes.h"
|
||||
#include "CDragInformation.h"
|
||||
|
||||
class CEventQueueTimer;
|
||||
class CScreen;
|
||||
|
@ -101,6 +102,9 @@ public:
|
|||
//! Received a chunk of file 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
|
||||
void sendFileToServer(const char* filename);
|
||||
|
||||
|
@ -193,8 +197,8 @@ private:
|
|||
void handleSuspend(const CEvent& event, void*);
|
||||
void handleResume(const CEvent& event, void*);
|
||||
void handleFileChunkSending(const CEvent&, void*);
|
||||
void handleFileRecieveComplete(const CEvent&, void*);
|
||||
void onFileRecieveComplete();
|
||||
void handleFileRecieveCompleted(const CEvent&, void*);
|
||||
void onFileRecieveCompleted();
|
||||
|
||||
public:
|
||||
bool m_mock;
|
||||
|
@ -223,6 +227,8 @@ private:
|
|||
CString m_receivedFileData;
|
||||
CString m_fileTransferSrc;
|
||||
CString m_fileTransferDes;
|
||||
CDragFileList m_dragFileList;
|
||||
CString m_dragFileExt;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -301,6 +301,9 @@ CServerProxy::parseMessage(const UInt8* code)
|
|||
else if (memcmp(code, kMsgDFileTransfer, 4) == 0) {
|
||||
fileChunkReceived();
|
||||
}
|
||||
else if (memcmp(code, kMsgDDragInfo, 4) == 0) {
|
||||
dragInfoReceived();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgCClose, 4) == 0) {
|
||||
// server wants us to hangup
|
||||
|
@ -865,7 +868,7 @@ void
|
|||
CServerProxy::fileChunkReceived()
|
||||
{
|
||||
// parse
|
||||
UInt8 mark;
|
||||
UInt8 mark = 0;
|
||||
CString content;
|
||||
CProtocolUtil::readf(m_stream, kMsgDFileTransfer + 4, &mark, &content);
|
||||
|
||||
|
@ -898,7 +901,7 @@ CServerProxy::fileChunkReceived()
|
|||
break;
|
||||
|
||||
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) {
|
||||
LOG((CLOG_DEBUG2 "file data transfer finished"));
|
||||
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
|
||||
CServerProxy::fileChunkSending(UInt8 mark, char* data, size_t dataSize)
|
||||
{
|
||||
|
|
|
@ -103,6 +103,7 @@ private:
|
|||
void queryInfo();
|
||||
void infoAcknowledgment();
|
||||
void fileChunkReceived();
|
||||
void dragInfoReceived();
|
||||
|
||||
private:
|
||||
typedef EResult (CServerProxy::*MessageParser)(const UInt8*);
|
||||
|
|
|
@ -40,6 +40,8 @@ public:
|
|||
newTimer(double duration, bool oneShot) const;
|
||||
virtual void deleteTimer(CEventQueueTimer*) const;
|
||||
|
||||
virtual void cacheCurrentEventQueueRef() {}
|
||||
|
||||
private:
|
||||
DWORD m_thread;
|
||||
UINT m_userEvent;
|
||||
|
|
|
@ -699,7 +699,7 @@ CMSWindowsScreen::fakeMouseButton(ButtonID id, bool press)
|
|||
}
|
||||
|
||||
void
|
||||
CMSWindowsScreen::fakeMouseMove(SInt32 x, SInt32 y) const
|
||||
CMSWindowsScreen::fakeMouseMove(SInt32 x, SInt32 y)
|
||||
{
|
||||
m_desks->fakeMouseMove(x, y);
|
||||
}
|
||||
|
|
|
@ -88,7 +88,7 @@ public:
|
|||
|
||||
// ISecondaryScreen overrides
|
||||
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 fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const;
|
||||
|
||||
|
|
|
@ -70,6 +70,9 @@ elseif (APPLE)
|
|||
COSXScreen.cpp
|
||||
COSXScreenSaver.cpp
|
||||
COSXScreenSaverUtil.m
|
||||
COSXPasteboardPeeker.m
|
||||
COSXDragSimulator.m
|
||||
COSXDragView.m
|
||||
)
|
||||
|
||||
elseif (UNIX)
|
||||
|
@ -110,9 +113,20 @@ if (UNIX)
|
|||
)
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
list(APPEND inc
|
||||
/System/Library/Frameworks
|
||||
)
|
||||
endif()
|
||||
|
||||
include_directories(${inc})
|
||||
add_library(platform STATIC ${src})
|
||||
|
||||
if (UNIX)
|
||||
target_link_libraries(platform io net ipc synergy ${libs})
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
FIND_LIBRARY(COCOA_LIBRARY Cocoa)
|
||||
target_link_libraries(platform ${COCOA_LIBRARY})
|
||||
endif()
|
||||
|
|
|
@ -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
|
|
@ -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];
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -99,7 +99,7 @@ COSXEventQueueBuffer::addEvent(UInt32 dataID)
|
|||
&event);
|
||||
|
||||
if (error == noErr) {
|
||||
error = PostEventToQueue(GetMainEventQueue(), event,
|
||||
error = PostEventToQueue(m_threadEventQueueRef, event,
|
||||
kEventPriorityStandard);
|
||||
ReleaseEvent(event);
|
||||
}
|
||||
|
@ -126,3 +126,9 @@ COSXEventQueueBuffer::deleteTimer(CEventQueueTimer* timer) const
|
|||
{
|
||||
delete timer;
|
||||
}
|
||||
|
||||
void
|
||||
COSXEventQueueBuffer::cacheCurrentEventQueueRef()
|
||||
{
|
||||
m_threadEventQueueRef = GetCurrentEventQueue();
|
||||
}
|
||||
|
|
|
@ -38,10 +38,12 @@ public:
|
|||
virtual CEventQueueTimer*
|
||||
newTimer(double duration, bool oneShot) const;
|
||||
virtual void deleteTimer(CEventQueueTimer*) const;
|
||||
virtual void cacheCurrentEventQueueRef();
|
||||
|
||||
private:
|
||||
EventRef m_event;
|
||||
IEventQueue* m_eventQueue;
|
||||
EventQueueRef m_threadEventQueueRef;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -32,6 +32,8 @@
|
|||
#include "TMethodEventJob.h"
|
||||
#include "TMethodJob.h"
|
||||
#include "XArch.h"
|
||||
#include "COSXDragSimulator.h"
|
||||
#include "COSXPasteboardPeeker.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
|
@ -95,7 +97,9 @@ COSXScreen::COSXScreen(IEventQueue* events, bool isPrimary, bool autoShowHideCur
|
|||
m_autoShowHideCursor(autoShowHideCursor),
|
||||
m_eventTapRLSR(nullptr),
|
||||
m_eventTapPort(nullptr),
|
||||
m_pmRootPort(0)
|
||||
m_pmRootPort(0),
|
||||
m_fakeDraggingStarted(false),
|
||||
m_getDropTargetThread(NULL)
|
||||
{
|
||||
try {
|
||||
m_displayID = CGMainDisplayID();
|
||||
|
@ -564,7 +568,7 @@ COSXScreen::fakeMouseButton(ButtonID id, bool press)
|
|||
|
||||
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];
|
||||
CGEventType type = thisButtonMap[state];
|
||||
|
@ -580,11 +584,60 @@ COSXScreen::fakeMouseButton(ButtonID id, bool press)
|
|||
m_lastSingleClickXCursor = m_xCursor;
|
||||
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
|
||||
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
|
||||
CGPoint pos;
|
||||
pos.x = x;
|
||||
|
@ -671,6 +724,12 @@ COSXScreen::showCursor()
|
|||
}
|
||||
|
||||
m_cursorHidden = false;
|
||||
|
||||
if (m_fakeDraggingStarted) {
|
||||
// TODO: use real file extension
|
||||
fakeDragging("txt", 3, m_xCursor, m_yCursor);
|
||||
fakeMouseButton(kButtonLeft, true);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1409,8 +1468,8 @@ COSXScreen::getScrollSpeedFactor() const
|
|||
void
|
||||
COSXScreen::enableDragTimer(bool enable)
|
||||
{
|
||||
UInt32 modifiers;
|
||||
MouseTrackingResult res;
|
||||
UInt32 modifiers;
|
||||
MouseTrackingResult res;
|
||||
|
||||
if (enable && m_dragTimer == NULL) {
|
||||
m_dragTimer = m_events->newTimer(0.01, NULL);
|
||||
|
@ -1430,8 +1489,8 @@ void
|
|||
COSXScreen::handleDrag(const CEvent&, void*)
|
||||
{
|
||||
Point p;
|
||||
UInt32 modifiers;
|
||||
MouseTrackingResult res;
|
||||
UInt32 modifiers;
|
||||
MouseTrackingResult res;
|
||||
|
||||
TrackMouseLocationWithOptions(NULL, 0, 0, &p, &modifiers, &res);
|
||||
|
||||
|
@ -1848,10 +1907,16 @@ COSXScreen::handleCGInputEvent(CGEventTapProxy proxy,
|
|||
case kCGEventOtherMouseUp:
|
||||
screen->onMouseButton(false, CGEventGetIntegerValueField(event, kCGMouseEventButtonNumber) + 1);
|
||||
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 kCGEventOtherMouseDragged:
|
||||
case kCGEventMouseMoved:
|
||||
pos = CGEventGetLocation(event);
|
||||
screen->onMouseMove(pos.x, pos.y);
|
||||
|
||||
|
@ -1942,3 +2007,27 @@ COSXScreen::CMouseButtonState::getFirstButtonDown() const
|
|||
}
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -79,7 +79,7 @@ public:
|
|||
|
||||
// ISecondaryScreen overrides
|
||||
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 fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const;
|
||||
|
||||
|
@ -98,6 +98,10 @@ public:
|
|||
virtual void setSequenceNumber(UInt32);
|
||||
virtual bool isPrimary() const;
|
||||
|
||||
virtual void fakeDraggingFiles(CString str);
|
||||
|
||||
const CString& getDropTarget() const { return m_dropTarget; }
|
||||
|
||||
protected:
|
||||
// IPlatformScreen overrides
|
||||
virtual void handleSystemEvent(const CEvent&, void*);
|
||||
|
@ -191,10 +195,16 @@ private:
|
|||
CGEventType type,
|
||||
CGEventRef event,
|
||||
void* refcon);
|
||||
static CGEventRef handleCGInputEventSecondary(CGEventTapProxy proxy,
|
||||
CGEventType type,
|
||||
CGEventRef event,
|
||||
void* refcon);
|
||||
static CGEventRef handleCGInputEventSecondary(CGEventTapProxy proxy,
|
||||
CGEventType type,
|
||||
CGEventRef event,
|
||||
void* refcon);
|
||||
|
||||
// convert CFString to char*
|
||||
static char* CFStringRefToUTF8String(CFStringRef aString);
|
||||
|
||||
void getDropTargetThread(void*);
|
||||
|
||||
private:
|
||||
struct CHotKeyItem {
|
||||
public:
|
||||
|
@ -334,6 +344,10 @@ private:
|
|||
bool m_autoShowHideCursor;
|
||||
|
||||
IEventQueue* m_events;
|
||||
|
||||
bool m_fakeDraggingStarted;
|
||||
CThread* m_getDropTargetThread;
|
||||
CString m_dropTarget;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -45,6 +45,8 @@ public:
|
|||
newTimer(double duration, bool oneShot) const;
|
||||
virtual void deleteTimer(CEventQueueTimer*) const;
|
||||
|
||||
virtual void cacheCurrentEventQueueRef() {}
|
||||
|
||||
private:
|
||||
void flush();
|
||||
|
||||
|
|
|
@ -832,7 +832,7 @@ CXWindowsScreen::fakeMouseButton(ButtonID button, bool press)
|
|||
}
|
||||
|
||||
void
|
||||
CXWindowsScreen::fakeMouseMove(SInt32 x, SInt32 y) const
|
||||
CXWindowsScreen::fakeMouseMove(SInt32 x, SInt32 y)
|
||||
{
|
||||
if (m_xinerama && m_xtestIsXineramaUnaware) {
|
||||
XWarpPointer(m_display, None, m_root, 0, 0, 0, 0, x, y);
|
||||
|
|
|
@ -66,7 +66,7 @@ public:
|
|||
|
||||
// ISecondaryScreen overrides
|
||||
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 fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const;
|
||||
|
||||
|
|
|
@ -79,6 +79,7 @@ public:
|
|||
virtual void screensaver(bool activate) = 0;
|
||||
virtual void resetOptions() = 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 CString getName() const;
|
||||
|
||||
|
|
|
@ -85,6 +85,7 @@ public:
|
|||
virtual void resetOptions() = 0;
|
||||
virtual void setOptions(const COptionsList& options) = 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;
|
||||
|
||||
private:
|
||||
|
|
|
@ -365,6 +365,13 @@ CClientProxy1_0::cryptoIv(const UInt8* iv)
|
|||
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
|
||||
CClientProxy1_0::fileChunkSending(UInt8 mark, char* data, size_t dataSize)
|
||||
{
|
||||
|
|
|
@ -60,6 +60,7 @@ public:
|
|||
virtual void resetOptions();
|
||||
virtual void setOptions(const COptionsList& options);
|
||||
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);
|
||||
|
||||
protected:
|
||||
|
|
|
@ -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
|
||||
CClientProxy1_5::fileChunkSending(UInt8 mark, char* data, size_t dataSize)
|
||||
{
|
||||
|
@ -79,7 +87,7 @@ void
|
|||
CClientProxy1_5::fileChunkReceived()
|
||||
{
|
||||
// parse
|
||||
UInt8 mark;
|
||||
UInt8 mark = 0;
|
||||
CString content;
|
||||
CProtocolUtil::readf(getStream(), kMsgDFileTransfer + 4, &mark, &content);
|
||||
|
||||
|
@ -113,7 +121,7 @@ CClientProxy1_5::fileChunkReceived()
|
|||
break;
|
||||
|
||||
case kFileEnd:
|
||||
m_events->addEvent(CEvent(m_events->forIScreen().fileRecieveComplete(), server));
|
||||
m_events->addEvent(CEvent(m_events->forIScreen().fileRecieveCompleted(), server));
|
||||
if (CLOG->getFilter() >= kDEBUG2) {
|
||||
LOG((CLOG_DEBUG2 "file data transfer finished"));
|
||||
m_elapsedTime += m_stopwatch.getTime();
|
||||
|
|
|
@ -29,6 +29,7 @@ public:
|
|||
CClientProxy1_5(const CString& name, synergy::IStream* adoptedStream, CServer* server, IEventQueue* events);
|
||||
~CClientProxy1_5();
|
||||
|
||||
virtual void draggingInfoSending(UInt32 fileCount, const char* data, size_t dataSize);
|
||||
virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize);
|
||||
virtual bool parseMessage(const UInt8* code);
|
||||
void fileChunkReceived();
|
||||
|
|
|
@ -249,6 +249,12 @@ CPrimaryClient::screensaver(bool)
|
|||
// ignore
|
||||
}
|
||||
|
||||
void
|
||||
CPrimaryClient::draggingInfoSending(UInt32 fileCount, const char* data, size_t dataSize)
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
|
||||
void
|
||||
CPrimaryClient::fileChunkSending(UInt8 mark, char* data, size_t dataSize)
|
||||
{
|
||||
|
|
|
@ -144,6 +144,7 @@ public:
|
|||
virtual void screensaver(bool activate);
|
||||
virtual void resetOptions();
|
||||
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);
|
||||
|
||||
private:
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include "CThread.h"
|
||||
#include "TMethodJob.h"
|
||||
#include "CFileChunker.h"
|
||||
#include "CDragInformation.h"
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <sstream>
|
||||
|
@ -167,10 +168,10 @@ CServer::CServer(CConfig& config, CPrimaryClient* primaryClient, CScreen* screen
|
|||
this,
|
||||
new TMethodEventJob<CServer>(this,
|
||||
&CServer::handleFileChunkSendingEvent));
|
||||
m_events->adoptHandler(m_events->forIScreen().fileRecieveComplete(),
|
||||
m_events->adoptHandler(m_events->forIScreen().fileRecieveCompleted(),
|
||||
this,
|
||||
new TMethodEventJob<CServer>(this,
|
||||
&CServer::handleFileRecieveCompleteEvent));
|
||||
&CServer::handleFileRecieveCompletedEvent));
|
||||
|
||||
// add connection
|
||||
addClient(m_primaryClient);
|
||||
|
@ -1472,9 +1473,9 @@ CServer::handleFileChunkSendingEvent(const CEvent& event, void*)
|
|||
}
|
||||
|
||||
void
|
||||
CServer::handleFileRecieveCompleteEvent(const CEvent& event, void*)
|
||||
CServer::handleFileRecieveCompletedEvent(const CEvent& event, void*)
|
||||
{
|
||||
onFileRecieveComplete();
|
||||
onFileRecieveCompleted();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1737,8 +1738,24 @@ CServer::onMouseMovePrimary(SInt32 x, SInt32 y)
|
|||
|
||||
// should we switch or not?
|
||||
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
|
||||
switchScreen(newScreen, x, y, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
|
@ -1930,7 +1947,7 @@ CServer::onFileChunkSending(const void* data)
|
|||
}
|
||||
|
||||
void
|
||||
CServer::onFileRecieveComplete()
|
||||
CServer::onFileRecieveCompleted()
|
||||
{
|
||||
if (isReceivedFileSizeValid()) {
|
||||
if (!m_fileTransferDes.empty()) {
|
||||
|
|
|
@ -310,7 +310,7 @@ private:
|
|||
void handleFakeInputBeginEvent(const CEvent&, void*);
|
||||
void handleFakeInputEndEvent(const CEvent&, void*);
|
||||
void handleFileChunkSendingEvent(const CEvent&, void*);
|
||||
void handleFileRecieveCompleteEvent(const CEvent&, void*);
|
||||
void handleFileRecieveCompletedEvent(const CEvent&, void*);
|
||||
|
||||
// event processing
|
||||
void onClipboardChanged(CBaseClientProxy* sender,
|
||||
|
@ -327,7 +327,7 @@ private:
|
|||
void onMouseMoveSecondary(SInt32 dx, SInt32 dy);
|
||||
void onMouseWheel(SInt32 xDelta, SInt32 yDelta);
|
||||
void onFileChunkSending(const void* data);
|
||||
void onFileRecieveComplete();
|
||||
void onFileRecieveCompleted();
|
||||
|
||||
// add client to list and attach event handlers for client
|
||||
bool addClient(CBaseClientProxy*);
|
||||
|
|
|
@ -50,6 +50,10 @@
|
|||
#include "COSXScreen.h"
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include "COSXDragSimulator.h"
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
|
||||
|
@ -531,7 +535,17 @@ CClientApp::mainLoop()
|
|||
// later. the timer installed by startClient() will take care of
|
||||
// that.
|
||||
DAEMON_RUNNING(true);
|
||||
|
||||
#if defined(__APPLE__)
|
||||
CThread thread(
|
||||
new TMethodJob<CClientApp>(
|
||||
this, &CClientApp::runEventsLoop,
|
||||
NULL));
|
||||
runCocoaApp();
|
||||
#else
|
||||
m_events->loop();
|
||||
#endif
|
||||
|
||||
DAEMON_RUNNING(false);
|
||||
|
||||
// close down
|
||||
|
@ -612,3 +626,10 @@ CClientApp::startNode()
|
|||
m_bye(kExitFailed);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CClientApp::runEventsLoop(void*)
|
||||
{
|
||||
m_events->cacheCurrentEventQueueRef();
|
||||
m_events->loop();
|
||||
}
|
||||
|
|
|
@ -85,6 +85,7 @@ public:
|
|||
|
||||
private:
|
||||
virtual bool parseArg(const int& argc, const char* const* argv, int& i);
|
||||
void runEventsLoop(void*);
|
||||
|
||||
private:
|
||||
CClient* s_client;
|
||||
|
|
|
@ -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 "";
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
};
|
|
@ -48,6 +48,7 @@ set(inc
|
|||
CArgsBase.h
|
||||
IAppUtil.h
|
||||
CFileChunker.h
|
||||
CDragInformation.h
|
||||
)
|
||||
|
||||
set(src
|
||||
|
@ -75,6 +76,7 @@ set(src
|
|||
CAppUtil.cpp
|
||||
CArgsBase.cpp
|
||||
CFileChunker.cpp
|
||||
CDragInformation.cpp
|
||||
)
|
||||
|
||||
if (WIN32)
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#define CPLATFORMSCREEN_H
|
||||
|
||||
#include "IPlatformScreen.h"
|
||||
#include <stdexcept>
|
||||
|
||||
//! Base screen implementation
|
||||
/*!
|
||||
|
@ -53,7 +54,7 @@ public:
|
|||
|
||||
// ISecondaryScreen overrides
|
||||
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 fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const = 0;
|
||||
|
||||
|
@ -76,6 +77,8 @@ public:
|
|||
virtual SInt32 pollActiveGroup() 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; }
|
||||
|
||||
// IPlatformScreen overrides
|
||||
|
@ -93,6 +96,10 @@ public:
|
|||
virtual void setSequenceNumber(UInt32) = 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:
|
||||
//! Update mouse buttons
|
||||
/*!
|
||||
|
|
|
@ -415,12 +415,36 @@ CScreen::pollActiveModifiers() const
|
|||
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&
|
||||
CScreen::getDraggingFileDir() const
|
||||
{
|
||||
return m_screen->getDraggingFileDir();
|
||||
}
|
||||
|
||||
const CString&
|
||||
CScreen::getDropTarget() const
|
||||
{
|
||||
return m_screen->getDropTarget();
|
||||
}
|
||||
|
||||
void*
|
||||
CScreen::getEventTarget() const
|
||||
{
|
||||
|
|
|
@ -219,6 +219,12 @@ public:
|
|||
*/
|
||||
void fakeInputEnd();
|
||||
|
||||
//! Change dragging status
|
||||
void setDraggingStarted(bool started);
|
||||
|
||||
//! Fake a files dragging operation
|
||||
void startDraggingFiles(CString str);
|
||||
|
||||
//@}
|
||||
//! @name accessors
|
||||
//@{
|
||||
|
@ -267,10 +273,18 @@ public:
|
|||
*/
|
||||
KeyModifierMask pollActiveModifiers() const;
|
||||
|
||||
//! Check if dragging has started.
|
||||
|
||||
bool getDraggingStarted() const;
|
||||
|
||||
//! Get dragging file's directory.
|
||||
|
||||
CString& getDraggingFileDir() const;
|
||||
|
||||
//! Get drop target directory.
|
||||
|
||||
const CString& getDropTarget() const;
|
||||
|
||||
//@}
|
||||
|
||||
// IScreen overrides
|
||||
|
|
|
@ -130,6 +130,9 @@ public:
|
|||
*/
|
||||
virtual void setSequenceNumber(UInt32) = 0;
|
||||
|
||||
//! Change dragging status
|
||||
virtual void setDraggingStarted(bool started) = 0;
|
||||
|
||||
//@}
|
||||
//! @name accessors
|
||||
//@{
|
||||
|
@ -162,7 +165,7 @@ public:
|
|||
|
||||
// ISecondaryScreen overrides
|
||||
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 fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const = 0;
|
||||
|
||||
|
@ -186,6 +189,11 @@ public:
|
|||
virtual void pollPressedKeys(KeyButtonSet& pressedKeys) const = 0;
|
||||
|
||||
virtual CString& getDraggingFileDir() = 0;
|
||||
virtual bool getDraggingStarted() = 0;
|
||||
|
||||
virtual void fakeDraggingFiles(CString str) = 0;
|
||||
virtual const CString&
|
||||
getDropTarget() const = 0;
|
||||
|
||||
protected:
|
||||
//! Handle system event
|
||||
|
|
|
@ -44,7 +44,7 @@ public:
|
|||
/*!
|
||||
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
|
||||
/*!
|
||||
|
|
|
@ -46,6 +46,7 @@ const char* kMsgDInfo = "DINF%2i%2i%2i%2i%2i%2i%2i";
|
|||
const char* kMsgDSetOptions = "DSOP%4I";
|
||||
const char* kMsgDCryptoIv = "DCIV%s";
|
||||
const char* kMsgDFileTransfer = "DFTR%1i%s";
|
||||
const char* kMsgDDragInfo = "DDRG%2i%s";
|
||||
const char* kMsgQInfo = "QINF";
|
||||
const char* kMsgEIncompatible = "EICV%2i%2i";
|
||||
const char* kMsgEBusy = "EBSY";
|
||||
|
|
|
@ -263,6 +263,12 @@ extern const char* kMsgDCryptoIv;
|
|||
// 2 means the file transfer is finished.
|
||||
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
|
||||
//
|
||||
|
|
|
@ -92,16 +92,16 @@ public:
|
|||
void sendMockData(void* eventTarget);
|
||||
|
||||
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_fileRecieveComplete(const CEvent& event, void*);
|
||||
void sendToClient_mockFile_fileRecieveCompleted(const CEvent& event, void*);
|
||||
|
||||
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_fileRecieveComplete(const CEvent& event, void*);
|
||||
void sendToServer_mockFile_fileRecieveCompleted(const CEvent& event, void*);
|
||||
|
||||
public:
|
||||
CTestEventQueue m_events;
|
||||
|
@ -159,16 +159,16 @@ TEST_F(NetworkTests, sendToClient_mockData)
|
|||
CClient client(&m_events, "stub", serverAddress, clientSocketFactory, NULL, &clientScreen, cryptoOptions);
|
||||
|
||||
m_events.adoptHandler(
|
||||
m_events.forIScreen().fileRecieveComplete(), &client,
|
||||
m_events.forIScreen().fileRecieveCompleted(), &client,
|
||||
new TMethodEventJob<NetworkTests>(
|
||||
this, &NetworkTests::sendToClient_mockData_fileRecieveComplete));
|
||||
this, &NetworkTests::sendToClient_mockData_fileRecieveCompleted));
|
||||
|
||||
client.connect();
|
||||
|
||||
m_events.initQuitTimeout(10);
|
||||
m_events.loop();
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -220,16 +220,16 @@ TEST_F(NetworkTests, sendToClient_mockFile)
|
|||
CClient client(&m_events, "stub", serverAddress, clientSocketFactory, NULL, &clientScreen, cryptoOptions);
|
||||
|
||||
m_events.adoptHandler(
|
||||
m_events.forIScreen().fileRecieveComplete(), &client,
|
||||
m_events.forIScreen().fileRecieveCompleted(), &client,
|
||||
new TMethodEventJob<NetworkTests>(
|
||||
this, &NetworkTests::sendToClient_mockFile_fileRecieveComplete));
|
||||
this, &NetworkTests::sendToClient_mockFile_fileRecieveCompleted));
|
||||
|
||||
client.connect();
|
||||
|
||||
m_events.initQuitTimeout(10);
|
||||
m_events.loop();
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -281,16 +281,16 @@ TEST_F(NetworkTests, sendToServer_mockData)
|
|||
this, &NetworkTests::sendToServer_mockData_handleClientConnected, &client));
|
||||
|
||||
m_events.adoptHandler(
|
||||
m_events.forIScreen().fileRecieveComplete(), &server,
|
||||
m_events.forIScreen().fileRecieveCompleted(), &server,
|
||||
new TMethodEventJob<NetworkTests>(
|
||||
this, &NetworkTests::sendToServer_mockData_fileRecieveComplete));
|
||||
this, &NetworkTests::sendToServer_mockData_fileRecieveCompleted));
|
||||
|
||||
client.connect();
|
||||
|
||||
m_events.initQuitTimeout(10);
|
||||
m_events.loop();
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -342,16 +342,16 @@ TEST_F(NetworkTests, sendToServer_mockFile)
|
|||
this, &NetworkTests::sendToServer_mockFile_handleClientConnected, &client));
|
||||
|
||||
m_events.adoptHandler(
|
||||
m_events.forIScreen().fileRecieveComplete(), &server,
|
||||
m_events.forIScreen().fileRecieveCompleted(), &server,
|
||||
new TMethodEventJob<NetworkTests>(
|
||||
this, &NetworkTests::sendToServer_mockFile_fileRecieveComplete));
|
||||
this, &NetworkTests::sendToServer_mockFile_fileRecieveCompleted));
|
||||
|
||||
client.connect();
|
||||
|
||||
m_events.initQuitTimeout(10);
|
||||
m_events.loop();
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -374,7 +374,7 @@ NetworkTests::sendToClient_mockData_handleClientConnected(const CEvent&, void* v
|
|||
}
|
||||
|
||||
void
|
||||
NetworkTests::sendToClient_mockData_fileRecieveComplete(const CEvent& event, void*)
|
||||
NetworkTests::sendToClient_mockData_fileRecieveCompleted(const CEvent& event, void*)
|
||||
{
|
||||
CClient* client = reinterpret_cast<CClient*>(event.getTarget());
|
||||
EXPECT_TRUE(client->isReceivedFileSizeValid());
|
||||
|
@ -401,7 +401,7 @@ NetworkTests::sendToClient_mockFile_handleClientConnected(const CEvent&, void* v
|
|||
}
|
||||
|
||||
void
|
||||
NetworkTests::sendToClient_mockFile_fileRecieveComplete(const CEvent& event, void*)
|
||||
NetworkTests::sendToClient_mockFile_fileRecieveCompleted(const CEvent& event, void*)
|
||||
{
|
||||
CClient* client = reinterpret_cast<CClient*>(event.getTarget());
|
||||
EXPECT_TRUE(client->isReceivedFileSizeValid());
|
||||
|
@ -417,7 +417,7 @@ NetworkTests::sendToServer_mockData_handleClientConnected(const CEvent&, void* v
|
|||
}
|
||||
|
||||
void
|
||||
NetworkTests::sendToServer_mockData_fileRecieveComplete(const CEvent& event, void*)
|
||||
NetworkTests::sendToServer_mockData_fileRecieveCompleted(const CEvent& event, void*)
|
||||
{
|
||||
CServer* server = reinterpret_cast<CServer*>(event.getTarget());
|
||||
EXPECT_TRUE(server->isReceivedFileSizeValid());
|
||||
|
@ -433,7 +433,7 @@ NetworkTests::sendToServer_mockFile_handleClientConnected(const CEvent&, void* v
|
|||
}
|
||||
|
||||
void
|
||||
NetworkTests::sendToServer_mockFile_fileRecieveComplete(const CEvent& event, void*)
|
||||
NetworkTests::sendToServer_mockFile_fileRecieveCompleted(const CEvent& event, void*)
|
||||
{
|
||||
CServer* server = reinterpret_cast<CServer*>(event.getTarget());
|
||||
EXPECT_TRUE(server->isReceivedFileSizeValid());
|
||||
|
|
|
@ -61,6 +61,7 @@ public:
|
|||
MOCK_METHOD0(forIKeyState, IKeyStateEvents&());
|
||||
MOCK_METHOD0(forIPrimaryScreen, IPrimaryScreenEvents&());
|
||||
MOCK_METHOD0(forIScreen, IScreenEvents&());
|
||||
MOCK_METHOD0(cacheCurrentEventQueueRef, void());
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue