Fixes to get win32 client and server up to date.
This commit is contained in:
parent
ea6b347b18
commit
dc19570621
|
@ -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<KeyID>(id),
|
||||
static_cast<KeyModifierMask>(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<KeyID>(id),
|
||||
static_cast<KeyModifierMask>(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<KeyID>(id),
|
||||
static_cast<KeyModifierMask>(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<ButtonID>(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<ButtonID>(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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include "CMSWindowsScreen.h"
|
||||
#include "ISecondaryScreen.h"
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
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<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:
|
||||
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
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "CThread.h"
|
||||
#include "CLog.h"
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
//
|
||||
// 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<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];
|
||||
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<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;
|
||||
|
||||
/*
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "CClipboard.h"
|
||||
#include <assert.h>
|
||||
|
||||
//
|
||||
// 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<UInt32>(buf[0]) << 24) |
|
||||
(static_cast<UInt32>(buf[1]) << 16) |
|
||||
(static_cast<UInt32>(buf[2]) << 8) |
|
||||
static_cast<UInt32>(buf[3]);
|
||||
const unsigned char* ubuf = reinterpret_cast<const unsigned char*>(buf);
|
||||
return (static_cast<UInt32>(ubuf[0]) << 24) |
|
||||
(static_cast<UInt32>(ubuf[1]) << 16) |
|
||||
(static_cast<UInt32>(ubuf[2]) << 8) |
|
||||
static_cast<UInt32>(ubuf[3]);
|
||||
}
|
||||
|
||||
void CClipboard::writeUInt32(CString* buf, UInt32 v) const
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue