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:
parent
3f6146b15f
commit
f15c9df85b
|
@ -2,8 +2,10 @@
|
||||||
#include "CInputPacketStream.h"
|
#include "CInputPacketStream.h"
|
||||||
#include "COutputPacketStream.h"
|
#include "COutputPacketStream.h"
|
||||||
#include "CProtocolUtil.h"
|
#include "CProtocolUtil.h"
|
||||||
|
#include "CClipboard.h"
|
||||||
#include "ISecondaryScreen.h"
|
#include "ISecondaryScreen.h"
|
||||||
#include "ProtocolTypes.h"
|
#include "ProtocolTypes.h"
|
||||||
|
#include "CLock.h"
|
||||||
#include "CThread.h"
|
#include "CThread.h"
|
||||||
#include "CTimerThread.h"
|
#include "CTimerThread.h"
|
||||||
#include "XSynergy.h"
|
#include "XSynergy.h"
|
||||||
|
@ -63,7 +65,7 @@ void CClient::run(const CNetworkAddress& serverAddress)
|
||||||
closeSecondaryScreen();
|
closeSecondaryScreen();
|
||||||
}
|
}
|
||||||
catch (XBase& e) {
|
catch (XBase& e) {
|
||||||
log((CLOG_ERR "client error: %s\n", e.what()));
|
log((CLOG_ERR "client error: %s", e.what()));
|
||||||
|
|
||||||
// clean up
|
// clean up
|
||||||
thread->cancel();
|
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
|
#include "CTCPSocket.h" // FIXME
|
||||||
void CClient::runSession(void*)
|
void CClient::runSession(void*)
|
||||||
{
|
{
|
||||||
|
@ -136,10 +149,10 @@ void CClient::runSession(void*)
|
||||||
// say hello back
|
// say hello back
|
||||||
log((CLOG_DEBUG "say hello version %d.%d", kMajorVersion, kMinorVersion));
|
log((CLOG_DEBUG "say hello version %d.%d", kMajorVersion, kMinorVersion));
|
||||||
CProtocolUtil::writef(output.get(), "Synergy%2i%2i%s",
|
CProtocolUtil::writef(output.get(), "Synergy%2i%2i%s",
|
||||||
kMajorVersion, kMinorVersion,
|
kMajorVersion, kMinorVersion, &m_name);
|
||||||
m_name.size(), m_name.data());
|
|
||||||
|
|
||||||
// record streams in a more useful place
|
// record streams in a more useful place
|
||||||
|
CLock lock(&m_mutex);
|
||||||
m_input = input.get();
|
m_input = input.get();
|
||||||
m_output = output.get();
|
m_output = output.get();
|
||||||
}
|
}
|
||||||
|
@ -291,7 +304,10 @@ void CClient::closeSecondaryScreen()
|
||||||
void CClient::onEnter()
|
void CClient::onEnter()
|
||||||
{
|
{
|
||||||
SInt32 x, y;
|
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);
|
m_screen->enter(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,13 +318,16 @@ void CClient::onLeave()
|
||||||
|
|
||||||
void CClient::onGrabClipboard()
|
void CClient::onGrabClipboard()
|
||||||
{
|
{
|
||||||
// FIXME
|
m_screen->grabClipboard();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CClient::onScreenSaver()
|
void CClient::onScreenSaver()
|
||||||
{
|
{
|
||||||
SInt32 on;
|
SInt32 on;
|
||||||
CProtocolUtil::readf(m_input, kMsgCScreenSaver + 4, &on);
|
{
|
||||||
|
CLock lock(&m_mutex);
|
||||||
|
CProtocolUtil::readf(m_input, kMsgCScreenSaver + 4, &on);
|
||||||
|
}
|
||||||
// FIXME
|
// FIXME
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,24 +336,63 @@ void CClient::onQueryInfo()
|
||||||
SInt32 w, h;
|
SInt32 w, h;
|
||||||
m_screen->getSize(&w, &h);
|
m_screen->getSize(&w, &h);
|
||||||
SInt32 zoneSize = m_screen->getJumpZoneSize();
|
SInt32 zoneSize = m_screen->getJumpZoneSize();
|
||||||
|
|
||||||
log((CLOG_DEBUG "sending info size=%d,%d zone=%d", w, h, zoneSize));
|
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);
|
CProtocolUtil::writef(m_output, kMsgDInfo, w, h, zoneSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CClient::onQueryClipboard()
|
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()
|
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()
|
void CClient::onKeyDown()
|
||||||
{
|
{
|
||||||
SInt32 id, mask;
|
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),
|
m_screen->keyDown(static_cast<KeyID>(id),
|
||||||
static_cast<KeyModifierMask>(mask));
|
static_cast<KeyModifierMask>(mask));
|
||||||
}
|
}
|
||||||
|
@ -342,7 +400,10 @@ void CClient::onKeyDown()
|
||||||
void CClient::onKeyRepeat()
|
void CClient::onKeyRepeat()
|
||||||
{
|
{
|
||||||
SInt32 id, mask, count;
|
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),
|
m_screen->keyRepeat(static_cast<KeyID>(id),
|
||||||
static_cast<KeyModifierMask>(mask),
|
static_cast<KeyModifierMask>(mask),
|
||||||
count);
|
count);
|
||||||
|
@ -351,7 +412,10 @@ void CClient::onKeyRepeat()
|
||||||
void CClient::onKeyUp()
|
void CClient::onKeyUp()
|
||||||
{
|
{
|
||||||
SInt32 id, mask;
|
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),
|
m_screen->keyUp(static_cast<KeyID>(id),
|
||||||
static_cast<KeyModifierMask>(mask));
|
static_cast<KeyModifierMask>(mask));
|
||||||
}
|
}
|
||||||
|
@ -359,27 +423,39 @@ void CClient::onKeyUp()
|
||||||
void CClient::onMouseDown()
|
void CClient::onMouseDown()
|
||||||
{
|
{
|
||||||
SInt32 id;
|
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));
|
m_screen->mouseDown(static_cast<ButtonID>(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CClient::onMouseUp()
|
void CClient::onMouseUp()
|
||||||
{
|
{
|
||||||
SInt32 id;
|
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));
|
m_screen->mouseUp(static_cast<ButtonID>(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CClient::onMouseMove()
|
void CClient::onMouseMove()
|
||||||
{
|
{
|
||||||
SInt32 x, y;
|
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);
|
m_screen->mouseMove(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CClient::onMouseWheel()
|
void CClient::onMouseWheel()
|
||||||
{
|
{
|
||||||
SInt32 delta;
|
SInt32 delta;
|
||||||
CProtocolUtil::readf(m_input, kMsgDMouseWheel + 4, &delta);
|
{
|
||||||
|
CLock lock(&m_mutex);
|
||||||
|
CProtocolUtil::readf(m_input, kMsgDMouseWheel + 4, &delta);
|
||||||
|
}
|
||||||
m_screen->mouseWheel(delta);
|
m_screen->mouseWheel(delta);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef CCLIENT_H
|
#ifndef CCLIENT_H
|
||||||
#define CCLIENT_H
|
#define CCLIENT_H
|
||||||
|
|
||||||
|
#include "CMutex.h"
|
||||||
#include "CString.h"
|
#include "CString.h"
|
||||||
#include "BasicTypes.h"
|
#include "BasicTypes.h"
|
||||||
|
|
||||||
|
@ -18,6 +19,9 @@ class CClient {
|
||||||
|
|
||||||
void run(const CNetworkAddress& serverAddress);
|
void run(const CNetworkAddress& serverAddress);
|
||||||
|
|
||||||
|
// handle events on client's screen
|
||||||
|
void onClipboardChanged();
|
||||||
|
|
||||||
// accessors
|
// accessors
|
||||||
|
|
||||||
|
|
||||||
|
@ -45,6 +49,7 @@ class CClient {
|
||||||
void onMouseWheel();
|
void onMouseWheel();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
CMutex m_mutex;
|
||||||
CString m_name;
|
CString m_name;
|
||||||
IInputStream* m_input;
|
IInputStream* m_input;
|
||||||
IOutputStream* m_output;
|
IOutputStream* m_output;
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "CMSWindowsSecondaryScreen.h"
|
#include "CMSWindowsSecondaryScreen.h"
|
||||||
|
#include "CMSWindowsClipboard.h"
|
||||||
#include "CClient.h"
|
#include "CClient.h"
|
||||||
|
#include "CClipboard.h"
|
||||||
#include "CThread.h"
|
#include "CThread.h"
|
||||||
#include "CLog.h"
|
#include "CLog.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
@ -10,7 +12,8 @@
|
||||||
|
|
||||||
CMSWindowsSecondaryScreen::CMSWindowsSecondaryScreen() :
|
CMSWindowsSecondaryScreen::CMSWindowsSecondaryScreen() :
|
||||||
m_client(NULL),
|
m_client(NULL),
|
||||||
m_window(NULL)
|
m_window(NULL),
|
||||||
|
m_nextClipboardWindow(NULL)
|
||||||
{
|
{
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
@ -20,6 +23,8 @@ CMSWindowsSecondaryScreen::~CMSWindowsSecondaryScreen()
|
||||||
assert(m_window == NULL);
|
assert(m_window == NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static CString s_log;
|
||||||
|
static CString s_logMore;
|
||||||
static HWND s_debug = NULL;
|
static HWND s_debug = NULL;
|
||||||
static HWND s_debugLog = NULL;
|
static HWND s_debugLog = NULL;
|
||||||
static DWORD s_thread = 0;
|
static DWORD s_thread = 0;
|
||||||
|
@ -32,39 +37,40 @@ static BOOL CALLBACK WINAPI debugProc(HWND, UINT msg, WPARAM wParam, LPARAM lPar
|
||||||
case WM_CLOSE:
|
case WM_CLOSE:
|
||||||
PostQuitMessage(0);
|
PostQuitMessage(0);
|
||||||
return TRUE;
|
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;
|
return FALSE;
|
||||||
}
|
}
|
||||||
static void debugOutput(const char* msg)
|
static void debugOutput(const char* msg)
|
||||||
{
|
{
|
||||||
if (s_thread != 0) {
|
s_logMore += msg;
|
||||||
const DWORD threadID = ::GetCurrentThreadId();
|
PostMessage(s_debug, WM_APP, 0, 0);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMSWindowsSecondaryScreen::run()
|
void CMSWindowsSecondaryScreen::run()
|
||||||
{
|
{
|
||||||
CLog::setOutputter(&debugOutput);
|
CLog::setOutputter(&debugOutput);
|
||||||
|
log((CLOG_INFO "entering event loop"));
|
||||||
doRun();
|
doRun();
|
||||||
|
log((CLOG_INFO "exiting event loop"));
|
||||||
CLog::setOutputter(NULL);
|
CLog::setOutputter(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMSWindowsSecondaryScreen::stop()
|
void CMSWindowsSecondaryScreen::stop()
|
||||||
{
|
{
|
||||||
|
log((CLOG_INFO "requesting event loop stop"));
|
||||||
doStop();
|
doStop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,6 +79,8 @@ void CMSWindowsSecondaryScreen::open(CClient* client)
|
||||||
assert(m_client == NULL);
|
assert(m_client == NULL);
|
||||||
assert(client != NULL);
|
assert(client != NULL);
|
||||||
|
|
||||||
|
log((CLOG_INFO "opening screen"));
|
||||||
|
|
||||||
// set the client
|
// set the client
|
||||||
m_client = client;
|
m_client = client;
|
||||||
|
|
||||||
|
@ -84,6 +92,8 @@ void CMSWindowsSecondaryScreen::close()
|
||||||
{
|
{
|
||||||
assert(m_client != NULL);
|
assert(m_client != NULL);
|
||||||
|
|
||||||
|
log((CLOG_INFO "closing screen"));
|
||||||
|
|
||||||
// close the display
|
// close the display
|
||||||
closeDisplay();
|
closeDisplay();
|
||||||
|
|
||||||
|
@ -95,6 +105,8 @@ void CMSWindowsSecondaryScreen::enter(SInt32 x, SInt32 y)
|
||||||
{
|
{
|
||||||
assert(m_window != NULL);
|
assert(m_window != NULL);
|
||||||
|
|
||||||
|
log((CLOG_INFO "entering screen at %d,%d", x, y));
|
||||||
|
|
||||||
// warp to requested location
|
// warp to requested location
|
||||||
SInt32 w, h;
|
SInt32 w, h;
|
||||||
getScreenSize(&w, &h);
|
getScreenSize(&w, &h);
|
||||||
|
@ -104,6 +116,7 @@ void CMSWindowsSecondaryScreen::enter(SInt32 x, SInt32 y)
|
||||||
0, 0);
|
0, 0);
|
||||||
|
|
||||||
// show cursor
|
// show cursor
|
||||||
|
log((CLOG_INFO "show cursor"));
|
||||||
ShowWindow(m_window, SW_HIDE);
|
ShowWindow(m_window, SW_HIDE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,6 +124,8 @@ void CMSWindowsSecondaryScreen::leave()
|
||||||
{
|
{
|
||||||
assert(m_window != NULL);
|
assert(m_window != NULL);
|
||||||
|
|
||||||
|
log((CLOG_INFO "leaving screen"));
|
||||||
|
|
||||||
// move hider window under the mouse (rather than moving the mouse
|
// move hider window under the mouse (rather than moving the mouse
|
||||||
// somewhere else on the screen)
|
// somewhere else on the screen)
|
||||||
POINT point;
|
POINT point;
|
||||||
|
@ -118,10 +133,27 @@ void CMSWindowsSecondaryScreen::leave()
|
||||||
MoveWindow(m_window, point.x, point.y, 1, 1, FALSE);
|
MoveWindow(m_window, point.x, point.y, 1, 1, FALSE);
|
||||||
|
|
||||||
// raise and show the hider window. take activation.
|
// raise and show the hider window. take activation.
|
||||||
|
log((CLOG_INFO "hide cursor"));
|
||||||
ShowWindow(m_window, SW_SHOWNORMAL);
|
ShowWindow(m_window, SW_SHOWNORMAL);
|
||||||
|
|
||||||
// hide cursor by moving it into the hider window
|
// if we think we own the clipboard but we don't then somebody
|
||||||
SetCursorPos(point.x, point.y);
|
// 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(
|
void CMSWindowsSecondaryScreen::keyDown(
|
||||||
|
@ -222,6 +254,25 @@ void CMSWindowsSecondaryScreen::mouseWheel(SInt32 delta)
|
||||||
mouse_event(MOUSEEVENTF_WHEEL, 0, 0, delta, 0);
|
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(
|
void CMSWindowsSecondaryScreen::getSize(
|
||||||
SInt32* width, SInt32* height) const
|
SInt32* width, SInt32* height) const
|
||||||
{
|
{
|
||||||
|
@ -233,6 +284,15 @@ SInt32 CMSWindowsSecondaryScreen::getJumpZoneSize() const
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CMSWindowsSecondaryScreen::getClipboard(
|
||||||
|
IClipboard* dst) const
|
||||||
|
{
|
||||||
|
assert(m_window != NULL);
|
||||||
|
|
||||||
|
CMSWindowsClipboard src(m_window);
|
||||||
|
CClipboard::copy(dst, &src);
|
||||||
|
}
|
||||||
|
|
||||||
#include "resource.h" // FIXME
|
#include "resource.h" // FIXME
|
||||||
|
|
||||||
void CMSWindowsSecondaryScreen::onOpenDisplay()
|
void CMSWindowsSecondaryScreen::onOpenDisplay()
|
||||||
|
@ -246,6 +306,10 @@ s_debugLog = ::GetDlgItem(s_debug, IDC_LOG);
|
||||||
CLog::setOutputter(&debugOutput);
|
CLog::setOutputter(&debugOutput);
|
||||||
ShowWindow(s_debug, SW_SHOWNORMAL);
|
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
|
// 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
|
// 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
|
// 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 |
|
m_window = CreateWindowEx(WS_EX_TOPMOST |
|
||||||
WS_EX_TRANSPARENT | WS_EX_TOOLWINDOW,
|
WS_EX_TRANSPARENT | WS_EX_TOOLWINDOW,
|
||||||
(LPCTSTR)getClass(), "Synergy",
|
(LPCTSTR)getClass(), "Synergy",
|
||||||
WS_POPUP | WS_DISABLED,
|
WS_POPUP,
|
||||||
0, 0, 1, 1, NULL, NULL,
|
0, 0, 1, 1, NULL, NULL,
|
||||||
getInstance(),
|
getInstance(),
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
// hide the cursor
|
// hide the cursor
|
||||||
leave();
|
leave();
|
||||||
|
|
||||||
|
// install our clipboard snooper
|
||||||
|
m_nextClipboardWindow = SetClipboardViewer(m_window);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMSWindowsSecondaryScreen::onCloseDisplay()
|
void CMSWindowsSecondaryScreen::onCloseDisplay()
|
||||||
{
|
{
|
||||||
assert(m_window != NULL);
|
assert(m_window != NULL);
|
||||||
|
|
||||||
|
// remove clipboard snooper
|
||||||
|
ChangeClipboardChain(m_window, m_nextClipboardWindow);
|
||||||
|
m_nextClipboardWindow = NULL;
|
||||||
|
|
||||||
// destroy window
|
// destroy window
|
||||||
DestroyWindow(m_window);
|
DestroyWindow(m_window);
|
||||||
m_window = NULL;
|
m_window = NULL;
|
||||||
|
@ -276,49 +347,56 @@ s_debug = NULL;
|
||||||
s_thread = 0;
|
s_thread = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CMSWindowsSecondaryScreen::onEvent(MSG* msg)
|
bool CMSWindowsSecondaryScreen::onPreTranslate(MSG* msg)
|
||||||
{
|
{
|
||||||
if (IsDialogMessage(s_debug, msg)) {
|
if (IsDialogMessage(s_debug, msg)) {
|
||||||
return true;
|
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
|
// FIXME -- handle display changes
|
||||||
case WM_PAINT:
|
case WM_PAINT:
|
||||||
ValidateRect(m_window, NULL);
|
ValidateRect(hwnd, NULL);
|
||||||
return true;
|
return 0;
|
||||||
|
|
||||||
case WM_MOUSEMOVE:
|
|
||||||
// mouse was moved. hide the hider window.
|
|
||||||
ShowWindow(m_window, SW_HIDE);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WM_ACTIVATEAPP:
|
case WM_ACTIVATEAPP:
|
||||||
if (msg->wParam == FALSE) {
|
if (wParam == FALSE) {
|
||||||
// some other app activated. hide the hider window.
|
// some other app activated. hide the hider window.
|
||||||
|
log((CLOG_INFO "show cursor"));
|
||||||
ShowWindow(m_window, SW_HIDE);
|
ShowWindow(m_window, SW_HIDE);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*
|
case WM_DRAWCLIPBOARD:
|
||||||
// FIXME -- handle screen resolution changes
|
log((CLOG_DEBUG "clipboard was taken"));
|
||||||
|
|
||||||
case SelectionClear:
|
// first pass it on
|
||||||
target->XXX(xevent.xselectionclear.);
|
SendMessage(m_nextClipboardWindow, msg, wParam, lParam);
|
||||||
break;
|
|
||||||
|
|
||||||
case SelectionNotify:
|
// now notify client that somebody changed the clipboard (unless
|
||||||
target->XXX(xevent.xselection.);
|
// we're now the owner, in which case it's because we took
|
||||||
break;
|
// ownership).
|
||||||
|
m_clipboardOwner = GetClipboardOwner();
|
||||||
|
if (m_clipboardOwner != m_window) {
|
||||||
|
m_client->onClipboardChanged();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
case SelectionRequest:
|
case WM_CHANGECBCHAIN:
|
||||||
target->XXX(xevent.xselectionrequest.);
|
if (m_nextClipboardWindow == (HWND)wParam)
|
||||||
break;
|
m_nextClipboardWindow = (HWND)lParam;
|
||||||
*/
|
else
|
||||||
|
SendMessage(m_nextClipboardWindow, msg, wParam, lParam);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
return DefWindowProc(hwnd, msg, wParam, lParam);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const UINT g_latin1[] =
|
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,
|
/* 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,
|
/* 0xd0 */ VK_F19, VK_F20, VK_F21, VK_F22, VK_F23, VK_F24, 0, 0,
|
||||||
/* 0xd8 */ 0, 0, 0, 0, 0, 0, 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,
|
/* 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,
|
/* 0xf0 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
/* 0xf8 */ 0, 0, 0, 0, 0, 0, 0, VK_DELETE
|
/* 0xf8 */ 0, 0, 0, 0, 0, 0, 0, VK_DELETE
|
||||||
};
|
};
|
||||||
|
|
|
@ -23,12 +23,16 @@ class CMSWindowsSecondaryScreen : public CMSWindowsScreen, public ISecondaryScre
|
||||||
virtual void mouseUp(ButtonID);
|
virtual void mouseUp(ButtonID);
|
||||||
virtual void mouseMove(SInt32 xAbsolute, SInt32 yAbsolute);
|
virtual void mouseMove(SInt32 xAbsolute, SInt32 yAbsolute);
|
||||||
virtual void mouseWheel(SInt32 delta);
|
virtual void mouseWheel(SInt32 delta);
|
||||||
|
virtual void setClipboard(const IClipboard*);
|
||||||
|
virtual void grabClipboard();
|
||||||
virtual void getSize(SInt32* width, SInt32* height) const;
|
virtual void getSize(SInt32* width, SInt32* height) const;
|
||||||
virtual SInt32 getJumpZoneSize() const;
|
virtual SInt32 getJumpZoneSize() const;
|
||||||
|
virtual void getClipboard(IClipboard*) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// CMSWindowsScreen overrides
|
// CMSWindowsScreen overrides
|
||||||
virtual bool onEvent(MSG*);
|
virtual bool onPreTranslate(MSG*);
|
||||||
|
virtual LRESULT onEvent(HWND, UINT, WPARAM, LPARAM);
|
||||||
virtual void onOpenDisplay();
|
virtual void onOpenDisplay();
|
||||||
virtual void onCloseDisplay();
|
virtual void onCloseDisplay();
|
||||||
|
|
||||||
|
@ -38,6 +42,8 @@ class CMSWindowsSecondaryScreen : public CMSWindowsScreen, public ISecondaryScre
|
||||||
private:
|
private:
|
||||||
CClient* m_client;
|
CClient* m_client;
|
||||||
HWND m_window;
|
HWND m_window;
|
||||||
|
HWND m_nextClipboardWindow;
|
||||||
|
HWND m_clipboardOwner;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -19,7 +19,7 @@ CXWindowsSecondaryScreen::CXWindowsSecondaryScreen() :
|
||||||
|
|
||||||
CXWindowsSecondaryScreen::~CXWindowsSecondaryScreen()
|
CXWindowsSecondaryScreen::~CXWindowsSecondaryScreen()
|
||||||
{
|
{
|
||||||
assert(m_window == None);
|
assert(m_window == None);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CXWindowsSecondaryScreen::run()
|
void CXWindowsSecondaryScreen::run()
|
||||||
|
@ -43,21 +43,46 @@ void CXWindowsSecondaryScreen::run()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
// FIXME -- handle screen resolution changes
|
|
||||||
|
|
||||||
case SelectionClear:
|
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;
|
break;
|
||||||
|
|
||||||
case SelectionNotify:
|
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;
|
break;
|
||||||
|
|
||||||
case SelectionRequest:
|
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;
|
break;
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -167,6 +192,19 @@ void CXWindowsSecondaryScreen::mouseWheel(SInt32)
|
||||||
// FIXME
|
// 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(
|
void CXWindowsSecondaryScreen::getSize(
|
||||||
SInt32* width, SInt32* height) const
|
SInt32* width, SInt32* height) const
|
||||||
{
|
{
|
||||||
|
@ -178,6 +216,13 @@ SInt32 CXWindowsSecondaryScreen::getJumpZoneSize() const
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CXWindowsSecondaryScreen::getClipboard(
|
||||||
|
IClipboard* clipboard) const
|
||||||
|
{
|
||||||
|
// FIXME -- don't use CurrentTime
|
||||||
|
getDisplayClipboard(clipboard, m_window, CurrentTime);
|
||||||
|
}
|
||||||
|
|
||||||
void CXWindowsSecondaryScreen::onOpenDisplay()
|
void CXWindowsSecondaryScreen::onOpenDisplay()
|
||||||
{
|
{
|
||||||
assert(m_window == None);
|
assert(m_window == None);
|
||||||
|
|
|
@ -23,8 +23,11 @@ class CXWindowsSecondaryScreen : public CXWindowsScreen, public ISecondaryScreen
|
||||||
virtual void mouseUp(ButtonID);
|
virtual void mouseUp(ButtonID);
|
||||||
virtual void mouseMove(SInt32 xAbsolute, SInt32 yAbsolute);
|
virtual void mouseMove(SInt32 xAbsolute, SInt32 yAbsolute);
|
||||||
virtual void mouseWheel(SInt32 delta);
|
virtual void mouseWheel(SInt32 delta);
|
||||||
|
virtual void setClipboard(const IClipboard*);
|
||||||
|
virtual void grabClipboard();
|
||||||
virtual void getSize(SInt32* width, SInt32* height) const;
|
virtual void getSize(SInt32* width, SInt32* height) const;
|
||||||
virtual SInt32 getJumpZoneSize() const;
|
virtual SInt32 getJumpZoneSize() const;
|
||||||
|
virtual void getClipboard(IClipboard*) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// CXWindowsScreen overrides
|
// CXWindowsScreen overrides
|
||||||
|
|
|
@ -41,7 +41,7 @@ int WINAPI WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
realMain("ingrid", __argv[1], 50001);
|
realMain("secondary", __argv[1], 50001);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
catch (XBase& e) {
|
catch (XBase& e) {
|
||||||
|
@ -64,7 +64,7 @@ int main(int argc, char** argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
realMain("ingrid", argv[1], 50001);
|
realMain("secondary", argv[1], 50001);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
catch (XBase& e) {
|
catch (XBase& e) {
|
||||||
|
|
|
@ -38,7 +38,7 @@ RSC=rc.exe
|
||||||
# PROP BASE Target_Dir ""
|
# PROP BASE Target_Dir ""
|
||||||
# PROP Use_MFC 0
|
# PROP Use_MFC 0
|
||||||
# PROP Use_Debug_Libraries 0
|
# PROP Use_Debug_Libraries 0
|
||||||
# PROP Output_Dir "Release"
|
# PROP Output_Dir "../Release"
|
||||||
# PROP Intermediate_Dir "Release"
|
# PROP Intermediate_Dir "Release"
|
||||||
# PROP Target_Dir ""
|
# PROP Target_Dir ""
|
||||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
|
# 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 BASE Target_Dir ""
|
||||||
# PROP Use_MFC 0
|
# PROP Use_MFC 0
|
||||||
# PROP Use_Debug_Libraries 1
|
# PROP Use_Debug_Libraries 1
|
||||||
# PROP Output_Dir "Debug"
|
# PROP Output_Dir "../Debug"
|
||||||
# PROP Intermediate_Dir "Debug"
|
# PROP Intermediate_Dir "Debug"
|
||||||
# PROP Target_Dir ""
|
# PROP Target_Dir ""
|
||||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
|
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
|
||||||
|
|
|
@ -44,6 +44,7 @@ int (PASCAL FAR *CNetwork::gethosterror)(void);
|
||||||
|
|
||||||
#if defined(CONFIG_PLATFORM_WIN32)
|
#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::WSACleanup)(void);
|
||||||
int (PASCAL FAR *CNetwork::__WSAFDIsSet)(CNetwork::Socket, fd_set FAR *);
|
int (PASCAL FAR *CNetwork::__WSAFDIsSet)(CNetwork::Socket, fd_set FAR *);
|
||||||
const int CNetwork::Error = SOCKET_ERROR;
|
const int CNetwork::Error = SOCKET_ERROR;
|
||||||
|
@ -220,6 +221,7 @@ int PASCAL FAR CNetwork::poll2(PollEntry fd[], int nfds, int timeout)
|
||||||
return Error;
|
return Error;
|
||||||
if (n == 0)
|
if (n == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
n = 0;
|
||||||
for (i = 0; i < nfds; ++i) {
|
for (i = 0; i < nfds; ++i) {
|
||||||
fd[i].revents = 0;
|
fd[i].revents = 0;
|
||||||
if (FD_ISSET(fd[i].fd, &readSet))
|
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;
|
fd[i].revents |= kPOLLOUT;
|
||||||
if (FD_ISSET(fd[i].fd, &errSet))
|
if (FD_ISSET(fd[i].fd, &errSet))
|
||||||
fd[i].revents |= kPOLLERR;
|
fd[i].revents |= kPOLLERR;
|
||||||
|
if (fd[i].revents != 0)
|
||||||
|
++n;
|
||||||
}
|
}
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
11
notes
11
notes
|
@ -87,11 +87,12 @@ win32:
|
||||||
handle display changes
|
handle display changes
|
||||||
|
|
||||||
---
|
---
|
||||||
win32 key translation (client)
|
not sending VK_?WIN and VK_APPS. possibly hotkeys being stolen.
|
||||||
get character for key (with appropriate shift)
|
|
||||||
keypad enter -> VK_???
|
VkKeyScan() doesn't get proper shift state unless we map shift
|
||||||
sys req -> VK_???
|
(etc?) to VK_SHIFT not VK_LSHIFT or VK_RSHIFT.
|
||||||
compose -> VK_???
|
|
||||||
|
not handling international characters
|
||||||
|
|
||||||
X11 key translation (server)
|
X11 key translation (server)
|
||||||
handle compose key?
|
handle compose key?
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#include "CMSWindowsPrimaryScreen.h"
|
#include "CMSWindowsPrimaryScreen.h"
|
||||||
|
#include "CMSWindowsClipboard.h"
|
||||||
#include "CServer.h"
|
#include "CServer.h"
|
||||||
#include "CSynergyHook.h"
|
#include "CSynergyHook.h"
|
||||||
|
#include "XSynergy.h"
|
||||||
#include "CThread.h"
|
#include "CThread.h"
|
||||||
#include "CLog.h"
|
#include "CLog.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
@ -13,6 +15,8 @@ CMSWindowsPrimaryScreen::CMSWindowsPrimaryScreen() :
|
||||||
m_server(NULL),
|
m_server(NULL),
|
||||||
m_active(false),
|
m_active(false),
|
||||||
m_window(NULL),
|
m_window(NULL),
|
||||||
|
m_nextClipboardWindow(NULL),
|
||||||
|
m_clipboardOwner(NULL),
|
||||||
m_hookLibrary(NULL),
|
m_hookLibrary(NULL),
|
||||||
m_mark(0),
|
m_mark(0),
|
||||||
m_markReceived(0)
|
m_markReceived(0)
|
||||||
|
@ -26,6 +30,8 @@ CMSWindowsPrimaryScreen::~CMSWindowsPrimaryScreen()
|
||||||
assert(m_hookLibrary == NULL);
|
assert(m_hookLibrary == NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static CString s_log;
|
||||||
|
static CString s_logMore;
|
||||||
static HWND s_debug = NULL;
|
static HWND s_debug = NULL;
|
||||||
static HWND s_debugLog = NULL;
|
static HWND s_debugLog = NULL;
|
||||||
static DWORD s_thread = 0;
|
static DWORD s_thread = 0;
|
||||||
|
@ -38,28 +44,26 @@ static BOOL CALLBACK WINAPI debugProc(HWND, UINT msg, WPARAM wParam, LPARAM lPar
|
||||||
case WM_CLOSE:
|
case WM_CLOSE:
|
||||||
PostQuitMessage(0);
|
PostQuitMessage(0);
|
||||||
return TRUE;
|
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;
|
return FALSE;
|
||||||
}
|
}
|
||||||
static void debugOutput(const char* msg)
|
static void debugOutput(const char* msg)
|
||||||
{
|
{
|
||||||
if (s_thread != 0) {
|
s_logMore += msg;
|
||||||
const DWORD threadID = ::GetCurrentThreadId();
|
PostMessage(s_debug, WM_APP, 0, 0);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMSWindowsPrimaryScreen::run()
|
void CMSWindowsPrimaryScreen::run()
|
||||||
|
@ -114,6 +118,13 @@ void CMSWindowsPrimaryScreen::enter(SInt32 x, SInt32 y)
|
||||||
|
|
||||||
void CMSWindowsPrimaryScreen::doEnter()
|
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
|
// set the zones that should cause a jump
|
||||||
SInt32 w, h;
|
SInt32 w, h;
|
||||||
getScreenSize(&w, &h);
|
getScreenSize(&w, &h);
|
||||||
|
@ -136,6 +147,16 @@ void CMSWindowsPrimaryScreen::leave()
|
||||||
// all messages prior to now are invalid
|
// all messages prior to now are invalid
|
||||||
nextMark();
|
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
|
// relay all mouse and keyboard events
|
||||||
SetRelayFunc setRelay = (SetRelayFunc)GetProcAddress(
|
SetRelayFunc setRelay = (SetRelayFunc)GetProcAddress(
|
||||||
m_hookLibrary, "setRelay");
|
m_hookLibrary, "setRelay");
|
||||||
|
@ -151,6 +172,30 @@ void CMSWindowsPrimaryScreen::leave()
|
||||||
|
|
||||||
// local client now active
|
// local client now active
|
||||||
m_active = true;
|
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)
|
void CMSWindowsPrimaryScreen::warpCursor(SInt32 x, SInt32 y)
|
||||||
|
@ -164,18 +209,22 @@ void CMSWindowsPrimaryScreen::warpCursor(SInt32 x, SInt32 y)
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMSWindowsPrimaryScreen::setClipboard(
|
void CMSWindowsPrimaryScreen::setClipboard(
|
||||||
const IClipboard* /*clipboard*/)
|
const IClipboard* src)
|
||||||
{
|
{
|
||||||
assert(m_window != NULL);
|
assert(m_window != NULL);
|
||||||
|
|
||||||
// FIXME -- should we retry until we get it?
|
CMSWindowsClipboard dst(m_window);
|
||||||
if (!OpenClipboard(m_window))
|
CClipboard::copy(&dst, src);
|
||||||
return;
|
}
|
||||||
if (EmptyClipboard()) {
|
|
||||||
log((CLOG_DEBUG "grabbed clipboard"));
|
void CMSWindowsPrimaryScreen::grabClipboard()
|
||||||
// FIXME -- set the clipboard data
|
{
|
||||||
|
assert(m_window != NULL);
|
||||||
|
|
||||||
|
CMSWindowsClipboard clipboard(m_window);
|
||||||
|
if (clipboard.open()) {
|
||||||
|
clipboard.close();
|
||||||
}
|
}
|
||||||
CloseClipboard();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMSWindowsPrimaryScreen::getSize(
|
void CMSWindowsPrimaryScreen::getSize(
|
||||||
|
@ -190,11 +239,12 @@ SInt32 CMSWindowsPrimaryScreen::getJumpZoneSize() const
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMSWindowsPrimaryScreen::getClipboard(
|
void CMSWindowsPrimaryScreen::getClipboard(
|
||||||
IClipboard* clipboard) const
|
IClipboard* dst) const
|
||||||
{
|
{
|
||||||
// FIXME -- put this in superclass?
|
assert(m_window != NULL);
|
||||||
// FIXME -- don't use CurrentTime
|
|
||||||
// getDisplayClipboard(clipboard, m_window, CurrentTime);
|
CMSWindowsClipboard src(m_window);
|
||||||
|
CClipboard::copy(dst, &src);
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "resource.h" // FIXME
|
#include "resource.h" // FIXME
|
||||||
|
@ -211,6 +261,10 @@ s_debugLog = ::GetDlgItem(s_debug, IDC_LOG);
|
||||||
CLog::setOutputter(&debugOutput);
|
CLog::setOutputter(&debugOutput);
|
||||||
ShowWindow(s_debug, SW_SHOWNORMAL);
|
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
|
// create the window
|
||||||
m_window = CreateWindowEx(WS_EX_TOPMOST |
|
m_window = CreateWindowEx(WS_EX_TOPMOST |
|
||||||
WS_EX_TRANSPARENT | WS_EX_TOOLWINDOW,
|
WS_EX_TRANSPARENT | WS_EX_TOOLWINDOW,
|
||||||
|
@ -219,6 +273,10 @@ ShowWindow(s_debug, SW_SHOWNORMAL);
|
||||||
0, 0, 1, 1, NULL, NULL,
|
0, 0, 1, 1, NULL, NULL,
|
||||||
getInstance(),
|
getInstance(),
|
||||||
NULL);
|
NULL);
|
||||||
|
assert(m_window != NULL);
|
||||||
|
|
||||||
|
// install our clipboard snooper
|
||||||
|
m_nextClipboardWindow = SetClipboardViewer(m_window);
|
||||||
|
|
||||||
// load the hook library
|
// load the hook library
|
||||||
bool hooked = false;
|
bool hooked = false;
|
||||||
|
@ -232,6 +290,8 @@ ShowWindow(s_debug, SW_SHOWNORMAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!hooked) {
|
if (!hooked) {
|
||||||
|
ChangeClipboardChain(m_window, m_nextClipboardWindow);
|
||||||
|
m_nextClipboardWindow = NULL;
|
||||||
DestroyWindow(m_window);
|
DestroyWindow(m_window);
|
||||||
m_window = NULL;
|
m_window = NULL;
|
||||||
// FIXME -- throw
|
// FIXME -- throw
|
||||||
|
@ -258,6 +318,10 @@ void CMSWindowsPrimaryScreen::onCloseDisplay()
|
||||||
FreeLibrary(m_hookLibrary);
|
FreeLibrary(m_hookLibrary);
|
||||||
m_hookLibrary = NULL;
|
m_hookLibrary = NULL;
|
||||||
|
|
||||||
|
// remove clipboard snooper
|
||||||
|
ChangeClipboardChain(m_window, m_nextClipboardWindow);
|
||||||
|
m_nextClipboardWindow = NULL;
|
||||||
|
|
||||||
// destroy window
|
// destroy window
|
||||||
DestroyWindow(m_window);
|
DestroyWindow(m_window);
|
||||||
m_window = NULL;
|
m_window = NULL;
|
||||||
|
@ -268,7 +332,7 @@ s_debug = NULL;
|
||||||
s_thread = 0;
|
s_thread = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CMSWindowsPrimaryScreen::onEvent(MSG* msg)
|
bool CMSWindowsPrimaryScreen::onPreTranslate(MSG* msg)
|
||||||
{
|
{
|
||||||
if (IsDialogMessage(s_debug, msg)) {
|
if (IsDialogMessage(s_debug, msg)) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -276,11 +340,6 @@ if (IsDialogMessage(s_debug, msg)) {
|
||||||
|
|
||||||
// handle event
|
// handle event
|
||||||
switch (msg->message) {
|
switch (msg->message) {
|
||||||
// FIXME -- handle display changes
|
|
||||||
case WM_PAINT:
|
|
||||||
ValidateRect(m_window, NULL);
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case SYNERGY_MSG_MARK:
|
case SYNERGY_MSG_MARK:
|
||||||
m_markReceived = msg->wParam;
|
m_markReceived = msg->wParam;
|
||||||
return true;
|
return true;
|
||||||
|
@ -288,7 +347,29 @@ if (IsDialogMessage(s_debug, msg)) {
|
||||||
case SYNERGY_MSG_KEY:
|
case SYNERGY_MSG_KEY:
|
||||||
// ignore if not at current mark
|
// ignore if not at current mark
|
||||||
if (m_mark == m_markReceived) {
|
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;
|
return true;
|
||||||
|
|
||||||
|
@ -357,74 +438,46 @@ if (IsDialogMessage(s_debug, msg)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
/*
|
}
|
||||||
case WM_MOUSEMOVE: {
|
|
||||||
if (!m_active) {
|
LRESULT CMSWindowsPrimaryScreen::onEvent(
|
||||||
// mouse entered a jump zone window
|
HWND hwnd, UINT msg,
|
||||||
POINT p;
|
WPARAM wParam, LPARAM lParam)
|
||||||
p.x = (short)LOWORD(msg.lParam);
|
{
|
||||||
p.y = (short)HIWORD(msg.lParam);
|
switch (msg) {
|
||||||
ClientToScreen(msg.hwnd, &p);
|
// FIXME -- handle display changes
|
||||||
log((CLOG_DEBUG "event: WM_MOUSEMOVE %d,%d", p.x, p.y));
|
case WM_PAINT:
|
||||||
m_server->onMouseMovePrimary((SInt32)p.x, (SInt32)p.y);
|
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;
|
catch (XBadClient&) {
|
||||||
}
|
// ignore. this can happen if we receive this event
|
||||||
|
// before we've fully started up.
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
break;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME -- simulate key repeat. X sends press/release for
|
case WM_CHANGECBCHAIN:
|
||||||
// repeat. must detect auto repeat and use kKeyRepeat.
|
if (m_nextClipboardWindow == (HWND)wParam)
|
||||||
case KeyRelease: {
|
m_nextClipboardWindow = (HWND)lParam;
|
||||||
log((CLOG_DEBUG "event: KeyRelease code=%d, state=0x%04x", xevent.xkey.keycode, xevent.xkey.state));
|
else
|
||||||
const KeyModifierMask mask = mapModifier(xevent.xkey.state);
|
SendMessage(m_nextClipboardWindow, msg, wParam, lParam);
|
||||||
const KeyID key = mapKey(xevent.xkey.keycode, mask);
|
return 0;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
return DefWindowProc(hwnd, msg, wParam, lParam);
|
return DefWindowProc(hwnd, msg, wParam, lParam);
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMSWindowsPrimaryScreen::nextMark()
|
void CMSWindowsPrimaryScreen::nextMark()
|
||||||
|
@ -434,34 +487,274 @@ void CMSWindowsPrimaryScreen::nextMark()
|
||||||
PostMessage(m_window, SYNERGY_MSG_MARK, ++m_mark, 0);
|
PostMessage(m_window, SYNERGY_MSG_MARK, ++m_mark, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
static const KeyID g_virtualKey[] =
|
||||||
bool CMSWindowsPrimaryScreen::keyboardHook(
|
|
||||||
int /*code*/, WPARAM wParam, LPARAM lParam)
|
|
||||||
{
|
{
|
||||||
if (m_active) {
|
/* 0x00 */ kKeyNone, // reserved
|
||||||
// handle keyboard events
|
/* 0x01 */ kKeyNone, // VK_LBUTTON
|
||||||
const KeyID key = mapKey(wParam, lParam);
|
/* 0x02 */ kKeyNone, // VK_RBUTTON
|
||||||
if (key != kKeyNone) {
|
/* 0x03 */ 0xff6b, // VK_CANCEL XK_Break
|
||||||
const KeyModifierMask modifiers = mapModifier(wParam, lParam);
|
/* 0x04 */ kKeyNone, // VK_MBUTTON
|
||||||
if ((lParam & KF_UP) == 0) {
|
/* 0x05 */ kKeyNone, // undefined
|
||||||
log((CLOG_DEBUG "event: key press key=%d", key));
|
/* 0x06 */ kKeyNone, // undefined
|
||||||
m_server->onKeyDown(key, modifiers);
|
/* 0x07 */ kKeyNone, // undefined
|
||||||
}
|
/* 0x08 */ 0xff08, // VK_BACK XK_Backspace
|
||||||
else {
|
/* 0x09 */ 0xff09, // VK_TAB VK_Tab
|
||||||
log((CLOG_DEBUG "event: key release key=%d", key));
|
/* 0x0a */ kKeyNone, // undefined
|
||||||
m_server->onKeyUp(key, modifiers);
|
/* 0x0b */ kKeyNone, // undefined
|
||||||
}
|
/* 0x0c */ 0xff0b, // VK_CLEAR XK_Clear
|
||||||
return true;
|
/* 0x0d */ 0xff0d, // VK_RETURN XK_Return
|
||||||
}
|
/* 0x0e */ kKeyNone, // undefined
|
||||||
}
|
/* 0x0f */ kKeyNone, // undefined
|
||||||
return false;
|
/* 0x10 */ 0xffe1, // VK_SHIFT XK_Shift_L
|
||||||
}
|
/* 0x11 */ 0xffe3, // VK_CONTROL XK_Control_L
|
||||||
#endif
|
/* 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(
|
KeyID CMSWindowsPrimaryScreen::mapKey(
|
||||||
WPARAM keycode, LPARAM info) const
|
WPARAM vkCode, LPARAM info,
|
||||||
|
KeyModifierMask* maskOut) const
|
||||||
{
|
{
|
||||||
// FIXME -- should be configurable
|
assert(maskOut != NULL);
|
||||||
|
|
||||||
|
// map modifier key
|
||||||
|
// FIXME -- should be configurable?
|
||||||
KeyModifierMask mask = 0;
|
KeyModifierMask mask = 0;
|
||||||
if (GetKeyState(VK_SHIFT) < 0)
|
if (GetKeyState(VK_SHIFT) < 0)
|
||||||
mask |= KeyModifierShift;
|
mask |= KeyModifierShift;
|
||||||
|
@ -477,14 +770,48 @@ KeyModifierMask CMSWindowsPrimaryScreen::mapModifier(
|
||||||
mask |= KeyModifierMeta;
|
mask |= KeyModifierMeta;
|
||||||
if ((GetKeyState(VK_SCROLL) & 1) != 0)
|
if ((GetKeyState(VK_SCROLL) & 1) != 0)
|
||||||
mask |= KeyModifierScrollLock;
|
mask |= KeyModifierScrollLock;
|
||||||
return mask;
|
*maskOut = mask;
|
||||||
}
|
|
||||||
|
|
||||||
KeyID CMSWindowsPrimaryScreen::mapKey(
|
KeyID id = g_virtualKey[vkCode];
|
||||||
WPARAM keycode, LPARAM info) const
|
if (id != kKeyNone) {
|
||||||
{
|
return id;
|
||||||
// FIXME -- must convert to X keysyms
|
}
|
||||||
return keycode;
|
|
||||||
|
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(
|
ButtonID CMSWindowsPrimaryScreen::mapButton(
|
||||||
|
|
|
@ -22,13 +22,15 @@ class CMSWindowsPrimaryScreen : public CMSWindowsScreen, public IPrimaryScreen {
|
||||||
virtual void leave();
|
virtual void leave();
|
||||||
virtual void warpCursor(SInt32 xAbsolute, SInt32 yAbsolute);
|
virtual void warpCursor(SInt32 xAbsolute, SInt32 yAbsolute);
|
||||||
virtual void setClipboard(const IClipboard*);
|
virtual void setClipboard(const IClipboard*);
|
||||||
|
virtual void grabClipboard();
|
||||||
virtual void getSize(SInt32* width, SInt32* height) const;
|
virtual void getSize(SInt32* width, SInt32* height) const;
|
||||||
virtual SInt32 getJumpZoneSize() const;
|
virtual SInt32 getJumpZoneSize() const;
|
||||||
virtual void getClipboard(IClipboard*) const;
|
virtual void getClipboard(IClipboard*) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// CMSWindowsScreen overrides
|
// CMSWindowsScreen overrides
|
||||||
virtual bool onEvent(MSG*);
|
virtual bool onPreTranslate(MSG*);
|
||||||
|
virtual LRESULT onEvent(HWND, UINT, WPARAM, LPARAM);
|
||||||
virtual void onOpenDisplay();
|
virtual void onOpenDisplay();
|
||||||
virtual void onCloseDisplay();
|
virtual void onCloseDisplay();
|
||||||
|
|
||||||
|
@ -37,17 +39,17 @@ class CMSWindowsPrimaryScreen : public CMSWindowsScreen, public IPrimaryScreen {
|
||||||
|
|
||||||
void nextMark();
|
void nextMark();
|
||||||
|
|
||||||
// bool keyboardHook(int, WPARAM, LPARAM);
|
KeyID mapKey(WPARAM keycode, LPARAM info,
|
||||||
// bool mouseHook(int, WPARAM, LPARAM);
|
KeyModifierMask* maskOut) const;
|
||||||
|
|
||||||
KeyModifierMask mapModifier(WPARAM keycode, LPARAM info) const;
|
|
||||||
KeyID mapKey(WPARAM keycode, LPARAM info) const;
|
|
||||||
ButtonID mapButton(WPARAM button) const;
|
ButtonID mapButton(WPARAM button) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CServer* m_server;
|
CServer* m_server;
|
||||||
bool m_active;
|
bool m_active;
|
||||||
HWND m_window;
|
HWND m_window;
|
||||||
|
HWND m_nextClipboardWindow;
|
||||||
|
HWND m_clipboardOwner;
|
||||||
|
HWND m_lastActive;
|
||||||
HINSTANCE m_hookLibrary;
|
HINSTANCE m_hookLibrary;
|
||||||
UInt32 m_mark;
|
UInt32 m_mark;
|
||||||
UInt32 m_markReceived;
|
UInt32 m_markReceived;
|
||||||
|
|
|
@ -43,7 +43,9 @@ else { wait(0); exit(1); }
|
||||||
|
|
||||||
CServer::CServer() : m_primary(NULL),
|
CServer::CServer() : m_primary(NULL),
|
||||||
m_active(NULL),
|
m_active(NULL),
|
||||||
m_primaryInfo(NULL)
|
m_primaryInfo(NULL),
|
||||||
|
m_clipboardSeqNum(0),
|
||||||
|
m_clipboardReady(false)
|
||||||
{
|
{
|
||||||
m_socketFactory = NULL;
|
m_socketFactory = NULL;
|
||||||
m_securityFactory = NULL;
|
m_securityFactory = NULL;
|
||||||
|
@ -78,7 +80,7 @@ void CServer::run()
|
||||||
closePrimaryScreen();
|
closePrimaryScreen();
|
||||||
}
|
}
|
||||||
catch (XBase& e) {
|
catch (XBase& e) {
|
||||||
log((CLOG_ERR "server error: %s\n", e.what()));
|
log((CLOG_ERR "server error: %s", e.what()));
|
||||||
|
|
||||||
// clean up
|
// clean up
|
||||||
cleanupThreads();
|
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));
|
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*/,
|
bool CServer::onCommandKey(KeyID /*id*/,
|
||||||
KeyModifierMask /*mask*/, bool /*down*/)
|
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);
|
assert(m_active != NULL);
|
||||||
|
|
||||||
// handle command keys
|
// handle command keys
|
||||||
|
@ -199,7 +289,7 @@ void CServer::onKeyRepeat(KeyID id, KeyModifierMask mask)
|
||||||
|
|
||||||
// relay
|
// relay
|
||||||
if (m_active->m_protocol != NULL) {
|
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;
|
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,
|
void CServer::switchScreen(CScreenInfo* dst,
|
||||||
SInt32 x, SInt32 y)
|
SInt32 x, SInt32 y)
|
||||||
{
|
{
|
||||||
|
@ -398,6 +483,7 @@ void CServer::switchScreen(CScreenInfo* dst,
|
||||||
assert(m_active != NULL);
|
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));
|
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.
|
// wrapping means leaving the active screen and entering it again.
|
||||||
// since that's a waste of time we skip that and just warp the
|
// 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
|
// leave active screen
|
||||||
if (m_active->m_protocol == NULL) {
|
if (m_active->m_protocol == NULL) {
|
||||||
m_primary->leave();
|
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 {
|
else {
|
||||||
m_active->m_protocol->sendLeave();
|
m_active->m_protocol->sendLeave();
|
||||||
|
@ -429,6 +507,17 @@ void CServer::switchScreen(CScreenInfo* dst,
|
||||||
else {
|
else {
|
||||||
m_active->m_protocol->sendEnter(x, y);
|
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 {
|
else {
|
||||||
if (m_active->m_protocol == NULL) {
|
if (m_active->m_protocol == NULL) {
|
||||||
|
@ -827,6 +916,13 @@ void CServer::openPrimaryScreen()
|
||||||
m_active->m_zoneSize = m_primary->getJumpZoneSize();
|
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));
|
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
|
// 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()
|
void CServer::closePrimaryScreen()
|
||||||
|
@ -979,7 +1075,8 @@ CServer::CScreenInfo::CScreenInfo(const CString& name,
|
||||||
m_name(name),
|
m_name(name),
|
||||||
m_protocol(protocol),
|
m_protocol(protocol),
|
||||||
m_width(0), m_height(0),
|
m_width(0), m_height(0),
|
||||||
m_zoneSize(0)
|
m_zoneSize(0),
|
||||||
|
m_gotClipboard(false)
|
||||||
{
|
{
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "KeyTypes.h"
|
#include "KeyTypes.h"
|
||||||
#include "MouseTypes.h"
|
#include "MouseTypes.h"
|
||||||
#include "CScreenMap.h"
|
#include "CScreenMap.h"
|
||||||
|
#include "CClipboard.h"
|
||||||
#include "CMutex.h"
|
#include "CMutex.h"
|
||||||
#include "CString.h"
|
#include "CString.h"
|
||||||
#include "XBase.h"
|
#include "XBase.h"
|
||||||
|
@ -36,16 +37,19 @@ class CServer {
|
||||||
// true iff the mouse enters a jump zone and jumps.
|
// true iff the mouse enters a jump zone and jumps.
|
||||||
void onKeyDown(KeyID, KeyModifierMask);
|
void onKeyDown(KeyID, KeyModifierMask);
|
||||||
void onKeyUp(KeyID, KeyModifierMask);
|
void onKeyUp(KeyID, KeyModifierMask);
|
||||||
void onKeyRepeat(KeyID, KeyModifierMask);
|
void onKeyRepeat(KeyID, KeyModifierMask, SInt32 count);
|
||||||
void onMouseDown(ButtonID);
|
void onMouseDown(ButtonID);
|
||||||
void onMouseUp(ButtonID);
|
void onMouseUp(ButtonID);
|
||||||
bool onMouseMovePrimary(SInt32 x, SInt32 y);
|
bool onMouseMovePrimary(SInt32 x, SInt32 y);
|
||||||
void onMouseMoveSecondary(SInt32 dx, SInt32 dy);
|
void onMouseMoveSecondary(SInt32 dx, SInt32 dy);
|
||||||
void onMouseWheel(SInt32 delta);
|
void onMouseWheel(SInt32 delta);
|
||||||
|
void grabClipboard();
|
||||||
|
|
||||||
// handle messages from clients
|
// handle messages from clients
|
||||||
void setInfo(const CString& clientName,
|
void setInfo(const CString& clientName,
|
||||||
SInt32 w, SInt32 h, SInt32 zoneSize);
|
SInt32 w, SInt32 h, SInt32 zoneSize);
|
||||||
|
void grabClipboard(const CString& clientName);
|
||||||
|
void setClipboard(UInt32 seqNum, const CString& data);
|
||||||
|
|
||||||
// accessors
|
// accessors
|
||||||
|
|
||||||
|
@ -91,6 +95,7 @@ class CServer {
|
||||||
IServerProtocol* m_protocol;
|
IServerProtocol* m_protocol;
|
||||||
SInt32 m_width, m_height;
|
SInt32 m_width, m_height;
|
||||||
SInt32 m_zoneSize;
|
SInt32 m_zoneSize;
|
||||||
|
bool m_gotClipboard;
|
||||||
};
|
};
|
||||||
|
|
||||||
// change the active screen
|
// change the active screen
|
||||||
|
@ -159,6 +164,12 @@ class CServer {
|
||||||
SInt32 m_x, m_y;
|
SInt32 m_x, m_y;
|
||||||
|
|
||||||
CScreenMap m_screenMap;
|
CScreenMap m_screenMap;
|
||||||
|
|
||||||
|
CClipboard m_clipboard;
|
||||||
|
CString m_clipboardData;
|
||||||
|
CString m_clipboardOwner;
|
||||||
|
UInt32 m_clipboardSeqNum;
|
||||||
|
bool m_clipboardReady;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -33,11 +33,12 @@ class CServerProtocol : public IServerProtocol {
|
||||||
virtual void sendClose() = 0;
|
virtual void sendClose() = 0;
|
||||||
virtual void sendEnter(SInt32 xAbs, SInt32 yAbs) = 0;
|
virtual void sendEnter(SInt32 xAbs, SInt32 yAbs) = 0;
|
||||||
virtual void sendLeave() = 0;
|
virtual void sendLeave() = 0;
|
||||||
|
virtual void sendClipboard(const CString&) = 0;
|
||||||
virtual void sendGrabClipboard() = 0;
|
virtual void sendGrabClipboard() = 0;
|
||||||
virtual void sendQueryClipboard() = 0;
|
virtual void sendQueryClipboard(UInt32 seqNum) = 0;
|
||||||
virtual void sendScreenSaver(bool on) = 0;
|
virtual void sendScreenSaver(bool on) = 0;
|
||||||
virtual void sendKeyDown(KeyID, KeyModifierMask) = 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 sendKeyUp(KeyID, KeyModifierMask) = 0;
|
||||||
virtual void sendMouseDown(ButtonID) = 0;
|
virtual void sendMouseDown(ButtonID) = 0;
|
||||||
virtual void sendMouseUp(ButtonID) = 0;
|
virtual void sendMouseUp(ButtonID) = 0;
|
||||||
|
@ -47,6 +48,8 @@ class CServerProtocol : public IServerProtocol {
|
||||||
protected:
|
protected:
|
||||||
//IServerProtocol overrides
|
//IServerProtocol overrides
|
||||||
virtual void recvInfo() = 0;
|
virtual void recvInfo() = 0;
|
||||||
|
virtual void recvClipboard() = 0;
|
||||||
|
virtual void recvGrabClipboard() = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CServer* m_server;
|
CServer* m_server;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "CServerProtocol1_0.h"
|
#include "CServerProtocol1_0.h"
|
||||||
#include "CServer.h"
|
#include "CServer.h"
|
||||||
|
#include "CClipboard.h"
|
||||||
#include "CProtocolUtil.h"
|
#include "CProtocolUtil.h"
|
||||||
#include "ProtocolTypes.h"
|
#include "ProtocolTypes.h"
|
||||||
#include "IInputStream.h"
|
#include "IInputStream.h"
|
||||||
|
@ -49,6 +50,12 @@ void CServerProtocol1_0::run()
|
||||||
if (memcmp(code, kMsgDInfo, 4) == 0) {
|
if (memcmp(code, kMsgDInfo, 4) == 0) {
|
||||||
recvInfo();
|
recvInfo();
|
||||||
}
|
}
|
||||||
|
else if (memcmp(code, kMsgCClipboard, 4) == 0) {
|
||||||
|
recvGrabClipboard();
|
||||||
|
}
|
||||||
|
else if (memcmp(code, kMsgDClipboard, 4) == 0) {
|
||||||
|
recvClipboard();
|
||||||
|
}
|
||||||
// FIXME -- more message here
|
// FIXME -- more message here
|
||||||
else {
|
else {
|
||||||
log((CLOG_ERR "unknown message from client \"%s\"", getClient().c_str()));
|
log((CLOG_ERR "unknown message from client \"%s\"", getClient().c_str()));
|
||||||
|
@ -96,16 +103,22 @@ void CServerProtocol1_0::sendLeave()
|
||||||
CProtocolUtil::writef(getOutputStream(), kMsgCLeave);
|
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()
|
void CServerProtocol1_0::sendGrabClipboard()
|
||||||
{
|
{
|
||||||
log((CLOG_INFO "send grab clipboard to \"%s\"", getClient().c_str()));
|
log((CLOG_INFO "send grab clipboard to \"%s\"", getClient().c_str()));
|
||||||
CProtocolUtil::writef(getOutputStream(), kMsgCClipboard);
|
CProtocolUtil::writef(getOutputStream(), kMsgCClipboard);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CServerProtocol1_0::sendQueryClipboard()
|
void CServerProtocol1_0::sendQueryClipboard(UInt32 seqNum)
|
||||||
{
|
{
|
||||||
log((CLOG_INFO "query clipboard to \"%s\"", getClient().c_str()));
|
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)
|
void CServerProtocol1_0::sendScreenSaver(bool on)
|
||||||
|
@ -122,10 +135,10 @@ void CServerProtocol1_0::sendKeyDown(
|
||||||
}
|
}
|
||||||
|
|
||||||
void CServerProtocol1_0::sendKeyRepeat(
|
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));
|
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(
|
void CServerProtocol1_0::sendKeyUp(
|
||||||
|
@ -179,3 +192,17 @@ void CServerProtocol1_0::recvInfo()
|
||||||
getServer()->setInfo(getClient(), w, h, zoneInfo);
|
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());
|
||||||
|
}
|
||||||
|
|
|
@ -18,11 +18,12 @@ class CServerProtocol1_0 : public CServerProtocol {
|
||||||
virtual void sendClose();
|
virtual void sendClose();
|
||||||
virtual void sendEnter(SInt32 xAbs, SInt32 yAbs);
|
virtual void sendEnter(SInt32 xAbs, SInt32 yAbs);
|
||||||
virtual void sendLeave();
|
virtual void sendLeave();
|
||||||
|
virtual void sendClipboard(const CString&);
|
||||||
virtual void sendGrabClipboard();
|
virtual void sendGrabClipboard();
|
||||||
virtual void sendQueryClipboard();
|
virtual void sendQueryClipboard(UInt32 seqNum);
|
||||||
virtual void sendScreenSaver(bool on);
|
virtual void sendScreenSaver(bool on);
|
||||||
virtual void sendKeyDown(KeyID, KeyModifierMask);
|
virtual void sendKeyDown(KeyID, KeyModifierMask);
|
||||||
virtual void sendKeyRepeat(KeyID, KeyModifierMask);
|
virtual void sendKeyRepeat(KeyID, KeyModifierMask, SInt32 count);
|
||||||
virtual void sendKeyUp(KeyID, KeyModifierMask);
|
virtual void sendKeyUp(KeyID, KeyModifierMask);
|
||||||
virtual void sendMouseDown(ButtonID);
|
virtual void sendMouseDown(ButtonID);
|
||||||
virtual void sendMouseUp(ButtonID);
|
virtual void sendMouseUp(ButtonID);
|
||||||
|
@ -32,6 +33,8 @@ class CServerProtocol1_0 : public CServerProtocol {
|
||||||
protected:
|
protected:
|
||||||
// IServerProtocol overrides
|
// IServerProtocol overrides
|
||||||
virtual void recvInfo();
|
virtual void recvInfo();
|
||||||
|
virtual void recvClipboard();
|
||||||
|
virtual void recvGrabClipboard();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -56,7 +56,10 @@ static void restoreCursor()
|
||||||
static LRESULT CALLBACK keyboardHook(int code, WPARAM wParam, LPARAM lParam)
|
static LRESULT CALLBACK keyboardHook(int code, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
if (code >= 0) {
|
if (code >= 0) {
|
||||||
// FIXME
|
if (g_relay) {
|
||||||
|
PostMessage(g_hwnd, SYNERGY_MSG_KEY, wParam, lParam);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return CallNextHookEx(g_keyboard, code, wParam, lParam);
|
return CallNextHookEx(g_keyboard, code, wParam, lParam);
|
||||||
|
|
|
@ -14,10 +14,10 @@
|
||||||
#define CSYNERGYHOOK_API
|
#define CSYNERGYHOOK_API
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define SYNERGY_MSG_MARK WM_APP + 0x0001 // mark id; <unused>
|
#define SYNERGY_MSG_MARK WM_APP + 0x0011 // mark id; <unused>
|
||||||
#define SYNERGY_MSG_KEY WM_APP + 0x0002 // vk code; key data
|
#define SYNERGY_MSG_KEY WM_APP + 0x0012 // vk code; key data
|
||||||
#define SYNERGY_MSG_MOUSE_BUTTON WM_APP + 0x0003 // button msg; <unused>
|
#define SYNERGY_MSG_MOUSE_BUTTON WM_APP + 0x0013 // button msg; <unused>
|
||||||
#define SYNERGY_MSG_MOUSE_MOVE WM_APP + 0x0004 // x; y
|
#define SYNERGY_MSG_MOUSE_MOVE WM_APP + 0x0014 // x; y
|
||||||
|
|
||||||
typedef int (*InstallFunc)(HWND);
|
typedef int (*InstallFunc)(HWND);
|
||||||
typedef int (*UninstallFunc)(void);
|
typedef int (*UninstallFunc)(void);
|
||||||
|
|
|
@ -117,19 +117,46 @@ void CXWindowsPrimaryScreen::run()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
case SelectionClear:
|
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;
|
break;
|
||||||
|
|
||||||
case SelectionNotify:
|
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;
|
break;
|
||||||
|
|
||||||
case SelectionRequest:
|
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;
|
break;
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -267,19 +294,17 @@ void CXWindowsPrimaryScreen::warpCursorNoLock(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <X11/Xatom.h> // FIXME
|
|
||||||
void CXWindowsPrimaryScreen::setClipboard(
|
void CXWindowsPrimaryScreen::setClipboard(
|
||||||
const IClipboard* /*clipboard*/)
|
const IClipboard* clipboard)
|
||||||
{
|
{
|
||||||
// FIXME -- put this in superclass?
|
|
||||||
// FIXME -- don't use CurrentTime
|
// FIXME -- don't use CurrentTime
|
||||||
CDisplayLock display(this);
|
setDisplayClipboard(clipboard, m_window, CurrentTime);
|
||||||
XSetSelectionOwner(display, XA_PRIMARY, m_window, CurrentTime);
|
}
|
||||||
if (XGetSelectionOwner(display, XA_PRIMARY) == m_window) {
|
|
||||||
// we got the selection
|
void CXWindowsPrimaryScreen::grabClipboard()
|
||||||
log((CLOG_DEBUG "grabbed clipboard"));
|
{
|
||||||
}
|
// FIXME -- don't use CurrentTime
|
||||||
// FIXME -- need to copy or adopt the clipboard to serve future requests
|
setDisplayClipboard(NULL, m_window, CurrentTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CXWindowsPrimaryScreen::getSize(
|
void CXWindowsPrimaryScreen::getSize(
|
||||||
|
@ -296,7 +321,6 @@ SInt32 CXWindowsPrimaryScreen::getJumpZoneSize() const
|
||||||
void CXWindowsPrimaryScreen::getClipboard(
|
void CXWindowsPrimaryScreen::getClipboard(
|
||||||
IClipboard* clipboard) const
|
IClipboard* clipboard) const
|
||||||
{
|
{
|
||||||
// FIXME -- put this in superclass?
|
|
||||||
// FIXME -- don't use CurrentTime
|
// FIXME -- don't use CurrentTime
|
||||||
getDisplayClipboard(clipboard, m_window, CurrentTime);
|
getDisplayClipboard(clipboard, m_window, CurrentTime);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ class CXWindowsPrimaryScreen : public CXWindowsScreen, public IPrimaryScreen {
|
||||||
virtual void leave();
|
virtual void leave();
|
||||||
virtual void warpCursor(SInt32 xAbsolute, SInt32 yAbsolute);
|
virtual void warpCursor(SInt32 xAbsolute, SInt32 yAbsolute);
|
||||||
virtual void setClipboard(const IClipboard*);
|
virtual void setClipboard(const IClipboard*);
|
||||||
|
virtual void grabClipboard();
|
||||||
virtual void getSize(SInt32* width, SInt32* height) const;
|
virtual void getSize(SInt32* width, SInt32* height) const;
|
||||||
virtual SInt32 getJumpZoneSize() const;
|
virtual SInt32 getJumpZoneSize() const;
|
||||||
virtual void getClipboard(IClipboard*) const;
|
virtual void getClipboard(IClipboard*) const;
|
||||||
|
|
|
@ -23,8 +23,8 @@ CFG=makehook - Win32 Debug
|
||||||
|
|
||||||
# Begin Project
|
# Begin Project
|
||||||
# PROP AllowPerConfigDependencies 0
|
# PROP AllowPerConfigDependencies 0
|
||||||
# PROP Scc_ProjName ""
|
# PROP Scc_ProjName "millpond"
|
||||||
# PROP Scc_LocalPath ""
|
# PROP Scc_LocalPath "."
|
||||||
MTL=midl.exe
|
MTL=midl.exe
|
||||||
|
|
||||||
!IF "$(CFG)" == "makehook - Win32 Release"
|
!IF "$(CFG)" == "makehook - Win32 Release"
|
||||||
|
|
|
@ -10,9 +10,9 @@ void realMain()
|
||||||
|
|
||||||
CScreenMap screenMap;
|
CScreenMap screenMap;
|
||||||
screenMap.addScreen("primary");
|
screenMap.addScreen("primary");
|
||||||
screenMap.addScreen("ingrid");
|
screenMap.addScreen("secondary");
|
||||||
screenMap.connect("primary", CScreenMap::kRight, "ingrid");
|
screenMap.connect("primary", CScreenMap::kRight, "secondary");
|
||||||
screenMap.connect("ingrid", CScreenMap::kLeft, "primary");
|
screenMap.connect("secondary", CScreenMap::kLeft, "primary");
|
||||||
|
|
||||||
CServer* server = NULL;
|
CServer* server = NULL;
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -38,7 +38,7 @@ RSC=rc.exe
|
||||||
# PROP BASE Target_Dir ""
|
# PROP BASE Target_Dir ""
|
||||||
# PROP Use_MFC 0
|
# PROP Use_MFC 0
|
||||||
# PROP Use_Debug_Libraries 0
|
# PROP Use_Debug_Libraries 0
|
||||||
# PROP Output_Dir "Release"
|
# PROP Output_Dir "../Release"
|
||||||
# PROP Intermediate_Dir "Release"
|
# PROP Intermediate_Dir "Release"
|
||||||
# PROP Target_Dir ""
|
# PROP Target_Dir ""
|
||||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
|
# 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 BASE Target_Dir ""
|
||||||
# PROP Use_MFC 0
|
# PROP Use_MFC 0
|
||||||
# PROP Use_Debug_Libraries 1
|
# PROP Use_Debug_Libraries 1
|
||||||
# PROP Output_Dir "Debug"
|
# PROP Output_Dir "../Debug"
|
||||||
# PROP Intermediate_Dir "Debug"
|
# PROP Intermediate_Dir "Debug"
|
||||||
# PROP Target_Dir ""
|
# PROP Target_Dir ""
|
||||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
|
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
|
||||||
|
|
|
@ -38,8 +38,8 @@ RSC=rc.exe
|
||||||
# PROP BASE Target_Dir ""
|
# PROP BASE Target_Dir ""
|
||||||
# PROP Use_MFC 0
|
# PROP Use_MFC 0
|
||||||
# PROP Use_Debug_Libraries 0
|
# PROP Use_Debug_Libraries 0
|
||||||
# PROP Output_Dir "Release"
|
# PROP Output_Dir "../Release"
|
||||||
# PROP Intermediate_Dir "Release"
|
# PROP Intermediate_Dir "ReleaseHook"
|
||||||
# PROP Target_Dir ""
|
# 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 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
|
# 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 BASE Target_Dir ""
|
||||||
# PROP Use_MFC 0
|
# PROP Use_MFC 0
|
||||||
# PROP Use_Debug_Libraries 1
|
# PROP Use_Debug_Libraries 1
|
||||||
# PROP Output_Dir "Debug"
|
# PROP Output_Dir "../Debug"
|
||||||
# PROP Intermediate_Dir "Debug"
|
# PROP Intermediate_Dir "DebugHook"
|
||||||
# PROP Target_Dir ""
|
# 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 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
|
# 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
|
||||||
|
|
|
@ -92,6 +92,10 @@ Project: "makehook"=.\server\makehook.dsp - Package Owner=<4>
|
||||||
|
|
||||||
Package=<5>
|
Package=<5>
|
||||||
{{{
|
{{{
|
||||||
|
begin source code control
|
||||||
|
millpond
|
||||||
|
.\server
|
||||||
|
end source code control
|
||||||
}}}
|
}}}
|
||||||
|
|
||||||
Package=<4>
|
Package=<4>
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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
|
|
@ -6,36 +6,190 @@
|
||||||
// CMSWindowsClipboard
|
// CMSWindowsClipboard
|
||||||
//
|
//
|
||||||
|
|
||||||
CMSWindowsClipboard::CMSWindowsClipboard()
|
CMSWindowsClipboard::CMSWindowsClipboard(HWND window) : m_window(window)
|
||||||
{
|
{
|
||||||
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
CMSWindowsClipboard::~CMSWindowsClipboard()
|
CMSWindowsClipboard::~CMSWindowsClipboard()
|
||||||
{
|
{
|
||||||
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMSWindowsClipboard::open()
|
bool CMSWindowsClipboard::open()
|
||||||
{
|
{
|
||||||
log((CLOG_INFO "open clipboard"));
|
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()
|
void CMSWindowsClipboard::close()
|
||||||
{
|
{
|
||||||
log((CLOG_INFO "close clipboard"));
|
log((CLOG_INFO "close clipboard"));
|
||||||
|
CloseClipboard();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMSWindowsClipboard::add(
|
void CMSWindowsClipboard::add(
|
||||||
EFormat format, const CString& data)
|
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,18 +2,27 @@
|
||||||
#define CMSWINDOWSCLIPBOARD_H
|
#define CMSWINDOWSCLIPBOARD_H
|
||||||
|
|
||||||
#include "IClipboard.h"
|
#include "IClipboard.h"
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
class CMSWindowsClipboard : public IClipboard {
|
class CMSWindowsClipboard : public IClipboard {
|
||||||
public:
|
public:
|
||||||
CMSWindowsClipboard();
|
CMSWindowsClipboard(HWND window);
|
||||||
virtual ~CMSWindowsClipboard();
|
virtual ~CMSWindowsClipboard();
|
||||||
|
|
||||||
// IClipboard overrides
|
// IClipboard overrides
|
||||||
virtual void open();
|
virtual bool open();
|
||||||
virtual void close();
|
virtual void close();
|
||||||
virtual void add(EFormat, const CString& data);
|
virtual void add(EFormat, const CString& data);
|
||||||
virtual bool has(EFormat) const;
|
virtual bool has(EFormat) const;
|
||||||
virtual CString get(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
|
#endif
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
HINSTANCE CMSWindowsScreen::s_instance = NULL;
|
HINSTANCE CMSWindowsScreen::s_instance = NULL;
|
||||||
|
CMSWindowsScreen* CMSWindowsScreen::s_screen = NULL;
|
||||||
|
|
||||||
CMSWindowsScreen::CMSWindowsScreen() :
|
CMSWindowsScreen::CMSWindowsScreen() :
|
||||||
m_class(0),
|
m_class(0),
|
||||||
|
@ -19,12 +20,14 @@ CMSWindowsScreen::CMSWindowsScreen() :
|
||||||
m_w(0), m_h(0),
|
m_w(0), m_h(0),
|
||||||
m_thread(0)
|
m_thread(0)
|
||||||
{
|
{
|
||||||
// do nothing
|
assert(s_screen == NULL);
|
||||||
|
s_screen = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
CMSWindowsScreen::~CMSWindowsScreen()
|
CMSWindowsScreen::~CMSWindowsScreen()
|
||||||
{
|
{
|
||||||
assert(m_class == 0);
|
assert(m_class == 0);
|
||||||
|
s_screen = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMSWindowsScreen::init(HINSTANCE instance)
|
void CMSWindowsScreen::init(HINSTANCE instance)
|
||||||
|
@ -46,7 +49,7 @@ void CMSWindowsScreen::doRun()
|
||||||
}
|
}
|
||||||
|
|
||||||
// dispatch message
|
// dispatch message
|
||||||
if (!onEvent(&msg)) {
|
if (!onPreTranslate(&msg)) {
|
||||||
TranslateMessage(&msg);
|
TranslateMessage(&msg);
|
||||||
DispatchMessage(&msg);
|
DispatchMessage(&msg);
|
||||||
}
|
}
|
||||||
|
@ -66,10 +69,13 @@ void CMSWindowsScreen::openDisplay()
|
||||||
// create a transparent cursor
|
// create a transparent cursor
|
||||||
int cw = GetSystemMetrics(SM_CXCURSOR);
|
int cw = GetSystemMetrics(SM_CXCURSOR);
|
||||||
int ch = GetSystemMetrics(SM_CYCURSOR);
|
int ch = GetSystemMetrics(SM_CYCURSOR);
|
||||||
UInt8* cursorBits = new UInt8[ch * ((cw + 31) >> 5)];
|
UInt8* cursorAND = new UInt8[ch * ((cw + 31) >> 2)];
|
||||||
memset(cursorBits, 0, ch * ((cw + 31) >> 5));
|
UInt8* cursorXOR = new UInt8[ch * ((cw + 31) >> 2)];
|
||||||
m_cursor = CreateCursor(s_instance, 0, 0, cw, ch, cursorBits, cursorBits);
|
memset(cursorAND, 0xff, ch * ((cw + 31) >> 2));
|
||||||
delete[] cursorBits;
|
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
|
// register a window class
|
||||||
WNDCLASSEX classInfo;
|
WNDCLASSEX classInfo;
|
||||||
|
@ -197,7 +203,7 @@ void CMSWindowsScreen::getDisplayClipboard(
|
||||||
|
|
||||||
// if we can use the format and we haven't already retrieved
|
// if we can use the format and we haven't already retrieved
|
||||||
// it then get it
|
// it then get it
|
||||||
if (expectedFormat == IClipboard::kNum) {
|
if (expectedFormat == IClipboard::kNumFormats) {
|
||||||
log((CLOG_DEBUG " no format for target", format));
|
log((CLOG_DEBUG " no format for target", format));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -215,7 +221,7 @@ void CMSWindowsScreen::getDisplayClipboard(
|
||||||
|
|
||||||
// use the actual format, not the expected
|
// use the actual format, not the expected
|
||||||
IClipboard::EFormat actualFormat = getFormat(format);
|
IClipboard::EFormat actualFormat = getFormat(format);
|
||||||
if (actualFormat == IClipboard::kNum) {
|
if (actualFormat == IClipboard::kNumFormats) {
|
||||||
log((CLOG_DEBUG " no format for target", format));
|
log((CLOG_DEBUG " no format for target", format));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -244,5 +250,6 @@ LRESULT CALLBACK CMSWindowsScreen::wndProc(
|
||||||
HWND hwnd, UINT msg,
|
HWND hwnd, UINT msg,
|
||||||
WPARAM wParam, LPARAM lParam)
|
WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
return DefWindowProc(hwnd, msg, wParam, lParam);
|
assert(s_screen != NULL);
|
||||||
|
return s_screen->onEvent(hwnd, msg, wParam, lParam);
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,8 +49,12 @@ class CMSWindowsScreen {
|
||||||
// copy the clipboard contents to clipboard
|
// copy the clipboard contents to clipboard
|
||||||
void getDisplayClipboard(IClipboard* clipboard, HWND) const;
|
void getDisplayClipboard(IClipboard* clipboard, HWND) const;
|
||||||
|
|
||||||
// called by doRun() to handle an event
|
// called by doRun() to handle an event. return true to skip
|
||||||
virtual bool onEvent(MSG*) = 0;
|
// 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
|
// called by openDisplay() to allow subclasses to prepare the display
|
||||||
virtual void onOpenDisplay() = 0;
|
virtual void onOpenDisplay() = 0;
|
||||||
|
@ -68,6 +72,7 @@ class CMSWindowsScreen {
|
||||||
HCURSOR m_cursor;
|
HCURSOR m_cursor;
|
||||||
SInt32 m_w, m_h;
|
SInt32 m_w, m_h;
|
||||||
DWORD m_thread;
|
DWORD m_thread;
|
||||||
|
static CMSWindowsScreen* s_screen;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -190,6 +190,12 @@ UInt32 CProtocolUtil::getLength(
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 's':
|
case 's':
|
||||||
|
assert(len == 0);
|
||||||
|
len = (va_arg(args, CString*))->size() + 4;
|
||||||
|
(void)va_arg(args, UInt8*);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'S':
|
||||||
assert(len == 0);
|
assert(len == 0);
|
||||||
len = va_arg(args, UInt32) + 4;
|
len = va_arg(args, UInt32) + 4;
|
||||||
(void)va_arg(args, UInt8*);
|
(void)va_arg(args, UInt8*);
|
||||||
|
@ -258,6 +264,21 @@ void CProtocolUtil::writef(void* buffer,
|
||||||
}
|
}
|
||||||
|
|
||||||
case 's': {
|
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);
|
assert(len == 0);
|
||||||
const UInt32 len = va_arg(args, UInt32);
|
const UInt32 len = va_arg(args, UInt32);
|
||||||
const UInt8* src = va_arg(args, UInt8*);
|
const UInt8* src = va_arg(args, UInt8*);
|
||||||
|
|
|
@ -20,7 +20,8 @@ class CProtocolUtil {
|
||||||
// %1i -- converts integer argument to 1 byte integer
|
// %1i -- converts integer argument to 1 byte integer
|
||||||
// %2i -- converts integer argument to 2 byte integer in NBO
|
// %2i -- converts integer argument to 2 byte integer in NBO
|
||||||
// %4i -- converts integer argument to 4 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*,
|
static void writef(IOutputStream*,
|
||||||
const char* fmt, ...);
|
const char* fmt, ...);
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,7 @@ void CXWindowsScreen::openDisplay()
|
||||||
|
|
||||||
// get some atoms
|
// get some atoms
|
||||||
m_atomTargets = XInternAtom(m_display, "TARGETS", False);
|
m_atomTargets = XInternAtom(m_display, "TARGETS", False);
|
||||||
|
m_atomMultiple = XInternAtom(m_display, "MULTIPLE", False);
|
||||||
m_atomData = XInternAtom(m_display, "DESTINATION", False);
|
m_atomData = XInternAtom(m_display, "DESTINATION", False);
|
||||||
m_atomINCR = XInternAtom(m_display, "INCR", False);
|
m_atomINCR = XInternAtom(m_display, "INCR", False);
|
||||||
m_atomText = XInternAtom(m_display, "TEXT", False);
|
m_atomText = XInternAtom(m_display, "TEXT", False);
|
||||||
|
@ -143,12 +144,12 @@ bool CXWindowsScreen::getEvent(XEvent* xevent) const
|
||||||
}
|
}
|
||||||
if (m_stop) {
|
if (m_stop) {
|
||||||
m_mutex.unlock();
|
m_mutex.unlock();
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
XNextEvent(m_display, xevent);
|
XNextEvent(m_display, xevent);
|
||||||
m_mutex.unlock();
|
m_mutex.unlock();
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,6 +159,34 @@ void CXWindowsScreen::doStop()
|
||||||
m_stop = true;
|
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(
|
void CXWindowsScreen::getDisplayClipboard(
|
||||||
IClipboard* clipboard,
|
IClipboard* clipboard,
|
||||||
Window requestor, Time timestamp) const
|
Window requestor, Time timestamp) const
|
||||||
|
@ -166,7 +195,8 @@ void CXWindowsScreen::getDisplayClipboard(
|
||||||
assert(requestor != None);
|
assert(requestor != None);
|
||||||
|
|
||||||
// clear the clipboard object
|
// clear the clipboard object
|
||||||
clipboard->open();
|
if (!clipboard->open())
|
||||||
|
return;
|
||||||
|
|
||||||
// block others from using the display while we get the clipboard.
|
// block others from using the display while we get the clipboard.
|
||||||
// in particular, this prevents the event thread from stealing the
|
// 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
|
// if we can use the format and we haven't already retrieved
|
||||||
// it then get it
|
// it then get it
|
||||||
if (expectedFormat == IClipboard::kNum) {
|
if (expectedFormat == IClipboard::kNumFormats) {
|
||||||
log((CLOG_DEBUG " no format for target", format));
|
log((CLOG_DEBUG " no format for target", format));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -227,7 +257,7 @@ void CXWindowsScreen::getDisplayClipboard(
|
||||||
|
|
||||||
// use the actual format, not the expected
|
// use the actual format, not the expected
|
||||||
IClipboard::EFormat actualFormat = getFormat(format);
|
IClipboard::EFormat actualFormat = getFormat(format);
|
||||||
if (actualFormat == IClipboard::kNum) {
|
if (actualFormat == IClipboard::kNumFormats) {
|
||||||
log((CLOG_DEBUG " no format for target", format));
|
log((CLOG_DEBUG " no format for target", format));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -452,7 +482,7 @@ IClipboard::EFormat CXWindowsScreen::getFormat(Atom src) const
|
||||||
src == m_atomText ||
|
src == m_atomText ||
|
||||||
src == m_atomCompoundText)
|
src == m_atomCompoundText)
|
||||||
return IClipboard::kText;
|
return IClipboard::kText;
|
||||||
return IClipboard::kNum;
|
return IClipboard::kNumFormats;
|
||||||
}
|
}
|
||||||
|
|
||||||
Bool CXWindowsScreen::findSelectionNotify(
|
Bool CXWindowsScreen::findSelectionNotify(
|
||||||
|
@ -473,6 +503,98 @@ Bool CXWindowsScreen::findPropertyNotify(
|
||||||
xevent->xproperty.state == PropertyNewValue) ? True : False;
|
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
|
// CXWindowsScreen::CDisplayLock
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
#ifndef CXWINDOWSSCREEN_H
|
#ifndef CXWINDOWSSCREEN_H
|
||||||
#define CXWINDOWSSCREEN_H
|
#define CXWINDOWSSCREEN_H
|
||||||
|
|
||||||
|
#include "CClipboard.h"
|
||||||
#include "CMutex.h"
|
#include "CMutex.h"
|
||||||
#include "IClipboard.h"
|
|
||||||
#include "BasicTypes.h"
|
#include "BasicTypes.h"
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
|
|
||||||
|
@ -54,12 +54,25 @@ class CXWindowsScreen {
|
||||||
// cause getEvent() to return false immediately and forever after
|
// cause getEvent() to return false immediately and forever after
|
||||||
void doStop();
|
void doStop();
|
||||||
|
|
||||||
|
bool setDisplayClipboard(const IClipboard* clipboard,
|
||||||
|
Window requestor, Time timestamp);
|
||||||
|
|
||||||
// copy the clipboard contents to clipboard. requestor must be a
|
// copy the clipboard contents to clipboard. requestor must be a
|
||||||
// valid window; it will be used to receive the transfer. timestamp
|
// valid window; it will be used to receive the transfer. timestamp
|
||||||
// should be the timestamp of the provoking event and not CurrentTime.
|
// should be the timestamp of the provoking event and not CurrentTime.
|
||||||
void getDisplayClipboard(IClipboard* clipboard,
|
void getDisplayClipboard(IClipboard* clipboard,
|
||||||
Window requestor, Time timestamp) const;
|
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
|
// called by openDisplay() to allow subclasses to prepare the display
|
||||||
virtual void onOpenDisplay() = 0;
|
virtual void onOpenDisplay() = 0;
|
||||||
|
|
||||||
|
@ -85,6 +98,14 @@ class CXWindowsScreen {
|
||||||
static Bool findPropertyNotify(Display*,
|
static Bool findPropertyNotify(Display*,
|
||||||
XEvent* xevent, XPointer arg);
|
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:
|
private:
|
||||||
Display* m_display;
|
Display* m_display;
|
||||||
int m_screen;
|
int m_screen;
|
||||||
|
@ -94,11 +115,15 @@ class CXWindowsScreen {
|
||||||
|
|
||||||
// atoms we'll need
|
// atoms we'll need
|
||||||
Atom m_atomTargets;
|
Atom m_atomTargets;
|
||||||
|
Atom m_atomMultiple;
|
||||||
Atom m_atomData;
|
Atom m_atomData;
|
||||||
Atom m_atomINCR;
|
Atom m_atomINCR;
|
||||||
Atom m_atomText;
|
Atom m_atomText;
|
||||||
Atom m_atomCompoundText;
|
Atom m_atomCompoundText;
|
||||||
|
|
||||||
|
// the contents of our selection
|
||||||
|
CClipboard m_clipboard;
|
||||||
|
|
||||||
// X is not thread safe
|
// X is not thread safe
|
||||||
CMutex m_mutex;
|
CMutex m_mutex;
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,14 +8,16 @@ class CString;
|
||||||
|
|
||||||
class IClipboard : public IInterface {
|
class IClipboard : public IInterface {
|
||||||
public:
|
public:
|
||||||
enum EFormat { kText, kNum };
|
enum EFormat { kText, kNumFormats };
|
||||||
|
|
||||||
// manipulators
|
// manipulators
|
||||||
|
|
||||||
// grab ownership of and clear the clipboard of all data.
|
// grab ownership of and clear the clipboard of all data.
|
||||||
// only add() may be called between an open() and its
|
// only add() may be called between an open() and its
|
||||||
// corresponding close().
|
// corresponding close(). if open() returns false then
|
||||||
virtual void open() = 0;
|
// 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().
|
// close the clipboard. close() must match a preceding open().
|
||||||
// this signals that the clipboard has been filled with all the
|
// this signals that the clipboard has been filled with all the
|
||||||
|
|
|
@ -54,11 +54,11 @@ class IPrimaryScreen : public IInterface {
|
||||||
/*
|
/*
|
||||||
// show or hide the screen saver
|
// show or hide the screen saver
|
||||||
virtual void onScreenSaver(bool show) = 0;
|
virtual void onScreenSaver(bool show) = 0;
|
||||||
|
|
||||||
// clipboard input
|
|
||||||
virtual void onClipboardChanged() = 0;
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// synergy should own the clipboard
|
||||||
|
virtual void grabClipboard() = 0;
|
||||||
|
|
||||||
// accessors
|
// accessors
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
#include "MouseTypes.h"
|
#include "MouseTypes.h"
|
||||||
|
|
||||||
class CClient;
|
class CClient;
|
||||||
//class IClipboard;
|
class IClipboard;
|
||||||
|
|
||||||
class ISecondaryScreen : public IInterface {
|
class ISecondaryScreen : public IInterface {
|
||||||
public:
|
public:
|
||||||
|
@ -50,18 +50,18 @@ class ISecondaryScreen : public IInterface {
|
||||||
virtual void mouseMove(SInt32 xAbsolute, SInt32 yAbsolute) = 0;
|
virtual void mouseMove(SInt32 xAbsolute, SInt32 yAbsolute) = 0;
|
||||||
virtual void mouseWheel(SInt32 delta) = 0;
|
virtual void mouseWheel(SInt32 delta) = 0;
|
||||||
|
|
||||||
/*
|
|
||||||
// set the screen's clipboard contents. this is usually called
|
// set the screen's clipboard contents. this is usually called
|
||||||
// soon after an enter().
|
// soon after an enter().
|
||||||
virtual void setClipboard(const IClipboard*) = 0;
|
virtual void setClipboard(const IClipboard*) = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
// show or hide the screen saver
|
// show or hide the screen saver
|
||||||
virtual void screenSaver(bool show) = 0;
|
virtual void screenSaver(bool show) = 0;
|
||||||
|
|
||||||
// clipboard input
|
|
||||||
virtual void clipboardChanged() = 0;
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// take ownership of clipboard
|
||||||
|
virtual void grabClipboard() = 0;
|
||||||
|
|
||||||
// accessors
|
// accessors
|
||||||
|
|
||||||
// get the size of the screen
|
// get the size of the screen
|
||||||
|
@ -70,10 +70,8 @@ class ISecondaryScreen : public IInterface {
|
||||||
// get the size of jump zone
|
// get the size of jump zone
|
||||||
virtual SInt32 getJumpZoneSize() const = 0;
|
virtual SInt32 getJumpZoneSize() const = 0;
|
||||||
|
|
||||||
/*
|
|
||||||
// get the screen's clipboard contents
|
// get the screen's clipboard contents
|
||||||
virtual void getClipboard(IClipboard*) const = 0;
|
virtual void getClipboard(IClipboard*) const = 0;
|
||||||
*/
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
#include "XSynergy.h"
|
#include "XSynergy.h"
|
||||||
#include "XIO.h"
|
#include "XIO.h"
|
||||||
|
|
||||||
|
class IClipboard;
|
||||||
|
|
||||||
class IServerProtocol : public IInterface {
|
class IServerProtocol : public IInterface {
|
||||||
public:
|
public:
|
||||||
// manipulators
|
// manipulators
|
||||||
|
@ -23,11 +25,12 @@ class IServerProtocol : public IInterface {
|
||||||
virtual void sendClose() = 0;
|
virtual void sendClose() = 0;
|
||||||
virtual void sendEnter(SInt32 xAbs, SInt32 yAbs) = 0;
|
virtual void sendEnter(SInt32 xAbs, SInt32 yAbs) = 0;
|
||||||
virtual void sendLeave() = 0;
|
virtual void sendLeave() = 0;
|
||||||
|
virtual void sendClipboard(const CString&) = 0;
|
||||||
virtual void sendGrabClipboard() = 0;
|
virtual void sendGrabClipboard() = 0;
|
||||||
virtual void sendQueryClipboard() = 0;
|
virtual void sendQueryClipboard(UInt32 seqNum) = 0;
|
||||||
virtual void sendScreenSaver(bool on) = 0;
|
virtual void sendScreenSaver(bool on) = 0;
|
||||||
virtual void sendKeyDown(KeyID, KeyModifierMask) = 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 sendKeyUp(KeyID, KeyModifierMask) = 0;
|
||||||
virtual void sendMouseDown(ButtonID) = 0;
|
virtual void sendMouseDown(ButtonID) = 0;
|
||||||
virtual void sendMouseUp(ButtonID) = 0;
|
virtual void sendMouseUp(ButtonID) = 0;
|
||||||
|
@ -40,6 +43,8 @@ class IServerProtocol : public IInterface {
|
||||||
// manipulators
|
// manipulators
|
||||||
|
|
||||||
virtual void recvInfo() = 0;
|
virtual void recvInfo() = 0;
|
||||||
|
virtual void recvClipboard() = 0;
|
||||||
|
virtual void recvGrabClipboard() = 0;
|
||||||
|
|
||||||
// accessors
|
// accessors
|
||||||
};
|
};
|
||||||
|
|
|
@ -19,6 +19,7 @@ CXXFILES = \
|
||||||
CInputPacketStream.cpp \
|
CInputPacketStream.cpp \
|
||||||
COutputPacketStream.cpp \
|
COutputPacketStream.cpp \
|
||||||
CProtocolUtil.cpp \
|
CProtocolUtil.cpp \
|
||||||
|
CClipboard.cpp \
|
||||||
CTCPSocketFactory.cpp \
|
CTCPSocketFactory.cpp \
|
||||||
CXWindowsClipboard.cpp \
|
CXWindowsClipboard.cpp \
|
||||||
CXWindowsScreen.cpp \
|
CXWindowsScreen.cpp \
|
||||||
|
|
|
@ -16,7 +16,7 @@ static const SInt32 kMinorVersion = 1;
|
||||||
static const char kMsgCClose[] = "CBYE"; // server
|
static const char kMsgCClose[] = "CBYE"; // server
|
||||||
static const char kMsgCEnter[] = "CINN%2i%2i"; // server
|
static const char kMsgCEnter[] = "CINN%2i%2i"; // server
|
||||||
static const char kMsgCLeave[] = "COUT"; // 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 kMsgCScreenSaver[] = "CSEC%1i"; // server
|
||||||
|
|
||||||
static const char kMsgDKeyDown[] = "DKDN%2i%2i"; // 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 kMsgDMouseUp[] = "DMUP%1i"; // server
|
||||||
static const char kMsgDMouseMove[] = "DMMV%2i%2i"; // server
|
static const char kMsgDMouseMove[] = "DMMV%2i%2i"; // server
|
||||||
static const char kMsgDMouseWheel[] = "DMWM%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 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 kMsgQInfo[] = "QINF"; // server
|
||||||
|
|
||||||
static const char kMsgEIncompatible[] = "EICV";
|
static const char kMsgEIncompatible[] = "EICV";
|
||||||
|
|
|
@ -87,6 +87,10 @@ LIB32=link.exe -lib
|
||||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CClipboard.cpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\CInputPacketStream.cpp
|
SOURCE=.\CInputPacketStream.cpp
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
@ -119,6 +123,10 @@ SOURCE=.\XSynergy.cpp
|
||||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CClipboard.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\CInputPacketStream.h
|
SOURCE=.\CInputPacketStream.h
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
Loading…
Reference in New Issue