Checkpointing improved key handling. This change adds non-ASCII
key handling to win32 on both client and server. It also changes the protocol and adds code to ensure every key pressed also gets released and that that doesn't get confused when the KeyID for the press is different from the KeyID of the release (or repeat).
This commit is contained in:
parent
cf7ab3459d
commit
11f90022e0
|
@ -365,21 +365,22 @@ CClient::setClipboardDirty(ClipboardID, bool)
|
|||
}
|
||||
|
||||
void
|
||||
CClient::keyDown(KeyID id, KeyModifierMask mask)
|
||||
CClient::keyDown(KeyID id, KeyModifierMask mask, KeyButton button)
|
||||
{
|
||||
m_screen->keyDown(id, mask);
|
||||
m_screen->keyDown(id, mask, button);
|
||||
}
|
||||
|
||||
void
|
||||
CClient::keyRepeat(KeyID id, KeyModifierMask mask, SInt32 count)
|
||||
CClient::keyRepeat(KeyID id, KeyModifierMask mask,
|
||||
SInt32 count, KeyButton button)
|
||||
{
|
||||
m_screen->keyRepeat(id, mask, count);
|
||||
m_screen->keyRepeat(id, mask, count, button);
|
||||
}
|
||||
|
||||
void
|
||||
CClient::keyUp(KeyID id, KeyModifierMask mask)
|
||||
CClient::keyUp(KeyID id, KeyModifierMask mask, KeyButton button)
|
||||
{
|
||||
m_screen->keyUp(id, mask);
|
||||
m_screen->keyUp(id, mask, button);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -152,9 +152,10 @@ public:
|
|||
virtual void setClipboard(ClipboardID, const CString&);
|
||||
virtual void grabClipboard(ClipboardID);
|
||||
virtual void setClipboardDirty(ClipboardID, bool dirty);
|
||||
virtual void keyDown(KeyID, KeyModifierMask);
|
||||
virtual void keyRepeat(KeyID, KeyModifierMask, SInt32 count);
|
||||
virtual void keyUp(KeyID, KeyModifierMask);
|
||||
virtual void keyDown(KeyID, KeyModifierMask, KeyButton);
|
||||
virtual void keyRepeat(KeyID, KeyModifierMask,
|
||||
SInt32 count, KeyButton);
|
||||
virtual void keyUp(KeyID, KeyModifierMask, KeyButton);
|
||||
virtual void mouseDown(ButtonID);
|
||||
virtual void mouseUp(ButtonID);
|
||||
virtual void mouseMove(SInt32 xAbs, SInt32 yAbs);
|
||||
|
|
|
@ -503,9 +503,10 @@ CServerProxy::keyDown()
|
|||
flushCompressedMouse();
|
||||
|
||||
// parse
|
||||
UInt16 id, mask;
|
||||
CProtocolUtil::readf(getInputStream(), kMsgDKeyDown + 4, &id, &mask);
|
||||
LOG((CLOG_DEBUG1 "recv key down id=%d, mask=0x%04x", id, mask));
|
||||
UInt16 id, mask, button;
|
||||
CProtocolUtil::readf(getInputStream(), kMsgDKeyDown + 4,
|
||||
&id, &mask, &button);
|
||||
LOG((CLOG_DEBUG1 "recv key down id=%d, mask=0x%04x, button=0x%04x", id, mask, button));
|
||||
|
||||
// translate
|
||||
KeyID id2 = translateKey(static_cast<KeyID>(id));
|
||||
|
@ -516,7 +517,7 @@ CServerProxy::keyDown()
|
|||
LOG((CLOG_DEBUG1 "key down translated to id=%d, mask=0x%04x", id2, mask2));
|
||||
|
||||
// forward
|
||||
getClient()->keyDown(id2, mask2);
|
||||
getClient()->keyDown(id2, mask2, button);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -526,10 +527,10 @@ CServerProxy::keyRepeat()
|
|||
flushCompressedMouse();
|
||||
|
||||
// parse
|
||||
UInt16 id, mask, count;
|
||||
CProtocolUtil::readf(getInputStream(),
|
||||
kMsgDKeyRepeat + 4, &id, &mask, &count);
|
||||
LOG((CLOG_DEBUG1 "recv key repeat id=%d, mask=0x%04x, count=%d", id, mask, count));
|
||||
UInt16 id, mask, count, button;
|
||||
CProtocolUtil::readf(getInputStream(), kMsgDKeyRepeat + 4,
|
||||
&id, &mask, &count, &button);
|
||||
LOG((CLOG_DEBUG1 "recv key repeat id=%d, mask=0x%04x, count=%d, button=0x%04x", id, mask, count, button));
|
||||
|
||||
// translate
|
||||
KeyID id2 = translateKey(static_cast<KeyID>(id));
|
||||
|
@ -540,7 +541,7 @@ CServerProxy::keyRepeat()
|
|||
LOG((CLOG_DEBUG1 "key down translated to id=%d, mask=0x%04x", id2, mask2));
|
||||
|
||||
// forward
|
||||
getClient()->keyRepeat(id2, mask2, count);
|
||||
getClient()->keyRepeat(id2, mask2, count, button);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -550,9 +551,9 @@ CServerProxy::keyUp()
|
|||
flushCompressedMouse();
|
||||
|
||||
// parse
|
||||
UInt16 id, mask;
|
||||
CProtocolUtil::readf(getInputStream(), kMsgDKeyUp + 4, &id, &mask);
|
||||
LOG((CLOG_DEBUG1 "recv key up id=%d, mask=0x%04x", id, mask));
|
||||
UInt16 id, mask, button;
|
||||
CProtocolUtil::readf(getInputStream(), kMsgDKeyUp + 4, &id, &mask, &button);
|
||||
LOG((CLOG_DEBUG1 "recv key up id=%d, mask=0x%04x, button=0x%04x", id, mask, button));
|
||||
|
||||
// translate
|
||||
KeyID id2 = translateKey(static_cast<KeyID>(id));
|
||||
|
@ -563,7 +564,7 @@ CServerProxy::keyUp()
|
|||
LOG((CLOG_DEBUG1 "key down translated to id=%d, mask=0x%04x", id2, mask2));
|
||||
|
||||
// forward
|
||||
getClient()->keyUp(id2, mask2);
|
||||
getClient()->keyUp(id2, mask2, button);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -521,9 +521,11 @@ CMSWindowsPrimaryScreen::onPreDispatch(const CEvent* event)
|
|||
|
||||
// process as if it were a key up
|
||||
KeyModifierMask mask;
|
||||
KeyButton button = static_cast<KeyButton>(
|
||||
(lParam & 0x00ff0000u) >> 16);
|
||||
const KeyID key = mapKey(wParam, lParam, &mask);
|
||||
LOG((CLOG_DEBUG1 "event: fake key release key=%d mask=0x%04x", key, mask));
|
||||
m_receiver->onKeyUp(key, mask);
|
||||
LOG((CLOG_DEBUG1 "event: fake key release key=%d mask=0x%04x button=0x%04x", key, mask, button));
|
||||
m_receiver->onKeyUp(key, mask, button);
|
||||
updateKey(wParam, false);
|
||||
}
|
||||
if ((m_keys[VK_RWIN] & 0x80) != 0 &&
|
||||
|
@ -536,9 +538,11 @@ CMSWindowsPrimaryScreen::onPreDispatch(const CEvent* event)
|
|||
|
||||
// process as if it were a key up
|
||||
KeyModifierMask mask;
|
||||
KeyButton button = static_cast<KeyButton>(
|
||||
(lParam & 0x00ff0000u) >> 16);
|
||||
const KeyID key = mapKey(wParam, lParam, &mask);
|
||||
LOG((CLOG_DEBUG1 "event: fake key release key=%d mask=0x%04x", key, mask));
|
||||
m_receiver->onKeyUp(key, mask);
|
||||
LOG((CLOG_DEBUG1 "event: fake key release key=%d mask=0x%04x button=0x%04x", key, mask, button));
|
||||
m_receiver->onKeyUp(key, mask, button);
|
||||
updateKey(wParam, false);
|
||||
}
|
||||
}
|
||||
|
@ -554,18 +558,20 @@ CMSWindowsPrimaryScreen::onPreDispatch(const CEvent* event)
|
|||
if (!ignore()) {
|
||||
KeyModifierMask mask;
|
||||
const KeyID key = mapKey(msg->wParam, msg->lParam, &mask);
|
||||
if (key != kKeyNone) {
|
||||
KeyButton button = static_cast<KeyButton>(
|
||||
(msg->lParam & 0x00ff0000u) >> 16);
|
||||
if (key != kKeyNone && key != kKeyMultiKey) {
|
||||
if ((msg->lParam & 0x80000000) == 0) {
|
||||
// key press
|
||||
const bool wasDown = ((msg->lParam & 0x40000000) != 0);
|
||||
const SInt32 repeat = (SInt32)(msg->lParam & 0xffff);
|
||||
if (repeat >= 2 || wasDown) {
|
||||
LOG((CLOG_DEBUG1 "event: key repeat key=%d mask=0x%04x count=%d", key, mask, repeat));
|
||||
m_receiver->onKeyRepeat(key, mask, repeat);
|
||||
LOG((CLOG_DEBUG1 "event: key repeat key=%d mask=0x%04x count=%d button=0x%04x", key, mask, repeat, button));
|
||||
m_receiver->onKeyRepeat(key, mask, repeat, button);
|
||||
}
|
||||
else {
|
||||
LOG((CLOG_DEBUG1 "event: key press key=%d mask=0x%04x", key, mask));
|
||||
m_receiver->onKeyDown(key, mask);
|
||||
LOG((CLOG_DEBUG1 "event: key press key=%d mask=0x%04x button=0x%04x", key, mask, button));
|
||||
m_receiver->onKeyDown(key, mask, button);
|
||||
}
|
||||
|
||||
// update key state
|
||||
|
@ -580,14 +586,14 @@ CMSWindowsPrimaryScreen::onPreDispatch(const CEvent* event)
|
|||
// keys like alt+tab, ctrl+esc, etc.
|
||||
if (m_is95Family && !isModifier(msg->wParam) &&
|
||||
(m_keys[msg->wParam] & 0x80) == 0) {
|
||||
LOG((CLOG_DEBUG1 "event: fake key press key=%d mask=0x%04x", key, mask));
|
||||
m_receiver->onKeyDown(key, mask);
|
||||
LOG((CLOG_DEBUG1 "event: fake key press key=%d mask=0x%04x button=0x%04x", key, mask, button));
|
||||
m_receiver->onKeyDown(key, mask, button);
|
||||
updateKey(msg->wParam, true);
|
||||
}
|
||||
|
||||
// do key up
|
||||
LOG((CLOG_DEBUG1 "event: key release key=%d mask=0x%04x", key, mask));
|
||||
m_receiver->onKeyUp(key, mask);
|
||||
LOG((CLOG_DEBUG1 "event: key release key=%d mask=0x%04x button=0x%04x", key, mask, button));
|
||||
m_receiver->onKeyUp(key, mask, button);
|
||||
|
||||
// update key state
|
||||
updateKey(msg->wParam, false);
|
||||
|
@ -1408,11 +1414,6 @@ CMSWindowsPrimaryScreen::mapKey(
|
|||
return id;
|
||||
}
|
||||
|
||||
// check for dead keys
|
||||
if (MapVirtualKey(vkCode, 2) >= 0x8000) {
|
||||
return kKeyMultiKey;
|
||||
}
|
||||
|
||||
// save the control state then clear it. ToAscii() maps ctrl+letter
|
||||
// to the corresponding control code and ctrl+backspace to delete.
|
||||
// we don't want that translation so we clear the control modifier
|
||||
|
@ -1421,14 +1422,21 @@ CMSWindowsPrimaryScreen::mapKey(
|
|||
BYTE lControl = m_keys[VK_LCONTROL];
|
||||
BYTE rControl = m_keys[VK_RCONTROL];
|
||||
BYTE control = m_keys[VK_CONTROL];
|
||||
BYTE lMenu = m_keys[VK_LMENU];
|
||||
BYTE menu = m_keys[VK_MENU];
|
||||
if ((mask & KeyModifierModeSwitch) == 0) {
|
||||
m_keys[VK_LCONTROL] = 0;
|
||||
m_keys[VK_RCONTROL] = 0;
|
||||
m_keys[VK_CONTROL] = 0;
|
||||
}
|
||||
else {
|
||||
m_keys[VK_LCONTROL] = 0x80;
|
||||
m_keys[VK_CONTROL] = 0x80;
|
||||
m_keys[VK_LMENU] = 0x80;
|
||||
m_keys[VK_MENU] = 0x80;
|
||||
}
|
||||
|
||||
// convert to ascii
|
||||
// FIXME -- support unicode
|
||||
WORD ascii;
|
||||
int result = ToAscii(vkCode, scanCode, m_keys, &ascii, 0);
|
||||
|
||||
|
@ -1436,23 +1444,45 @@ CMSWindowsPrimaryScreen::mapKey(
|
|||
m_keys[VK_LCONTROL] = lControl;
|
||||
m_keys[VK_RCONTROL] = rControl;
|
||||
m_keys[VK_CONTROL] = control;
|
||||
m_keys[VK_LMENU] = lMenu;
|
||||
m_keys[VK_MENU] = menu;
|
||||
|
||||
// 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 is less than zero then it was a dead key. leave it
|
||||
// there.
|
||||
if (result < 0) {
|
||||
ToAscii(vkCode, scanCode, m_keys, &ascii, 0);
|
||||
return kKeyMultiKey;
|
||||
}
|
||||
|
||||
// if result is 1 then the key was succesfully converted
|
||||
else if (result == 1) {
|
||||
if (ascii >= 0x80) {
|
||||
// character is not really ASCII. instead it's some
|
||||
// character in the current ANSI code page. try to
|
||||
// convert that to a Unicode character. if we fail
|
||||
// then use the single byte character as is.
|
||||
char src = static_cast<char>(ascii & 0xff);
|
||||
wchar_t unicode;
|
||||
if (MultiByteToWideChar(CP_THREAD_ACP, MB_PRECOMPOSED,
|
||||
&src, 1, &unicode, 1) > 0) {
|
||||
return static_cast<KeyID>(unicode);
|
||||
}
|
||||
}
|
||||
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) {
|
||||
// if the two characters are the same and this is a key release
|
||||
// then this event is the dead key being released. we put the
|
||||
// dead key back in that case, otherwise we discard both key
|
||||
// events because we can't compose the character. alternatively
|
||||
// we could generate key events for both keys.
|
||||
if (((ascii & 0xff00) >> 8) != (ascii & 0x00ff) ||
|
||||
(info & 0x80000000) == 0) {
|
||||
// cannot compose key
|
||||
return kKeyNone;
|
||||
}
|
||||
|
||||
// get the scan code of the dead key and the shift state
|
||||
// required to generate it.
|
||||
vkCode = VkKeyScan(static_cast<TCHAR>(ascii & 0x00ff));
|
||||
|
|
|
@ -49,7 +49,8 @@ CMSWindowsSecondaryScreen::~CMSWindowsSecondaryScreen()
|
|||
}
|
||||
|
||||
void
|
||||
CMSWindowsSecondaryScreen::keyDown(KeyID key, KeyModifierMask mask)
|
||||
CMSWindowsSecondaryScreen::keyDown(KeyID key,
|
||||
KeyModifierMask mask, KeyButton button)
|
||||
{
|
||||
Keystrokes keys;
|
||||
UINT virtualKey;
|
||||
|
@ -89,11 +90,14 @@ CMSWindowsSecondaryScreen::keyDown(KeyID key, KeyModifierMask mask)
|
|||
m_fakeKeys[VK_MENU] |= 0x80;
|
||||
break;
|
||||
}
|
||||
|
||||
// note which server key generated this key
|
||||
m_serverKeyMap[button] = virtualKey;
|
||||
}
|
||||
|
||||
void
|
||||
CMSWindowsSecondaryScreen::keyRepeat(KeyID key,
|
||||
KeyModifierMask mask, SInt32 count)
|
||||
KeyModifierMask mask, SInt32 count, KeyButton button)
|
||||
{
|
||||
Keystrokes keys;
|
||||
UINT virtualKey;
|
||||
|
@ -101,6 +105,12 @@ CMSWindowsSecondaryScreen::keyRepeat(KeyID key,
|
|||
CLock lock(&m_mutex);
|
||||
m_screen->syncDesktop();
|
||||
|
||||
// if we haven't seen this button go down then ignore it
|
||||
ServerKeyMap::iterator index = m_serverKeyMap.find(button);
|
||||
if (index == m_serverKeyMap.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// get the sequence of keys to simulate key repeat and the final
|
||||
// modifier state.
|
||||
m_mask = mapKey(keys, virtualKey, key, mask, kRepeat);
|
||||
|
@ -108,12 +118,40 @@ CMSWindowsSecondaryScreen::keyRepeat(KeyID key,
|
|||
return;
|
||||
}
|
||||
|
||||
// if we've seen this button (and we should have) then make sure
|
||||
// we release the same key we pressed when we saw it.
|
||||
ServerKeyMap::iterator index = m_serverKeyMap.find(button);
|
||||
if (index != m_serverKeyMap.end() && virtualKey != index->second) {
|
||||
// replace key up with previous keycode but leave key down
|
||||
// alone so it uses the new keycode and store that keycode
|
||||
// in the server key map.
|
||||
for (Keystrokes::iterator index2 = keys.begin();
|
||||
index2 != keys.end(); ++index2) {
|
||||
if (index2->m_virtualKey == index->second) {
|
||||
index2->m_virtualKey = index->second;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// note that old key is now up
|
||||
m_keys[index->second] = false;
|
||||
m_fakeKeys[index->second] = false;
|
||||
|
||||
// map server key to new key
|
||||
index->second = virtualKey;
|
||||
|
||||
// note that new key is now down
|
||||
m_keys[index->second] = true;
|
||||
m_fakeKeys[index->second] = true;
|
||||
}
|
||||
|
||||
// generate key events
|
||||
doKeystrokes(keys, count);
|
||||
}
|
||||
|
||||
void
|
||||
CMSWindowsSecondaryScreen::keyUp(KeyID key, KeyModifierMask mask)
|
||||
CMSWindowsSecondaryScreen::keyUp(KeyID key,
|
||||
KeyModifierMask mask, KeyButton button)
|
||||
{
|
||||
Keystrokes keys;
|
||||
UINT virtualKey;
|
||||
|
@ -121,11 +159,41 @@ CMSWindowsSecondaryScreen::keyUp(KeyID key, KeyModifierMask mask)
|
|||
CLock lock(&m_mutex);
|
||||
m_screen->syncDesktop();
|
||||
|
||||
// if we haven't seen this button go down then ignore it
|
||||
ServerKeyMap::iterator index = m_serverKeyMap.find(button);
|
||||
if (index == m_serverKeyMap.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// get the sequence of keys to simulate key release and the final
|
||||
// modifier state.
|
||||
m_mask = mapKey(keys, virtualKey, key, mask, kRelease);
|
||||
|
||||
// if there are no keys to generate then we should at least generate
|
||||
// a key release for the key we pressed.
|
||||
if (keys.empty()) {
|
||||
return;
|
||||
Keystroke keystroke;
|
||||
virtualKey = index->second;
|
||||
keystroke.m_virtualKey = virtualKey;
|
||||
keystroke.m_press = false;
|
||||
keystroke.m_repeat = false;
|
||||
keys.push_back(keystroke);
|
||||
}
|
||||
|
||||
// if we've seen this button (and we should have) then make sure
|
||||
// we release the same key we pressed when we saw it.
|
||||
if (index != m_serverKeyMap.end() && virtualKey != index->second) {
|
||||
// replace key up with previous virtual key
|
||||
for (Keystrokes::iterator index2 = keys.begin();
|
||||
index2 != keys.end(); ++index2) {
|
||||
if (index2->m_virtualKey == virtualKey) {
|
||||
index2->m_virtualKey = index->second;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// use old virtual key
|
||||
virtualKey = index->second;
|
||||
}
|
||||
|
||||
// generate key events
|
||||
|
@ -177,6 +245,11 @@ CMSWindowsSecondaryScreen::keyUp(KeyID key, KeyModifierMask mask)
|
|||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// remove server key from map
|
||||
if (index != m_serverKeyMap.end()) {
|
||||
m_serverKeyMap.erase(index);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -716,8 +789,20 @@ CMSWindowsSecondaryScreen::mapKey(Keystrokes& keys, UINT& virtualKey,
|
|||
// if not in map then ask system to convert character
|
||||
if (virtualKey == 0) {
|
||||
// translate. return no keys if unknown key.
|
||||
// FIXME -- handle unicode
|
||||
TCHAR ascii = static_cast<TCHAR>(id & 0x000000ff);
|
||||
char ascii;
|
||||
wchar_t unicode = static_cast<wchar_t>(id & 0x0000ffff);
|
||||
BOOL error;
|
||||
if (WideCharToMultiByte(CP_THREAD_ACP,
|
||||
#if defined(WC_NO_BEST_FIT_CHARS)
|
||||
WC_NO_BEST_FIT_CHARS |
|
||||
#endif
|
||||
WC_COMPOSITECHECK |
|
||||
WC_DEFAULTCHAR,
|
||||
&unicode, 1,
|
||||
&ascii, 1, NULL, &error) == 0 || error) {
|
||||
LOG((CLOG_DEBUG2 "character %d not in code page", id));
|
||||
return m_mask;
|
||||
}
|
||||
SHORT vk = VkKeyScan(ascii);
|
||||
if (vk == 0xffff) {
|
||||
LOG((CLOG_DEBUG2 "no virtual key for character %d", id));
|
||||
|
|
|
@ -38,9 +38,10 @@ public:
|
|||
virtual ~CMSWindowsSecondaryScreen();
|
||||
|
||||
// CSecondaryScreen overrides
|
||||
virtual void keyDown(KeyID, KeyModifierMask);
|
||||
virtual void keyRepeat(KeyID, KeyModifierMask, SInt32 count);
|
||||
virtual void keyUp(KeyID, KeyModifierMask);
|
||||
virtual void keyDown(KeyID, KeyModifierMask, KeyButton);
|
||||
virtual void keyRepeat(KeyID, KeyModifierMask,
|
||||
SInt32 count, KeyButton);
|
||||
virtual void keyUp(KeyID, KeyModifierMask, KeyButton);
|
||||
virtual void mouseDown(ButtonID);
|
||||
virtual void mouseUp(ButtonID);
|
||||
virtual void mouseMove(SInt32 xAbsolute, SInt32 yAbsolute);
|
||||
|
@ -83,6 +84,7 @@ private:
|
|||
bool m_repeat;
|
||||
};
|
||||
typedef std::vector<Keystroke> Keystrokes;
|
||||
typedef std::map<KeyButton, UINT> ServerKeyMap;
|
||||
|
||||
// open/close desktop (for windows 95/98/me)
|
||||
bool openDesktop();
|
||||
|
@ -123,6 +125,9 @@ private:
|
|||
|
||||
// current active modifiers
|
||||
KeyModifierMask m_mask;
|
||||
|
||||
// map server key buttons to local virtual keys
|
||||
ServerKeyMap m_serverKeyMap;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -241,12 +241,15 @@ CXWindowsPrimaryScreen::onEvent(CEvent* event)
|
|||
const KeyModifierMask mask = mapModifier(xevent.xkey.state);
|
||||
const KeyID key = mapKey(&xevent.xkey);
|
||||
if (key != kKeyNone) {
|
||||
m_receiver->onKeyDown(key, mask);
|
||||
m_receiver->onKeyDown(key, mask,
|
||||
static_cast<KeyButton>(xevent.xkey.keycode));
|
||||
if (key == kKeyCapsLock && m_capsLockHalfDuplex) {
|
||||
m_receiver->onKeyUp(key, mask | KeyModifierCapsLock);
|
||||
m_receiver->onKeyUp(key, mask | KeyModifierCapsLock,
|
||||
static_cast<KeyButton>(xevent.xkey.keycode));
|
||||
}
|
||||
else if (key == kKeyNumLock && m_numLockHalfDuplex) {
|
||||
m_receiver->onKeyUp(key, mask | KeyModifierNumLock);
|
||||
m_receiver->onKeyUp(key, mask | KeyModifierNumLock,
|
||||
static_cast<KeyButton>(xevent.xkey.keycode));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -280,12 +283,15 @@ CXWindowsPrimaryScreen::onEvent(CEvent* event)
|
|||
// no press event follows so it's a plain release
|
||||
LOG((CLOG_DEBUG1 "event: KeyRelease code=%d, state=0x%04x", xevent.xkey.keycode, xevent.xkey.state));
|
||||
if (key == kKeyCapsLock && m_capsLockHalfDuplex) {
|
||||
m_receiver->onKeyDown(key, mask);
|
||||
m_receiver->onKeyDown(key, mask,
|
||||
static_cast<KeyButton>(xevent.xkey.keycode));
|
||||
}
|
||||
else if (key == kKeyNumLock && m_numLockHalfDuplex) {
|
||||
m_receiver->onKeyDown(key, mask);
|
||||
m_receiver->onKeyDown(key, mask,
|
||||
static_cast<KeyButton>(xevent.xkey.keycode));
|
||||
}
|
||||
m_receiver->onKeyUp(key, mask);
|
||||
m_receiver->onKeyUp(key, mask,
|
||||
static_cast<KeyButton>(xevent.xkey.keycode));
|
||||
}
|
||||
else {
|
||||
// found a press event following so it's a repeat.
|
||||
|
@ -293,7 +299,8 @@ CXWindowsPrimaryScreen::onEvent(CEvent* event)
|
|||
// repeats but we'll just send a repeat of 1.
|
||||
// note that we discard the press event.
|
||||
LOG((CLOG_DEBUG1 "event: repeat code=%d, state=0x%04x", xevent.xkey.keycode, xevent.xkey.state));
|
||||
m_receiver->onKeyRepeat(key, mask, 1);
|
||||
m_receiver->onKeyRepeat(key, mask, 1,
|
||||
static_cast<KeyButton>(xevent.xkey.keycode));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -95,7 +95,8 @@ CXWindowsSecondaryScreen::~CXWindowsSecondaryScreen()
|
|||
}
|
||||
|
||||
void
|
||||
CXWindowsSecondaryScreen::keyDown(KeyID key, KeyModifierMask mask)
|
||||
CXWindowsSecondaryScreen::keyDown(KeyID key,
|
||||
KeyModifierMask mask, KeyButton button)
|
||||
{
|
||||
Keystrokes keys;
|
||||
KeyCode keycode;
|
||||
|
@ -113,15 +114,24 @@ CXWindowsSecondaryScreen::keyDown(KeyID key, KeyModifierMask mask)
|
|||
// note that key is now down
|
||||
m_keys[keycode] = true;
|
||||
m_fakeKeys[keycode] = true;
|
||||
|
||||
// note which server key generated this key
|
||||
m_serverKeyMap[button] = keycode;
|
||||
}
|
||||
|
||||
void
|
||||
CXWindowsSecondaryScreen::keyRepeat(KeyID key,
|
||||
KeyModifierMask mask, SInt32 count)
|
||||
KeyModifierMask mask, SInt32 count, KeyButton button)
|
||||
{
|
||||
Keystrokes keys;
|
||||
KeyCode keycode;
|
||||
|
||||
// if we haven't seen this button go down then ignore it
|
||||
ServerKeyMap::iterator index = m_serverKeyMap.find(button);
|
||||
if (index == m_serverKeyMap.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// get the sequence of keys to simulate key repeat and the final
|
||||
// modifier state.
|
||||
m_mask = mapKey(keys, keycode, key, mask, kRepeat);
|
||||
|
@ -129,21 +139,78 @@ CXWindowsSecondaryScreen::keyRepeat(KeyID key,
|
|||
return;
|
||||
}
|
||||
|
||||
// if we've seen this button (and we should have) then make sure
|
||||
// we release the same key we pressed when we saw it.
|
||||
if (index != m_serverKeyMap.end() && keycode != index->second) {
|
||||
// replace key up with previous keycode but leave key down
|
||||
// alone so it uses the new keycode and store that keycode
|
||||
// in the server key map.
|
||||
for (Keystrokes::iterator index2 = keys.begin();
|
||||
index2 != keys.end(); ++index2) {
|
||||
if (index2->m_keycode == index->second) {
|
||||
index2->m_keycode = index->second;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// note that old key is now up
|
||||
m_keys[index->second] = false;
|
||||
m_fakeKeys[index->second] = false;
|
||||
|
||||
// map server key to new key
|
||||
index->second = keycode;
|
||||
|
||||
// note that new key is now down
|
||||
m_keys[index->second] = true;
|
||||
m_fakeKeys[index->second] = true;
|
||||
}
|
||||
|
||||
// generate key events
|
||||
doKeystrokes(keys, count);
|
||||
}
|
||||
|
||||
void
|
||||
CXWindowsSecondaryScreen::keyUp(KeyID key, KeyModifierMask mask)
|
||||
CXWindowsSecondaryScreen::keyUp(KeyID key,
|
||||
KeyModifierMask mask, KeyButton button)
|
||||
{
|
||||
Keystrokes keys;
|
||||
KeyCode keycode;
|
||||
|
||||
// if we haven't seen this button go down then ignore it
|
||||
ServerKeyMap::iterator index = m_serverKeyMap.find(button);
|
||||
if (index == m_serverKeyMap.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// get the sequence of keys to simulate key release and the final
|
||||
// modifier state.
|
||||
m_mask = mapKey(keys, keycode, key, mask, kRelease);
|
||||
|
||||
// if there are no keys to generate then we should at least generate
|
||||
// a key release for the key we pressed.
|
||||
if (keys.empty()) {
|
||||
return;
|
||||
Keystroke keystroke;
|
||||
keycode = index->second;
|
||||
keystroke.m_keycode = keycode;
|
||||
keystroke.m_press = False;
|
||||
keystroke.m_repeat = false;
|
||||
keys.push_back(keystroke);
|
||||
}
|
||||
|
||||
// if we've seen this button (and we should have) then make sure
|
||||
// we release the same key we pressed when we saw it.
|
||||
if (index != m_serverKeyMap.end() && keycode != index->second) {
|
||||
// replace key up with previous keycode
|
||||
for (Keystrokes::iterator index2 = keys.begin();
|
||||
index2 != keys.end(); ++index2) {
|
||||
if (index2->m_keycode == keycode) {
|
||||
index2->m_keycode = index->second;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// use old keycode
|
||||
keycode = index->second;
|
||||
}
|
||||
|
||||
// generate key events
|
||||
|
@ -152,6 +219,11 @@ CXWindowsSecondaryScreen::keyUp(KeyID key, KeyModifierMask mask)
|
|||
// note that key is now up
|
||||
m_keys[keycode] = false;
|
||||
m_fakeKeys[keycode] = false;
|
||||
|
||||
// remove server key from map
|
||||
if (index != m_serverKeyMap.end()) {
|
||||
m_serverKeyMap.erase(index);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -37,9 +37,10 @@ public:
|
|||
virtual ~CXWindowsSecondaryScreen();
|
||||
|
||||
// CSecondaryScreen overrides
|
||||
virtual void keyDown(KeyID, KeyModifierMask);
|
||||
virtual void keyRepeat(KeyID, KeyModifierMask, SInt32 count);
|
||||
virtual void keyUp(KeyID, KeyModifierMask);
|
||||
virtual void keyDown(KeyID, KeyModifierMask, KeyButton);
|
||||
virtual void keyRepeat(KeyID, KeyModifierMask,
|
||||
SInt32 count, KeyButton);
|
||||
virtual void keyUp(KeyID, KeyModifierMask, KeyButton);
|
||||
virtual void mouseDown(ButtonID);
|
||||
virtual void mouseUp(ButtonID);
|
||||
virtual void mouseMove(SInt32 x, SInt32 y);
|
||||
|
@ -91,6 +92,7 @@ private:
|
|||
typedef std::map<KeySym, KeyCodeMask> KeyCodeMap;
|
||||
typedef KeyCodeMap::const_iterator KeyCodeIndex;
|
||||
typedef std::map<KeyCode, unsigned int> ModifierMap;
|
||||
typedef std::map<KeyButton, KeyCode> ServerKeyMap;
|
||||
|
||||
unsigned int mapButton(ButtonID button) const;
|
||||
|
||||
|
@ -165,6 +167,9 @@ private:
|
|||
|
||||
// maps keycodes to modifier indices
|
||||
ModifierMap m_keycodeToModifier;
|
||||
|
||||
// map server key buttons to local keycodes
|
||||
ServerKeyMap m_serverKeyMap;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -68,9 +68,10 @@ public:
|
|||
virtual void setClipboard(ClipboardID, const CString&) = 0;
|
||||
virtual void grabClipboard(ClipboardID) = 0;
|
||||
virtual void setClipboardDirty(ClipboardID, bool) = 0;
|
||||
virtual void keyDown(KeyID, KeyModifierMask) = 0;
|
||||
virtual void keyRepeat(KeyID, KeyModifierMask, SInt32 count) = 0;
|
||||
virtual void keyUp(KeyID, KeyModifierMask) = 0;
|
||||
virtual void keyDown(KeyID, KeyModifierMask, KeyButton) = 0;
|
||||
virtual void keyRepeat(KeyID, KeyModifierMask,
|
||||
SInt32 count, KeyButton) = 0;
|
||||
virtual void keyUp(KeyID, KeyModifierMask, KeyButton) = 0;
|
||||
virtual void mouseDown(ButtonID) = 0;
|
||||
virtual void mouseUp(ButtonID) = 0;
|
||||
virtual void mouseMove(SInt32 xAbs, SInt32 yAbs) = 0;
|
||||
|
|
|
@ -200,24 +200,25 @@ CClientProxy1_0::setClipboardDirty(ClipboardID id, bool dirty)
|
|||
}
|
||||
|
||||
void
|
||||
CClientProxy1_0::keyDown(KeyID key, KeyModifierMask mask)
|
||||
CClientProxy1_0::keyDown(KeyID key, KeyModifierMask mask, KeyButton)
|
||||
{
|
||||
LOG((CLOG_DEBUG1 "send key down to \"%s\" id=%d, mask=0x%04x", getName().c_str(), key, mask));
|
||||
CProtocolUtil::writef(getOutputStream(), kMsgDKeyDown, key, mask);
|
||||
CProtocolUtil::writef(getOutputStream(), kMsgDKeyDown1_0, key, mask);
|
||||
}
|
||||
|
||||
void
|
||||
CClientProxy1_0::keyRepeat(KeyID key, KeyModifierMask mask, SInt32 count)
|
||||
CClientProxy1_0::keyRepeat(KeyID key, KeyModifierMask mask,
|
||||
SInt32 count, KeyButton)
|
||||
{
|
||||
LOG((CLOG_DEBUG1 "send key repeat to \"%s\" id=%d, mask=0x%04x, count=%d", getName().c_str(), key, mask, count));
|
||||
CProtocolUtil::writef(getOutputStream(), kMsgDKeyRepeat, key, mask, count);
|
||||
CProtocolUtil::writef(getOutputStream(), kMsgDKeyRepeat1_0, key, mask, count);
|
||||
}
|
||||
|
||||
void
|
||||
CClientProxy1_0::keyUp(KeyID key, KeyModifierMask mask)
|
||||
CClientProxy1_0::keyUp(KeyID key, KeyModifierMask mask, KeyButton)
|
||||
{
|
||||
LOG((CLOG_DEBUG1 "send key up to \"%s\" id=%d, mask=0x%04x", getName().c_str(), key, mask));
|
||||
CProtocolUtil::writef(getOutputStream(), kMsgDKeyUp, key, mask);
|
||||
CProtocolUtil::writef(getOutputStream(), kMsgDKeyUp1_0, key, mask);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -37,9 +37,10 @@ public:
|
|||
virtual void setClipboard(ClipboardID, const CString&);
|
||||
virtual void grabClipboard(ClipboardID);
|
||||
virtual void setClipboardDirty(ClipboardID, bool);
|
||||
virtual void keyDown(KeyID, KeyModifierMask);
|
||||
virtual void keyRepeat(KeyID, KeyModifierMask, SInt32 count);
|
||||
virtual void keyUp(KeyID, KeyModifierMask);
|
||||
virtual void keyDown(KeyID, KeyModifierMask, KeyButton);
|
||||
virtual void keyRepeat(KeyID, KeyModifierMask,
|
||||
SInt32 count, KeyButton);
|
||||
virtual void keyUp(KeyID, KeyModifierMask, KeyButton);
|
||||
virtual void mouseDown(ButtonID);
|
||||
virtual void mouseUp(ButtonID);
|
||||
virtual void mouseMove(SInt32 xAbs, SInt32 yAbs);
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "CClientProxy1_1.h"
|
||||
#include "CProtocolUtil.h"
|
||||
#include "CLog.h"
|
||||
#include <cstring>
|
||||
|
||||
//
|
||||
// CClientProxy1_1
|
||||
//
|
||||
|
||||
CClientProxy1_1::CClientProxy1_1(IServer* server, const CString& name,
|
||||
IInputStream* input, IOutputStream* output) :
|
||||
CClientProxy1_0(server, name, input, output)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
CClientProxy1_1::~CClientProxy1_1()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void
|
||||
CClientProxy1_1::keyDown(KeyID key, KeyModifierMask mask, KeyButton button)
|
||||
{
|
||||
LOG((CLOG_DEBUG1 "send key down to \"%s\" id=%d, mask=0x%04x, button=0x%04x", getName().c_str(), key, mask, button));
|
||||
CProtocolUtil::writef(getOutputStream(), kMsgDKeyDown, key, mask, button);
|
||||
}
|
||||
|
||||
void
|
||||
CClientProxy1_1::keyRepeat(KeyID key, KeyModifierMask mask,
|
||||
SInt32 count, KeyButton button)
|
||||
{
|
||||
LOG((CLOG_DEBUG1 "send key repeat to \"%s\" id=%d, mask=0x%04x, count=%d, button=0x%04x", getName().c_str(), key, mask, count, button));
|
||||
CProtocolUtil::writef(getOutputStream(), kMsgDKeyRepeat, key, mask, count, button);
|
||||
}
|
||||
|
||||
void
|
||||
CClientProxy1_1::keyUp(KeyID key, KeyModifierMask mask, KeyButton button)
|
||||
{
|
||||
LOG((CLOG_DEBUG1 "send key up to \"%s\" id=%d, mask=0x%04x, button=0x%04x", getName().c_str(), key, mask, button));
|
||||
CProtocolUtil::writef(getOutputStream(), kMsgDKeyUp, key, mask, button);
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 Chris Schoeneman
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef CCLIENTPROXY1_1_H
|
||||
#define CCLIENTPROXY1_1_H
|
||||
|
||||
#include "CClientProxy1_0.h"
|
||||
|
||||
//! Proxy for client implementing protocol version 1.1
|
||||
class CClientProxy1_1 : public CClientProxy1_0 {
|
||||
public:
|
||||
CClientProxy1_1(IServer* server, const CString& name,
|
||||
IInputStream* adoptedInput,
|
||||
IOutputStream* adoptedOutput);
|
||||
~CClientProxy1_1();
|
||||
|
||||
// IClient overrides
|
||||
virtual void keyDown(KeyID, KeyModifierMask, KeyButton);
|
||||
virtual void keyRepeat(KeyID, KeyModifierMask,
|
||||
SInt32 count, KeyButton);
|
||||
virtual void keyUp(KeyID, KeyModifierMask, KeyButton);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -201,19 +201,19 @@ CPrimaryClient::setClipboardDirty(ClipboardID id, bool dirty)
|
|||
}
|
||||
|
||||
void
|
||||
CPrimaryClient::keyDown(KeyID, KeyModifierMask)
|
||||
CPrimaryClient::keyDown(KeyID, KeyModifierMask, KeyButton)
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
|
||||
void
|
||||
CPrimaryClient::keyRepeat(KeyID, KeyModifierMask, SInt32)
|
||||
CPrimaryClient::keyRepeat(KeyID, KeyModifierMask, SInt32, KeyButton)
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
|
||||
void
|
||||
CPrimaryClient::keyUp(KeyID, KeyModifierMask)
|
||||
CPrimaryClient::keyUp(KeyID, KeyModifierMask, KeyButton)
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
|
|
|
@ -107,9 +107,10 @@ public:
|
|||
virtual void setClipboard(ClipboardID, const CString&);
|
||||
virtual void grabClipboard(ClipboardID);
|
||||
virtual void setClipboardDirty(ClipboardID, bool);
|
||||
virtual void keyDown(KeyID, KeyModifierMask);
|
||||
virtual void keyRepeat(KeyID, KeyModifierMask, SInt32 count);
|
||||
virtual void keyUp(KeyID, KeyModifierMask);
|
||||
virtual void keyDown(KeyID, KeyModifierMask, KeyButton);
|
||||
virtual void keyRepeat(KeyID, KeyModifierMask,
|
||||
SInt32 count, KeyButton);
|
||||
virtual void keyUp(KeyID, KeyModifierMask, KeyButton);
|
||||
virtual void mouseDown(ButtonID);
|
||||
virtual void mouseUp(ButtonID);
|
||||
virtual void mouseMove(SInt32 xAbs, SInt32 yAbs);
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "COutputPacketStream.h"
|
||||
#include "CProtocolUtil.h"
|
||||
#include "CClientProxy1_0.h"
|
||||
#include "CClientProxy1_1.h"
|
||||
#include "OptionTypes.h"
|
||||
#include "ProtocolTypes.h"
|
||||
#include "XScreen.h"
|
||||
|
@ -615,9 +616,9 @@ CServer::onOneShotTimerExpired(UInt32 id)
|
|||
}
|
||||
|
||||
void
|
||||
CServer::onKeyDown(KeyID id, KeyModifierMask mask)
|
||||
CServer::onKeyDown(KeyID id, KeyModifierMask mask, KeyButton button)
|
||||
{
|
||||
LOG((CLOG_DEBUG1 "onKeyDown id=%d mask=0x%04x", id, mask));
|
||||
LOG((CLOG_DEBUG1 "onKeyDown id=%d mask=0x%04x button=0x%04x", id, mask, button));
|
||||
CLock lock(&m_mutex);
|
||||
assert(m_active != NULL);
|
||||
|
||||
|
@ -627,13 +628,13 @@ CServer::onKeyDown(KeyID id, KeyModifierMask mask)
|
|||
}
|
||||
|
||||
// relay
|
||||
m_active->keyDown(id, mask);
|
||||
m_active->keyDown(id, mask, button);
|
||||
}
|
||||
|
||||
void
|
||||
CServer::onKeyUp(KeyID id, KeyModifierMask mask)
|
||||
CServer::onKeyUp(KeyID id, KeyModifierMask mask, KeyButton button)
|
||||
{
|
||||
LOG((CLOG_DEBUG1 "onKeyUp id=%d mask=0x%04x", id, mask));
|
||||
LOG((CLOG_DEBUG1 "onKeyUp id=%d mask=0x%04x button=0x%04x", id, mask, button));
|
||||
CLock lock(&m_mutex);
|
||||
assert(m_active != NULL);
|
||||
|
||||
|
@ -643,13 +644,14 @@ CServer::onKeyUp(KeyID id, KeyModifierMask mask)
|
|||
}
|
||||
|
||||
// relay
|
||||
m_active->keyUp(id, mask);
|
||||
m_active->keyUp(id, mask, button);
|
||||
}
|
||||
|
||||
void
|
||||
CServer::onKeyRepeat(KeyID id, KeyModifierMask mask, SInt32 count)
|
||||
CServer::onKeyRepeat(KeyID id, KeyModifierMask mask,
|
||||
SInt32 count, KeyButton button)
|
||||
{
|
||||
LOG((CLOG_DEBUG1 "onKeyRepeat id=%d mask=0x%04x count=%d", id, mask, count));
|
||||
LOG((CLOG_DEBUG1 "onKeyRepeat id=%d mask=0x%04x count=%d button=0x%04x", id, mask, count, button));
|
||||
CLock lock(&m_mutex);
|
||||
assert(m_active != NULL);
|
||||
|
||||
|
@ -660,7 +662,7 @@ CServer::onKeyRepeat(KeyID id, KeyModifierMask mask, SInt32 count)
|
|||
}
|
||||
|
||||
// relay
|
||||
m_active->keyRepeat(id, mask, count);
|
||||
m_active->keyRepeat(id, mask, count, button);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1698,18 +1700,7 @@ CServer::handshakeClient(IDataSocket* socket)
|
|||
}
|
||||
|
||||
// disallow invalid version numbers
|
||||
if (major < 0 || minor < 0) {
|
||||
throw XIncompatibleClient(major, minor);
|
||||
}
|
||||
|
||||
// disallow connection from test versions to release versions
|
||||
if (major == 0 && kProtocolMajorVersion != 0) {
|
||||
throw XIncompatibleClient(major, minor);
|
||||
}
|
||||
|
||||
// hangup (with error) if version isn't supported
|
||||
if (major > kProtocolMajorVersion ||
|
||||
(major == kProtocolMajorVersion && minor > kProtocolMinorVersion)) {
|
||||
if (major <= 0 || minor < 0) {
|
||||
throw XIncompatibleClient(major, minor);
|
||||
}
|
||||
|
||||
|
@ -1720,7 +1711,22 @@ CServer::handshakeClient(IDataSocket* socket)
|
|||
|
||||
// create client proxy for highest version supported by the client
|
||||
LOG((CLOG_DEBUG1 "creating proxy for client \"%s\" version %d.%d", name.c_str(), major, minor));
|
||||
proxy = new CClientProxy1_0(this, name, input, output);
|
||||
if (major == 1) {
|
||||
switch (minor) {
|
||||
case 0:
|
||||
proxy = new CClientProxy1_0(this, name, input, output);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
proxy = new CClientProxy1_1(this, name, input, output);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// hangup (with error) if version isn't supported
|
||||
if (proxy == NULL) {
|
||||
throw XIncompatibleClient(major, minor);
|
||||
}
|
||||
|
||||
// negotiate
|
||||
// FIXME
|
||||
|
|
|
@ -187,9 +187,10 @@ public:
|
|||
// IPrimaryScreenReceiver overrides
|
||||
virtual void onScreensaver(bool activated);
|
||||
virtual void onOneShotTimerExpired(UInt32 id);
|
||||
virtual void onKeyDown(KeyID, KeyModifierMask);
|
||||
virtual void onKeyUp(KeyID, KeyModifierMask);
|
||||
virtual void onKeyRepeat(KeyID, KeyModifierMask, SInt32 count);
|
||||
virtual void onKeyDown(KeyID, KeyModifierMask, KeyButton);
|
||||
virtual void onKeyUp(KeyID, KeyModifierMask, KeyButton);
|
||||
virtual void onKeyRepeat(KeyID, KeyModifierMask,
|
||||
SInt32 count, KeyButton);
|
||||
virtual void onMouseDown(ButtonID);
|
||||
virtual void onMouseUp(ButtonID);
|
||||
virtual bool onMouseMovePrimary(SInt32 x, SInt32 y);
|
||||
|
|
|
@ -27,6 +27,7 @@ noinst_LIBRARIES = libserver.a
|
|||
libserver_a_SOURCES = \
|
||||
CClientProxy.cpp \
|
||||
CClientProxy1_0.cpp \
|
||||
CClientProxy1_1.cpp \
|
||||
CConfig.cpp \
|
||||
CHTTPServer.cpp \
|
||||
CPrimaryClient.cpp \
|
||||
|
|
|
@ -124,23 +124,28 @@ public:
|
|||
//! Notify of key press
|
||||
/*!
|
||||
Synthesize key events to generate a press of key \c id. If possible
|
||||
match the given modifier mask.
|
||||
match the given modifier mask. The KeyButton identifies the physical
|
||||
key on the server that generated this key down. The client must
|
||||
ensure that a key up or key repeat that uses the same KeyButton will
|
||||
synthesize an up or repeat for the same client key synthesized by
|
||||
keyDown().
|
||||
*/
|
||||
virtual void keyDown(KeyID id, KeyModifierMask) = 0;
|
||||
virtual void keyDown(KeyID id, KeyModifierMask, KeyButton) = 0;
|
||||
|
||||
//! Notify of key repeat
|
||||
/*!
|
||||
Synthesize key events to generate a press and release of key \c id
|
||||
\c count times. If possible match the given modifier mask.
|
||||
*/
|
||||
virtual void keyRepeat(KeyID id, KeyModifierMask, SInt32 count) = 0;
|
||||
virtual void keyRepeat(KeyID id, KeyModifierMask,
|
||||
SInt32 count, KeyButton) = 0;
|
||||
|
||||
//! Notify of key release
|
||||
/*!
|
||||
Synthesize key events to generate a release of key \c id. If possible
|
||||
match the given modifier mask.
|
||||
*/
|
||||
virtual void keyUp(KeyID id, KeyModifierMask) = 0;
|
||||
virtual void keyUp(KeyID id, KeyModifierMask, KeyButton) = 0;
|
||||
|
||||
//! Notify of mouse press
|
||||
/*!
|
||||
|
|
|
@ -103,23 +103,28 @@ public:
|
|||
//! Notify of key press
|
||||
/*!
|
||||
Synthesize key events to generate a press of key \c id. If possible
|
||||
match the given modifier mask.
|
||||
match the given modifier mask. The KeyButton identifies the physical
|
||||
key on the server that generated this key down. The client must
|
||||
ensure that a key up or key repeat that uses the same KeyButton will
|
||||
synthesize an up or repeat for the same client key synthesized by
|
||||
keyDown().
|
||||
*/
|
||||
virtual void keyDown(KeyID id, KeyModifierMask) = 0;
|
||||
virtual void keyDown(KeyID id, KeyModifierMask, KeyButton) = 0;
|
||||
|
||||
//! Notify of key repeat
|
||||
/*!
|
||||
Synthesize key events to generate a press and release of key \c id
|
||||
\c count times. If possible match the given modifier mask.
|
||||
*/
|
||||
virtual void keyRepeat(KeyID id, KeyModifierMask, SInt32 count) = 0;
|
||||
virtual void keyRepeat(KeyID id, KeyModifierMask,
|
||||
SInt32 count, KeyButton) = 0;
|
||||
|
||||
//! Notify of key release
|
||||
/*!
|
||||
Synthesize key events to generate a release of key \c id. If possible
|
||||
match the given modifier mask.
|
||||
*/
|
||||
virtual void keyUp(KeyID id, KeyModifierMask) = 0;
|
||||
virtual void keyUp(KeyID id, KeyModifierMask, KeyButton) = 0;
|
||||
|
||||
//! Notify of mouse press
|
||||
/*!
|
||||
|
|
|
@ -43,11 +43,12 @@ public:
|
|||
// call to notify of events. onMouseMovePrimary() returns
|
||||
// true iff the mouse enters a jump zone and jumps.
|
||||
//! Notify of key press
|
||||
virtual void onKeyDown(KeyID, KeyModifierMask) = 0;
|
||||
virtual void onKeyDown(KeyID, KeyModifierMask, KeyButton) = 0;
|
||||
//! Notify of key release
|
||||
virtual void onKeyUp(KeyID, KeyModifierMask) = 0;
|
||||
virtual void onKeyUp(KeyID, KeyModifierMask, KeyButton) = 0;
|
||||
//! Notify of key repeat
|
||||
virtual void onKeyRepeat(KeyID, KeyModifierMask, SInt32 count) = 0;
|
||||
virtual void onKeyRepeat(KeyID, KeyModifierMask,
|
||||
SInt32 count, KeyButton) = 0;
|
||||
//! Notify of mouse button press
|
||||
virtual void onMouseDown(ButtonID) = 0;
|
||||
//! Notify of mouse button release
|
||||
|
|
|
@ -19,12 +19,19 @@
|
|||
|
||||
//! Key ID
|
||||
/*!
|
||||
Type to hold a key identifier. The encoding is UTF-32, using
|
||||
Type to hold a key symbol identifier. The encoding is UTF-32, using
|
||||
U+E000 through U+EFFF for the various control keys (e.g. arrow
|
||||
keys, function keys, modifier keys, etc).
|
||||
*/
|
||||
typedef UInt32 KeyID;
|
||||
|
||||
//! Key Code
|
||||
/*!
|
||||
Type to hold a physical key identifier. That is, it identifies a
|
||||
physical key on the keyboard.
|
||||
*/
|
||||
typedef UInt16 KeyButton;
|
||||
|
||||
//! Modifier key mask
|
||||
/*!
|
||||
Type to hold a bitmask of key modifiers (e.g. shift keys).
|
||||
|
|
|
@ -18,8 +18,10 @@
|
|||
#include "BasicTypes.h"
|
||||
|
||||
// protocol version number
|
||||
// 1.0: initial protocol
|
||||
// 1.1: adds KeyCode to key press, release, and repeat
|
||||
static const SInt16 kProtocolMajorVersion = 1;
|
||||
static const SInt16 kProtocolMinorVersion = 0;
|
||||
static const SInt16 kProtocolMinorVersion = 1;
|
||||
|
||||
// default contact port number
|
||||
static const UInt16 kDefaultPort = 24800;
|
||||
|
@ -137,16 +139,34 @@ static const char kMsgCInfoAck[] = "CIAK";
|
|||
//
|
||||
|
||||
// key pressed: primary -> secondary
|
||||
// $1 = KeyID, $2 = KeyModifierMask
|
||||
static const char kMsgDKeyDown[] = "DKDN%2i%2i";
|
||||
// $1 = KeyID, $2 = KeyModifierMask, $3 = KeyButton
|
||||
// the KeyButton identifies the physical key on the primary used to
|
||||
// generate this key. the secondary should note the KeyButton along
|
||||
// with the physical key it uses to generate the key press. on
|
||||
// release, the secondary can then use the primary's KeyButton to
|
||||
// find its corresponding physical key and release it. this is
|
||||
// necessary because the KeyID on release may not be the KeyID of
|
||||
// the press. this can happen with combining (dead) keys or if
|
||||
// the keyboard layouts are not identical and the user releases
|
||||
// a modifier key before releasing the modified key.
|
||||
static const char kMsgDKeyDown[] = "DKDN%2i%2i%2i";
|
||||
|
||||
// key pressed 1.0: same as above but without KeyButton
|
||||
static const char kMsgDKeyDown1_0[] = "DKDN%2i%2i";
|
||||
|
||||
// key auto-repeat: primary -> secondary
|
||||
// $1 = KeyID, $2 = KeyModifierMask, $3 = number of repeats
|
||||
static const char kMsgDKeyRepeat[] = "DKRP%2i%2i%2i";
|
||||
// $1 = KeyID, $2 = KeyModifierMask, $3 = number of repeats, $4 = KeyButton
|
||||
static const char kMsgDKeyRepeat[] = "DKRP%2i%2i%2i%2i";
|
||||
|
||||
// key auto-repeat 1.0: same as above but without KeyButton
|
||||
static const char kMsgDKeyRepeat1_0[] = "DKRP%2i%2i%2i";
|
||||
|
||||
// key released: primary -> secondary
|
||||
// $1 = KeyID, $2 = KeyModifierMask
|
||||
static const char kMsgDKeyUp[] = "DKUP%2i%2i";
|
||||
// $1 = KeyID, $2 = KeyModifierMask, $3 = KeyButton
|
||||
static const char kMsgDKeyUp[] = "DKUP%2i%2i%2i";
|
||||
|
||||
// key released 1.0: same as above but without KeyButton
|
||||
static const char kMsgDKeyUp1_0[] = "DKUP%2i%2i";
|
||||
|
||||
// mouse button pressed: primary -> secondary
|
||||
// $1 = ButtonID
|
||||
|
|
Loading…
Reference in New Issue