From dc195706215c4e176256a7a0d4110489978567a0 Mon Sep 17 00:00:00 2001 From: crs Date: Tue, 30 Apr 2002 16:23:03 +0000 Subject: [PATCH] Fixes to get win32 client and server up to date. --- client/CClient.cpp | 29 +- client/CMSWindowsSecondaryScreen.cpp | 421 ++++++++++++++++++++++----- client/CMSWindowsSecondaryScreen.h | 24 +- server/CMSWindowsPrimaryScreen.cpp | 411 +++++++++++++++++++------- server/CMSWindowsPrimaryScreen.h | 11 +- server/CServerProtocol1_0.cpp | 6 +- server/server.rc | 8 +- synergy/CClipboard.cpp | 12 +- synergy/CMSWindowsClipboard.cpp | 24 +- synergy/CMSWindowsClipboard.h | 4 +- synergy/synergy.dsp | 4 + 11 files changed, 746 insertions(+), 208 deletions(-) diff --git a/client/CClient.cpp b/client/CClient.cpp index f41dc791..2e278cb7 100644 --- a/client/CClient.cpp +++ b/client/CClient.cpp @@ -116,7 +116,10 @@ void CClient::onClipboardChanged(ClipboardID id) // send data log((CLOG_DEBUG "sending clipboard %d seqnum=%d, size=%d", id, m_seqNum, data.size())); - CProtocolUtil::writef(m_output, kMsgDClipboard, id, m_seqNum, &data); + if (m_output != NULL) { +// FIXME -- will we send the clipboard when we connect? + CProtocolUtil::writef(m_output, kMsgDClipboard, id, m_seqNum, &data); + } } } @@ -200,7 +203,7 @@ void CClient::runSession(void*) // handle messages from server for (;;) { // wait for reply - log((CLOG_DEBUG1 "waiting for message")); + log((CLOG_DEBUG2 "waiting for message")); UInt8 code[4]; UInt32 n = input->read(code, 4); @@ -259,6 +262,7 @@ void CClient::runSession(void*) } else if (memcmp(code, kMsgCClose, 4) == 0) { // server wants us to hangup + log((CLOG_DEBUG1 "recv close")); break; } else { @@ -342,11 +346,14 @@ void CClient::onEnter() CProtocolUtil::readf(m_input, kMsgCEnter + 4, &x, &y, &m_seqNum); m_active = true; } + log((CLOG_DEBUG1 "recv enter, %d,%d %d", x, y, m_seqNum)); m_screen->enter(x, y); } void CClient::onLeave() { + log((CLOG_DEBUG1 "recv leave")); + // tell screen we're leaving m_screen->leave(); @@ -391,7 +398,7 @@ void CClient::onGrabClipboard() { CLock lock(&m_mutex); 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 if (id >= kClipboardEnd) { @@ -411,6 +418,7 @@ void CClient::onScreenSaver() CLock lock(&m_mutex); CProtocolUtil::readf(m_input, kMsgCScreenSaver + 4, &on); } + log((CLOG_DEBUG1 "recv screen saver on=%d", on)); // FIXME } @@ -435,7 +443,7 @@ void CClient::onSetClipboard() CLock lock(&m_mutex); 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 if (id >= kClipboardEnd) { @@ -452,22 +460,24 @@ void CClient::onSetClipboard() void CClient::onKeyDown() { - SInt16 id, mask; + UInt16 id, mask; { CLock lock(&m_mutex); 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(id), static_cast(mask)); } void CClient::onKeyRepeat() { - SInt16 id, mask, count; + UInt16 id, mask, count; { CLock lock(&m_mutex); 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(id), static_cast(mask), count); @@ -475,11 +485,12 @@ void CClient::onKeyRepeat() void CClient::onKeyUp() { - SInt16 id, mask; + UInt16 id, mask; { CLock lock(&m_mutex); 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(id), static_cast(mask)); } @@ -491,6 +502,7 @@ void CClient::onMouseDown() CLock lock(&m_mutex); CProtocolUtil::readf(m_input, kMsgDMouseDown + 4, &id); } + log((CLOG_DEBUG1 "recv mouse down id=%d", id)); m_screen->mouseDown(static_cast(id)); } @@ -501,6 +513,7 @@ void CClient::onMouseUp() CLock lock(&m_mutex); CProtocolUtil::readf(m_input, kMsgDMouseUp + 4, &id); } + log((CLOG_DEBUG1 "recv mouse up id=%d", id)); m_screen->mouseUp(static_cast(id)); } @@ -511,6 +524,7 @@ void CClient::onMouseMove() CLock lock(&m_mutex); CProtocolUtil::readf(m_input, kMsgDMouseMove + 4, &x, &y); } + log((CLOG_DEBUG2 "recv mouse move %d,%d", x, y)); m_screen->mouseMove(x, y); } @@ -521,5 +535,6 @@ void CClient::onMouseWheel() CLock lock(&m_mutex); CProtocolUtil::readf(m_input, kMsgDMouseWheel + 4, &delta); } + log((CLOG_DEBUG2 "recv mouse wheel %+d", delta)); m_screen->mouseWheel(delta); } diff --git a/client/CMSWindowsSecondaryScreen.cpp b/client/CMSWindowsSecondaryScreen.cpp index 74ce2874..e1dc6ab4 100644 --- a/client/CMSWindowsSecondaryScreen.cpp +++ b/client/CMSWindowsSecondaryScreen.cpp @@ -86,6 +86,14 @@ void CMSWindowsSecondaryScreen::open(CClient* client) // open the display openDisplay(); + + // update key state + updateKeys(); + updateModifiers(); + + // assume primary has all clipboards + for (ClipboardID id = 0; id < kClipboardEnd; ++id) + grabClipboard(id); } void CMSWindowsSecondaryScreen::close() @@ -118,6 +126,10 @@ void CMSWindowsSecondaryScreen::enter(SInt32 x, SInt32 y) // show cursor log((CLOG_INFO "show cursor")); ShowWindow(m_window, SW_HIDE); + + // update our keyboard state to reflect the local state + updateKeys(); + updateModifiers(); } void CMSWindowsSecondaryScreen::leave() @@ -151,7 +163,8 @@ void CMSWindowsSecondaryScreen::leave() if (m_clipboardOwner != clipboardOwner) { m_clipboardOwner = clipboardOwner; 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( KeyID key, KeyModifierMask mask) { - const UINT vkey = mapKey(key, mask); - if (vkey != 0) { - const UINT code = MapVirtualKey(vkey, 0); - keybd_event(vkey, code, 0, 0); + Keystrokes keys; + UINT virtualKey; + + // 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( KeyID key, KeyModifierMask mask, SInt32 count) { - const UINT vkey = mapKey(key, mask); - if (vkey != 0) { - const UINT code = MapVirtualKey(vkey, 0); - for (SInt32 i = 0; i < count; ++i) { - keybd_event(vkey, code, KEYEVENTF_KEYUP, 0); - keybd_event(vkey, code, 0, 0); + Keystrokes keys; + UINT virtualKey; + + // 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 (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); } } } @@ -182,61 +218,43 @@ void CMSWindowsSecondaryScreen::keyRepeat( void CMSWindowsSecondaryScreen::keyUp( KeyID key, KeyModifierMask mask) { - const UINT vkey = mapKey(key, mask); - if (vkey != 0) { - const UINT code = MapVirtualKey(vkey, 0); - keybd_event(vkey, code, KEYEVENTF_KEYUP, 0); + Keystrokes keys; + UINT virtualKey; + + // 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) { // map button id to button flag - DWORD flags; - switch (button) { - case kButtonLeft: - flags = MOUSEEVENTF_LEFTDOWN; - break; - - case kButtonMiddle: - flags = MOUSEEVENTF_MIDDLEDOWN; - break; - - case kButtonRight: - flags = MOUSEEVENTF_RIGHTDOWN; - break; - - default: - return; - } + DWORD flags = mapButton(button); // send event - mouse_event(flags, 0, 0, 0, 0); + if (flags != 0) + mouse_event(flags, 0, 0, 0, 0); } void CMSWindowsSecondaryScreen::mouseUp(ButtonID button) { // map button id to button flag - DWORD flags; - switch (button) { - case kButtonLeft: - flags = MOUSEEVENTF_LEFTUP; - break; - - case kButtonMiddle: - flags = MOUSEEVENTF_MIDDLEUP; - break; - - case kButtonRight: - flags = MOUSEEVENTF_RIGHTUP; - break; - - default: - return; - } + DWORD flags = mapButton(button); // send event - mouse_event(flags, 0, 0, 0, 0); + if (flags != 0) + mouse_event(flags, 0, 0, 0, 0); } void CMSWindowsSecondaryScreen::mouseMove(SInt32 x, SInt32 y) @@ -255,7 +273,7 @@ void CMSWindowsSecondaryScreen::mouseWheel(SInt32 delta) } void CMSWindowsSecondaryScreen::setClipboard( - const IClipboard* src) + ClipboardID id, const IClipboard* src) { assert(m_window != NULL); @@ -263,12 +281,12 @@ void CMSWindowsSecondaryScreen::setClipboard( CClipboard::copy(&dst, src); } -void CMSWindowsSecondaryScreen::grabClipboard() +void CMSWindowsSecondaryScreen::grabClipboard(ClipboardID id) { assert(m_window != NULL); CMSWindowsClipboard clipboard(m_window); - if (clipboard.open()) { + if (clipboard.open(0)) { clipboard.close(); } } @@ -285,7 +303,7 @@ SInt32 CMSWindowsSecondaryScreen::getJumpZoneSize() const } void CMSWindowsSecondaryScreen::getClipboard( - IClipboard* dst) const + ClipboardID id, IClipboard* dst) const { assert(m_window != NULL); @@ -385,7 +403,8 @@ LRESULT CMSWindowsSecondaryScreen::onEvent( // ownership). m_clipboardOwner = GetClipboardOwner(); if (m_clipboardOwner != m_window) { - m_client->onClipboardChanged(); + m_client->onClipboardChanged(kClipboardClipboard); + m_client->onClipboardChanged(kClipboardSelection); } return 0; @@ -887,33 +906,281 @@ static const UINT* g_mapTable[] = /* 0xfc */ NULL, g_terminal, g_function, g_miscellany }; -UINT CMSWindowsSecondaryScreen::mapKey( - KeyID id, KeyModifierMask /*mask*/) const +DWORD CMSWindowsSecondaryScreen::mapButton( + ButtonID button) const { - const UInt32 mapID = ((id >> 8) & 0xff); - const UInt32 code = (id & 0xff); + // map button id to button flag + switch (button) { + case kButtonLeft: + return MOUSEEVENTF_LEFTDOWN; - // lookup the key table - const UINT* map = g_mapTable[mapID]; - if (map == NULL) { + case kButtonMiddle: + return MOUSEEVENTF_MIDDLEDOWN; + + case kButtonRight: + return MOUSEEVENTF_RIGHTDOWN; + + default: return 0; } +} - if (mapID == 0) { - SHORT scan = VkKeyScan(code); - if (scan != 0xffff) { - // FIXME -- must ensure shift state is correct. that means - // tracking the shift state from the moment we enter until - // the moment we leave (and probably disallowing leave if - // any shift keys are down). if current shift state is - // correct then do nothing extra, otherwise must surround - // injected key event with injected shift key events to - // get shift key in correct state then back to the previous - // state. - return (UINT)LOBYTE(scan); +KeyModifierMask CMSWindowsSecondaryScreen::mapKey( + Keystrokes& keys, + UINT& virtualKey, + KeyID id, KeyModifierMask mask, + bool press) const +{ + // lookup the key table + const UInt32 mapID = ((id >> 8) & 0xff); + const UINT* map = g_mapTable[mapID]; + if (map == NULL) { + // unknown key + 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)); + } + } + + else { + // 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)); + } + } + } + } } } - // lookup the key in the table - return map[code]; + // 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; } diff --git a/client/CMSWindowsSecondaryScreen.h b/client/CMSWindowsSecondaryScreen.h index 196817af..dbd9b5a8 100644 --- a/client/CMSWindowsSecondaryScreen.h +++ b/client/CMSWindowsSecondaryScreen.h @@ -3,6 +3,8 @@ #include "CMSWindowsScreen.h" #include "ISecondaryScreen.h" +#include +#include class CMSWindowsSecondaryScreen : public CMSWindowsScreen, public ISecondaryScreen { public: @@ -23,11 +25,11 @@ public: virtual void mouseUp(ButtonID); virtual void mouseMove(SInt32 xAbsolute, SInt32 yAbsolute); virtual void mouseWheel(SInt32 delta); - virtual void setClipboard(const IClipboard*); - virtual void grabClipboard(); + virtual void setClipboard(ClipboardID, const IClipboard*); + virtual void grabClipboard(ClipboardID); virtual void getSize(SInt32* width, SInt32* height) const; virtual SInt32 getJumpZoneSize() const; - virtual void getClipboard(IClipboard*) const; + virtual void getClipboard(ClipboardID, IClipboard*) const; protected: // CMSWindowsScreen overrides @@ -37,13 +39,27 @@ protected: virtual void onCloseDisplay(); private: - UINT mapKey(KeyID, KeyModifierMask) const; + typedef std::pair Keystroke; + typedef std::vector Keystrokes; + + DWORD mapButton(ButtonID button) const; + KeyModifierMask mapKey(Keystrokes&, UINT& virtualKey, KeyID, + KeyModifierMask, bool press) const; + + void updateKeys(); + void updateModifiers(); private: CClient* m_client; HWND m_window; HWND m_nextClipboardWindow; HWND m_clipboardOwner; + + // virtual key states + BYTE m_keys[256]; + + // current active modifiers + KeyModifierMask m_mask; }; #endif diff --git a/server/CMSWindowsPrimaryScreen.cpp b/server/CMSWindowsPrimaryScreen.cpp index f7ef900e..9c4f3169 100644 --- a/server/CMSWindowsPrimaryScreen.cpp +++ b/server/CMSWindowsPrimaryScreen.cpp @@ -6,6 +6,7 @@ #include "CThread.h" #include "CLog.h" #include +#include // // CMSWindowsPrimaryScreen @@ -86,6 +87,9 @@ void CMSWindowsPrimaryScreen::open(CServer* server) // set the server m_server = server; + // get keyboard state + updateKeys(); + // open the display openDisplay(); @@ -189,7 +193,8 @@ void CMSWindowsPrimaryScreen::leave() try { m_clipboardOwner = clipboardOwner; if (m_clipboardOwner != m_window) { - m_server->grabClipboard(); + m_server->grabClipboard(kClipboardClipboard); + m_server->grabClipboard(kClipboardSelection); } } catch (XBadClient&) { @@ -209,7 +214,7 @@ void CMSWindowsPrimaryScreen::warpCursor(SInt32 x, SInt32 y) } void CMSWindowsPrimaryScreen::setClipboard( - const IClipboard* src) + ClipboardID id, const IClipboard* src) { assert(m_window != NULL); @@ -217,12 +222,12 @@ void CMSWindowsPrimaryScreen::setClipboard( CClipboard::copy(&dst, src); } -void CMSWindowsPrimaryScreen::grabClipboard() +void CMSWindowsPrimaryScreen::grabClipboard(ClipboardID id) { assert(m_window != NULL); CMSWindowsClipboard clipboard(m_window); - if (clipboard.open()) { + if (clipboard.open(0)) { clipboard.close(); } } @@ -239,7 +244,7 @@ SInt32 CMSWindowsPrimaryScreen::getJumpZoneSize() const } void CMSWindowsPrimaryScreen::getClipboard( - IClipboard* dst) const + ClipboardID id, IClipboard* dst) const { assert(m_window != NULL); @@ -349,24 +354,29 @@ if (IsDialogMessage(s_debug, msg)) { if (m_mark == m_markReceived) { 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)); + log((CLOG_DEBUG1 "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)); + log((CLOG_DEBUG1 "event: key press key=%d mask=0x%04x", key, mask)); m_server->onKeyDown(key, mask); } + + // update key state + updateKey(msg->wParam, true); } else { // 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); + + // 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_MBUTTONDOWN: case WM_RBUTTONDOWN: - log((CLOG_DEBUG "event: button press button=%d", button)); + log((CLOG_DEBUG1 "event: button press button=%d", button)); if (button != kButtonNone) { 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_MBUTTONUP: case WM_RBUTTONUP: - log((CLOG_DEBUG "event: button release button=%d", button)); + log((CLOG_DEBUG1 "event: button release button=%d", button)); if (button != kButtonNone) { 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 y = (SInt32)msg->lParam; 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); } else { - log((CLOG_DEBUG "event: active move %d,%d", x, y)); + log((CLOG_DEBUG2 "event: active move %d,%d", x, y)); // get screen size SInt32 w, h; @@ -461,7 +471,8 @@ LRESULT CMSWindowsPrimaryScreen::onEvent( try { m_clipboardOwner = GetClipboardOwner(); if (m_clipboardOwner != m_window) { - m_server->grabClipboard(); + m_server->grabClipboard(kClipboardClipboard); + m_server->grabClipboard(kClipboardSelection); } } catch (XBadClient&) { @@ -521,7 +532,7 @@ static const KeyID g_virtualKey[] = /* 0x1d */ kKeyNone, // VK_NONCONVERT /* 0x1e */ kKeyNone, // VK_ACCEPT /* 0x1f */ kKeyNone, // VK_MODECHANGE - /* 0x20 */ 0xff20, // VK_SPACE XK_space + /* 0x20 */ 0x0020, // VK_SPACE XK_space /* 0x21 */ 0xff55, // VK_PRIOR XK_Prior /* 0x22 */ 0xff56, // VK_NEXT XK_Next /* 0x23 */ 0xff57, // VK_END XK_End @@ -537,16 +548,16 @@ static const KeyID g_virtualKey[] = /* 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 + /* 0x30 */ kKeyNone, // VK_0 XK_0 + /* 0x31 */ kKeyNone, // VK_1 XK_1 + /* 0x32 */ kKeyNone, // VK_2 XK_2 + /* 0x33 */ kKeyNone, // VK_3 XK_3 + /* 0x34 */ kKeyNone, // VK_4 XK_4 + /* 0x35 */ kKeyNone, // VK_5 XK_5 + /* 0x36 */ kKeyNone, // VK_6 XK_6 + /* 0x37 */ kKeyNone, // VK_7 XK_7 + /* 0x38 */ kKeyNone, // VK_8 XK_8 + /* 0x39 */ kKeyNone, // VK_9 XK_9 /* 0x3a */ kKeyNone, // undefined /* 0x3b */ kKeyNone, // undefined /* 0x3c */ kKeyNone, // undefined @@ -554,32 +565,32 @@ static const KeyID g_virtualKey[] = /* 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 + /* 0x41 */ kKeyNone, // VK_A XK_A + /* 0x42 */ kKeyNone, // VK_B XK_B + /* 0x43 */ kKeyNone, // VK_C XK_C + /* 0x44 */ kKeyNone, // VK_D XK_D + /* 0x45 */ kKeyNone, // VK_E XK_E + /* 0x46 */ kKeyNone, // VK_F XK_F + /* 0x47 */ kKeyNone, // VK_G XK_G + /* 0x48 */ kKeyNone, // VK_H XK_H + /* 0x49 */ kKeyNone, // VK_I XK_I + /* 0x4a */ kKeyNone, // VK_J XK_J + /* 0x4b */ kKeyNone, // VK_K XK_K + /* 0x4c */ kKeyNone, // VK_L XK_L + /* 0x4d */ kKeyNone, // VK_M XK_M + /* 0x4e */ kKeyNone, // VK_N XK_N + /* 0x4f */ kKeyNone, // VK_O XK_O + /* 0x50 */ kKeyNone, // VK_P XK_P + /* 0x51 */ kKeyNone, // VK_Q XK_Q + /* 0x52 */ kKeyNone, // VK_R XK_R + /* 0x53 */ kKeyNone, // VK_S XK_S + /* 0x54 */ kKeyNone, // VK_T XK_T + /* 0x55 */ kKeyNone, // VK_U XK_U + /* 0x56 */ kKeyNone, // VK_V XK_V + /* 0x57 */ kKeyNone, // VK_W XK_W + /* 0x58 */ kKeyNone, // VK_X XK_X + /* 0x59 */ kKeyNone, // VK_Y XK_Y + /* 0x5a */ kKeyNone, // VK_Z XK_Z /* 0x5b */ 0xffe7, // VK_LWIN XK_Meta_L /* 0x5c */ 0xffe8, // VK_RWIN XK_Meta_R /* 0x5d */ 0xff67, // VK_APPS XK_Menu @@ -649,12 +660,12 @@ static const KeyID g_virtualKey[] = /* 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 + /* 0xa0 */ 0xffe1, // VK_LSHIFT XK_Shift_L + /* 0xa1 */ 0xffe2, // VK_RSHIFT XK_Shift_R + /* 0xa2 */ 0xffe3, // VK_LCONTROL XK_Control_L + /* 0xa3 */ 0xffe4, // VK_RCONTROL XK_Control_R + /* 0xa4 */ 0xffe9, // VK_LMENU XK_Alt_L + /* 0xa5 */ 0xffea, // VK_RMENU XK_Alt_R /* 0xa6 */ kKeyNone, // unassigned /* 0xa7 */ kKeyNone, // unassigned /* 0xa8 */ kKeyNone, // unassigned @@ -749,69 +760,157 @@ static const KeyID g_virtualKey[] = KeyID CMSWindowsPrimaryScreen::mapKey( 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); // map modifier key - // FIXME -- should be configurable? 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; - if ((GetKeyState(VK_CAPITAL) & 1) != 0) - mask |= KeyModifierCapsLock; - if (GetKeyState(VK_CONTROL) < 0) + if (((m_keys[VK_LCONTROL] | + m_keys[VK_RCONTROL] | + m_keys[VK_CONTROL]) & 0x80) != 0) mask |= KeyModifierControl; - if (GetKeyState(VK_MENU) < 0) + if (((m_keys[VK_LMENU] | + m_keys[VK_RMENU] | + m_keys[VK_MENU]) & 0x80) != 0) mask |= KeyModifierAlt; - if ((GetKeyState(VK_NUMLOCK) & 1) != 0) - mask |= KeyModifierNumLock; - if (GetKeyState(VK_LWIN) < 0 || GetKeyState(VK_RWIN) < 0) + if (((m_keys[VK_LWIN] | + m_keys[VK_RWIN]) & 0x80) != 0) 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; *maskOut = mask; + // get the scan code + UINT scanCode = static_cast((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]; if (id != kKeyNone) { return id; } - BYTE state[256]; - GetKeyboardState(state); + // check for dead keys + 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; - int result = ToAscii(vkCode, MapVirtualKey(0, vkCode), state, &ascii, 0); - if (result > 0) { - // FIXME -- handle dead keys - return (KeyID)(ascii & 0x00ff); + int result = ToAscii(vkCode, scanCode, m_keys, &ascii, 0); + + // restore control state + 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(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; - -/* - 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( @@ -834,3 +933,117 @@ ButtonID CMSWindowsPrimaryScreen::mapButton( 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; + } + } +} diff --git a/server/CMSWindowsPrimaryScreen.h b/server/CMSWindowsPrimaryScreen.h index bfa1eb56..9e19a4b5 100644 --- a/server/CMSWindowsPrimaryScreen.h +++ b/server/CMSWindowsPrimaryScreen.h @@ -21,11 +21,11 @@ public: virtual void enter(SInt32 xAbsolute, SInt32 yAbsolute); virtual void leave(); virtual void warpCursor(SInt32 xAbsolute, SInt32 yAbsolute); - virtual void setClipboard(const IClipboard*); - virtual void grabClipboard(); + virtual void setClipboard(ClipboardID, const IClipboard*); + virtual void grabClipboard(ClipboardID); virtual void getSize(SInt32* width, SInt32* height) const; virtual SInt32 getJumpZoneSize() const; - virtual void getClipboard(IClipboard*) const; + virtual void getClipboard(ClipboardID, IClipboard*) const; protected: // CMSWindowsScreen overrides @@ -40,8 +40,10 @@ private: void nextMark(); KeyID mapKey(WPARAM keycode, LPARAM info, - KeyModifierMask* maskOut) const; + KeyModifierMask* maskOut); ButtonID mapButton(WPARAM button) const; + void updateKeys(); + void updateKey(UINT vkCode, bool press); private: CServer* m_server; @@ -53,6 +55,7 @@ private: HINSTANCE m_hookLibrary; UInt32 m_mark; UInt32 m_markReceived; + BYTE m_keys[256]; }; #endif diff --git a/server/CServerProtocol1_0.cpp b/server/CServerProtocol1_0.cpp index c69b1144..33159fc2 100644 --- a/server/CServerProtocol1_0.cpp +++ b/server/CServerProtocol1_0.cpp @@ -118,7 +118,7 @@ void CServerProtocol1_0::sendGrabClipboard(ClipboardID id) 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); } @@ -132,7 +132,7 @@ void CServerProtocol1_0::sendKeyDown( void CServerProtocol1_0::sendKeyRepeat( 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); } @@ -167,7 +167,7 @@ void CServerProtocol1_0::sendMouseMove( void CServerProtocol1_0::sendMouseWheel( 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); } diff --git a/server/server.rc b/server/server.rc index 60c3a920..731c32ce 100644 --- a/server/server.rc +++ b/server/server.rc @@ -52,12 +52,12 @@ END // 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 CAPTION "Synergy" FONT 8, "MS Sans Serif" 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 END @@ -73,9 +73,9 @@ BEGIN IDD_SYNERGY, DIALOG BEGIN LEFTMARGIN, 7 - RIGHTMARGIN, 322 + RIGHTMARGIN, 524 TOPMARGIN, 7 - BOTTOMMARGIN, 151 + BOTTOMMARGIN, 152 END END #endif // APSTUDIO_INVOKED diff --git a/synergy/CClipboard.cpp b/synergy/CClipboard.cpp index e5021aab..bf5d94ed 100644 --- a/synergy/CClipboard.cpp +++ b/synergy/CClipboard.cpp @@ -1,4 +1,5 @@ #include "CClipboard.h" +#include // // CClipboard @@ -92,7 +93,7 @@ void CClipboard::unmarshall(const CString& data, Time time) index += 4; // read each format - for (UInt32 format = 0; format < numFormats; ++format) { + for (UInt32 i = 0; i < numFormats; ++i) { // get the format id UInt32 format = readUInt32(index); index += 4; @@ -144,10 +145,11 @@ CString CClipboard::marshall() const UInt32 CClipboard::readUInt32(const char* buf) const { - return (static_cast(buf[0]) << 24) | - (static_cast(buf[1]) << 16) | - (static_cast(buf[2]) << 8) | - static_cast(buf[3]); + const unsigned char* ubuf = reinterpret_cast(buf); + return (static_cast(ubuf[0]) << 24) | + (static_cast(ubuf[1]) << 16) | + (static_cast(ubuf[2]) << 8) | + static_cast(ubuf[3]); } void CClipboard::writeUInt32(CString* buf, UInt32 v) const diff --git a/synergy/CMSWindowsClipboard.cpp b/synergy/CMSWindowsClipboard.cpp index 4b0049cf..f1b2060b 100644 --- a/synergy/CMSWindowsClipboard.cpp +++ b/synergy/CMSWindowsClipboard.cpp @@ -6,7 +6,9 @@ // CMSWindowsClipboard // -CMSWindowsClipboard::CMSWindowsClipboard(HWND window) : m_window(window) +CMSWindowsClipboard::CMSWindowsClipboard(HWND window) : + m_window(window), + m_time(0) { // do nothing } @@ -16,7 +18,7 @@ CMSWindowsClipboard::~CMSWindowsClipboard() // do nothing } -bool CMSWindowsClipboard::open() +bool CMSWindowsClipboard::open(Time time) { log((CLOG_INFO "open clipboard")); @@ -29,7 +31,12 @@ bool CMSWindowsClipboard::open() } else { log((CLOG_WARN "failed to grab clipboard")); + CloseClipboard(); + return false; } + + m_time = time; + return true; } @@ -71,6 +78,11 @@ void CMSWindowsClipboard::add( CloseClipboard(); } +IClipboard::Time CMSWindowsClipboard::getTime() const +{ + return m_time; +} + bool CMSWindowsClipboard::has(EFormat format) const { const UINT win32Format = convertFormatToWin32(format); @@ -122,7 +134,7 @@ HANDLE CMSWindowsClipboard::convertTextToWin32( const CString& data) const { // compute size of converted text - UInt32 dstSize = 0; + UInt32 dstSize = 1; const UInt32 srcSize = data.size(); const char* src = data.c_str(); for (UInt32 index = 0; index < srcSize; ++index) { @@ -148,6 +160,7 @@ HANDLE CMSWindowsClipboard::convertTextToWin32( } dst[dstSize++] = src[index]; } + dst[dstSize] = '\0'; // done converting GlobalUnlock(gData); @@ -162,9 +175,12 @@ CString CMSWindowsClipboard::convertTextFromWin32( // get source data and it's size const char* src = (const char*)GlobalLock(handle); UInt32 srcSize = (SInt32)GlobalSize(handle); - if (src == NULL || srcSize == 0) + if (src == NULL || srcSize <= 1) return CString(); + // ignore trailing NUL + --srcSize; + // compute size of converted text UInt32 dstSize = 0; UInt32 index; diff --git a/synergy/CMSWindowsClipboard.h b/synergy/CMSWindowsClipboard.h index 8fae59c0..0010af57 100644 --- a/synergy/CMSWindowsClipboard.h +++ b/synergy/CMSWindowsClipboard.h @@ -10,9 +10,10 @@ public: virtual ~CMSWindowsClipboard(); // IClipboard overrides - virtual bool open(); + virtual bool open(Time); virtual void close(); virtual void add(EFormat, const CString& data); + virtual Time getTime() const; virtual bool has(EFormat) const; virtual CString get(EFormat) const; @@ -23,6 +24,7 @@ private: private: HWND m_window; + Time m_time; }; #endif diff --git a/synergy/synergy.dsp b/synergy/synergy.dsp index 6b95ec97..91f325ee 100644 --- a/synergy/synergy.dsp +++ b/synergy/synergy.dsp @@ -131,6 +131,10 @@ SOURCE=.\CInputPacketStream.h # End Source File # Begin Source File +SOURCE=.\ClipboardTypes.h +# End Source File +# Begin Source File + SOURCE=.\CMSWindowsClipboard.h # End Source File # Begin Source File