Fixes to get win32 client and server up to date.

This commit is contained in:
crs 2002-04-30 16:23:03 +00:00
parent ea6b347b18
commit dc19570621
11 changed files with 746 additions and 208 deletions

View File

@ -116,9 +116,12 @@ void CClient::onClipboardChanged(ClipboardID id)
// send data // send data
log((CLOG_DEBUG "sending clipboard %d seqnum=%d, size=%d", id, m_seqNum, data.size())); log((CLOG_DEBUG "sending clipboard %d seqnum=%d, size=%d", id, m_seqNum, data.size()));
if (m_output != NULL) {
// FIXME -- will we send the clipboard when we connect?
CProtocolUtil::writef(m_output, kMsgDClipboard, id, m_seqNum, &data); CProtocolUtil::writef(m_output, kMsgDClipboard, id, m_seqNum, &data);
} }
} }
}
#include "CTCPSocket.h" // FIXME #include "CTCPSocket.h" // FIXME
void CClient::runSession(void*) void CClient::runSession(void*)
@ -200,7 +203,7 @@ void CClient::runSession(void*)
// handle messages from server // handle messages from server
for (;;) { for (;;) {
// wait for reply // wait for reply
log((CLOG_DEBUG1 "waiting for message")); log((CLOG_DEBUG2 "waiting for message"));
UInt8 code[4]; UInt8 code[4];
UInt32 n = input->read(code, 4); UInt32 n = input->read(code, 4);
@ -259,6 +262,7 @@ void CClient::runSession(void*)
} }
else if (memcmp(code, kMsgCClose, 4) == 0) { else if (memcmp(code, kMsgCClose, 4) == 0) {
// server wants us to hangup // server wants us to hangup
log((CLOG_DEBUG1 "recv close"));
break; break;
} }
else { else {
@ -342,11 +346,14 @@ void CClient::onEnter()
CProtocolUtil::readf(m_input, kMsgCEnter + 4, &x, &y, &m_seqNum); CProtocolUtil::readf(m_input, kMsgCEnter + 4, &x, &y, &m_seqNum);
m_active = true; m_active = true;
} }
log((CLOG_DEBUG1 "recv enter, %d,%d %d", x, y, m_seqNum));
m_screen->enter(x, y); m_screen->enter(x, y);
} }
void CClient::onLeave() void CClient::onLeave()
{ {
log((CLOG_DEBUG1 "recv leave"));
// tell screen we're leaving // tell screen we're leaving
m_screen->leave(); m_screen->leave();
@ -391,7 +398,7 @@ void CClient::onGrabClipboard()
{ {
CLock lock(&m_mutex); CLock lock(&m_mutex);
CProtocolUtil::readf(m_input, kMsgCClipboard + 4, &id, &seqNum); CProtocolUtil::readf(m_input, kMsgCClipboard + 4, &id, &seqNum);
log((CLOG_DEBUG "received clipboard %d grab", id)); log((CLOG_DEBUG "recv grab clipboard %d", id));
// validate // validate
if (id >= kClipboardEnd) { if (id >= kClipboardEnd) {
@ -411,6 +418,7 @@ void CClient::onScreenSaver()
CLock lock(&m_mutex); CLock lock(&m_mutex);
CProtocolUtil::readf(m_input, kMsgCScreenSaver + 4, &on); CProtocolUtil::readf(m_input, kMsgCScreenSaver + 4, &on);
} }
log((CLOG_DEBUG1 "recv screen saver on=%d", on));
// FIXME // FIXME
} }
@ -435,7 +443,7 @@ void CClient::onSetClipboard()
CLock lock(&m_mutex); CLock lock(&m_mutex);
CProtocolUtil::readf(m_input, kMsgDClipboard + 4, &id, &seqNum, &data); CProtocolUtil::readf(m_input, kMsgDClipboard + 4, &id, &seqNum, &data);
} }
log((CLOG_DEBUG "received clipboard %d size=%d", id, data.size())); log((CLOG_DEBUG "recv clipboard %d size=%d", id, data.size()));
// validate // validate
if (id >= kClipboardEnd) { if (id >= kClipboardEnd) {
@ -452,22 +460,24 @@ void CClient::onSetClipboard()
void CClient::onKeyDown() void CClient::onKeyDown()
{ {
SInt16 id, mask; UInt16 id, mask;
{ {
CLock lock(&m_mutex); CLock lock(&m_mutex);
CProtocolUtil::readf(m_input, kMsgDKeyDown + 4, &id, &mask); CProtocolUtil::readf(m_input, kMsgDKeyDown + 4, &id, &mask);
} }
log((CLOG_DEBUG1 "recv key down id=%d, mask=0x%04x", id, mask));
m_screen->keyDown(static_cast<KeyID>(id), m_screen->keyDown(static_cast<KeyID>(id),
static_cast<KeyModifierMask>(mask)); static_cast<KeyModifierMask>(mask));
} }
void CClient::onKeyRepeat() void CClient::onKeyRepeat()
{ {
SInt16 id, mask, count; UInt16 id, mask, count;
{ {
CLock lock(&m_mutex); CLock lock(&m_mutex);
CProtocolUtil::readf(m_input, kMsgDKeyRepeat + 4, &id, &mask, &count); CProtocolUtil::readf(m_input, kMsgDKeyRepeat + 4, &id, &mask, &count);
} }
log((CLOG_DEBUG1 "recv key repeat id=%d, mask=0x%04x, count=%d", 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);
@ -475,11 +485,12 @@ void CClient::onKeyRepeat()
void CClient::onKeyUp() void CClient::onKeyUp()
{ {
SInt16 id, mask; UInt16 id, mask;
{ {
CLock lock(&m_mutex); CLock lock(&m_mutex);
CProtocolUtil::readf(m_input, kMsgDKeyUp + 4, &id, &mask); CProtocolUtil::readf(m_input, kMsgDKeyUp + 4, &id, &mask);
} }
log((CLOG_DEBUG1 "recv key up id=%d, mask=0x%04x", id, mask));
m_screen->keyUp(static_cast<KeyID>(id), m_screen->keyUp(static_cast<KeyID>(id),
static_cast<KeyModifierMask>(mask)); static_cast<KeyModifierMask>(mask));
} }
@ -491,6 +502,7 @@ void CClient::onMouseDown()
CLock lock(&m_mutex); CLock lock(&m_mutex);
CProtocolUtil::readf(m_input, kMsgDMouseDown + 4, &id); CProtocolUtil::readf(m_input, kMsgDMouseDown + 4, &id);
} }
log((CLOG_DEBUG1 "recv mouse down id=%d", id));
m_screen->mouseDown(static_cast<ButtonID>(id)); m_screen->mouseDown(static_cast<ButtonID>(id));
} }
@ -501,6 +513,7 @@ void CClient::onMouseUp()
CLock lock(&m_mutex); CLock lock(&m_mutex);
CProtocolUtil::readf(m_input, kMsgDMouseUp + 4, &id); CProtocolUtil::readf(m_input, kMsgDMouseUp + 4, &id);
} }
log((CLOG_DEBUG1 "recv mouse up id=%d", id));
m_screen->mouseUp(static_cast<ButtonID>(id)); m_screen->mouseUp(static_cast<ButtonID>(id));
} }
@ -511,6 +524,7 @@ void CClient::onMouseMove()
CLock lock(&m_mutex); CLock lock(&m_mutex);
CProtocolUtil::readf(m_input, kMsgDMouseMove + 4, &x, &y); CProtocolUtil::readf(m_input, kMsgDMouseMove + 4, &x, &y);
} }
log((CLOG_DEBUG2 "recv mouse move %d,%d", x, y));
m_screen->mouseMove(x, y); m_screen->mouseMove(x, y);
} }
@ -521,5 +535,6 @@ void CClient::onMouseWheel()
CLock lock(&m_mutex); CLock lock(&m_mutex);
CProtocolUtil::readf(m_input, kMsgDMouseWheel + 4, &delta); CProtocolUtil::readf(m_input, kMsgDMouseWheel + 4, &delta);
} }
log((CLOG_DEBUG2 "recv mouse wheel %+d", delta));
m_screen->mouseWheel(delta); m_screen->mouseWheel(delta);
} }

View File

@ -86,6 +86,14 @@ void CMSWindowsSecondaryScreen::open(CClient* client)
// open the display // open the display
openDisplay(); openDisplay();
// update key state
updateKeys();
updateModifiers();
// assume primary has all clipboards
for (ClipboardID id = 0; id < kClipboardEnd; ++id)
grabClipboard(id);
} }
void CMSWindowsSecondaryScreen::close() void CMSWindowsSecondaryScreen::close()
@ -118,6 +126,10 @@ void CMSWindowsSecondaryScreen::enter(SInt32 x, SInt32 y)
// show cursor // show cursor
log((CLOG_INFO "show cursor")); log((CLOG_INFO "show cursor"));
ShowWindow(m_window, SW_HIDE); ShowWindow(m_window, SW_HIDE);
// update our keyboard state to reflect the local state
updateKeys();
updateModifiers();
} }
void CMSWindowsSecondaryScreen::leave() void CMSWindowsSecondaryScreen::leave()
@ -151,7 +163,8 @@ void CMSWindowsSecondaryScreen::leave()
if (m_clipboardOwner != clipboardOwner) { if (m_clipboardOwner != clipboardOwner) {
m_clipboardOwner = clipboardOwner; m_clipboardOwner = clipboardOwner;
if (m_clipboardOwner != m_window) { if (m_clipboardOwner != m_window) {
m_client->onClipboardChanged(); m_client->onClipboardChanged(kClipboardClipboard);
m_client->onClipboardChanged(kClipboardSelection);
} }
} }
} }
@ -159,22 +172,45 @@ void CMSWindowsSecondaryScreen::leave()
void CMSWindowsSecondaryScreen::keyDown( void CMSWindowsSecondaryScreen::keyDown(
KeyID key, KeyModifierMask mask) KeyID key, KeyModifierMask mask)
{ {
const UINT vkey = mapKey(key, mask); Keystrokes keys;
if (vkey != 0) { UINT virtualKey;
const UINT code = MapVirtualKey(vkey, 0);
keybd_event(vkey, code, 0, 0); // get the sequence of keys to simulate key press and the final
// modifier state.
m_mask = mapKey(keys, virtualKey, key, mask, true);
if (keys.empty())
return;
// generate key events
for (Keystrokes::const_iterator k = keys.begin(); k != keys.end(); ++k) {
const UINT code = MapVirtualKey(k->first, 0);
keybd_event(k->first, code, k->second ? 0 : KEYEVENTF_KEYUP, 0);
} }
// note that key is now down
m_keys[virtualKey] |= 0x80;
} }
void CMSWindowsSecondaryScreen::keyRepeat( void CMSWindowsSecondaryScreen::keyRepeat(
KeyID key, KeyModifierMask mask, SInt32 count) KeyID key, KeyModifierMask mask, SInt32 count)
{ {
const UINT vkey = mapKey(key, mask); Keystrokes keys;
if (vkey != 0) { UINT virtualKey;
const UINT code = MapVirtualKey(vkey, 0);
// get the sequence of keys to simulate key release and the final
// modifier state.
m_mask = mapKey(keys, virtualKey, key, mask, true);
if (keys.empty())
return;
// generate key events
// YYY -- need to know which code in Keystrokes should be repeated;
// then repeat only that key count times
for (SInt32 i = 0; i < count; ++i) { for (SInt32 i = 0; i < count; ++i) {
keybd_event(vkey, code, KEYEVENTF_KEYUP, 0); for (Keystrokes::const_iterator k = keys.begin();
keybd_event(vkey, code, 0, 0); k != keys.end(); ++k) {
const UINT code = MapVirtualKey(k->first, 0);
keybd_event(k->first, code, k->second ? 0 : KEYEVENTF_KEYUP, 0);
} }
} }
} }
@ -182,60 +218,42 @@ void CMSWindowsSecondaryScreen::keyRepeat(
void CMSWindowsSecondaryScreen::keyUp( void CMSWindowsSecondaryScreen::keyUp(
KeyID key, KeyModifierMask mask) KeyID key, KeyModifierMask mask)
{ {
const UINT vkey = mapKey(key, mask); Keystrokes keys;
if (vkey != 0) { UINT virtualKey;
const UINT code = MapVirtualKey(vkey, 0);
keybd_event(vkey, code, KEYEVENTF_KEYUP, 0); // get the sequence of keys to simulate key release and the final
// modifier state.
m_mask = mapKey(keys, virtualKey, key, mask, false);
if (keys.empty())
return;
// generate key events
for (Keystrokes::const_iterator k = keys.begin(); k != keys.end(); ++k) {
const UINT code = MapVirtualKey(k->first, 0);
keybd_event(k->first, code, k->second ? 0 : KEYEVENTF_KEYUP, 0);
} }
// note that key is now up
m_keys[virtualKey] &= ~0x80;
} }
void CMSWindowsSecondaryScreen::mouseDown(ButtonID button) void CMSWindowsSecondaryScreen::mouseDown(ButtonID button)
{ {
// map button id to button flag // map button id to button flag
DWORD flags; DWORD flags = mapButton(button);
switch (button) {
case kButtonLeft:
flags = MOUSEEVENTF_LEFTDOWN;
break;
case kButtonMiddle:
flags = MOUSEEVENTF_MIDDLEDOWN;
break;
case kButtonRight:
flags = MOUSEEVENTF_RIGHTDOWN;
break;
default:
return;
}
// send event // send event
if (flags != 0)
mouse_event(flags, 0, 0, 0, 0); mouse_event(flags, 0, 0, 0, 0);
} }
void CMSWindowsSecondaryScreen::mouseUp(ButtonID button) void CMSWindowsSecondaryScreen::mouseUp(ButtonID button)
{ {
// map button id to button flag // map button id to button flag
DWORD flags; DWORD flags = mapButton(button);
switch (button) {
case kButtonLeft:
flags = MOUSEEVENTF_LEFTUP;
break;
case kButtonMiddle:
flags = MOUSEEVENTF_MIDDLEUP;
break;
case kButtonRight:
flags = MOUSEEVENTF_RIGHTUP;
break;
default:
return;
}
// send event // send event
if (flags != 0)
mouse_event(flags, 0, 0, 0, 0); mouse_event(flags, 0, 0, 0, 0);
} }
@ -255,7 +273,7 @@ void CMSWindowsSecondaryScreen::mouseWheel(SInt32 delta)
} }
void CMSWindowsSecondaryScreen::setClipboard( void CMSWindowsSecondaryScreen::setClipboard(
const IClipboard* src) ClipboardID id, const IClipboard* src)
{ {
assert(m_window != NULL); assert(m_window != NULL);
@ -263,12 +281,12 @@ void CMSWindowsSecondaryScreen::setClipboard(
CClipboard::copy(&dst, src); CClipboard::copy(&dst, src);
} }
void CMSWindowsSecondaryScreen::grabClipboard() void CMSWindowsSecondaryScreen::grabClipboard(ClipboardID id)
{ {
assert(m_window != NULL); assert(m_window != NULL);
CMSWindowsClipboard clipboard(m_window); CMSWindowsClipboard clipboard(m_window);
if (clipboard.open()) { if (clipboard.open(0)) {
clipboard.close(); clipboard.close();
} }
} }
@ -285,7 +303,7 @@ SInt32 CMSWindowsSecondaryScreen::getJumpZoneSize() const
} }
void CMSWindowsSecondaryScreen::getClipboard( void CMSWindowsSecondaryScreen::getClipboard(
IClipboard* dst) const ClipboardID id, IClipboard* dst) const
{ {
assert(m_window != NULL); assert(m_window != NULL);
@ -385,7 +403,8 @@ LRESULT CMSWindowsSecondaryScreen::onEvent(
// ownership). // ownership).
m_clipboardOwner = GetClipboardOwner(); m_clipboardOwner = GetClipboardOwner();
if (m_clipboardOwner != m_window) { if (m_clipboardOwner != m_window) {
m_client->onClipboardChanged(); m_client->onClipboardChanged(kClipboardClipboard);
m_client->onClipboardChanged(kClipboardSelection);
} }
return 0; return 0;
@ -887,33 +906,281 @@ static const UINT* g_mapTable[] =
/* 0xfc */ NULL, g_terminal, g_function, g_miscellany /* 0xfc */ NULL, g_terminal, g_function, g_miscellany
}; };
UINT CMSWindowsSecondaryScreen::mapKey( DWORD CMSWindowsSecondaryScreen::mapButton(
KeyID id, KeyModifierMask /*mask*/) const ButtonID button) const
{ {
const UInt32 mapID = ((id >> 8) & 0xff); // map button id to button flag
const UInt32 code = (id & 0xff); switch (button) {
case kButtonLeft:
return MOUSEEVENTF_LEFTDOWN;
// lookup the key table case kButtonMiddle:
const UINT* map = g_mapTable[mapID]; return MOUSEEVENTF_MIDDLEDOWN;
if (map == NULL) {
case kButtonRight:
return MOUSEEVENTF_RIGHTDOWN;
default:
return 0; return 0;
} }
}
if (mapID == 0) { KeyModifierMask CMSWindowsSecondaryScreen::mapKey(
SHORT scan = VkKeyScan(code); Keystrokes& keys,
if (scan != 0xffff) { UINT& virtualKey,
// FIXME -- must ensure shift state is correct. that means KeyID id, KeyModifierMask mask,
// tracking the shift state from the moment we enter until bool press) const
// the moment we leave (and probably disallowing leave if {
// any shift keys are down). if current shift state is // lookup the key table
// correct then do nothing extra, otherwise must surround const UInt32 mapID = ((id >> 8) & 0xff);
// injected key event with injected shift key events to const UINT* map = g_mapTable[mapID];
// get shift key in correct state then back to the previous if (map == NULL) {
// state. // unknown key
return (UINT)LOBYTE(scan); return m_mask;
}
// look up virtual key for id. default output mask carries over
// the current toggle modifier states.
const UInt32 code = (id & 0xff);
virtualKey = map[code];
KeyModifierMask outMask = (m_mask &
(KeyModifierCapsLock |
KeyModifierNumLock |
KeyModifierScrollLock));
// if not in map then ask system to convert ascii character
if (virtualKey == 0) {
if (mapID != 0) {
// not ascii
return m_mask;
}
// translate. return no keys if unknown key.
SHORT vk = VkKeyScan(code);
if (vk == 0xffff) {
return m_mask;
}
// convert system modifier mask to our mask
if (HIBYTE(vk) & 1)
outMask |= KeyModifierShift;
if (HIBYTE(vk) & 2)
outMask |= KeyModifierControl;
if (HIBYTE(vk) & 4)
outMask |= KeyModifierAlt;
// if caps-lock is on and so is shift then turn off caps-lock
if (outMask & (KeyModifierShift | KeyModifierCapsLock) ==
(KeyModifierShift | KeyModifierCapsLock))
outMask &= ~KeyModifierCapsLock;
// get virtual key
virtualKey = LOBYTE(vk);
}
// if in map then figure out correct modifier state
else {
// check numeric keypad. note that while KeyID distinguishes
// between the keypad movement keys (e.g. Home, left arrow),
// the virtual keys do not. however, the virtual keys do
// distinguish between keypad numbers and operators (e.g.
// add, multiply) and their main keyboard counterparts.
// therefore, we can ignore the num-lock state for movement
// virtual keys but not for numeric keys.
if (virtualKey >= VK_NUMPAD0 && virtualKey <= VK_DIVIDE) {
// set required shift state based on current numlock state
if ((outMask & KeyModifierNumLock) == 0)
outMask |= KeyModifierShift;
}
// FIXME -- should check for LeftTab KeySym
}
// a list of modifier key info
class CModifierInfo {
public:
KeyModifierMask mask;
UINT virtualKey;
UINT virtualKey2;
bool isToggle;
};
static const CModifierInfo s_modifier[] = {
{ KeyModifierShift, VK_LSHIFT, VK_RSHIFT, false },
{ KeyModifierControl, VK_LCONTROL, VK_RCONTROL, false },
{ KeyModifierAlt, VK_LMENU, VK_RMENU, false },
{ KeyModifierMeta, VK_LWIN, VK_RWIN, false },
{ KeyModifierCapsLock, VK_CAPITAL, 0, true },
{ KeyModifierNumLock, VK_NUMLOCK, 0, true },
{ KeyModifierScrollLock, VK_SCROLL, 0, true }
};
static const unsigned int s_numModifiers =
sizeof(s_modifier) / sizeof(s_modifier[0]);
// note if the key is a modifier
unsigned int modifierIndex;
switch (virtualKey) {
case VK_SHIFT:
case VK_LSHIFT:
case VK_RSHIFT:
modifierIndex = 0;
break;
case VK_CONTROL:
case VK_LCONTROL:
case VK_RCONTROL:
modifierIndex = 1;
break;
case VK_MENU:
case VK_LMENU:
case VK_RMENU:
modifierIndex = 2;
break;
case VK_LWIN:
case VK_RWIN:
modifierIndex = 3;
break;
case VK_CAPITAL:
modifierIndex = 4;
break;
case VK_NUMLOCK:
modifierIndex = 5;
break;
case VK_SCROLL:
modifierIndex = 6;
break;
default:
modifierIndex = s_numModifiers;
break;
}
const bool isModifier = (modifierIndex != s_numModifiers);
// add the key events required to get to the modifier state
// necessary to generate an event yielding id. also save the
// key events required to restore the state. if the key is
// a modifier key then skip this because modifiers should not
// modify modifiers.
Keystrokes undo;
if (outMask != m_mask && !isModifier) {
for (unsigned int i = 0; i < s_numModifiers; ++i) {
KeyModifierMask bit = s_modifier[i].mask;
if ((outMask & bit) != (m_mask & bit)) {
if ((outMask & bit) != 0) {
// modifier is not active but should be. if the
// modifier is a toggle then toggle it on with a
// press/release, otherwise activate it with a
// press.
const UINT modifierKey = s_modifier[i].virtualKey;
keys.push_back(std::make_pair(modifierKey, true));
if (s_modifier[i].isToggle) {
keys.push_back(std::make_pair(modifierKey, false));
undo.push_back(std::make_pair(modifierKey, false));
undo.push_back(std::make_pair(modifierKey, true));
}
else {
undo.push_back(std::make_pair(modifierKey, false));
} }
} }
// lookup the key in the table else {
return map[code]; // modifier is active but should not be. if the
// modifier is a toggle then toggle it off with a
// press/release, otherwise deactivate it with a
// release. we must check each keycode for the
// modifier if not a toggle.
if (s_modifier[i].isToggle) {
const UINT modifierKey = s_modifier[i].virtualKey;
keys.push_back(std::make_pair(modifierKey, true));
keys.push_back(std::make_pair(modifierKey, false));
undo.push_back(std::make_pair(modifierKey, false));
undo.push_back(std::make_pair(modifierKey, true));
}
else {
UINT key = s_modifier[i].virtualKey;
if ((m_keys[key] & 0x80) != 0) {
keys.push_back(std::make_pair(key, false));
undo.push_back(std::make_pair(key, true));
}
key = s_modifier[i].virtualKey2;
if ((m_keys[key] & 0x80) != 0) {
keys.push_back(std::make_pair(key, false));
undo.push_back(std::make_pair(key, true));
}
}
}
}
}
}
// add the key event
keys.push_back(std::make_pair(virtualKey, press));
// add key events to restore the modifier state. apply events in
// the reverse order that they're stored in undo.
while (!undo.empty()) {
keys.push_back(undo.back());
undo.pop_back();
}
// if the key is a modifier key then compute the modifier mask after
// this key is pressed.
mask = m_mask;
if (isModifier) {
// toggle keys modify the state on press if toggling on and on
// release if toggling off. other keys set the bit on press
// and clear the bit on release.
// FIXME -- verify if that's true on win32
if (s_modifier[modifierIndex].isToggle) {
if (((mask & s_modifier[modifierIndex].mask) == 0) == press)
mask ^= s_modifier[modifierIndex].mask;
}
else if (press) {
mask |= s_modifier[modifierIndex].mask;
}
else {
// can't reset bit until all keys that set it are released.
// scan those keys to see if any are pressed.
bool down = false;
if ((m_keys[s_modifier[modifierIndex].virtualKey] & 0x80) != 0) {
down = true;
}
if ((m_keys[s_modifier[modifierIndex].virtualKey2] & 0x80) != 0) {
down = true;
}
if (!down)
mask &= ~s_modifier[modifierIndex].mask;
}
}
return mask;
}
void CMSWindowsSecondaryScreen::updateKeys()
{
GetKeyboardState(m_keys);
}
void CMSWindowsSecondaryScreen::updateModifiers()
{
// update active modifier mask
m_mask = 0;
if ((m_keys[VK_LSHIFT] & 0x80) != 0 || (m_keys[VK_RSHIFT] & 0x80) != 0)
m_mask |= KeyModifierShift;
if ((m_keys[VK_LCONTROL] & 0x80) != 0 || (m_keys[VK_RCONTROL] & 0x80) != 0)
m_mask |= KeyModifierControl;
if ((m_keys[VK_LMENU] & 0x80) != 0 || (m_keys[VK_RMENU] & 0x80) != 0)
m_mask |= KeyModifierAlt;
if ((m_keys[VK_LWIN] & 0x80) != 0 || (m_keys[VK_RWIN] & 0x80) != 0)
m_mask |= KeyModifierMeta;
if ((m_keys[VK_CAPITAL] & 0x01) != 0)
m_mask |= KeyModifierCapsLock;
if ((m_keys[VK_NUMLOCK] & 0x01) != 0)
m_mask |= KeyModifierNumLock;
if ((m_keys[VK_SCROLL] & 0x01) != 0)
m_mask |= KeyModifierScrollLock;
} }

View File

@ -3,6 +3,8 @@
#include "CMSWindowsScreen.h" #include "CMSWindowsScreen.h"
#include "ISecondaryScreen.h" #include "ISecondaryScreen.h"
#include <map>
#include <vector>
class CMSWindowsSecondaryScreen : public CMSWindowsScreen, public ISecondaryScreen { class CMSWindowsSecondaryScreen : public CMSWindowsScreen, public ISecondaryScreen {
public: public:
@ -23,11 +25,11 @@ public:
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 setClipboard(ClipboardID, const IClipboard*);
virtual void grabClipboard(); virtual void grabClipboard(ClipboardID);
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(ClipboardID, IClipboard*) const;
protected: protected:
// CMSWindowsScreen overrides // CMSWindowsScreen overrides
@ -37,13 +39,27 @@ protected:
virtual void onCloseDisplay(); virtual void onCloseDisplay();
private: private:
UINT mapKey(KeyID, KeyModifierMask) const; typedef std::pair<UINT, bool> Keystroke;
typedef std::vector<Keystroke> Keystrokes;
DWORD mapButton(ButtonID button) const;
KeyModifierMask mapKey(Keystrokes&, UINT& virtualKey, KeyID,
KeyModifierMask, bool press) const;
void updateKeys();
void updateModifiers();
private: private:
CClient* m_client; CClient* m_client;
HWND m_window; HWND m_window;
HWND m_nextClipboardWindow; HWND m_nextClipboardWindow;
HWND m_clipboardOwner; HWND m_clipboardOwner;
// virtual key states
BYTE m_keys[256];
// current active modifiers
KeyModifierMask m_mask;
}; };
#endif #endif

View File

@ -6,6 +6,7 @@
#include "CThread.h" #include "CThread.h"
#include "CLog.h" #include "CLog.h"
#include <assert.h> #include <assert.h>
#include <string.h>
// //
// CMSWindowsPrimaryScreen // CMSWindowsPrimaryScreen
@ -86,6 +87,9 @@ void CMSWindowsPrimaryScreen::open(CServer* server)
// set the server // set the server
m_server = server; m_server = server;
// get keyboard state
updateKeys();
// open the display // open the display
openDisplay(); openDisplay();
@ -189,7 +193,8 @@ void CMSWindowsPrimaryScreen::leave()
try { try {
m_clipboardOwner = clipboardOwner; m_clipboardOwner = clipboardOwner;
if (m_clipboardOwner != m_window) { if (m_clipboardOwner != m_window) {
m_server->grabClipboard(); m_server->grabClipboard(kClipboardClipboard);
m_server->grabClipboard(kClipboardSelection);
} }
} }
catch (XBadClient&) { catch (XBadClient&) {
@ -209,7 +214,7 @@ void CMSWindowsPrimaryScreen::warpCursor(SInt32 x, SInt32 y)
} }
void CMSWindowsPrimaryScreen::setClipboard( void CMSWindowsPrimaryScreen::setClipboard(
const IClipboard* src) ClipboardID id, const IClipboard* src)
{ {
assert(m_window != NULL); assert(m_window != NULL);
@ -217,12 +222,12 @@ void CMSWindowsPrimaryScreen::setClipboard(
CClipboard::copy(&dst, src); CClipboard::copy(&dst, src);
} }
void CMSWindowsPrimaryScreen::grabClipboard() void CMSWindowsPrimaryScreen::grabClipboard(ClipboardID id)
{ {
assert(m_window != NULL); assert(m_window != NULL);
CMSWindowsClipboard clipboard(m_window); CMSWindowsClipboard clipboard(m_window);
if (clipboard.open()) { if (clipboard.open(0)) {
clipboard.close(); clipboard.close();
} }
} }
@ -239,7 +244,7 @@ SInt32 CMSWindowsPrimaryScreen::getJumpZoneSize() const
} }
void CMSWindowsPrimaryScreen::getClipboard( void CMSWindowsPrimaryScreen::getClipboard(
IClipboard* dst) const ClipboardID id, IClipboard* dst) const
{ {
assert(m_window != NULL); assert(m_window != NULL);
@ -349,24 +354,29 @@ if (IsDialogMessage(s_debug, msg)) {
if (m_mark == m_markReceived) { if (m_mark == m_markReceived) {
KeyModifierMask mask; KeyModifierMask mask;
const KeyID key = mapKey(msg->wParam, msg->lParam, &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 (key != kKeyNone) {
if ((msg->lParam & 0x80000000) == 0) { if ((msg->lParam & 0x80000000) == 0) {
// key press // key press
const SInt32 repeat = (SInt32)(msg->lParam & 0xffff); const SInt32 repeat = (SInt32)(msg->lParam & 0xffff);
if (repeat >= 2) { if (repeat >= 2) {
log((CLOG_DEBUG "event: key repeat key=%d mask=0x%04x count=%d", key, mask, repeat)); log((CLOG_DEBUG1 "event: key repeat key=%d mask=0x%04x count=%d", key, mask, repeat));
m_server->onKeyRepeat(key, mask, repeat); m_server->onKeyRepeat(key, mask, repeat);
} }
else { else {
log((CLOG_DEBUG "event: key press key=%d mask=0x%04x", key, mask)); log((CLOG_DEBUG1 "event: key press key=%d mask=0x%04x", key, mask));
m_server->onKeyDown(key, mask); m_server->onKeyDown(key, mask);
} }
// update key state
updateKey(msg->wParam, true);
} }
else { else {
// key release // key release
log((CLOG_DEBUG "event: key release key=%d mask=0x%04x", key, mask)); log((CLOG_DEBUG1 "event: key release key=%d mask=0x%04x", key, mask));
m_server->onKeyUp(key, mask); m_server->onKeyUp(key, mask);
// update key state
updateKey(msg->wParam, false);
} }
} }
@ -381,7 +391,7 @@ log((CLOG_DEBUG "event: key event vk=%d info=0x%08x", msg->wParam, msg->lParam))
case WM_LBUTTONDOWN: case WM_LBUTTONDOWN:
case WM_MBUTTONDOWN: case WM_MBUTTONDOWN:
case WM_RBUTTONDOWN: case WM_RBUTTONDOWN:
log((CLOG_DEBUG "event: button press button=%d", button)); log((CLOG_DEBUG1 "event: button press button=%d", button));
if (button != kButtonNone) { if (button != kButtonNone) {
m_server->onMouseDown(button); m_server->onMouseDown(button);
} }
@ -390,7 +400,7 @@ log((CLOG_DEBUG "event: key event vk=%d info=0x%08x", msg->wParam, msg->lParam))
case WM_LBUTTONUP: case WM_LBUTTONUP:
case WM_MBUTTONUP: case WM_MBUTTONUP:
case WM_RBUTTONUP: case WM_RBUTTONUP:
log((CLOG_DEBUG "event: button release button=%d", button)); log((CLOG_DEBUG1 "event: button release button=%d", button));
if (button != kButtonNone) { if (button != kButtonNone) {
m_server->onMouseUp(button); m_server->onMouseUp(button);
} }
@ -405,11 +415,11 @@ log((CLOG_DEBUG "event: key event vk=%d info=0x%08x", msg->wParam, msg->lParam))
SInt32 x = (SInt32)msg->wParam; SInt32 x = (SInt32)msg->wParam;
SInt32 y = (SInt32)msg->lParam; SInt32 y = (SInt32)msg->lParam;
if (!m_active) { if (!m_active) {
log((CLOG_DEBUG "event: inactive move %d,%d", x, y)); log((CLOG_DEBUG2 "event: inactive move %d,%d", x, y));
m_server->onMouseMovePrimary(x, y); m_server->onMouseMovePrimary(x, y);
} }
else { else {
log((CLOG_DEBUG "event: active move %d,%d", x, y)); log((CLOG_DEBUG2 "event: active move %d,%d", x, y));
// get screen size // get screen size
SInt32 w, h; SInt32 w, h;
@ -461,7 +471,8 @@ LRESULT CMSWindowsPrimaryScreen::onEvent(
try { try {
m_clipboardOwner = GetClipboardOwner(); m_clipboardOwner = GetClipboardOwner();
if (m_clipboardOwner != m_window) { if (m_clipboardOwner != m_window) {
m_server->grabClipboard(); m_server->grabClipboard(kClipboardClipboard);
m_server->grabClipboard(kClipboardSelection);
} }
} }
catch (XBadClient&) { catch (XBadClient&) {
@ -521,7 +532,7 @@ static const KeyID g_virtualKey[] =
/* 0x1d */ kKeyNone, // VK_NONCONVERT /* 0x1d */ kKeyNone, // VK_NONCONVERT
/* 0x1e */ kKeyNone, // VK_ACCEPT /* 0x1e */ kKeyNone, // VK_ACCEPT
/* 0x1f */ kKeyNone, // VK_MODECHANGE /* 0x1f */ kKeyNone, // VK_MODECHANGE
/* 0x20 */ 0xff20, // VK_SPACE XK_space /* 0x20 */ 0x0020, // VK_SPACE XK_space
/* 0x21 */ 0xff55, // VK_PRIOR XK_Prior /* 0x21 */ 0xff55, // VK_PRIOR XK_Prior
/* 0x22 */ 0xff56, // VK_NEXT XK_Next /* 0x22 */ 0xff56, // VK_NEXT XK_Next
/* 0x23 */ 0xff57, // VK_END XK_End /* 0x23 */ 0xff57, // VK_END XK_End
@ -537,16 +548,16 @@ static const KeyID g_virtualKey[] =
/* 0x2d */ 0xff63, // VK_INSERT XK_Insert /* 0x2d */ 0xff63, // VK_INSERT XK_Insert
/* 0x2e */ 0xffff, // VK_DELETE XK_Delete /* 0x2e */ 0xffff, // VK_DELETE XK_Delete
/* 0x2f */ 0xff6a, // VK_HELP XK_Help /* 0x2f */ 0xff6a, // VK_HELP XK_Help
/* 0x30 */ 0x0030, // VK_0 XK_0 /* 0x30 */ kKeyNone, // VK_0 XK_0
/* 0x31 */ 0x0031, // VK_1 XK_1 /* 0x31 */ kKeyNone, // VK_1 XK_1
/* 0x32 */ 0x0032, // VK_2 XK_2 /* 0x32 */ kKeyNone, // VK_2 XK_2
/* 0x33 */ 0x0033, // VK_3 XK_3 /* 0x33 */ kKeyNone, // VK_3 XK_3
/* 0x34 */ 0x0034, // VK_4 XK_4 /* 0x34 */ kKeyNone, // VK_4 XK_4
/* 0x35 */ 0x0035, // VK_5 XK_5 /* 0x35 */ kKeyNone, // VK_5 XK_5
/* 0x36 */ 0x0036, // VK_6 XK_6 /* 0x36 */ kKeyNone, // VK_6 XK_6
/* 0x37 */ 0x0037, // VK_7 XK_7 /* 0x37 */ kKeyNone, // VK_7 XK_7
/* 0x38 */ 0x0038, // VK_8 XK_8 /* 0x38 */ kKeyNone, // VK_8 XK_8
/* 0x39 */ 0x0039, // VK_9 XK_9 /* 0x39 */ kKeyNone, // VK_9 XK_9
/* 0x3a */ kKeyNone, // undefined /* 0x3a */ kKeyNone, // undefined
/* 0x3b */ kKeyNone, // undefined /* 0x3b */ kKeyNone, // undefined
/* 0x3c */ kKeyNone, // undefined /* 0x3c */ kKeyNone, // undefined
@ -554,32 +565,32 @@ static const KeyID g_virtualKey[] =
/* 0x3e */ kKeyNone, // undefined /* 0x3e */ kKeyNone, // undefined
/* 0x3f */ kKeyNone, // undefined /* 0x3f */ kKeyNone, // undefined
/* 0x40 */ kKeyNone, // undefined /* 0x40 */ kKeyNone, // undefined
/* 0x41 */ 0x0041, // VK_A XK_A /* 0x41 */ kKeyNone, // VK_A XK_A
/* 0x42 */ 0x0042, // VK_B XK_B /* 0x42 */ kKeyNone, // VK_B XK_B
/* 0x43 */ 0x0043, // VK_C XK_C /* 0x43 */ kKeyNone, // VK_C XK_C
/* 0x44 */ 0x0044, // VK_D XK_D /* 0x44 */ kKeyNone, // VK_D XK_D
/* 0x45 */ 0x0045, // VK_E XK_E /* 0x45 */ kKeyNone, // VK_E XK_E
/* 0x46 */ 0x0046, // VK_F XK_F /* 0x46 */ kKeyNone, // VK_F XK_F
/* 0x47 */ 0x0047, // VK_G XK_G /* 0x47 */ kKeyNone, // VK_G XK_G
/* 0x48 */ 0x0048, // VK_H XK_H /* 0x48 */ kKeyNone, // VK_H XK_H
/* 0x49 */ 0x0049, // VK_I XK_I /* 0x49 */ kKeyNone, // VK_I XK_I
/* 0x4a */ 0x004a, // VK_J XK_J /* 0x4a */ kKeyNone, // VK_J XK_J
/* 0x4b */ 0x004b, // VK_K XK_K /* 0x4b */ kKeyNone, // VK_K XK_K
/* 0x4c */ 0x004c, // VK_L XK_L /* 0x4c */ kKeyNone, // VK_L XK_L
/* 0x4d */ 0x004d, // VK_M XK_M /* 0x4d */ kKeyNone, // VK_M XK_M
/* 0x4e */ 0x004e, // VK_N XK_N /* 0x4e */ kKeyNone, // VK_N XK_N
/* 0x4f */ 0x004f, // VK_O XK_O /* 0x4f */ kKeyNone, // VK_O XK_O
/* 0x50 */ 0x0050, // VK_P XK_P /* 0x50 */ kKeyNone, // VK_P XK_P
/* 0x51 */ 0x0051, // VK_Q XK_Q /* 0x51 */ kKeyNone, // VK_Q XK_Q
/* 0x52 */ 0x0052, // VK_R XK_R /* 0x52 */ kKeyNone, // VK_R XK_R
/* 0x53 */ 0x0053, // VK_S XK_S /* 0x53 */ kKeyNone, // VK_S XK_S
/* 0x54 */ 0x0054, // VK_T XK_T /* 0x54 */ kKeyNone, // VK_T XK_T
/* 0x55 */ 0x0055, // VK_U XK_U /* 0x55 */ kKeyNone, // VK_U XK_U
/* 0x56 */ 0x0056, // VK_V XK_V /* 0x56 */ kKeyNone, // VK_V XK_V
/* 0x57 */ 0x0057, // VK_W XK_W /* 0x57 */ kKeyNone, // VK_W XK_W
/* 0x58 */ 0x0058, // VK_X XK_X /* 0x58 */ kKeyNone, // VK_X XK_X
/* 0x59 */ 0x0059, // VK_Y XK_Y /* 0x59 */ kKeyNone, // VK_Y XK_Y
/* 0x5a */ 0x005a, // VK_Z XK_Z /* 0x5a */ kKeyNone, // VK_Z XK_Z
/* 0x5b */ 0xffe7, // VK_LWIN XK_Meta_L /* 0x5b */ 0xffe7, // VK_LWIN XK_Meta_L
/* 0x5c */ 0xffe8, // VK_RWIN XK_Meta_R /* 0x5c */ 0xffe8, // VK_RWIN XK_Meta_R
/* 0x5d */ 0xff67, // VK_APPS XK_Menu /* 0x5d */ 0xff67, // VK_APPS XK_Menu
@ -649,12 +660,12 @@ static const KeyID g_virtualKey[] =
/* 0x9d */ kKeyNone, // unassigned /* 0x9d */ kKeyNone, // unassigned
/* 0x9e */ kKeyNone, // unassigned /* 0x9e */ kKeyNone, // unassigned
/* 0x9f */ kKeyNone, // unassigned /* 0x9f */ kKeyNone, // unassigned
/* 0xa0 */ kKeyNone, // unassigned /* 0xa0 */ 0xffe1, // VK_LSHIFT XK_Shift_L
/* 0xa1 */ kKeyNone, // unassigned /* 0xa1 */ 0xffe2, // VK_RSHIFT XK_Shift_R
/* 0xa2 */ kKeyNone, // unassigned /* 0xa2 */ 0xffe3, // VK_LCONTROL XK_Control_L
/* 0xa3 */ kKeyNone, // unassigned /* 0xa3 */ 0xffe4, // VK_RCONTROL XK_Control_R
/* 0xa4 */ kKeyNone, // unassigned /* 0xa4 */ 0xffe9, // VK_LMENU XK_Alt_L
/* 0xa5 */ kKeyNone, // unassigned /* 0xa5 */ 0xffea, // VK_RMENU XK_Alt_R
/* 0xa6 */ kKeyNone, // unassigned /* 0xa6 */ kKeyNone, // unassigned
/* 0xa7 */ kKeyNone, // unassigned /* 0xa7 */ kKeyNone, // unassigned
/* 0xa8 */ kKeyNone, // unassigned /* 0xa8 */ kKeyNone, // unassigned
@ -749,69 +760,157 @@ static const KeyID g_virtualKey[] =
KeyID CMSWindowsPrimaryScreen::mapKey( KeyID CMSWindowsPrimaryScreen::mapKey(
WPARAM vkCode, LPARAM info, WPARAM vkCode, LPARAM info,
KeyModifierMask* maskOut) const KeyModifierMask* maskOut)
{ {
// note: known microsoft bugs
// Q72583 -- MapVirtualKey() maps keypad keys incorrectly
// 95,98: num pad vk code -> invalid scan code
// 95,98,NT4: num pad scan code -> bad vk code except
// SEPARATOR, MULTIPLY, SUBTRACT, ADD
static const KeyID XK_Multi_key = 0xff20;
assert(maskOut != NULL); assert(maskOut != NULL);
// map modifier key // map modifier key
// FIXME -- should be configurable?
KeyModifierMask mask = 0; KeyModifierMask mask = 0;
if (GetKeyState(VK_SHIFT) < 0) if (((m_keys[VK_LSHIFT] |
m_keys[VK_RSHIFT] |
m_keys[VK_SHIFT]) & 0x80) != 0)
mask |= KeyModifierShift; mask |= KeyModifierShift;
if ((GetKeyState(VK_CAPITAL) & 1) != 0) if (((m_keys[VK_LCONTROL] |
mask |= KeyModifierCapsLock; m_keys[VK_RCONTROL] |
if (GetKeyState(VK_CONTROL) < 0) m_keys[VK_CONTROL]) & 0x80) != 0)
mask |= KeyModifierControl; mask |= KeyModifierControl;
if (GetKeyState(VK_MENU) < 0) if (((m_keys[VK_LMENU] |
m_keys[VK_RMENU] |
m_keys[VK_MENU]) & 0x80) != 0)
mask |= KeyModifierAlt; mask |= KeyModifierAlt;
if ((GetKeyState(VK_NUMLOCK) & 1) != 0) if (((m_keys[VK_LWIN] |
mask |= KeyModifierNumLock; m_keys[VK_RWIN]) & 0x80) != 0)
if (GetKeyState(VK_LWIN) < 0 || GetKeyState(VK_RWIN) < 0)
mask |= KeyModifierMeta; mask |= KeyModifierMeta;
if ((GetKeyState(VK_SCROLL) & 1) != 0) if ((m_keys[VK_CAPITAL] & 0x01) != 0)
mask |= KeyModifierCapsLock;
if ((m_keys[VK_NUMLOCK] & 0x01) != 0)
mask |= KeyModifierNumLock;
if ((m_keys[VK_SCROLL] & 0x01) != 0)
mask |= KeyModifierScrollLock; mask |= KeyModifierScrollLock;
*maskOut = mask; *maskOut = mask;
// get the scan code
UINT scanCode = static_cast<UINT>((info & 0xff0000) >> 16);
// convert virtual key to one that distinguishes between left and
// right for keys that have left/right versions. known scan codes
// that don't have left/right versions are passed through unchanged.
// unknown scan codes return 0.
UINT vkCode2 = MapVirtualKey(scanCode, 3);
// work around bug Q72583 (bad num pad conversion in MapVirtualKey())
if (vkCode >= VK_NUMPAD0 && vkCode <= VK_DIVIDE)
vkCode2 = vkCode;
// MapVirtualKey() appears to map VK_LWIN, VK_RWIN, VK_APPS to
// some other meaningless virtual key. work around that bug.
else if (vkCode >= VK_LWIN && vkCode <= VK_APPS)
vkCode2 = vkCode;
// sadly, win32 will not distinguish between the left and right
// control and alt keys using the above function. however, we
// can check for those: if bit 24 of info is set then the key
// is a "extended" key, such as the right control and right alt
// keys.
if ((info & 0x1000000) != 0) {
switch (vkCode2) {
case VK_LCONTROL:
vkCode2 = VK_RCONTROL;
break;
case VK_LMENU:
vkCode2 = VK_RMENU;
break;
}
}
// use left/right distinguishing virtual key
vkCode = vkCode2;
log((CLOG_DEBUG1 "key vk=%d scan=%d", vkCode, scanCode));
// handle some keys via table lookup
KeyID id = g_virtualKey[vkCode]; KeyID id = g_virtualKey[vkCode];
if (id != kKeyNone) { if (id != kKeyNone) {
return id; return id;
} }
BYTE state[256]; // check for dead keys
GetKeyboardState(state); if (MapVirtualKey(vkCode, 2) >= 0x8000) {
return XK_Multi_key;
}
// ToAscii() maps ctrl+letter to the corresponding control code
// and ctrl+backspace to delete. if we've got a control code or
// delete then do ToAscii() again but without the control state.
// ToAscii() interprets the control modifier state which we don't
// want. so save the control state then clear it.
BYTE lControl = m_keys[VK_LCONTROL];
BYTE rControl = m_keys[VK_RCONTROL];
BYTE control = m_keys[VK_CONTROL];
m_keys[VK_LCONTROL] = 0;
m_keys[VK_RCONTROL] = 0;
m_keys[VK_CONTROL] = 0;
// convert to ascii
WORD ascii; WORD ascii;
int result = ToAscii(vkCode, MapVirtualKey(0, vkCode), state, &ascii, 0); int result = ToAscii(vkCode, scanCode, m_keys, &ascii, 0);
if (result > 0) {
// FIXME -- handle dead keys // restore control state
return (KeyID)(ascii & 0x00ff); m_keys[VK_LCONTROL] = lControl;
m_keys[VK_RCONTROL] = rControl;
m_keys[VK_CONTROL] = control;
// if result is less than zero then it was a dead key. that key
// is remembered by the keyboard which we don't want. remove it
// by calling ToAscii() again with arbitrary arguments.
if (result < 0) {
ToAscii(vkCode, scanCode, m_keys, &ascii, 0);
return XK_Multi_key;
} }
// if result is 1 then the key was succesfully converted
else if (result == 1) {
return static_cast<KeyID>(ascii & 0x00ff);
}
// if result is 2 then a previous dead key could not be composed.
// put the old dead key back.
else if (result == 2) {
// get the scan code of the dead key and the shift state
// required to generate it.
vkCode = VkKeyScan(ascii & 0x00ff);
// set shift state required to generate key
BYTE keys[256];
memset(keys, 0, sizeof(keys));
if (vkCode & 0x0100)
keys[VK_SHIFT] = 0x80;
if (vkCode & 0x0100)
keys[VK_CONTROL] = 0x80;
if (vkCode & 0x0100)
keys[VK_MENU] = 0x80;
// strip shift state off of virtual key code
vkCode &= 0x00ff;
// get the scan code for the key
scanCode = MapVirtualKey(vkCode, 0);
// put it back
ToAscii(vkCode, scanCode, keys, &ascii, 0);
return XK_Multi_key;
}
// cannot convert key
return kKeyNone; 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(
@ -834,3 +933,117 @@ ButtonID CMSWindowsPrimaryScreen::mapButton(
return kButtonNone; return kButtonNone;
} }
} }
void CMSWindowsPrimaryScreen::updateKeys()
{
// clear key state
memset(m_keys, 0, sizeof(m_keys));
// we only care about the modifier key states
m_keys[VK_LSHIFT] = GetKeyState(VK_LSHIFT);
m_keys[VK_RSHIFT] = GetKeyState(VK_RSHIFT);
m_keys[VK_SHIFT] = GetKeyState(VK_SHIFT);
m_keys[VK_LCONTROL] = GetKeyState(VK_LCONTROL);
m_keys[VK_RCONTROL] = GetKeyState(VK_RCONTROL);
m_keys[VK_CONTROL] = GetKeyState(VK_CONTROL);
m_keys[VK_LMENU] = GetKeyState(VK_LMENU);
m_keys[VK_RMENU] = GetKeyState(VK_RMENU);
m_keys[VK_MENU] = GetKeyState(VK_MENU);
m_keys[VK_LWIN] = GetKeyState(VK_LWIN);
m_keys[VK_RWIN] = GetKeyState(VK_RWIN);
m_keys[VK_APPS] = GetKeyState(VK_APPS);
m_keys[VK_CAPITAL] = GetKeyState(VK_CAPITAL);
m_keys[VK_NUMLOCK] = GetKeyState(VK_NUMLOCK);
m_keys[VK_SCROLL] = GetKeyState(VK_SCROLL);
}
void CMSWindowsPrimaryScreen::updateKey(
UINT vkCode, bool press)
{
if (press) {
switch (vkCode) {
case VK_LSHIFT:
case VK_RSHIFT:
case VK_SHIFT:
m_keys[vkCode] |= 0x80;
m_keys[VK_SHIFT] |= 0x80;
break;
case VK_LCONTROL:
case VK_RCONTROL:
case VK_CONTROL:
m_keys[vkCode] |= 0x80;
m_keys[VK_CONTROL] |= 0x80;
break;
case VK_LMENU:
case VK_RMENU:
case VK_MENU:
m_keys[vkCode] |= 0x80;
m_keys[VK_MENU] |= 0x80;
break;
case VK_LWIN:
case VK_RWIN:
case VK_APPS:
m_keys[vkCode] |= 0x80;
break;
case VK_CAPITAL:
case VK_NUMLOCK:
case VK_SCROLL:
// toggle keys
m_keys[vkCode] |= 0x80;
if ((m_keys[vkCode] & 0x01) == 0) {
m_keys[vkCode] |= 0x01;
}
break;
}
}
else {
switch (vkCode) {
case VK_LSHIFT:
case VK_RSHIFT:
case VK_SHIFT:
m_keys[vkCode] &= ~0x80;
if (((m_keys[VK_LSHIFT] | m_keys[VK_RSHIFT]) & 0x80) == 0) {
m_keys[VK_SHIFT] &= ~0x80;
}
break;
case VK_LCONTROL:
case VK_RCONTROL:
case VK_CONTROL:
m_keys[vkCode] &= ~0x80;
if (((m_keys[VK_LCONTROL] | m_keys[VK_RCONTROL]) & 0x80) == 0) {
m_keys[VK_CONTROL] &= ~0x80;
}
break;
case VK_LMENU:
case VK_RMENU:
case VK_MENU:
m_keys[vkCode] &= ~0x80;
if (((m_keys[VK_LMENU] | m_keys[VK_RMENU]) & 0x80) == 0) {
m_keys[VK_MENU] &= ~0x80;
}
break;
case VK_LWIN:
case VK_RWIN:
case VK_APPS:
m_keys[vkCode] &= ~0x80;
break;
case VK_CAPITAL:
case VK_NUMLOCK:
case VK_SCROLL:
// toggle keys
m_keys[vkCode] &= ~0x80;
if ((m_keys[vkCode] & 0x01) != 0) {
m_keys[vkCode] &= ~0x01;
}
break;
}
}
}

View File

@ -21,11 +21,11 @@ public:
virtual void enter(SInt32 xAbsolute, SInt32 yAbsolute); virtual void enter(SInt32 xAbsolute, SInt32 yAbsolute);
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(ClipboardID, const IClipboard*);
virtual void grabClipboard(); virtual void grabClipboard(ClipboardID);
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(ClipboardID, IClipboard*) const;
protected: protected:
// CMSWindowsScreen overrides // CMSWindowsScreen overrides
@ -40,8 +40,10 @@ private:
void nextMark(); void nextMark();
KeyID mapKey(WPARAM keycode, LPARAM info, KeyID mapKey(WPARAM keycode, LPARAM info,
KeyModifierMask* maskOut) const; KeyModifierMask* maskOut);
ButtonID mapButton(WPARAM button) const; ButtonID mapButton(WPARAM button) const;
void updateKeys();
void updateKey(UINT vkCode, bool press);
private: private:
CServer* m_server; CServer* m_server;
@ -53,6 +55,7 @@ private:
HINSTANCE m_hookLibrary; HINSTANCE m_hookLibrary;
UInt32 m_mark; UInt32 m_mark;
UInt32 m_markReceived; UInt32 m_markReceived;
BYTE m_keys[256];
}; };
#endif #endif

View File

@ -118,7 +118,7 @@ void CServerProtocol1_0::sendGrabClipboard(ClipboardID id)
void CServerProtocol1_0::sendScreenSaver(bool on) void CServerProtocol1_0::sendScreenSaver(bool on)
{ {
log((CLOG_DEBUG1 "send screen saver to \"%s\"", getClient().c_str())); log((CLOG_DEBUG1 "send screen saver to \"%s\" on=%d", getClient().c_str(), on ? 1 : 0));
CProtocolUtil::writef(getOutputStream(), kMsgCScreenSaver, on ? 1 : 0); CProtocolUtil::writef(getOutputStream(), kMsgCScreenSaver, on ? 1 : 0);
} }
@ -132,7 +132,7 @@ void CServerProtocol1_0::sendKeyDown(
void CServerProtocol1_0::sendKeyRepeat( void CServerProtocol1_0::sendKeyRepeat(
KeyID key, KeyModifierMask mask, SInt32 count) KeyID key, KeyModifierMask mask, SInt32 count)
{ {
log((CLOG_DEBUG1 "send key repeat to \"%s\" id=%d, mask=0x%04x", getClient().c_str(), key, mask)); log((CLOG_DEBUG1 "send key repeat to \"%s\" id=%d, mask=0x%04x, count=%d", getClient().c_str(), key, mask, count));
CProtocolUtil::writef(getOutputStream(), kMsgDKeyRepeat, key, mask, count); CProtocolUtil::writef(getOutputStream(), kMsgDKeyRepeat, key, mask, count);
} }
@ -167,7 +167,7 @@ void CServerProtocol1_0::sendMouseMove(
void CServerProtocol1_0::sendMouseWheel( void CServerProtocol1_0::sendMouseWheel(
SInt32 delta) SInt32 delta)
{ {
log((CLOG_DEBUG1 "send mouse wheel to \"%s\" %+d", getClient().c_str(), delta)); log((CLOG_DEBUG2 "send mouse wheel to \"%s\" %+d", getClient().c_str(), delta));
CProtocolUtil::writef(getOutputStream(), kMsgDMouseWheel, delta); CProtocolUtil::writef(getOutputStream(), kMsgDMouseWheel, delta);
} }

View File

@ -52,12 +52,12 @@ END
// Dialog // Dialog
// //
IDD_SYNERGY DIALOG DISCARDABLE 0, 0, 329, 158 IDD_SYNERGY DIALOG DISCARDABLE 0, 0, 531, 159
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Synergy" CAPTION "Synergy"
FONT 8, "MS Sans Serif" FONT 8, "MS Sans Serif"
BEGIN BEGIN
EDITTEXT IDC_LOG,7,7,315,144,ES_MULTILINE | ES_AUTOHSCROLL | EDITTEXT IDC_LOG,7,7,517,145,ES_MULTILINE | ES_AUTOHSCROLL |
ES_READONLY | WS_VSCROLL | WS_HSCROLL ES_READONLY | WS_VSCROLL | WS_HSCROLL
END END
@ -73,9 +73,9 @@ BEGIN
IDD_SYNERGY, DIALOG IDD_SYNERGY, DIALOG
BEGIN BEGIN
LEFTMARGIN, 7 LEFTMARGIN, 7
RIGHTMARGIN, 322 RIGHTMARGIN, 524
TOPMARGIN, 7 TOPMARGIN, 7
BOTTOMMARGIN, 151 BOTTOMMARGIN, 152
END END
END END
#endif // APSTUDIO_INVOKED #endif // APSTUDIO_INVOKED

View File

@ -1,4 +1,5 @@
#include "CClipboard.h" #include "CClipboard.h"
#include <assert.h>
// //
// CClipboard // CClipboard
@ -92,7 +93,7 @@ void CClipboard::unmarshall(const CString& data, Time time)
index += 4; index += 4;
// read each format // read each format
for (UInt32 format = 0; format < numFormats; ++format) { for (UInt32 i = 0; i < numFormats; ++i) {
// get the format id // get the format id
UInt32 format = readUInt32(index); UInt32 format = readUInt32(index);
index += 4; index += 4;
@ -144,10 +145,11 @@ CString CClipboard::marshall() const
UInt32 CClipboard::readUInt32(const char* buf) const UInt32 CClipboard::readUInt32(const char* buf) const
{ {
return (static_cast<UInt32>(buf[0]) << 24) | const unsigned char* ubuf = reinterpret_cast<const unsigned char*>(buf);
(static_cast<UInt32>(buf[1]) << 16) | return (static_cast<UInt32>(ubuf[0]) << 24) |
(static_cast<UInt32>(buf[2]) << 8) | (static_cast<UInt32>(ubuf[1]) << 16) |
static_cast<UInt32>(buf[3]); (static_cast<UInt32>(ubuf[2]) << 8) |
static_cast<UInt32>(ubuf[3]);
} }
void CClipboard::writeUInt32(CString* buf, UInt32 v) const void CClipboard::writeUInt32(CString* buf, UInt32 v) const

View File

@ -6,7 +6,9 @@
// CMSWindowsClipboard // CMSWindowsClipboard
// //
CMSWindowsClipboard::CMSWindowsClipboard(HWND window) : m_window(window) CMSWindowsClipboard::CMSWindowsClipboard(HWND window) :
m_window(window),
m_time(0)
{ {
// do nothing // do nothing
} }
@ -16,7 +18,7 @@ CMSWindowsClipboard::~CMSWindowsClipboard()
// do nothing // do nothing
} }
bool CMSWindowsClipboard::open() bool CMSWindowsClipboard::open(Time time)
{ {
log((CLOG_INFO "open clipboard")); log((CLOG_INFO "open clipboard"));
@ -29,7 +31,12 @@ bool CMSWindowsClipboard::open()
} }
else { else {
log((CLOG_WARN "failed to grab clipboard")); log((CLOG_WARN "failed to grab clipboard"));
CloseClipboard();
return false;
} }
m_time = time;
return true; return true;
} }
@ -71,6 +78,11 @@ void CMSWindowsClipboard::add(
CloseClipboard(); CloseClipboard();
} }
IClipboard::Time CMSWindowsClipboard::getTime() const
{
return m_time;
}
bool CMSWindowsClipboard::has(EFormat format) const bool CMSWindowsClipboard::has(EFormat format) const
{ {
const UINT win32Format = convertFormatToWin32(format); const UINT win32Format = convertFormatToWin32(format);
@ -122,7 +134,7 @@ HANDLE CMSWindowsClipboard::convertTextToWin32(
const CString& data) const const CString& data) const
{ {
// compute size of converted text // compute size of converted text
UInt32 dstSize = 0; UInt32 dstSize = 1;
const UInt32 srcSize = data.size(); const UInt32 srcSize = data.size();
const char* src = data.c_str(); const char* src = data.c_str();
for (UInt32 index = 0; index < srcSize; ++index) { for (UInt32 index = 0; index < srcSize; ++index) {
@ -148,6 +160,7 @@ HANDLE CMSWindowsClipboard::convertTextToWin32(
} }
dst[dstSize++] = src[index]; dst[dstSize++] = src[index];
} }
dst[dstSize] = '\0';
// done converting // done converting
GlobalUnlock(gData); GlobalUnlock(gData);
@ -162,9 +175,12 @@ CString CMSWindowsClipboard::convertTextFromWin32(
// get source data and it's size // get source data and it's size
const char* src = (const char*)GlobalLock(handle); const char* src = (const char*)GlobalLock(handle);
UInt32 srcSize = (SInt32)GlobalSize(handle); UInt32 srcSize = (SInt32)GlobalSize(handle);
if (src == NULL || srcSize == 0) if (src == NULL || srcSize <= 1)
return CString(); return CString();
// ignore trailing NUL
--srcSize;
// compute size of converted text // compute size of converted text
UInt32 dstSize = 0; UInt32 dstSize = 0;
UInt32 index; UInt32 index;

View File

@ -10,9 +10,10 @@ public:
virtual ~CMSWindowsClipboard(); virtual ~CMSWindowsClipboard();
// IClipboard overrides // IClipboard overrides
virtual bool open(); virtual bool open(Time);
virtual void close(); virtual void close();
virtual void add(EFormat, const CString& data); virtual void add(EFormat, const CString& data);
virtual Time getTime() const;
virtual bool has(EFormat) const; virtual bool has(EFormat) const;
virtual CString get(EFormat) const; virtual CString get(EFormat) const;
@ -23,6 +24,7 @@ private:
private: private:
HWND m_window; HWND m_window;
Time m_time;
}; };
#endif #endif

View File

@ -131,6 +131,10 @@ SOURCE=.\CInputPacketStream.h
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\ClipboardTypes.h
# End Source File
# Begin Source File
SOURCE=.\CMSWindowsClipboard.h SOURCE=.\CMSWindowsClipboard.h
# End Source File # End Source File
# Begin Source File # Begin Source File