added platform independent clipboard transfer stuff

clipboard owner support (MS windows done, X windows partial)
added key transfer on ms windows
mutex fixes in CClient (had race conditions)
faster debug output in ms windows
changed temporary screen name to "secondary"
network fixes on ms windows (poll returned wrong result)
fixed transparent cursor on ms windows
This commit is contained in:
crs 2001-11-25 18:32:41 +00:00
parent 3f6146b15f
commit f15c9df85b
43 changed files with 1590 additions and 324 deletions

View File

@ -2,8 +2,10 @@
#include "CInputPacketStream.h"
#include "COutputPacketStream.h"
#include "CProtocolUtil.h"
#include "CClipboard.h"
#include "ISecondaryScreen.h"
#include "ProtocolTypes.h"
#include "CLock.h"
#include "CThread.h"
#include "CTimerThread.h"
#include "XSynergy.h"
@ -63,7 +65,7 @@ void CClient::run(const CNetworkAddress& serverAddress)
closeSecondaryScreen();
}
catch (XBase& e) {
log((CLOG_ERR "client error: %s\n", e.what()));
log((CLOG_ERR "client error: %s", e.what()));
// clean up
thread->cancel();
@ -83,6 +85,17 @@ void CClient::run(const CNetworkAddress& serverAddress)
}
}
void CClient::onClipboardChanged()
{
log((CLOG_DEBUG "sending clipboard changed"));
CLock lock(&m_mutex);
if (m_output != NULL) {
// m_output can be NULL if the screen calls this method
// before we've gotten around to connecting to the server.
CProtocolUtil::writef(m_output, kMsgCClipboard);
}
}
#include "CTCPSocket.h" // FIXME
void CClient::runSession(void*)
{
@ -136,10 +149,10 @@ void CClient::runSession(void*)
// say hello back
log((CLOG_DEBUG "say hello version %d.%d", kMajorVersion, kMinorVersion));
CProtocolUtil::writef(output.get(), "Synergy%2i%2i%s",
kMajorVersion, kMinorVersion,
m_name.size(), m_name.data());
kMajorVersion, kMinorVersion, &m_name);
// record streams in a more useful place
CLock lock(&m_mutex);
m_input = input.get();
m_output = output.get();
}
@ -291,7 +304,10 @@ void CClient::closeSecondaryScreen()
void CClient::onEnter()
{
SInt32 x, y;
CProtocolUtil::readf(m_input, kMsgCEnter + 4, &x, &y);
{
CLock lock(&m_mutex);
CProtocolUtil::readf(m_input, kMsgCEnter + 4, &x, &y);
}
m_screen->enter(x, y);
}
@ -302,13 +318,16 @@ void CClient::onLeave()
void CClient::onGrabClipboard()
{
// FIXME
m_screen->grabClipboard();
}
void CClient::onScreenSaver()
{
SInt32 on;
CProtocolUtil::readf(m_input, kMsgCScreenSaver + 4, &on);
{
CLock lock(&m_mutex);
CProtocolUtil::readf(m_input, kMsgCScreenSaver + 4, &on);
}
// FIXME
}
@ -317,24 +336,63 @@ void CClient::onQueryInfo()
SInt32 w, h;
m_screen->getSize(&w, &h);
SInt32 zoneSize = m_screen->getJumpZoneSize();
log((CLOG_DEBUG "sending info size=%d,%d zone=%d", w, h, zoneSize));
CLock lock(&m_mutex);
CProtocolUtil::writef(m_output, kMsgDInfo, w, h, zoneSize);
}
void CClient::onQueryClipboard()
{
// FIXME
// parse message
UInt32 seqNum;
CClipboard clipboard;
{
CLock lock(&m_mutex);
CProtocolUtil::readf(m_input, kMsgQClipboard + 4, &seqNum);
}
log((CLOG_DEBUG "received query clipboard seqnum=%d", seqNum));
// get screen's clipboard data
m_screen->getClipboard(&clipboard);
// marshall the data
CString data = clipboard.marshall();
// send it
log((CLOG_DEBUG "sending clipboard seqnum=%d, size=%d", seqNum, data.size()));
{
CLock lock(&m_mutex);
CProtocolUtil::writef(m_output, kMsgDClipboard, seqNum, &data);
}
}
void CClient::onSetClipboard()
{
// FIXME
CString data;
{
// parse message
UInt32 seqNum;
CLock lock(&m_mutex);
CProtocolUtil::readf(m_input, kMsgDClipboard + 4, &seqNum, &data);
}
log((CLOG_DEBUG "received clipboard size=%d", data.size()));
// unmarshall
CClipboard clipboard;
clipboard.unmarshall(data);
// set screen's clipboard
m_screen->setClipboard(&clipboard);
}
void CClient::onKeyDown()
{
SInt32 id, mask;
CProtocolUtil::readf(m_input, kMsgDKeyDown + 4, &id, &mask);
{
CLock lock(&m_mutex);
CProtocolUtil::readf(m_input, kMsgDKeyDown + 4, &id, &mask);
}
m_screen->keyDown(static_cast<KeyID>(id),
static_cast<KeyModifierMask>(mask));
}
@ -342,7 +400,10 @@ void CClient::onKeyDown()
void CClient::onKeyRepeat()
{
SInt32 id, mask, count;
CProtocolUtil::readf(m_input, kMsgDKeyRepeat + 4, &id, &mask, &count);
{
CLock lock(&m_mutex);
CProtocolUtil::readf(m_input, kMsgDKeyRepeat + 4, &id, &mask, &count);
}
m_screen->keyRepeat(static_cast<KeyID>(id),
static_cast<KeyModifierMask>(mask),
count);
@ -351,7 +412,10 @@ void CClient::onKeyRepeat()
void CClient::onKeyUp()
{
SInt32 id, mask;
CProtocolUtil::readf(m_input, kMsgDKeyUp + 4, &id, &mask);
{
CLock lock(&m_mutex);
CProtocolUtil::readf(m_input, kMsgDKeyUp + 4, &id, &mask);
}
m_screen->keyUp(static_cast<KeyID>(id),
static_cast<KeyModifierMask>(mask));
}
@ -359,27 +423,39 @@ void CClient::onKeyUp()
void CClient::onMouseDown()
{
SInt32 id;
CProtocolUtil::readf(m_input, kMsgDMouseDown + 4, &id);
{
CLock lock(&m_mutex);
CProtocolUtil::readf(m_input, kMsgDMouseDown + 4, &id);
}
m_screen->mouseDown(static_cast<ButtonID>(id));
}
void CClient::onMouseUp()
{
SInt32 id;
CProtocolUtil::readf(m_input, kMsgDMouseUp + 4, &id);
{
CLock lock(&m_mutex);
CProtocolUtil::readf(m_input, kMsgDMouseUp + 4, &id);
}
m_screen->mouseUp(static_cast<ButtonID>(id));
}
void CClient::onMouseMove()
{
SInt32 x, y;
CProtocolUtil::readf(m_input, kMsgDMouseMove + 4, &x, &y);
{
CLock lock(&m_mutex);
CProtocolUtil::readf(m_input, kMsgDMouseMove + 4, &x, &y);
}
m_screen->mouseMove(x, y);
}
void CClient::onMouseWheel()
{
SInt32 delta;
CProtocolUtil::readf(m_input, kMsgDMouseWheel + 4, &delta);
{
CLock lock(&m_mutex);
CProtocolUtil::readf(m_input, kMsgDMouseWheel + 4, &delta);
}
m_screen->mouseWheel(delta);
}

View File

@ -1,6 +1,7 @@
#ifndef CCLIENT_H
#define CCLIENT_H
#include "CMutex.h"
#include "CString.h"
#include "BasicTypes.h"
@ -18,6 +19,9 @@ class CClient {
void run(const CNetworkAddress& serverAddress);
// handle events on client's screen
void onClipboardChanged();
// accessors
@ -45,6 +49,7 @@ class CClient {
void onMouseWheel();
private:
CMutex m_mutex;
CString m_name;
IInputStream* m_input;
IOutputStream* m_output;

View File

@ -1,5 +1,7 @@
#include "CMSWindowsSecondaryScreen.h"
#include "CMSWindowsClipboard.h"
#include "CClient.h"
#include "CClipboard.h"
#include "CThread.h"
#include "CLog.h"
#include <assert.h>
@ -10,7 +12,8 @@
CMSWindowsSecondaryScreen::CMSWindowsSecondaryScreen() :
m_client(NULL),
m_window(NULL)
m_window(NULL),
m_nextClipboardWindow(NULL)
{
// do nothing
}
@ -20,6 +23,8 @@ CMSWindowsSecondaryScreen::~CMSWindowsSecondaryScreen()
assert(m_window == NULL);
}
static CString s_log;
static CString s_logMore;
static HWND s_debug = NULL;
static HWND s_debugLog = NULL;
static DWORD s_thread = 0;
@ -32,39 +37,40 @@ static BOOL CALLBACK WINAPI debugProc(HWND, UINT msg, WPARAM wParam, LPARAM lPar
case WM_CLOSE:
PostQuitMessage(0);
return TRUE;
case WM_APP:
if (!s_logMore.empty()) {
if (s_log.size() > 20000)
s_log = s_logMore;
else
s_log += s_logMore;
s_logMore = "";
SendMessage(s_debugLog, WM_SETTEXT, FALSE, (LPARAM)(LPCTSTR)s_log.c_str());
SendMessage(s_debugLog, EM_SETSEL, s_log.size(), s_log.size());
SendMessage(s_debugLog, EM_SCROLLCARET, 0, 0);
}
return TRUE;
}
return FALSE;
}
static void debugOutput(const char* msg)
{
if (s_thread != 0) {
const DWORD threadID = ::GetCurrentThreadId();
if (threadID != s_thread) {
GetDesktopWindow();
AttachThreadInput(threadID, s_thread, TRUE);
}
}
DWORD len = SendMessage(s_debugLog, WM_GETTEXTLENGTH, 0, 0);
if (len > 20000) {
SendMessage(s_debugLog, EM_SETSEL, -1, 0);
SendMessage(s_debugLog, WM_SETTEXT, FALSE, (LPARAM)(LPCTSTR)msg);
}
else {
SendMessage(s_debugLog, EM_SETSEL, -1, len);
SendMessage(s_debugLog, EM_REPLACESEL, FALSE, (LPARAM)(LPCTSTR)msg);
}
SendMessage(s_debugLog, EM_SCROLLCARET, 0, 0);
s_logMore += msg;
PostMessage(s_debug, WM_APP, 0, 0);
}
void CMSWindowsSecondaryScreen::run()
{
CLog::setOutputter(&debugOutput);
log((CLOG_INFO "entering event loop"));
doRun();
log((CLOG_INFO "exiting event loop"));
CLog::setOutputter(NULL);
}
void CMSWindowsSecondaryScreen::stop()
{
log((CLOG_INFO "requesting event loop stop"));
doStop();
}
@ -73,6 +79,8 @@ void CMSWindowsSecondaryScreen::open(CClient* client)
assert(m_client == NULL);
assert(client != NULL);
log((CLOG_INFO "opening screen"));
// set the client
m_client = client;
@ -84,6 +92,8 @@ void CMSWindowsSecondaryScreen::close()
{
assert(m_client != NULL);
log((CLOG_INFO "closing screen"));
// close the display
closeDisplay();
@ -95,6 +105,8 @@ void CMSWindowsSecondaryScreen::enter(SInt32 x, SInt32 y)
{
assert(m_window != NULL);
log((CLOG_INFO "entering screen at %d,%d", x, y));
// warp to requested location
SInt32 w, h;
getScreenSize(&w, &h);
@ -104,6 +116,7 @@ void CMSWindowsSecondaryScreen::enter(SInt32 x, SInt32 y)
0, 0);
// show cursor
log((CLOG_INFO "show cursor"));
ShowWindow(m_window, SW_HIDE);
}
@ -111,6 +124,8 @@ void CMSWindowsSecondaryScreen::leave()
{
assert(m_window != NULL);
log((CLOG_INFO "leaving screen"));
// move hider window under the mouse (rather than moving the mouse
// somewhere else on the screen)
POINT point;
@ -118,10 +133,27 @@ void CMSWindowsSecondaryScreen::leave()
MoveWindow(m_window, point.x, point.y, 1, 1, FALSE);
// raise and show the hider window. take activation.
log((CLOG_INFO "hide cursor"));
ShowWindow(m_window, SW_SHOWNORMAL);
// hide cursor by moving it into the hider window
SetCursorPos(point.x, point.y);
// if we think we own the clipboard but we don't then somebody
// grabbed the clipboard on this screen without us knowing.
// tell the server that this screen grabbed the clipboard.
//
// this works around bugs in the clipboard viewer chain.
// sometimes NT will simply never send WM_DRAWCLIPBOARD
// messages for no apparent reason and rebooting fixes the
// problem. since we don't want a broken clipboard until the
// next reboot we do this double check. clipboard ownership
// won't be reflected on other screens until we leave but at
// least the clipboard itself will work.
HWND clipboardOwner = GetClipboardOwner();
if (m_clipboardOwner != clipboardOwner) {
m_clipboardOwner = clipboardOwner;
if (m_clipboardOwner != m_window) {
m_client->onClipboardChanged();
}
}
}
void CMSWindowsSecondaryScreen::keyDown(
@ -222,6 +254,25 @@ void CMSWindowsSecondaryScreen::mouseWheel(SInt32 delta)
mouse_event(MOUSEEVENTF_WHEEL, 0, 0, delta, 0);
}
void CMSWindowsSecondaryScreen::setClipboard(
const IClipboard* src)
{
assert(m_window != NULL);
CMSWindowsClipboard dst(m_window);
CClipboard::copy(&dst, src);
}
void CMSWindowsSecondaryScreen::grabClipboard()
{
assert(m_window != NULL);
CMSWindowsClipboard clipboard(m_window);
if (clipboard.open()) {
clipboard.close();
}
}
void CMSWindowsSecondaryScreen::getSize(
SInt32* width, SInt32* height) const
{
@ -233,6 +284,15 @@ SInt32 CMSWindowsSecondaryScreen::getJumpZoneSize() const
return 0;
}
void CMSWindowsSecondaryScreen::getClipboard(
IClipboard* dst) const
{
assert(m_window != NULL);
CMSWindowsClipboard src(m_window);
CClipboard::copy(dst, &src);
}
#include "resource.h" // FIXME
void CMSWindowsSecondaryScreen::onOpenDisplay()
@ -246,6 +306,10 @@ s_debugLog = ::GetDlgItem(s_debug, IDC_LOG);
CLog::setOutputter(&debugOutput);
ShowWindow(s_debug, SW_SHOWNORMAL);
// initialize clipboard owner to current owner. we don't want
// to take ownership of the clipboard just by starting up.
m_clipboardOwner = GetClipboardOwner();
// create the cursor hiding window. this window is used to hide the
// cursor when it's not on the screen. the window is hidden as soon
// as the cursor enters the screen or the display's real cursor is
@ -253,19 +317,26 @@ ShowWindow(s_debug, SW_SHOWNORMAL);
m_window = CreateWindowEx(WS_EX_TOPMOST |
WS_EX_TRANSPARENT | WS_EX_TOOLWINDOW,
(LPCTSTR)getClass(), "Synergy",
WS_POPUP | WS_DISABLED,
WS_POPUP,
0, 0, 1, 1, NULL, NULL,
getInstance(),
NULL);
// hide the cursor
leave();
// install our clipboard snooper
m_nextClipboardWindow = SetClipboardViewer(m_window);
}
void CMSWindowsSecondaryScreen::onCloseDisplay()
{
assert(m_window != NULL);
// remove clipboard snooper
ChangeClipboardChain(m_window, m_nextClipboardWindow);
m_nextClipboardWindow = NULL;
// destroy window
DestroyWindow(m_window);
m_window = NULL;
@ -276,49 +347,56 @@ s_debug = NULL;
s_thread = 0;
}
bool CMSWindowsSecondaryScreen::onEvent(MSG* msg)
bool CMSWindowsSecondaryScreen::onPreTranslate(MSG* msg)
{
if (IsDialogMessage(s_debug, msg)) {
return true;
}
return false;
}
// handle event
switch (msg->message) {
LRESULT CMSWindowsSecondaryScreen::onEvent(
HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam)
{
switch (msg) {
// FIXME -- handle display changes
case WM_PAINT:
ValidateRect(m_window, NULL);
return true;
case WM_MOUSEMOVE:
// mouse was moved. hide the hider window.
ShowWindow(m_window, SW_HIDE);
break;
ValidateRect(hwnd, NULL);
return 0;
case WM_ACTIVATEAPP:
if (msg->wParam == FALSE) {
if (wParam == FALSE) {
// some other app activated. hide the hider window.
log((CLOG_INFO "show cursor"));
ShowWindow(m_window, SW_HIDE);
}
break;
/*
// FIXME -- handle screen resolution changes
case WM_DRAWCLIPBOARD:
log((CLOG_DEBUG "clipboard was taken"));
case SelectionClear:
target->XXX(xevent.xselectionclear.);
break;
// first pass it on
SendMessage(m_nextClipboardWindow, msg, wParam, lParam);
case SelectionNotify:
target->XXX(xevent.xselection.);
break;
// now notify client that somebody changed the clipboard (unless
// we're now the owner, in which case it's because we took
// ownership).
m_clipboardOwner = GetClipboardOwner();
if (m_clipboardOwner != m_window) {
m_client->onClipboardChanged();
}
return 0;
case SelectionRequest:
target->XXX(xevent.xselectionrequest.);
break;
*/
case WM_CHANGECBCHAIN:
if (m_nextClipboardWindow == (HWND)wParam)
m_nextClipboardWindow = (HWND)lParam;
else
SendMessage(m_nextClipboardWindow, msg, wParam, lParam);
return 0;
}
return false;
return DefWindowProc(hwnd, msg, wParam, lParam);
}
static const UINT g_latin1[] =
@ -745,9 +823,11 @@ static const UINT g_miscellany[] =
/* 0xc8 */ VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16, VK_F17, VK_F18,
/* 0xd0 */ VK_F19, VK_F20, VK_F21, VK_F22, VK_F23, VK_F24, 0, 0,
/* 0xd8 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xe0 */ 0, VK_LSHIFT, VK_RSHIFT, VK_LCONTROL,
/* FIXME -- want to use LSHIFT, LCONTROL, and LMENU but those don't seem
* to affect the shift state for VkKeyScan. */
/* 0xe0 */ 0, VK_SHIFT, VK_RSHIFT, VK_CONTROL,
/* 0xe4 */ VK_RCONTROL, VK_CAPITAL, 0, VK_LWIN,
/* 0xe8 */ VK_RWIN, VK_LMENU, VK_RMENU, 0, 0, 0, 0, 0,
/* 0xe8 */ VK_RWIN, VK_MENU, VK_RMENU, 0, 0, 0, 0, 0,
/* 0xf0 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xf8 */ 0, 0, 0, 0, 0, 0, 0, VK_DELETE
};

View File

@ -23,12 +23,16 @@ class CMSWindowsSecondaryScreen : public CMSWindowsScreen, public ISecondaryScre
virtual void mouseUp(ButtonID);
virtual void mouseMove(SInt32 xAbsolute, SInt32 yAbsolute);
virtual void mouseWheel(SInt32 delta);
virtual void setClipboard(const IClipboard*);
virtual void grabClipboard();
virtual void getSize(SInt32* width, SInt32* height) const;
virtual SInt32 getJumpZoneSize() const;
virtual void getClipboard(IClipboard*) const;
protected:
// CMSWindowsScreen overrides
virtual bool onEvent(MSG*);
virtual bool onPreTranslate(MSG*);
virtual LRESULT onEvent(HWND, UINT, WPARAM, LPARAM);
virtual void onOpenDisplay();
virtual void onCloseDisplay();
@ -38,6 +42,8 @@ class CMSWindowsSecondaryScreen : public CMSWindowsScreen, public ISecondaryScre
private:
CClient* m_client;
HWND m_window;
HWND m_nextClipboardWindow;
HWND m_clipboardOwner;
};
#endif

View File

@ -19,7 +19,7 @@ CXWindowsSecondaryScreen::CXWindowsSecondaryScreen() :
CXWindowsSecondaryScreen::~CXWindowsSecondaryScreen()
{
assert(m_window == None);
assert(m_window == None);
}
void CXWindowsSecondaryScreen::run()
@ -43,21 +43,46 @@ void CXWindowsSecondaryScreen::run()
break;
}
/*
// FIXME -- handle screen resolution changes
case SelectionClear:
target->XXX(xevent.xselectionclear.);
// we just lost the selection. that means someone else
// grabbed the selection so this screen is now the
// selection owner. report that to the server.
m_client->onClipboardChanged();
break;
case SelectionNotify:
target->XXX(xevent.xselection.);
// notification of selection transferred. we shouldn't
// get this here because we handle them in the selection
// retrieval methods. we'll just delete the property
// with the data (satisfying the usual ICCCM protocol).
if (xevent.xselection.property != None) {
CDisplayLock display(this);
XDeleteProperty(display, m_window, xevent.xselection.property);
}
break;
case SelectionRequest:
target->XXX(xevent.xselectionrequest.);
// somebody is asking for clipboard data
if (xevent.xselectionrequest.owner == m_window) {
addClipboardRequest(m_window,
xevent.xselectionrequest.requestor,
xevent.xselectionrequest.selection,
xevent.xselectionrequest.target,
xevent.xselectionrequest.property,
xevent.xselectionrequest.time);
}
break;
case PropertyNotify:
// clipboard transfers involve property changes so forward
// the event to the superclass. we only care about the
// deletion of properties.
if (xevent.xproperty.state == PropertyDelete) {
processClipboardRequest(xevent.xproperty.window,
xevent.xproperty.atom,
xevent.xproperty.time);
}
break;
*/
}
}
}
@ -167,6 +192,19 @@ void CXWindowsSecondaryScreen::mouseWheel(SInt32)
// FIXME
}
void CXWindowsSecondaryScreen::setClipboard(
const IClipboard* clipboard)
{
// FIXME -- don't use CurrentTime
setDisplayClipboard(clipboard, m_window, CurrentTime);
}
void CXWindowsSecondaryScreen::grabClipboard()
{
// FIXME -- don't use CurrentTime
setDisplayClipboard(NULL, m_window, CurrentTime);
}
void CXWindowsSecondaryScreen::getSize(
SInt32* width, SInt32* height) const
{
@ -178,6 +216,13 @@ SInt32 CXWindowsSecondaryScreen::getJumpZoneSize() const
return 0;
}
void CXWindowsSecondaryScreen::getClipboard(
IClipboard* clipboard) const
{
// FIXME -- don't use CurrentTime
getDisplayClipboard(clipboard, m_window, CurrentTime);
}
void CXWindowsSecondaryScreen::onOpenDisplay()
{
assert(m_window == None);

View File

@ -23,8 +23,11 @@ class CXWindowsSecondaryScreen : public CXWindowsScreen, public ISecondaryScreen
virtual void mouseUp(ButtonID);
virtual void mouseMove(SInt32 xAbsolute, SInt32 yAbsolute);
virtual void mouseWheel(SInt32 delta);
virtual void setClipboard(const IClipboard*);
virtual void grabClipboard();
virtual void getSize(SInt32* width, SInt32* height) const;
virtual SInt32 getJumpZoneSize() const;
virtual void getClipboard(IClipboard*) const;
protected:
// CXWindowsScreen overrides

View File

@ -41,7 +41,7 @@ int WINAPI WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
}
try {
realMain("ingrid", __argv[1], 50001);
realMain("secondary", __argv[1], 50001);
return 0;
}
catch (XBase& e) {
@ -64,7 +64,7 @@ int main(int argc, char** argv)
}
try {
realMain("ingrid", argv[1], 50001);
realMain("secondary", argv[1], 50001);
return 0;
}
catch (XBase& e) {

View File

@ -38,7 +38,7 @@ RSC=rc.exe
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Output_Dir "../Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
@ -64,7 +64,7 @@ LINK32=link.exe
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Output_Dir "../Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c

View File

@ -44,6 +44,7 @@ int (PASCAL FAR *CNetwork::gethosterror)(void);
#if defined(CONFIG_PLATFORM_WIN32)
int (PASCAL FAR *CNetwork::select)(int nfds, fd_set FAR *readfds, fd_set FAR *writefds, fd_set FAR *exceptfds, const struct timeval FAR *timeout);
int (PASCAL FAR *CNetwork::WSACleanup)(void);
int (PASCAL FAR *CNetwork::__WSAFDIsSet)(CNetwork::Socket, fd_set FAR *);
const int CNetwork::Error = SOCKET_ERROR;
@ -220,6 +221,7 @@ int PASCAL FAR CNetwork::poll2(PollEntry fd[], int nfds, int timeout)
return Error;
if (n == 0)
return 0;
n = 0;
for (i = 0; i < nfds; ++i) {
fd[i].revents = 0;
if (FD_ISSET(fd[i].fd, &readSet))
@ -228,6 +230,8 @@ int PASCAL FAR CNetwork::poll2(PollEntry fd[], int nfds, int timeout)
fd[i].revents |= kPOLLOUT;
if (FD_ISSET(fd[i].fd, &errSet))
fd[i].revents |= kPOLLERR;
if (fd[i].revents != 0)
++n;
}
return n;
}

11
notes
View File

@ -87,11 +87,12 @@ win32:
handle display changes
---
win32 key translation (client)
get character for key (with appropriate shift)
keypad enter -> VK_???
sys req -> VK_???
compose -> VK_???
not sending VK_?WIN and VK_APPS. possibly hotkeys being stolen.
VkKeyScan() doesn't get proper shift state unless we map shift
(etc?) to VK_SHIFT not VK_LSHIFT or VK_RSHIFT.
not handling international characters
X11 key translation (server)
handle compose key?

View File

@ -1,6 +1,8 @@
#include "CMSWindowsPrimaryScreen.h"
#include "CMSWindowsClipboard.h"
#include "CServer.h"
#include "CSynergyHook.h"
#include "XSynergy.h"
#include "CThread.h"
#include "CLog.h"
#include <assert.h>
@ -13,6 +15,8 @@ CMSWindowsPrimaryScreen::CMSWindowsPrimaryScreen() :
m_server(NULL),
m_active(false),
m_window(NULL),
m_nextClipboardWindow(NULL),
m_clipboardOwner(NULL),
m_hookLibrary(NULL),
m_mark(0),
m_markReceived(0)
@ -26,6 +30,8 @@ CMSWindowsPrimaryScreen::~CMSWindowsPrimaryScreen()
assert(m_hookLibrary == NULL);
}
static CString s_log;
static CString s_logMore;
static HWND s_debug = NULL;
static HWND s_debugLog = NULL;
static DWORD s_thread = 0;
@ -38,28 +44,26 @@ static BOOL CALLBACK WINAPI debugProc(HWND, UINT msg, WPARAM wParam, LPARAM lPar
case WM_CLOSE:
PostQuitMessage(0);
return TRUE;
case WM_APP:
if (!s_logMore.empty()) {
if (s_log.size() > 20000)
s_log = s_logMore;
else
s_log += s_logMore;
s_logMore = "";
SendMessage(s_debugLog, WM_SETTEXT, FALSE, (LPARAM)(LPCTSTR)s_log.c_str());
SendMessage(s_debugLog, EM_SETSEL, s_log.size(), s_log.size());
SendMessage(s_debugLog, EM_SCROLLCARET, 0, 0);
}
return TRUE;
}
return FALSE;
}
static void debugOutput(const char* msg)
{
if (s_thread != 0) {
const DWORD threadID = ::GetCurrentThreadId();
if (threadID != s_thread) {
GetDesktopWindow();
AttachThreadInput(threadID, s_thread, TRUE);
}
}
DWORD len = SendMessage(s_debugLog, WM_GETTEXTLENGTH, 0, 0);
if (len > 20000) {
SendMessage(s_debugLog, EM_SETSEL, -1, 0);
SendMessage(s_debugLog, WM_SETTEXT, FALSE, (LPARAM)(LPCTSTR)msg);
}
else {
SendMessage(s_debugLog, EM_SETSEL, -1, len);
SendMessage(s_debugLog, EM_REPLACESEL, FALSE, (LPARAM)(LPCTSTR)msg);
}
SendMessage(s_debugLog, EM_SCROLLCARET, 0, 0);
s_logMore += msg;
PostMessage(s_debug, WM_APP, 0, 0);
}
void CMSWindowsPrimaryScreen::run()
@ -114,6 +118,13 @@ void CMSWindowsPrimaryScreen::enter(SInt32 x, SInt32 y)
void CMSWindowsPrimaryScreen::doEnter()
{
// release the capture
ReleaseCapture();
// hide our window and restore the foreground window
SetForegroundWindow(m_lastActive);
ShowWindow(m_window, SW_HIDE);
// set the zones that should cause a jump
SInt32 w, h;
getScreenSize(&w, &h);
@ -136,6 +147,16 @@ void CMSWindowsPrimaryScreen::leave()
// all messages prior to now are invalid
nextMark();
// remember the active window before we leave
m_lastActive = GetForegroundWindow();
// show our window and put it in the foreground
ShowWindow(m_window, SW_SHOW);
SetForegroundWindow(m_window);
// capture the cursor so we don't lose keyboard input
SetCapture(m_window);
// relay all mouse and keyboard events
SetRelayFunc setRelay = (SetRelayFunc)GetProcAddress(
m_hookLibrary, "setRelay");
@ -151,6 +172,30 @@ void CMSWindowsPrimaryScreen::leave()
// local client now active
m_active = true;
// if we think we own the clipboard but we don't then somebody
// grabbed the clipboard on this screen without us knowing.
// tell the server that this screen grabbed the clipboard.
//
// this works around bugs in the clipboard viewer chain.
// sometimes NT will simply never send WM_DRAWCLIPBOARD
// messages for no apparent reason and rebooting fixes the
// problem. since we don't want a broken clipboard until the
// next reboot we do this double check. clipboard ownership
// won't be reflected on other screens until we leave but at
// least the clipboard itself will work.
HWND clipboardOwner = GetClipboardOwner();
if (m_clipboardOwner != clipboardOwner) {
try {
m_clipboardOwner = clipboardOwner;
if (m_clipboardOwner != m_window) {
m_server->grabClipboard();
}
}
catch (XBadClient&) {
// ignore
}
}
}
void CMSWindowsPrimaryScreen::warpCursor(SInt32 x, SInt32 y)
@ -164,18 +209,22 @@ void CMSWindowsPrimaryScreen::warpCursor(SInt32 x, SInt32 y)
}
void CMSWindowsPrimaryScreen::setClipboard(
const IClipboard* /*clipboard*/)
const IClipboard* src)
{
assert(m_window != NULL);
// FIXME -- should we retry until we get it?
if (!OpenClipboard(m_window))
return;
if (EmptyClipboard()) {
log((CLOG_DEBUG "grabbed clipboard"));
// FIXME -- set the clipboard data
CMSWindowsClipboard dst(m_window);
CClipboard::copy(&dst, src);
}
void CMSWindowsPrimaryScreen::grabClipboard()
{
assert(m_window != NULL);
CMSWindowsClipboard clipboard(m_window);
if (clipboard.open()) {
clipboard.close();
}
CloseClipboard();
}
void CMSWindowsPrimaryScreen::getSize(
@ -190,11 +239,12 @@ SInt32 CMSWindowsPrimaryScreen::getJumpZoneSize() const
}
void CMSWindowsPrimaryScreen::getClipboard(
IClipboard* clipboard) const
IClipboard* dst) const
{
// FIXME -- put this in superclass?
// FIXME -- don't use CurrentTime
// getDisplayClipboard(clipboard, m_window, CurrentTime);
assert(m_window != NULL);
CMSWindowsClipboard src(m_window);
CClipboard::copy(dst, &src);
}
#include "resource.h" // FIXME
@ -211,6 +261,10 @@ s_debugLog = ::GetDlgItem(s_debug, IDC_LOG);
CLog::setOutputter(&debugOutput);
ShowWindow(s_debug, SW_SHOWNORMAL);
// initialize clipboard owner to current owner. we don't want
// to take ownership of the clipboard just by starting up.
m_clipboardOwner = GetClipboardOwner();
// create the window
m_window = CreateWindowEx(WS_EX_TOPMOST |
WS_EX_TRANSPARENT | WS_EX_TOOLWINDOW,
@ -219,6 +273,10 @@ ShowWindow(s_debug, SW_SHOWNORMAL);
0, 0, 1, 1, NULL, NULL,
getInstance(),
NULL);
assert(m_window != NULL);
// install our clipboard snooper
m_nextClipboardWindow = SetClipboardViewer(m_window);
// load the hook library
bool hooked = false;
@ -232,6 +290,8 @@ ShowWindow(s_debug, SW_SHOWNORMAL);
}
}
if (!hooked) {
ChangeClipboardChain(m_window, m_nextClipboardWindow);
m_nextClipboardWindow = NULL;
DestroyWindow(m_window);
m_window = NULL;
// FIXME -- throw
@ -258,6 +318,10 @@ void CMSWindowsPrimaryScreen::onCloseDisplay()
FreeLibrary(m_hookLibrary);
m_hookLibrary = NULL;
// remove clipboard snooper
ChangeClipboardChain(m_window, m_nextClipboardWindow);
m_nextClipboardWindow = NULL;
// destroy window
DestroyWindow(m_window);
m_window = NULL;
@ -268,7 +332,7 @@ s_debug = NULL;
s_thread = 0;
}
bool CMSWindowsPrimaryScreen::onEvent(MSG* msg)
bool CMSWindowsPrimaryScreen::onPreTranslate(MSG* msg)
{
if (IsDialogMessage(s_debug, msg)) {
return true;
@ -276,11 +340,6 @@ if (IsDialogMessage(s_debug, msg)) {
// handle event
switch (msg->message) {
// FIXME -- handle display changes
case WM_PAINT:
ValidateRect(m_window, NULL);
return true;
case SYNERGY_MSG_MARK:
m_markReceived = msg->wParam;
return true;
@ -288,7 +347,29 @@ if (IsDialogMessage(s_debug, msg)) {
case SYNERGY_MSG_KEY:
// ignore if not at current mark
if (m_mark == m_markReceived) {
// FIXME -- vk code; key data
KeyModifierMask mask;
const KeyID key = mapKey(msg->wParam, msg->lParam, &mask);
log((CLOG_DEBUG "event: key event vk=%d info=0x%08x", msg->wParam, msg->lParam));
if (key != kKeyNone) {
if ((msg->lParam & 0x80000000) == 0) {
// key press
const SInt32 repeat = (SInt32)(msg->lParam & 0xffff);
if (repeat >= 2) {
log((CLOG_DEBUG "event: key repeat key=%d mask=0x%04x count=%d", key, mask, repeat));
m_server->onKeyRepeat(key, mask, repeat);
}
else {
log((CLOG_DEBUG "event: key press key=%d mask=0x%04x", key, mask));
m_server->onKeyDown(key, mask);
}
}
else {
// key release
log((CLOG_DEBUG "event: key release key=%d mask=0x%04x", key, mask));
m_server->onKeyUp(key, mask);
}
}
}
return true;
@ -357,74 +438,46 @@ if (IsDialogMessage(s_debug, msg)) {
}
return false;
/*
case WM_MOUSEMOVE: {
if (!m_active) {
// mouse entered a jump zone window
POINT p;
p.x = (short)LOWORD(msg.lParam);
p.y = (short)HIWORD(msg.lParam);
ClientToScreen(msg.hwnd, &p);
log((CLOG_DEBUG "event: WM_MOUSEMOVE %d,%d", p.x, p.y));
m_server->onMouseMovePrimary((SInt32)p.x, (SInt32)p.y);
}
LRESULT CMSWindowsPrimaryScreen::onEvent(
HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam)
{
switch (msg) {
// FIXME -- handle display changes
case WM_PAINT:
ValidateRect(hwnd, NULL);
return 0;
case WM_DRAWCLIPBOARD:
log((CLOG_DEBUG "clipboard was taken"));
// first pass it on
SendMessage(m_nextClipboardWindow, msg, wParam, lParam);
// now notify server that somebody changed the clipboard.
// skip that if we're the new owner.
try {
m_clipboardOwner = GetClipboardOwner();
if (m_clipboardOwner != m_window) {
m_server->grabClipboard();
}
}
break;
}
case KeyPress: {
log((CLOG_DEBUG "event: KeyPress code=%d, state=0x%04x", xevent.xkey.keycode, xevent.xkey.state));
const KeyModifierMask mask = mapModifier(xevent.xkey.state);
const KeyID key = mapKey(xevent.xkey.keycode, mask);
if (key != kKeyNULL) {
m_server->onKeyDown(key, mask);
catch (XBadClient&) {
// ignore. this can happen if we receive this event
// before we've fully started up.
}
break;
}
return 0;
// FIXME -- simulate key repeat. X sends press/release for
// repeat. must detect auto repeat and use kKeyRepeat.
case KeyRelease: {
log((CLOG_DEBUG "event: KeyRelease code=%d, state=0x%04x", xevent.xkey.keycode, xevent.xkey.state));
const KeyModifierMask mask = mapModifier(xevent.xkey.state);
const KeyID key = mapKey(xevent.xkey.keycode, mask);
if (key != kKeyNULL) {
m_server->onKeyUp(key, mask);
}
break;
}
case ButtonPress: {
log((CLOG_DEBUG "event: ButtonPress button=%d", xevent.xbutton.button));
const ButtonID button = mapButton(xevent.xbutton.button);
if (button != kButtonNULL) {
m_server->onMouseDown(button);
}
break;
}
case ButtonRelease: {
log((CLOG_DEBUG "event: ButtonRelease button=%d", xevent.xbutton.button));
const ButtonID button = mapButton(xevent.xbutton.button);
if (button != kButtonNULL) {
m_server->onMouseUp(button);
}
break;
}
case SelectionClear:
target->XXX(xevent.xselectionclear.);
break;
case SelectionNotify:
target->XXX(xevent.xselection.);
break;
case SelectionRequest:
target->XXX(xevent.xselectionrequest.);
break;
case WM_CHANGECBCHAIN:
if (m_nextClipboardWindow == (HWND)wParam)
m_nextClipboardWindow = (HWND)lParam;
else
SendMessage(m_nextClipboardWindow, msg, wParam, lParam);
return 0;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
*/
}
void CMSWindowsPrimaryScreen::nextMark()
@ -434,34 +487,274 @@ void CMSWindowsPrimaryScreen::nextMark()
PostMessage(m_window, SYNERGY_MSG_MARK, ++m_mark, 0);
}
#if 0
bool CMSWindowsPrimaryScreen::keyboardHook(
int /*code*/, WPARAM wParam, LPARAM lParam)
static const KeyID g_virtualKey[] =
{
if (m_active) {
// handle keyboard events
const KeyID key = mapKey(wParam, lParam);
if (key != kKeyNone) {
const KeyModifierMask modifiers = mapModifier(wParam, lParam);
if ((lParam & KF_UP) == 0) {
log((CLOG_DEBUG "event: key press key=%d", key));
m_server->onKeyDown(key, modifiers);
}
else {
log((CLOG_DEBUG "event: key release key=%d", key));
m_server->onKeyUp(key, modifiers);
}
return true;
}
}
return false;
}
#endif
/* 0x00 */ kKeyNone, // reserved
/* 0x01 */ kKeyNone, // VK_LBUTTON
/* 0x02 */ kKeyNone, // VK_RBUTTON
/* 0x03 */ 0xff6b, // VK_CANCEL XK_Break
/* 0x04 */ kKeyNone, // VK_MBUTTON
/* 0x05 */ kKeyNone, // undefined
/* 0x06 */ kKeyNone, // undefined
/* 0x07 */ kKeyNone, // undefined
/* 0x08 */ 0xff08, // VK_BACK XK_Backspace
/* 0x09 */ 0xff09, // VK_TAB VK_Tab
/* 0x0a */ kKeyNone, // undefined
/* 0x0b */ kKeyNone, // undefined
/* 0x0c */ 0xff0b, // VK_CLEAR XK_Clear
/* 0x0d */ 0xff0d, // VK_RETURN XK_Return
/* 0x0e */ kKeyNone, // undefined
/* 0x0f */ kKeyNone, // undefined
/* 0x10 */ 0xffe1, // VK_SHIFT XK_Shift_L
/* 0x11 */ 0xffe3, // VK_CONTROL XK_Control_L
/* 0x12 */ 0xffe9, // VK_MENU XK_Alt_L
/* 0x13 */ 0xff13, // VK_PAUSE XK_Pause
/* 0x14 */ 0xffe5, // VK_CAPITAL XK_Caps_Lock
/* 0x15 */ kKeyNone, // VK_KANA
/* 0x16 */ kKeyNone, // VK_HANGUL
/* 0x17 */ kKeyNone, // VK_JUNJA
/* 0x18 */ kKeyNone, // VK_FINAL
/* 0x19 */ kKeyNone, // VK_KANJI
/* 0x1a */ kKeyNone, // undefined
/* 0x1b */ 0xff1b, // VK_ESCAPE XK_Escape
/* 0x1c */ kKeyNone, // VK_CONVERT
/* 0x1d */ kKeyNone, // VK_NONCONVERT
/* 0x1e */ kKeyNone, // VK_ACCEPT
/* 0x1f */ kKeyNone, // VK_MODECHANGE
/* 0x20 */ 0xff20, // VK_SPACE XK_space
/* 0x21 */ 0xff55, // VK_PRIOR XK_Prior
/* 0x22 */ 0xff56, // VK_NEXT XK_Next
/* 0x23 */ 0xff57, // VK_END XK_End
/* 0x24 */ 0xff50, // VK_HOME XK_Home
/* 0x25 */ 0xff51, // VK_LEFT XK_Left
/* 0x26 */ 0xff52, // VK_UP XK_Up
/* 0x27 */ 0xff53, // VK_RIGHT XK_Right
/* 0x28 */ 0xff54, // VK_DOWN XK_Down
/* 0x29 */ 0xff60, // VK_SELECT XK_Select
/* 0x2a */ kKeyNone, // VK_PRINT
/* 0x2b */ 0xff62, // VK_EXECUTE XK_Execute
/* 0x2c */ 0xff61, // VK_SNAPSHOT XK_Print
/* 0x2d */ 0xff63, // VK_INSERT XK_Insert
/* 0x2e */ 0xffff, // VK_DELETE XK_Delete
/* 0x2f */ 0xff6a, // VK_HELP XK_Help
/* 0x30 */ 0x0030, // VK_0 XK_0
/* 0x31 */ 0x0031, // VK_1 XK_1
/* 0x32 */ 0x0032, // VK_2 XK_2
/* 0x33 */ 0x0033, // VK_3 XK_3
/* 0x34 */ 0x0034, // VK_4 XK_4
/* 0x35 */ 0x0035, // VK_5 XK_5
/* 0x36 */ 0x0036, // VK_6 XK_6
/* 0x37 */ 0x0037, // VK_7 XK_7
/* 0x38 */ 0x0038, // VK_8 XK_8
/* 0x39 */ 0x0039, // VK_9 XK_9
/* 0x3a */ kKeyNone, // undefined
/* 0x3b */ kKeyNone, // undefined
/* 0x3c */ kKeyNone, // undefined
/* 0x3d */ kKeyNone, // undefined
/* 0x3e */ kKeyNone, // undefined
/* 0x3f */ kKeyNone, // undefined
/* 0x40 */ kKeyNone, // undefined
/* 0x41 */ 0x0041, // VK_A XK_A
/* 0x42 */ 0x0042, // VK_B XK_B
/* 0x43 */ 0x0043, // VK_C XK_C
/* 0x44 */ 0x0044, // VK_D XK_D
/* 0x45 */ 0x0045, // VK_E XK_E
/* 0x46 */ 0x0046, // VK_F XK_F
/* 0x47 */ 0x0047, // VK_G XK_G
/* 0x48 */ 0x0048, // VK_H XK_H
/* 0x49 */ 0x0049, // VK_I XK_I
/* 0x4a */ 0x004a, // VK_J XK_J
/* 0x4b */ 0x004b, // VK_K XK_K
/* 0x4c */ 0x004c, // VK_L XK_L
/* 0x4d */ 0x004d, // VK_M XK_M
/* 0x4e */ 0x004e, // VK_N XK_N
/* 0x4f */ 0x004f, // VK_O XK_O
/* 0x50 */ 0x0050, // VK_P XK_P
/* 0x51 */ 0x0051, // VK_Q XK_Q
/* 0x52 */ 0x0052, // VK_R XK_R
/* 0x53 */ 0x0053, // VK_S XK_S
/* 0x54 */ 0x0054, // VK_T XK_T
/* 0x55 */ 0x0055, // VK_U XK_U
/* 0x56 */ 0x0056, // VK_V XK_V
/* 0x57 */ 0x0057, // VK_W XK_W
/* 0x58 */ 0x0058, // VK_X XK_X
/* 0x59 */ 0x0059, // VK_Y XK_Y
/* 0x5a */ 0x005a, // VK_Z XK_Z
/* 0x5b */ 0xffe7, // VK_LWIN XK_Meta_L
/* 0x5c */ 0xffe8, // VK_RWIN XK_Meta_R
/* 0x5d */ 0xff67, // VK_APPS XK_Menu
/* 0x5e */ kKeyNone, // undefined
/* 0x5f */ kKeyNone, // undefined
/* 0x60 */ 0xffb0, // VK_NUMPAD0 XK_KP_0
/* 0x61 */ 0xffb1, // VK_NUMPAD1 XK_KP_1
/* 0x62 */ 0xffb2, // VK_NUMPAD2 XK_KP_2
/* 0x63 */ 0xffb3, // VK_NUMPAD3 XK_KP_3
/* 0x64 */ 0xffb4, // VK_NUMPAD4 XK_KP_4
/* 0x65 */ 0xffb5, // VK_NUMPAD5 XK_KP_5
/* 0x66 */ 0xffb6, // VK_NUMPAD6 XK_KP_6
/* 0x67 */ 0xffb7, // VK_NUMPAD7 XK_KP_7
/* 0x68 */ 0xffb8, // VK_NUMPAD8 XK_KP_8
/* 0x69 */ 0xffb9, // VK_NUMPAD9 XK_KP_9
/* 0x6a */ 0xffaa, // VK_MULTIPLY XK_KP_Multiply
/* 0x6b */ 0xffab, // VK_ADD XK_KP_Add
/* 0x6c */ 0xffac, // VK_SEPARATOR XK_KP_Separator
/* 0x6d */ 0xffad, // VK_SUBTRACT XK_KP_Subtract
/* 0x6e */ 0xffae, // VK_DECIMAL XK_KP_Decimal
/* 0x6f */ 0xffaf, // VK_DIVIDE XK_KP_Divide
/* 0x70 */ 0xffbe, // VK_F1 XK_F1
/* 0x71 */ 0xffbf, // VK_F2 XK_F2
/* 0x72 */ 0xffc0, // VK_F3 XK_F3
/* 0x73 */ 0xffc1, // VK_F4 XK_F4
/* 0x74 */ 0xffc2, // VK_F5 XK_F5
/* 0x75 */ 0xffc3, // VK_F6 XK_F6
/* 0x76 */ 0xffc4, // VK_F7 XK_F7
/* 0x77 */ 0xffc5, // VK_F8 XK_F8
/* 0x78 */ 0xffc6, // VK_F9 XK_F9
/* 0x79 */ 0xffc7, // VK_F10 XK_F10
/* 0x7a */ 0xffc8, // VK_F11 XK_F11
/* 0x7b */ 0xffc9, // VK_F12 XK_F12
/* 0x7c */ 0xffca, // VK_F13 XK_F13
/* 0x7d */ 0xffcb, // VK_F14 XK_F14
/* 0x7e */ 0xffcc, // VK_F15 XK_F15
/* 0x7f */ 0xffcd, // VK_F16 XK_F16
/* 0x80 */ 0xffce, // VK_F17 XK_F17
/* 0x81 */ 0xffcf, // VK_F18 XK_F18
/* 0x82 */ 0xffd0, // VK_F19 XK_F19
/* 0x83 */ 0xffd1, // VK_F20 XK_F20
/* 0x84 */ 0xffd2, // VK_F21 XK_F21
/* 0x85 */ 0xffd3, // VK_F22 XK_F22
/* 0x86 */ 0xffd4, // VK_F23 XK_F23
/* 0x87 */ 0xffd5, // VK_F24 XK_F24
/* 0x88 */ kKeyNone, // unassigned
/* 0x89 */ kKeyNone, // unassigned
/* 0x8a */ kKeyNone, // unassigned
/* 0x8b */ kKeyNone, // unassigned
/* 0x8c */ kKeyNone, // unassigned
/* 0x8d */ kKeyNone, // unassigned
/* 0x8e */ kKeyNone, // unassigned
/* 0x8f */ kKeyNone, // unassigned
/* 0x90 */ 0xff7f, // VK_NUMLOCK XK_Num_Lock
/* 0x91 */ 0xff14, // VK_SCROLL XK_Scroll_Lock
/* 0x92 */ kKeyNone, // unassigned
/* 0x93 */ kKeyNone, // unassigned
/* 0x94 */ kKeyNone, // unassigned
/* 0x95 */ kKeyNone, // unassigned
/* 0x96 */ kKeyNone, // unassigned
/* 0x97 */ kKeyNone, // unassigned
/* 0x98 */ kKeyNone, // unassigned
/* 0x99 */ kKeyNone, // unassigned
/* 0x9a */ kKeyNone, // unassigned
/* 0x9b */ kKeyNone, // unassigned
/* 0x9c */ kKeyNone, // unassigned
/* 0x9d */ kKeyNone, // unassigned
/* 0x9e */ kKeyNone, // unassigned
/* 0x9f */ kKeyNone, // unassigned
/* 0xa0 */ kKeyNone, // unassigned
/* 0xa1 */ kKeyNone, // unassigned
/* 0xa2 */ kKeyNone, // unassigned
/* 0xa3 */ kKeyNone, // unassigned
/* 0xa4 */ kKeyNone, // unassigned
/* 0xa5 */ kKeyNone, // unassigned
/* 0xa6 */ kKeyNone, // unassigned
/* 0xa7 */ kKeyNone, // unassigned
/* 0xa8 */ kKeyNone, // unassigned
/* 0xa9 */ kKeyNone, // unassigned
/* 0xaa */ kKeyNone, // unassigned
/* 0xab */ kKeyNone, // unassigned
/* 0xac */ kKeyNone, // unassigned
/* 0xad */ kKeyNone, // unassigned
/* 0xae */ kKeyNone, // unassigned
/* 0xaf */ kKeyNone, // unassigned
/* 0xb0 */ kKeyNone, // unassigned
/* 0xb1 */ kKeyNone, // unassigned
/* 0xb2 */ kKeyNone, // unassigned
/* 0xb3 */ kKeyNone, // unassigned
/* 0xb4 */ kKeyNone, // unassigned
/* 0xb5 */ kKeyNone, // unassigned
/* 0xb6 */ kKeyNone, // unassigned
/* 0xb7 */ kKeyNone, // unassigned
/* 0xb8 */ kKeyNone, // unassigned
/* 0xb9 */ kKeyNone, // unassigned
/* 0xba */ kKeyNone, // OEM specific
/* 0xbb */ kKeyNone, // OEM specific
/* 0xbc */ kKeyNone, // OEM specific
/* 0xbd */ kKeyNone, // OEM specific
/* 0xbe */ kKeyNone, // OEM specific
/* 0xbf */ kKeyNone, // OEM specific
/* 0xc0 */ kKeyNone, // OEM specific
/* 0xc1 */ kKeyNone, // unassigned
/* 0xc2 */ kKeyNone, // unassigned
/* 0xc3 */ kKeyNone, // unassigned
/* 0xc4 */ kKeyNone, // unassigned
/* 0xc5 */ kKeyNone, // unassigned
/* 0xc6 */ kKeyNone, // unassigned
/* 0xc7 */ kKeyNone, // unassigned
/* 0xc8 */ kKeyNone, // unassigned
/* 0xc9 */ kKeyNone, // unassigned
/* 0xca */ kKeyNone, // unassigned
/* 0xcb */ kKeyNone, // unassigned
/* 0xcc */ kKeyNone, // unassigned
/* 0xcd */ kKeyNone, // unassigned
/* 0xce */ kKeyNone, // unassigned
/* 0xcf */ kKeyNone, // unassigned
/* 0xd0 */ kKeyNone, // unassigned
/* 0xd1 */ kKeyNone, // unassigned
/* 0xd2 */ kKeyNone, // unassigned
/* 0xd3 */ kKeyNone, // unassigned
/* 0xd4 */ kKeyNone, // unassigned
/* 0xd5 */ kKeyNone, // unassigned
/* 0xd6 */ kKeyNone, // unassigned
/* 0xd7 */ kKeyNone, // unassigned
/* 0xd8 */ kKeyNone, // unassigned
/* 0xd9 */ kKeyNone, // unassigned
/* 0xda */ kKeyNone, // unassigned
/* 0xdb */ kKeyNone, // OEM specific
/* 0xdc */ kKeyNone, // OEM specific
/* 0xdd */ kKeyNone, // OEM specific
/* 0xde */ kKeyNone, // OEM specific
/* 0xdf */ kKeyNone, // OEM specific
/* 0xe0 */ kKeyNone, // OEM specific
/* 0xe1 */ kKeyNone, // OEM specific
/* 0xe2 */ kKeyNone, // OEM specific
/* 0xe3 */ kKeyNone, // OEM specific
/* 0xe4 */ kKeyNone, // OEM specific
/* 0xe5 */ kKeyNone, // unassigned
/* 0xe6 */ kKeyNone, // OEM specific
/* 0xe7 */ kKeyNone, // unassigned
/* 0xe8 */ kKeyNone, // unassigned
/* 0xe9 */ kKeyNone, // OEM specific
/* 0xea */ kKeyNone, // OEM specific
/* 0xeb */ kKeyNone, // OEM specific
/* 0xec */ kKeyNone, // OEM specific
/* 0xed */ kKeyNone, // OEM specific
/* 0xee */ kKeyNone, // OEM specific
/* 0xef */ kKeyNone, // OEM specific
/* 0xf0 */ kKeyNone, // OEM specific
/* 0xf1 */ kKeyNone, // OEM specific
/* 0xf2 */ kKeyNone, // OEM specific
/* 0xf3 */ kKeyNone, // OEM specific
/* 0xf4 */ kKeyNone, // OEM specific
/* 0xf5 */ kKeyNone, // OEM specific
/* 0xf6 */ kKeyNone, // VK_ATTN
/* 0xf7 */ kKeyNone, // VK_CRSEL
/* 0xf8 */ kKeyNone, // VK_EXSEL
/* 0xf9 */ kKeyNone, // VK_EREOF
/* 0xfa */ kKeyNone, // VK_PLAY
/* 0xfb */ kKeyNone, // VK_ZOOM
/* 0xfc */ kKeyNone, // reserved
/* 0xfd */ kKeyNone, // VK_PA1
/* 0xfe */ kKeyNone, // VK_OEM_CLEAR
/* 0xff */ kKeyNone // reserved
};
KeyModifierMask CMSWindowsPrimaryScreen::mapModifier(
WPARAM keycode, LPARAM info) const
KeyID CMSWindowsPrimaryScreen::mapKey(
WPARAM vkCode, LPARAM info,
KeyModifierMask* maskOut) const
{
// FIXME -- should be configurable
assert(maskOut != NULL);
// map modifier key
// FIXME -- should be configurable?
KeyModifierMask mask = 0;
if (GetKeyState(VK_SHIFT) < 0)
mask |= KeyModifierShift;
@ -477,14 +770,48 @@ KeyModifierMask CMSWindowsPrimaryScreen::mapModifier(
mask |= KeyModifierMeta;
if ((GetKeyState(VK_SCROLL) & 1) != 0)
mask |= KeyModifierScrollLock;
return mask;
}
*maskOut = mask;
KeyID CMSWindowsPrimaryScreen::mapKey(
WPARAM keycode, LPARAM info) const
{
// FIXME -- must convert to X keysyms
return keycode;
KeyID id = g_virtualKey[vkCode];
if (id != kKeyNone) {
return id;
}
BYTE state[256];
GetKeyboardState(state);
WORD ascii;
int result = ToAscii(vkCode, MapVirtualKey(0, vkCode), state, &ascii, 0);
if (result > 0) {
// FIXME -- handle dead keys
return (KeyID)(ascii & 0x00ff);
}
return kKeyNone;
/*
UINT character = MapVirtualKey(2, vkCode);
if (character != 0) {
if ((character & ~0xff) != 0) {
// dead key (i.e. a key to compose with the next)
// FIXME
return kKeyNone;
}
else {
// map character
KeyID id = g_virtualKey[character & 0xff];
// uppercase to lowercase conversion
if ((mask & KeyModifierShift) == 0 && id >= 'A' && id <= 'Z')
id += 0x20;
return id;
}
}
else {
// non-ascii key
return g_virtualKey[vkCode];
}
*/
}
ButtonID CMSWindowsPrimaryScreen::mapButton(

View File

@ -22,13 +22,15 @@ class CMSWindowsPrimaryScreen : public CMSWindowsScreen, public IPrimaryScreen {
virtual void leave();
virtual void warpCursor(SInt32 xAbsolute, SInt32 yAbsolute);
virtual void setClipboard(const IClipboard*);
virtual void grabClipboard();
virtual void getSize(SInt32* width, SInt32* height) const;
virtual SInt32 getJumpZoneSize() const;
virtual void getClipboard(IClipboard*) const;
protected:
// CMSWindowsScreen overrides
virtual bool onEvent(MSG*);
virtual bool onPreTranslate(MSG*);
virtual LRESULT onEvent(HWND, UINT, WPARAM, LPARAM);
virtual void onOpenDisplay();
virtual void onCloseDisplay();
@ -37,17 +39,17 @@ class CMSWindowsPrimaryScreen : public CMSWindowsScreen, public IPrimaryScreen {
void nextMark();
// bool keyboardHook(int, WPARAM, LPARAM);
// bool mouseHook(int, WPARAM, LPARAM);
KeyModifierMask mapModifier(WPARAM keycode, LPARAM info) const;
KeyID mapKey(WPARAM keycode, LPARAM info) const;
KeyID mapKey(WPARAM keycode, LPARAM info,
KeyModifierMask* maskOut) const;
ButtonID mapButton(WPARAM button) const;
private:
CServer* m_server;
bool m_active;
HWND m_window;
HWND m_nextClipboardWindow;
HWND m_clipboardOwner;
HWND m_lastActive;
HINSTANCE m_hookLibrary;
UInt32 m_mark;
UInt32 m_markReceived;

View File

@ -43,7 +43,9 @@ else { wait(0); exit(1); }
CServer::CServer() : m_primary(NULL),
m_active(NULL),
m_primaryInfo(NULL)
m_primaryInfo(NULL),
m_clipboardSeqNum(0),
m_clipboardReady(false)
{
m_socketFactory = NULL;
m_securityFactory = NULL;
@ -78,7 +80,7 @@ void CServer::run()
closePrimaryScreen();
}
catch (XBase& e) {
log((CLOG_ERR "server error: %s\n", e.what()));
log((CLOG_ERR "server error: %s", e.what()));
// clean up
cleanupThreads();
@ -148,6 +150,93 @@ void CServer::setInfo(const CString& client,
log((CLOG_NOTE "client \"%s\" size=%dx%d zone=%d", client.c_str(), w, h, zoneSize));
}
void CServer::grabClipboard()
{
grabClipboard(m_primaryInfo->m_name);
}
void CServer::grabClipboard(const CString& client)
{
CLock lock(&m_mutex);
// client must be connected
CScreenList::iterator index = m_screens.find(client);
if (index == m_screens.end()) {
throw XBadClient();
}
log((CLOG_NOTE "client \"%s\" grabbed clipboard from \"%s\"", client.c_str(), m_clipboardOwner.c_str()));
// save the clipboard owner
m_clipboardOwner = client;
// mark client as having the clipboard data
index->second->m_gotClipboard = true;
// tell all other clients to take ownership of clipboard and mark
// them as not having the data yet.
for (index = m_screens.begin(); index != m_screens.end(); ++index) {
if (index->first != client) {
CScreenInfo* info = index->second;
info->m_gotClipboard = false;
if (info->m_protocol == NULL) {
m_primary->grabClipboard();
}
else {
info->m_protocol->sendGrabClipboard();
}
}
}
// increment the clipboard sequence number so we can identify the
// clipboard query's response.
++m_clipboardSeqNum;
// begin getting the clipboard data
if (m_active->m_protocol == NULL) {
// get clipboard immediately from primary screen
m_primary->getClipboard(&m_clipboard);
m_clipboardData = m_clipboard.marshall();
m_clipboardReady = true;
}
else {
// clear out the clipboard since existing data is now out of date.
if (m_clipboard.open()) {
m_clipboard.close();
}
m_clipboardReady = false;
// send request but don't wait for reply
m_active->m_protocol->sendQueryClipboard(m_clipboardSeqNum);
}
}
void CServer::setClipboard(
UInt32 seqNum, const CString& data)
{
// update the clipboard if the sequence number matches
CLock lock(&m_mutex);
if (seqNum == m_clipboardSeqNum) {
// unmarshall into our clipboard buffer
m_clipboardData = data;
m_clipboard.unmarshall(m_clipboardData);
m_clipboardReady = true;
// if the active client doesn't have the clipboard data
// (and it won't unless the client is the one sending us
// the data) then send the data now.
if (!m_active->m_gotClipboard) {
if (m_active->m_protocol == NULL) {
m_primary->setClipboard(&m_clipboard);
}
else {
m_active->m_protocol->sendClipboard(m_clipboardData);
}
m_active->m_gotClipboard = true;
}
}
}
bool CServer::onCommandKey(KeyID /*id*/,
KeyModifierMask /*mask*/, bool /*down*/)
{
@ -186,9 +275,10 @@ void CServer::onKeyUp(KeyID id, KeyModifierMask mask)
}
}
void CServer::onKeyRepeat(KeyID id, KeyModifierMask mask)
void CServer::onKeyRepeat(
KeyID id, KeyModifierMask mask, SInt32 count)
{
log((CLOG_DEBUG "onKeyRepeat id=%d mask=0x%04x", id, mask));
log((CLOG_DEBUG "onKeyRepeat id=%d mask=0x%04x count=%d", id, mask, count));
assert(m_active != NULL);
// handle command keys
@ -199,7 +289,7 @@ void CServer::onKeyRepeat(KeyID id, KeyModifierMask mask)
// relay
if (m_active->m_protocol != NULL) {
m_active->m_protocol->sendKeyRepeat(id, mask);
m_active->m_protocol->sendKeyRepeat(id, mask, count);
}
}
@ -385,11 +475,6 @@ bool CServer::isLockedToScreen() const
return false;
}
#if defined(CONFIG_PLATFORM_WIN32)
#include "CMSWindowsClipboard.h" // FIXME
#elif defined(CONFIG_PLATFORM_UNIX)
#include "CXWindowsClipboard.h" // FIXME
#endif
void CServer::switchScreen(CScreenInfo* dst,
SInt32 x, SInt32 y)
{
@ -398,6 +483,7 @@ void CServer::switchScreen(CScreenInfo* dst,
assert(m_active != NULL);
log((CLOG_NOTE "switch from \"%s\" to \"%s\" at %d,%d", m_active->m_name.c_str(), dst->m_name.c_str(), x, y));
// FIXME -- we're not locked here but we probably should be
// wrapping means leaving the active screen and entering it again.
// since that's a waste of time we skip that and just warp the
@ -406,14 +492,6 @@ void CServer::switchScreen(CScreenInfo* dst,
// leave active screen
if (m_active->m_protocol == NULL) {
m_primary->leave();
// FIXME -- testing
#if defined(CONFIG_PLATFORM_WIN32)
CMSWindowsClipboard clipboard;
#elif defined(CONFIG_PLATFORM_UNIX)
CXWindowsClipboard clipboard;
#endif
m_primary->getClipboard(&clipboard);
}
else {
m_active->m_protocol->sendLeave();
@ -429,6 +507,17 @@ void CServer::switchScreen(CScreenInfo* dst,
else {
m_active->m_protocol->sendEnter(x, y);
}
// send the clipboard data if we haven't done so yet
if (m_clipboardReady && !m_active->m_gotClipboard) {
if (m_active->m_protocol == NULL) {
m_primary->setClipboard(&m_clipboard);
}
else {
m_active->m_protocol->sendClipboard(m_clipboardData);
}
m_active->m_gotClipboard = true;
}
}
else {
if (m_active->m_protocol == NULL) {
@ -827,6 +916,13 @@ void CServer::openPrimaryScreen()
m_active->m_zoneSize = m_primary->getJumpZoneSize();
log((CLOG_NOTE "server size=%dx%d zone=%d", m_active->m_width, m_active->m_height, m_active->m_zoneSize));
// FIXME -- need way for primary screen to call us back
// set the clipboard owner to the primary screen and then get the
// current clipboard data.
m_primary->getClipboard(&m_clipboard);
m_clipboardData = m_clipboard.marshall();
m_clipboardReady = true;
m_clipboardOwner = m_active->m_name;
}
void CServer::closePrimaryScreen()
@ -979,7 +1075,8 @@ CServer::CScreenInfo::CScreenInfo(const CString& name,
m_name(name),
m_protocol(protocol),
m_width(0), m_height(0),
m_zoneSize(0)
m_zoneSize(0),
m_gotClipboard(false)
{
// do nothing
}

View File

@ -4,6 +4,7 @@
#include "KeyTypes.h"
#include "MouseTypes.h"
#include "CScreenMap.h"
#include "CClipboard.h"
#include "CMutex.h"
#include "CString.h"
#include "XBase.h"
@ -36,16 +37,19 @@ class CServer {
// true iff the mouse enters a jump zone and jumps.
void onKeyDown(KeyID, KeyModifierMask);
void onKeyUp(KeyID, KeyModifierMask);
void onKeyRepeat(KeyID, KeyModifierMask);
void onKeyRepeat(KeyID, KeyModifierMask, SInt32 count);
void onMouseDown(ButtonID);
void onMouseUp(ButtonID);
bool onMouseMovePrimary(SInt32 x, SInt32 y);
void onMouseMoveSecondary(SInt32 dx, SInt32 dy);
void onMouseWheel(SInt32 delta);
void grabClipboard();
// handle messages from clients
void setInfo(const CString& clientName,
SInt32 w, SInt32 h, SInt32 zoneSize);
void grabClipboard(const CString& clientName);
void setClipboard(UInt32 seqNum, const CString& data);
// accessors
@ -91,6 +95,7 @@ class CServer {
IServerProtocol* m_protocol;
SInt32 m_width, m_height;
SInt32 m_zoneSize;
bool m_gotClipboard;
};
// change the active screen
@ -159,6 +164,12 @@ class CServer {
SInt32 m_x, m_y;
CScreenMap m_screenMap;
CClipboard m_clipboard;
CString m_clipboardData;
CString m_clipboardOwner;
UInt32 m_clipboardSeqNum;
bool m_clipboardReady;
};
#endif

View File

@ -33,11 +33,12 @@ class CServerProtocol : public IServerProtocol {
virtual void sendClose() = 0;
virtual void sendEnter(SInt32 xAbs, SInt32 yAbs) = 0;
virtual void sendLeave() = 0;
virtual void sendClipboard(const CString&) = 0;
virtual void sendGrabClipboard() = 0;
virtual void sendQueryClipboard() = 0;
virtual void sendQueryClipboard(UInt32 seqNum) = 0;
virtual void sendScreenSaver(bool on) = 0;
virtual void sendKeyDown(KeyID, KeyModifierMask) = 0;
virtual void sendKeyRepeat(KeyID, KeyModifierMask) = 0;
virtual void sendKeyRepeat(KeyID, KeyModifierMask, SInt32 count) = 0;
virtual void sendKeyUp(KeyID, KeyModifierMask) = 0;
virtual void sendMouseDown(ButtonID) = 0;
virtual void sendMouseUp(ButtonID) = 0;
@ -47,6 +48,8 @@ class CServerProtocol : public IServerProtocol {
protected:
//IServerProtocol overrides
virtual void recvInfo() = 0;
virtual void recvClipboard() = 0;
virtual void recvGrabClipboard() = 0;
private:
CServer* m_server;

View File

@ -1,5 +1,6 @@
#include "CServerProtocol1_0.h"
#include "CServer.h"
#include "CClipboard.h"
#include "CProtocolUtil.h"
#include "ProtocolTypes.h"
#include "IInputStream.h"
@ -49,6 +50,12 @@ void CServerProtocol1_0::run()
if (memcmp(code, kMsgDInfo, 4) == 0) {
recvInfo();
}
else if (memcmp(code, kMsgCClipboard, 4) == 0) {
recvGrabClipboard();
}
else if (memcmp(code, kMsgDClipboard, 4) == 0) {
recvClipboard();
}
// FIXME -- more message here
else {
log((CLOG_ERR "unknown message from client \"%s\"", getClient().c_str()));
@ -96,16 +103,22 @@ void CServerProtocol1_0::sendLeave()
CProtocolUtil::writef(getOutputStream(), kMsgCLeave);
}
void CServerProtocol1_0::sendClipboard(const CString& data)
{
log((CLOG_INFO "send clipboard to \"%s\" size=%d", getClient().c_str(), data.size()));
CProtocolUtil::writef(getOutputStream(), kMsgDClipboard, 0, &data);
}
void CServerProtocol1_0::sendGrabClipboard()
{
log((CLOG_INFO "send grab clipboard to \"%s\"", getClient().c_str()));
CProtocolUtil::writef(getOutputStream(), kMsgCClipboard);
}
void CServerProtocol1_0::sendQueryClipboard()
void CServerProtocol1_0::sendQueryClipboard(UInt32 seqNum)
{
log((CLOG_INFO "query clipboard to \"%s\"", getClient().c_str()));
CProtocolUtil::writef(getOutputStream(), kMsgQClipboard);
CProtocolUtil::writef(getOutputStream(), kMsgQClipboard, seqNum);
}
void CServerProtocol1_0::sendScreenSaver(bool on)
@ -122,10 +135,10 @@ void CServerProtocol1_0::sendKeyDown(
}
void CServerProtocol1_0::sendKeyRepeat(
KeyID key, KeyModifierMask mask)
KeyID key, KeyModifierMask mask, SInt32 count)
{
log((CLOG_INFO "send key repeat to \"%s\" id=%d, mask=0x%04x", getClient().c_str(), key, mask));
CProtocolUtil::writef(getOutputStream(), kMsgDKeyRepeat, key, mask);
CProtocolUtil::writef(getOutputStream(), kMsgDKeyRepeat, key, mask, count);
}
void CServerProtocol1_0::sendKeyUp(
@ -179,3 +192,17 @@ void CServerProtocol1_0::recvInfo()
getServer()->setInfo(getClient(), w, h, zoneInfo);
}
void CServerProtocol1_0::recvClipboard()
{
UInt32 seqNum;
CString data;
CProtocolUtil::readf(getInputStream(), kMsgDClipboard + 4, &seqNum, &data);
log((CLOG_INFO "received client \"%s\" clipboard seqnum=%d, size=%d", getClient().c_str(), seqNum, data.size()));
getServer()->setClipboard(seqNum, data);
}
void CServerProtocol1_0::recvGrabClipboard()
{
log((CLOG_INFO "received client \"%s\" grabbed clipboard", getClient().c_str()));
getServer()->grabClipboard(getClient());
}

View File

@ -18,11 +18,12 @@ class CServerProtocol1_0 : public CServerProtocol {
virtual void sendClose();
virtual void sendEnter(SInt32 xAbs, SInt32 yAbs);
virtual void sendLeave();
virtual void sendClipboard(const CString&);
virtual void sendGrabClipboard();
virtual void sendQueryClipboard();
virtual void sendQueryClipboard(UInt32 seqNum);
virtual void sendScreenSaver(bool on);
virtual void sendKeyDown(KeyID, KeyModifierMask);
virtual void sendKeyRepeat(KeyID, KeyModifierMask);
virtual void sendKeyRepeat(KeyID, KeyModifierMask, SInt32 count);
virtual void sendKeyUp(KeyID, KeyModifierMask);
virtual void sendMouseDown(ButtonID);
virtual void sendMouseUp(ButtonID);
@ -32,6 +33,8 @@ class CServerProtocol1_0 : public CServerProtocol {
protected:
// IServerProtocol overrides
virtual void recvInfo();
virtual void recvClipboard();
virtual void recvGrabClipboard();
};
#endif

View File

@ -56,7 +56,10 @@ static void restoreCursor()
static LRESULT CALLBACK keyboardHook(int code, WPARAM wParam, LPARAM lParam)
{
if (code >= 0) {
// FIXME
if (g_relay) {
PostMessage(g_hwnd, SYNERGY_MSG_KEY, wParam, lParam);
return 1;
}
}
return CallNextHookEx(g_keyboard, code, wParam, lParam);

View File

@ -14,10 +14,10 @@
#define CSYNERGYHOOK_API
#endif
#define SYNERGY_MSG_MARK WM_APP + 0x0001 // mark id; <unused>
#define SYNERGY_MSG_KEY WM_APP + 0x0002 // vk code; key data
#define SYNERGY_MSG_MOUSE_BUTTON WM_APP + 0x0003 // button msg; <unused>
#define SYNERGY_MSG_MOUSE_MOVE WM_APP + 0x0004 // x; y
#define SYNERGY_MSG_MARK WM_APP + 0x0011 // mark id; <unused>
#define SYNERGY_MSG_KEY WM_APP + 0x0012 // vk code; key data
#define SYNERGY_MSG_MOUSE_BUTTON WM_APP + 0x0013 // button msg; <unused>
#define SYNERGY_MSG_MOUSE_MOVE WM_APP + 0x0014 // x; y
typedef int (*InstallFunc)(HWND);
typedef int (*UninstallFunc)(void);

View File

@ -117,19 +117,46 @@ void CXWindowsPrimaryScreen::run()
break;
}
/*
case SelectionClear:
target->XXX(xevent.xselectionclear.);
// we just lost the selection. that means someone else
// grabbed the selection so this screen is now the
// selection owner. report that to the server.
m_server->grabClipboard();
break;
case SelectionNotify:
target->XXX(xevent.xselection.);
// notification of selection transferred. we shouldn't
// get this here because we handle them in the selection
// retrieval methods. we'll just delete the property
// with the data (satisfying the usual ICCCM protocol).
if (xevent.xselection.property != None) {
CDisplayLock display(this);
XDeleteProperty(display, m_window, xevent.xselection.property);
}
break;
case SelectionRequest:
target->XXX(xevent.xselectionrequest.);
// somebody is asking for clipboard data
if (xevent.xselectionrequest.owner == m_window) {
addClipboardRequest(m_window,
xevent.xselectionrequest.requestor,
xevent.xselectionrequest.selection,
xevent.xselectionrequest.target,
xevent.xselectionrequest.property,
xevent.xselectionrequest.time);
}
break;
case PropertyNotify:
// clipboard transfers involve property changes so forward
// the event to the superclass. we only care about the
// deletion of properties.
if (xevent.xproperty.state == PropertyDelete) {
processClipboardRequest(xevent.xproperty.window,
xevent.xproperty.atom,
xevent.xproperty.time);
}
break;
*/
}
}
}
@ -267,19 +294,17 @@ void CXWindowsPrimaryScreen::warpCursorNoLock(
}
}
#include <X11/Xatom.h> // FIXME
void CXWindowsPrimaryScreen::setClipboard(
const IClipboard* /*clipboard*/)
const IClipboard* clipboard)
{
// FIXME -- put this in superclass?
// FIXME -- don't use CurrentTime
CDisplayLock display(this);
XSetSelectionOwner(display, XA_PRIMARY, m_window, CurrentTime);
if (XGetSelectionOwner(display, XA_PRIMARY) == m_window) {
// we got the selection
log((CLOG_DEBUG "grabbed clipboard"));
}
// FIXME -- need to copy or adopt the clipboard to serve future requests
setDisplayClipboard(clipboard, m_window, CurrentTime);
}
void CXWindowsPrimaryScreen::grabClipboard()
{
// FIXME -- don't use CurrentTime
setDisplayClipboard(NULL, m_window, CurrentTime);
}
void CXWindowsPrimaryScreen::getSize(
@ -296,7 +321,6 @@ SInt32 CXWindowsPrimaryScreen::getJumpZoneSize() const
void CXWindowsPrimaryScreen::getClipboard(
IClipboard* clipboard) const
{
// FIXME -- put this in superclass?
// FIXME -- don't use CurrentTime
getDisplayClipboard(clipboard, m_window, CurrentTime);
}

View File

@ -20,6 +20,7 @@ class CXWindowsPrimaryScreen : public CXWindowsScreen, public IPrimaryScreen {
virtual void leave();
virtual void warpCursor(SInt32 xAbsolute, SInt32 yAbsolute);
virtual void setClipboard(const IClipboard*);
virtual void grabClipboard();
virtual void getSize(SInt32* width, SInt32* height) const;
virtual SInt32 getJumpZoneSize() const;
virtual void getClipboard(IClipboard*) const;

View File

@ -23,8 +23,8 @@ CFG=makehook - Win32 Debug
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
# PROP Scc_ProjName "millpond"
# PROP Scc_LocalPath "."
MTL=midl.exe
!IF "$(CFG)" == "makehook - Win32 Release"

View File

@ -10,9 +10,9 @@ void realMain()
CScreenMap screenMap;
screenMap.addScreen("primary");
screenMap.addScreen("ingrid");
screenMap.connect("primary", CScreenMap::kRight, "ingrid");
screenMap.connect("ingrid", CScreenMap::kLeft, "primary");
screenMap.addScreen("secondary");
screenMap.connect("primary", CScreenMap::kRight, "secondary");
screenMap.connect("secondary", CScreenMap::kLeft, "primary");
CServer* server = NULL;
try {

View File

@ -38,7 +38,7 @@ RSC=rc.exe
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Output_Dir "../Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
@ -64,7 +64,7 @@ LINK32=link.exe
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Output_Dir "../Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c

View File

@ -38,8 +38,8 @@ RSC=rc.exe
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Output_Dir "../Release"
# PROP Intermediate_Dir "ReleaseHook"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SYNRGYHK_EXPORTS" /YX /FD /c
# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\base" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SYNRGYHK_EXPORTS" /FD /c
@ -64,8 +64,8 @@ LINK32=link.exe
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Output_Dir "../Debug"
# PROP Intermediate_Dir "DebugHook"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SYNRGYHK_EXPORTS" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "..\base" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SYNRGYHK_EXPORTS" /FD /GZ /c

View File

@ -92,6 +92,10 @@ Project: "makehook"=.\server\makehook.dsp - Package Owner=<4>
Package=<5>
{{{
begin source code control
millpond
.\server
end source code control
}}}
Package=<4>

137
synergy/CClipboard.cpp Normal file
View File

@ -0,0 +1,137 @@
#include "CClipboard.h"
//
// CClipboard
//
CClipboard::CClipboard()
{
// do nothing
}
CClipboard::~CClipboard()
{
// do nothing
}
bool CClipboard::open()
{
// clear all data
for (SInt32 index = 0; index < kNumFormats; ++index) {
m_data[index] = "";
m_added[index] = false;
}
return true;
}
void CClipboard::close()
{
// do nothing
}
void CClipboard::add(EFormat format, const CString& data)
{
m_data[format] = data;
m_added[format] = true;
}
bool CClipboard::has(EFormat format) const
{
return m_added[format];
}
CString CClipboard::get(EFormat format) const
{
return m_data[format];
}
void CClipboard::copy(IClipboard* dst, const IClipboard* src)
{
if (dst->open()) {
for (SInt32 format = 0; format != IClipboard::kNumFormats; ++format) {
IClipboard::EFormat eFormat = (IClipboard::EFormat)format;
if (src->has(eFormat)) {
dst->add(eFormat, src->get(eFormat));
}
}
dst->close();
}
}
void CClipboard::unmarshall(const CString& data)
{
const char* index = data.data();
// clear existing data
open();
// read the number of formats
const UInt32 numFormats = readUInt32(index);
index += 4;
// read each format
for (UInt32 format = 0; format < numFormats; ++format) {
// get the format id
UInt32 format = readUInt32(index);
index += 4;
// get the size of the format data
UInt32 size = readUInt32(index);
index += 4;
// save the data
m_added[format] = true;
m_data[format] = CString(index, size);
index += size;
}
// done
close();
}
CString CClipboard::marshall() const
{
CString data;
// compute size of marshalled data
UInt32 size = 4;
UInt32 numFormats = 0;
UInt32 format;
for (format = 0; format != IClipboard::kNumFormats; ++format) {
if (m_added[format]) {
++numFormats;
size += 4 + 4 + m_data[format].size();
}
}
// allocate space
data.reserve(size);
// marshall the data
writeUInt32(&data, numFormats);
for (format = 0; format != IClipboard::kNumFormats; ++format) {
if (m_added[format]) {
writeUInt32(&data, format);
writeUInt32(&data, m_data[format].size());
data += m_data[format];
}
}
return data;
}
UInt32 CClipboard::readUInt32(const char* buf) const
{
return (static_cast<UInt32>(buf[0]) << 24) |
(static_cast<UInt32>(buf[1]) << 16) |
(static_cast<UInt32>(buf[2]) << 8) |
static_cast<UInt32>(buf[3]);
}
void CClipboard::writeUInt32(CString* buf, UInt32 v) const
{
*buf += static_cast<UInt8>((v >> 24) & 0xff);
*buf += static_cast<UInt8>((v >> 16) & 0xff);
*buf += static_cast<UInt8>((v >> 8) & 0xff);
*buf += static_cast<UInt8>( v & 0xff);
}

49
synergy/CClipboard.h Normal file
View File

@ -0,0 +1,49 @@
#ifndef CCLIPBOARD_H
#define CCLIPBOARD_H
//
// CClipboard -- stores clipboard data in a memory buffer
//
#include "IClipboard.h"
#include "CString.h"
class CClipboard : public IClipboard {
public:
CClipboard();
virtual ~CClipboard();
// manipulators
// unmarshall clipboard data
void unmarshall(const CString& data);
// accessors
// marshall clipboard data
CString marshall() const;
// IClipboard overrides
virtual bool open();
virtual void close();
virtual void add(EFormat, const CString& data);
virtual bool has(EFormat) const;
virtual CString get(EFormat) const;
// accessors
// transfer all the data in one clipboard to another. the
// clipboards can be of any concrete clipboard type (and
// they don't have to be the same type).
static void copy(IClipboard* dst, const IClipboard* src);
private:
UInt32 readUInt32(const char*) const;
void writeUInt32(CString*, UInt32) const;
private:
bool m_added[kNumFormats];
CString m_data[kNumFormats];
};
#endif

View File

@ -6,36 +6,190 @@
// CMSWindowsClipboard
//
CMSWindowsClipboard::CMSWindowsClipboard()
CMSWindowsClipboard::CMSWindowsClipboard(HWND window) : m_window(window)
{
// do nothing
}
CMSWindowsClipboard::~CMSWindowsClipboard()
{
// do nothing
}
void CMSWindowsClipboard::open()
bool CMSWindowsClipboard::open()
{
log((CLOG_INFO "open clipboard"));
if (!OpenClipboard(m_window)) {
log((CLOG_WARN "failed to open clipboard"));
return false;
}
if (EmptyClipboard()) {
log((CLOG_DEBUG "grabbed clipboard"));
}
else {
log((CLOG_WARN "failed to grab clipboard"));
}
return true;
}
void CMSWindowsClipboard::close()
{
log((CLOG_INFO "close clipboard"));
CloseClipboard();
}
void CMSWindowsClipboard::add(
EFormat format, const CString& data)
{
log((CLOG_INFO "add clipboard format: %d\n%s", format, data.c_str()));
log((CLOG_INFO "add %d bytes to clipboard format: %d", data.size(), format));
if (!OpenClipboard(m_window)) {
log((CLOG_WARN "failed to open clipboard"));
return;
}
// convert data to win32 required form
const UINT win32Format = convertFormatToWin32(format);
HANDLE win32Data;
switch (win32Format) {
case CF_TEXT:
win32Data = convertTextToWin32(data);
break;
default:
win32Data = NULL;
break;
}
// put the data on the clipboard
if (win32Data != NULL) {
SetClipboardData(win32Format, win32Data);
}
// done with clipboard
CloseClipboard();
}
bool CMSWindowsClipboard::has(EFormat /*format*/) const
bool CMSWindowsClipboard::has(EFormat format) const
{
return false;
const UINT win32Format = convertFormatToWin32(format);
return (win32Format != 0 && IsClipboardFormatAvailable(win32Format) != 0);
}
CString CMSWindowsClipboard::get(EFormat /*format*/) const
CString CMSWindowsClipboard::get(EFormat format) const
{
return CString();
// get the win32 format. return empty data if unknown format.
const UINT win32Format = convertFormatToWin32(format);
if (win32Format == 0)
return CString();
if (!OpenClipboard(m_window)) {
log((CLOG_WARN "failed to open clipboard"));
return CString();
}
// get a handle to the clipboard data and convert it
HANDLE win32Data = GetClipboardData(win32Format);
CString data;
if (win32Data != NULL) {
// convert the data
switch (win32Format) {
case CF_TEXT:
data = convertTextFromWin32(win32Data);
}
}
// close the clipboard
CloseClipboard();
return data;
}
UINT CMSWindowsClipboard::convertFormatToWin32(
EFormat format) const
{
switch (format) {
case kText:
return CF_TEXT;
default:
return 0;
}
}
HANDLE CMSWindowsClipboard::convertTextToWin32(
const CString& data) const
{
// compute size of converted text
UInt32 dstSize = 0;
const UInt32 srcSize = data.size();
const char* src = data.c_str();
for (UInt32 index = 0; index < srcSize; ++index) {
if (src[index] == '\n') {
// add \r
++dstSize;
}
++dstSize;
}
// allocate
HGLOBAL gData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, dstSize);
if (gData != NULL) {
// get a pointer to the allocated memory
char* dst = (char*)GlobalLock(gData);
if (dst != NULL) {
// convert text. we change LF to CRLF.
dstSize = 0;
for (UInt32 index = 0; index < srcSize; ++index) {
if (src[index] == '\n') {
// add \r
dst[dstSize++] = '\r';
}
dst[dstSize++] = src[index];
}
// done converting
GlobalUnlock(gData);
}
}
return gData;
}
CString CMSWindowsClipboard::convertTextFromWin32(
HANDLE handle) const
{
// get source data and it's size
const char* src = (const char*)GlobalLock(handle);
UInt32 srcSize = (SInt32)GlobalSize(handle);
if (src == NULL || srcSize == 0)
return CString();
// compute size of converted text
UInt32 dstSize = 0;
UInt32 index;
for (index = 0; index < srcSize; ++index) {
if (src[index] == '\r') {
// skip \r
if (index + 1 < srcSize && src[index + 1] == '\n')
++index;
}
++dstSize;
}
// allocate
CString data;
data.reserve(dstSize);
// convert text. we change CRLF to LF.
for (index = 0; index < srcSize; ++index) {
if (src[index] == '\r') {
// skip \r
if (index + 1 < srcSize && src[index + 1] == '\n')
++index;
}
data += src[index];
}
return data;
}

View File

@ -2,18 +2,27 @@
#define CMSWINDOWSCLIPBOARD_H
#include "IClipboard.h"
#include <windows.h>
class CMSWindowsClipboard : public IClipboard {
public:
CMSWindowsClipboard();
CMSWindowsClipboard(HWND window);
virtual ~CMSWindowsClipboard();
// IClipboard overrides
virtual void open();
virtual bool open();
virtual void close();
virtual void add(EFormat, const CString& data);
virtual bool has(EFormat) const;
virtual CString get(EFormat) const;
private:
UINT convertFormatToWin32(EFormat) const;
HANDLE convertTextToWin32(const CString& data) const;
CString convertTextFromWin32(HANDLE) const;
private:
HWND m_window;
};
#endif

View File

@ -12,6 +12,7 @@
//
HINSTANCE CMSWindowsScreen::s_instance = NULL;
CMSWindowsScreen* CMSWindowsScreen::s_screen = NULL;
CMSWindowsScreen::CMSWindowsScreen() :
m_class(0),
@ -19,12 +20,14 @@ CMSWindowsScreen::CMSWindowsScreen() :
m_w(0), m_h(0),
m_thread(0)
{
// do nothing
assert(s_screen == NULL);
s_screen = this;
}
CMSWindowsScreen::~CMSWindowsScreen()
{
assert(m_class == 0);
s_screen = NULL;
}
void CMSWindowsScreen::init(HINSTANCE instance)
@ -46,7 +49,7 @@ void CMSWindowsScreen::doRun()
}
// dispatch message
if (!onEvent(&msg)) {
if (!onPreTranslate(&msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
@ -66,10 +69,13 @@ void CMSWindowsScreen::openDisplay()
// create a transparent cursor
int cw = GetSystemMetrics(SM_CXCURSOR);
int ch = GetSystemMetrics(SM_CYCURSOR);
UInt8* cursorBits = new UInt8[ch * ((cw + 31) >> 5)];
memset(cursorBits, 0, ch * ((cw + 31) >> 5));
m_cursor = CreateCursor(s_instance, 0, 0, cw, ch, cursorBits, cursorBits);
delete[] cursorBits;
UInt8* cursorAND = new UInt8[ch * ((cw + 31) >> 2)];
UInt8* cursorXOR = new UInt8[ch * ((cw + 31) >> 2)];
memset(cursorAND, 0xff, ch * ((cw + 31) >> 2));
memset(cursorXOR, 0x00, ch * ((cw + 31) >> 2));
m_cursor = CreateCursor(s_instance, 0, 0, cw, ch, cursorAND, cursorXOR);
delete[] cursorXOR;
delete[] cursorAND;
// register a window class
WNDCLASSEX classInfo;
@ -197,7 +203,7 @@ void CMSWindowsScreen::getDisplayClipboard(
// if we can use the format and we haven't already retrieved
// it then get it
if (expectedFormat == IClipboard::kNum) {
if (expectedFormat == IClipboard::kNumFormats) {
log((CLOG_DEBUG " no format for target", format));
continue;
}
@ -215,7 +221,7 @@ void CMSWindowsScreen::getDisplayClipboard(
// use the actual format, not the expected
IClipboard::EFormat actualFormat = getFormat(format);
if (actualFormat == IClipboard::kNum) {
if (actualFormat == IClipboard::kNumFormats) {
log((CLOG_DEBUG " no format for target", format));
continue;
}
@ -244,5 +250,6 @@ LRESULT CALLBACK CMSWindowsScreen::wndProc(
HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam)
{
return DefWindowProc(hwnd, msg, wParam, lParam);
assert(s_screen != NULL);
return s_screen->onEvent(hwnd, msg, wParam, lParam);
}

View File

@ -49,8 +49,12 @@ class CMSWindowsScreen {
// copy the clipboard contents to clipboard
void getDisplayClipboard(IClipboard* clipboard, HWND) const;
// called by doRun() to handle an event
virtual bool onEvent(MSG*) = 0;
// called by doRun() to handle an event. return true to skip
// event translation and dispatch.
virtual bool onPreTranslate(MSG*) = 0;
// called by window proc. subclass must call DefWindowProc() if necessary
virtual LRESULT onEvent(HWND, UINT, WPARAM, LPARAM) = 0;
// called by openDisplay() to allow subclasses to prepare the display
virtual void onOpenDisplay() = 0;
@ -68,6 +72,7 @@ class CMSWindowsScreen {
HCURSOR m_cursor;
SInt32 m_w, m_h;
DWORD m_thread;
static CMSWindowsScreen* s_screen;
};
#endif

View File

@ -190,6 +190,12 @@ UInt32 CProtocolUtil::getLength(
break;
case 's':
assert(len == 0);
len = (va_arg(args, CString*))->size() + 4;
(void)va_arg(args, UInt8*);
break;
case 'S':
assert(len == 0);
len = va_arg(args, UInt32) + 4;
(void)va_arg(args, UInt8*);
@ -258,6 +264,21 @@ void CProtocolUtil::writef(void* buffer,
}
case 's': {
assert(len == 0);
const CString* src = va_arg(args, CString*);
const UInt32 len = (src != NULL) ? src->size() : 0;
*dst++ = static_cast<UInt8>((len >> 24) & 0xff);
*dst++ = static_cast<UInt8>((len >> 16) & 0xff);
*dst++ = static_cast<UInt8>((len >> 8) & 0xff);
*dst++ = static_cast<UInt8>( len & 0xff);
if (len != 0) {
memcpy(dst, src->data(), len);
dst += len;
}
break;
}
case 'S': {
assert(len == 0);
const UInt32 len = va_arg(args, UInt32);
const UInt8* src = va_arg(args, UInt8*);

View File

@ -20,7 +20,8 @@ class CProtocolUtil {
// %1i -- converts integer argument to 1 byte integer
// %2i -- converts integer argument to 2 byte integer in NBO
// %4i -- converts integer argument to 4 byte integer in NBO
// %s -- converts integer N and const UInt8* to stream of N bytes
// %s -- converts CString* to stream of bytes
// %S -- converts integer N and const UInt8* to stream of N bytes
static void writef(IOutputStream*,
const char* fmt, ...);

View File

@ -52,6 +52,7 @@ void CXWindowsScreen::openDisplay()
// get some atoms
m_atomTargets = XInternAtom(m_display, "TARGETS", False);
m_atomMultiple = XInternAtom(m_display, "MULTIPLE", False);
m_atomData = XInternAtom(m_display, "DESTINATION", False);
m_atomINCR = XInternAtom(m_display, "INCR", False);
m_atomText = XInternAtom(m_display, "TEXT", False);
@ -143,12 +144,12 @@ bool CXWindowsScreen::getEvent(XEvent* xevent) const
}
if (m_stop) {
m_mutex.unlock();
return true;
return false;
}
else {
XNextEvent(m_display, xevent);
m_mutex.unlock();
return false;
return true;
}
}
@ -158,6 +159,34 @@ void CXWindowsScreen::doStop()
m_stop = true;
}
bool CXWindowsScreen::setDisplayClipboard(
const IClipboard* clipboard,
Window requestor, Time timestamp)
{
CLock lock(&m_mutex);
XSetSelectionOwner(m_display, XA_PRIMARY, requestor, timestamp);
if (XGetSelectionOwner(m_display, XA_PRIMARY) == requestor) {
// we got the selection
log((CLOG_DEBUG "grabbed clipboard"));
if (clipboard != NULL) {
// save clipboard to serve requests
CClipboard::copy(&m_clipboard, clipboard);
}
else {
// clear clipboard
if (m_clipboard.open()) {
m_clipboard.close();
}
}
return true;
}
return false;
}
void CXWindowsScreen::getDisplayClipboard(
IClipboard* clipboard,
Window requestor, Time timestamp) const
@ -166,7 +195,8 @@ void CXWindowsScreen::getDisplayClipboard(
assert(requestor != None);
// clear the clipboard object
clipboard->open();
if (!clipboard->open())
return;
// block others from using the display while we get the clipboard.
// in particular, this prevents the event thread from stealing the
@ -209,7 +239,7 @@ void CXWindowsScreen::getDisplayClipboard(
// if we can use the format and we haven't already retrieved
// it then get it
if (expectedFormat == IClipboard::kNum) {
if (expectedFormat == IClipboard::kNumFormats) {
log((CLOG_DEBUG " no format for target", format));
continue;
}
@ -227,7 +257,7 @@ void CXWindowsScreen::getDisplayClipboard(
// use the actual format, not the expected
IClipboard::EFormat actualFormat = getFormat(format);
if (actualFormat == IClipboard::kNum) {
if (actualFormat == IClipboard::kNumFormats) {
log((CLOG_DEBUG " no format for target", format));
continue;
}
@ -452,7 +482,7 @@ IClipboard::EFormat CXWindowsScreen::getFormat(Atom src) const
src == m_atomText ||
src == m_atomCompoundText)
return IClipboard::kText;
return IClipboard::kNum;
return IClipboard::kNumFormats;
}
Bool CXWindowsScreen::findSelectionNotify(
@ -473,6 +503,98 @@ Bool CXWindowsScreen::findPropertyNotify(
xevent->xproperty.state == PropertyNewValue) ? True : False;
}
void CXWindowsScreen::addClipboardRequest(
Window /*owner*/, Window requestor,
Atom selection, Atom target,
Atom property, Time time)
{
// mutex the display
CLock lock(&m_mutex);
// check the target
IClipboard::EFormat format = IClipboard::kNumFormats;
if (selection == XA_PRIMARY) {
if (target == m_atomTargets) {
// send the list of available targets
sendClipboardTargetsNotify(requestor, property, time);
return;
}
else if (target == m_atomMultiple) {
// add a multiple request
if (property != None) {
addClipboardMultipleRequest(requestor, property, time);
return;
}
}
else {
format = getFormat(target);
}
}
// if we can't handle the format then send a failure notification
if (format == IClipboard::kNumFormats) {
XEvent event;
event.xselection.type = SelectionNotify;
event.xselection.display = m_display;
event.xselection.requestor = requestor;
event.xselection.selection = selection;
event.xselection.target = target;
event.xselection.property = None;
event.xselection.time = time;
XSendEvent(m_display, requestor, False, 0, &event);
return;
}
// we could process short requests without adding to the request
// queue but we'll keep things simple by doing all requests the
// same way.
// FIXME
}
void CXWindowsScreen::sendClipboardTargetsNotify(
Window requestor,
Atom property, Time time)
{
// construct response
// FIXME
// set property
// FIXME
// send notification
XEvent event;
event.xselection.type = SelectionNotify;
event.xselection.display = m_display;
event.xselection.requestor = requestor;
event.xselection.selection = XA_PRIMARY;
event.xselection.target = m_atomTargets;
event.xselection.property = property;
event.xselection.time = time;
XSendEvent(m_display, requestor, False, 0, &event);
}
void CXWindowsScreen::processClipboardRequest(
Window requestor,
Atom property, Time time)
{
// FIXME
}
void CXWindowsScreen::addClipboardRequest(
Window requestor,
Atom property, Time time,
IClipboard::EFormat format)
{
// FIXME
}
void CXWindowsScreen::addClipboardMultipleRequest(
Window requestor,
Atom property, Time time)
{
// FIXME
}
//
// CXWindowsScreen::CDisplayLock

View File

@ -1,8 +1,8 @@
#ifndef CXWINDOWSSCREEN_H
#define CXWINDOWSSCREEN_H
#include "CClipboard.h"
#include "CMutex.h"
#include "IClipboard.h"
#include "BasicTypes.h"
#include <X11/Xlib.h>
@ -54,12 +54,25 @@ class CXWindowsScreen {
// cause getEvent() to return false immediately and forever after
void doStop();
bool setDisplayClipboard(const IClipboard* clipboard,
Window requestor, Time timestamp);
// copy the clipboard contents to clipboard. requestor must be a
// valid window; it will be used to receive the transfer. timestamp
// should be the timestamp of the provoking event and not CurrentTime.
void getDisplayClipboard(IClipboard* clipboard,
Window requestor, Time timestamp) const;
// add a selection request to the request list
void addClipboardRequest(
Window owner, Window requestor,
Atom selection, Atom target,
Atom property, Time time);
// continue processing a selection request
void processClipboardRequest(Window window,
Atom property, Time time);
// called by openDisplay() to allow subclasses to prepare the display
virtual void onOpenDisplay() = 0;
@ -85,6 +98,14 @@ class CXWindowsScreen {
static Bool findPropertyNotify(Display*,
XEvent* xevent, XPointer arg);
void sendClipboardTargetsNotify(Window requestor,
Atom property, Time time);
void addClipboardRequest(Window requestor,
Atom property, Time time,
IClipboard::EFormat);
void addClipboardMultipleRequest(Window requestor,
Atom property, Time time);
private:
Display* m_display;
int m_screen;
@ -94,11 +115,15 @@ class CXWindowsScreen {
// atoms we'll need
Atom m_atomTargets;
Atom m_atomMultiple;
Atom m_atomData;
Atom m_atomINCR;
Atom m_atomText;
Atom m_atomCompoundText;
// the contents of our selection
CClipboard m_clipboard;
// X is not thread safe
CMutex m_mutex;
};

View File

@ -8,14 +8,16 @@ class CString;
class IClipboard : public IInterface {
public:
enum EFormat { kText, kNum };
enum EFormat { kText, kNumFormats };
// manipulators
// grab ownership of and clear the clipboard of all data.
// only add() may be called between an open() and its
// corresponding close().
virtual void open() = 0;
// corresponding close(). if open() returns false then
// the clipboard could not be opened or grabbed; do not
// call close() in that case.
virtual bool open() = 0;
// close the clipboard. close() must match a preceding open().
// this signals that the clipboard has been filled with all the

View File

@ -54,11 +54,11 @@ class IPrimaryScreen : public IInterface {
/*
// show or hide the screen saver
virtual void onScreenSaver(bool show) = 0;
// clipboard input
virtual void onClipboardChanged() = 0;
*/
// synergy should own the clipboard
virtual void grabClipboard() = 0;
// accessors
/*

View File

@ -7,7 +7,7 @@
#include "MouseTypes.h"
class CClient;
//class IClipboard;
class IClipboard;
class ISecondaryScreen : public IInterface {
public:
@ -50,18 +50,18 @@ class ISecondaryScreen : public IInterface {
virtual void mouseMove(SInt32 xAbsolute, SInt32 yAbsolute) = 0;
virtual void mouseWheel(SInt32 delta) = 0;
/*
// set the screen's clipboard contents. this is usually called
// soon after an enter().
virtual void setClipboard(const IClipboard*) = 0;
/*
// show or hide the screen saver
virtual void screenSaver(bool show) = 0;
// clipboard input
virtual void clipboardChanged() = 0;
*/
// take ownership of clipboard
virtual void grabClipboard() = 0;
// accessors
// get the size of the screen
@ -70,10 +70,8 @@ class ISecondaryScreen : public IInterface {
// get the size of jump zone
virtual SInt32 getJumpZoneSize() const = 0;
/*
// get the screen's clipboard contents
virtual void getClipboard(IClipboard*) const = 0;
*/
};
#endif

View File

@ -7,6 +7,8 @@
#include "XSynergy.h"
#include "XIO.h"
class IClipboard;
class IServerProtocol : public IInterface {
public:
// manipulators
@ -23,11 +25,12 @@ class IServerProtocol : public IInterface {
virtual void sendClose() = 0;
virtual void sendEnter(SInt32 xAbs, SInt32 yAbs) = 0;
virtual void sendLeave() = 0;
virtual void sendClipboard(const CString&) = 0;
virtual void sendGrabClipboard() = 0;
virtual void sendQueryClipboard() = 0;
virtual void sendQueryClipboard(UInt32 seqNum) = 0;
virtual void sendScreenSaver(bool on) = 0;
virtual void sendKeyDown(KeyID, KeyModifierMask) = 0;
virtual void sendKeyRepeat(KeyID, KeyModifierMask) = 0;
virtual void sendKeyRepeat(KeyID, KeyModifierMask, SInt32 count) = 0;
virtual void sendKeyUp(KeyID, KeyModifierMask) = 0;
virtual void sendMouseDown(ButtonID) = 0;
virtual void sendMouseUp(ButtonID) = 0;
@ -40,6 +43,8 @@ class IServerProtocol : public IInterface {
// manipulators
virtual void recvInfo() = 0;
virtual void recvClipboard() = 0;
virtual void recvGrabClipboard() = 0;
// accessors
};

View File

@ -19,6 +19,7 @@ CXXFILES = \
CInputPacketStream.cpp \
COutputPacketStream.cpp \
CProtocolUtil.cpp \
CClipboard.cpp \
CTCPSocketFactory.cpp \
CXWindowsClipboard.cpp \
CXWindowsScreen.cpp \

View File

@ -16,7 +16,7 @@ static const SInt32 kMinorVersion = 1;
static const char kMsgCClose[] = "CBYE"; // server
static const char kMsgCEnter[] = "CINN%2i%2i"; // server
static const char kMsgCLeave[] = "COUT"; // server
static const char kMsgCClipboard[] = "CCLP"; // server
static const char kMsgCClipboard[] = "CCLP"; // server/client
static const char kMsgCScreenSaver[] = "CSEC%1i"; // server
static const char kMsgDKeyDown[] = "DKDN%2i%2i"; // server
@ -26,10 +26,10 @@ static const char kMsgDMouseDown[] = "DMDN%1i"; // server
static const char kMsgDMouseUp[] = "DMUP%1i"; // server
static const char kMsgDMouseMove[] = "DMMV%2i%2i"; // server
static const char kMsgDMouseWheel[] = "DMWM%2i"; // server
static const char kMsgDClipboard[] = "DCLP%s"; // server
static const char kMsgDClipboard[] = "DCLP%4i%s"; // server/client
static const char kMsgDInfo[] = "DINF%2i%2i%2i"; // client
static const char kMsgQClipboard[] = "QCLP"; // server
static const char kMsgQClipboard[] = "QCLP%4i"; // server
static const char kMsgQInfo[] = "QINF"; // server
static const char kMsgEIncompatible[] = "EICV";

View File

@ -87,6 +87,10 @@ LIB32=link.exe -lib
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\CClipboard.cpp
# End Source File
# Begin Source File
SOURCE=.\CInputPacketStream.cpp
# End Source File
# Begin Source File
@ -119,6 +123,10 @@ SOURCE=.\XSynergy.cpp
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=.\CClipboard.h
# End Source File
# Begin Source File
SOURCE=.\CInputPacketStream.h
# End Source File
# Begin Source File