diff --git a/client/CXWindowsSecondaryScreen.cpp b/client/CXWindowsSecondaryScreen.cpp index b0187ccb..968cf5cf 100644 --- a/client/CXWindowsSecondaryScreen.cpp +++ b/client/CXWindowsSecondaryScreen.cpp @@ -371,8 +371,8 @@ CXWindowsSecondaryScreen::mapKey(Keystrokes& keys, KeyCode& keycode, // that cannot be accomodated. // note if the key is the caps lock and it's "half-duplex" - const bool isHalfDuplex = ((id == XK_Caps_Lock && m_capsLockHalfDuplex) || - (id == XK_Num_Lock && m_numLockHalfDuplex)); + const bool isHalfDuplex = ((id == kKeyCapsLock && m_capsLockHalfDuplex) || + (id == kKeyNumLock && m_numLockHalfDuplex)); // ignore releases and repeats for half-duplex keys if (isHalfDuplex && action != kPress) { @@ -385,10 +385,10 @@ CXWindowsSecondaryScreen::mapKey(Keystrokes& keys, KeyCode& keycode, if (!findKeyCode(keycode, outMask, id, maskToX(mask))) { // we cannot generate the desired keysym because no key // maps to that keysym. just return the current mask. - log((CLOG_DEBUG2 "no keycode for keysym %d modifiers 0x%04x", id, mask)); + log((CLOG_DEBUG2 "no keycode for KeyID %d modifiers 0x%04x", id, mask)); return m_mask; } - log((CLOG_DEBUG2 "keysym %d -> keycode %d modifiers 0x%04x", id, keycode, outMask)); + log((CLOG_DEBUG2 "keysym %d -> KeyID %d modifiers 0x%04x", id, keycode, outMask)); // if we cannot match the modifier mask then don't return any // keys and just return the current mask. @@ -580,67 +580,93 @@ bool CXWindowsSecondaryScreen::findKeyCode(KeyCode& keycode, unsigned int& maskOut, KeyID id, unsigned int maskIn) const { - // if XK_Tab is requested with shift active then try XK_ISO_Left_Tab + // convert id to keysym + KeySym keysym = 0; + switch (id & 0xffffff00) { + case 0x0000: + // Latin-1 + keysym = static_cast(id); + break; + + case 0xee00: + // ISO 9995 Function and Modifier Keys + if (id == kKeyLeftTab) { + keysym = XK_ISO_Left_Tab; + } + break; + + case 0xef00: + // MISCELLANY + keysym = static_cast(id - 0xef00 + 0xff00); + break; + } + + // fail if unknown key + if (keysym == 0) { + return false; + } + + // if kKeyTab is requested with shift active then try XK_ISO_Left_Tab // instead. if that doesn't work, we'll fall back to XK_Tab with // shift active. this is to handle primary screens that don't map // XK_ISO_Left_Tab sending events to secondary screens that do. - if (id == XK_Tab && (maskIn & ShiftMask) != 0) { - id = XK_ISO_Left_Tab; + if (keysym == XK_Tab && (maskIn & ShiftMask) != 0) { + keysym = XK_ISO_Left_Tab; maskIn &= ~ShiftMask; } // find a keycode to generate id. XKeysymToKeycode() almost does // what we need but won't tell us which index to use with the // keycode. return false if there's no keycode to generate id. - KeyCodeMap::const_iterator index = m_keycodeMap.find(id); + KeyCodeMap::const_iterator index = m_keycodeMap.find(keysym); if (index == m_keycodeMap.end()) { // try backup keysym for certain keys (particularly the numpad // keys since most laptops don't have a separate numpad and the // numpad overlaying the main keyboard may not have movement // key bindings). - switch (id) { + switch (keysym) { case XK_KP_Home: - id = XK_Home; + keysym = XK_Home; break; case XK_KP_Left: - id = XK_Left; + keysym = XK_Left; break; case XK_KP_Up: - id = XK_Up; + keysym = XK_Up; break; case XK_KP_Right: - id = XK_Right; + keysym = XK_Right; break; case XK_KP_Down: - id = XK_Down; + keysym = XK_Down; break; case XK_KP_Prior: - id = XK_Prior; + keysym = XK_Prior; break; case XK_KP_Next: - id = XK_Next; + keysym = XK_Next; break; case XK_KP_End: - id = XK_End; + keysym = XK_End; break; case XK_KP_Insert: - id = XK_Insert; + keysym = XK_Insert; break; case XK_KP_Delete: - id = XK_Delete; + keysym = XK_Delete; break; case XK_ISO_Left_Tab: - id = XK_Tab; + keysym = XK_Tab; maskIn |= ShiftMask; break; @@ -648,7 +674,7 @@ CXWindowsSecondaryScreen::findKeyCode(KeyCode& keycode, return false; } - index = m_keycodeMap.find(id); + index = m_keycodeMap.find(keysym); if (index == m_keycodeMap.end()) { return false; } @@ -659,14 +685,14 @@ CXWindowsSecondaryScreen::findKeyCode(KeyCode& keycode, // compute output mask. that's the set of modifiers that need to // be enabled when the keycode event is encountered in order to - // generate the id keysym and match maskIn. it's possible that + // generate the keysym and match maskIn. it's possible that // maskIn wants, say, a shift key to be down but that would make // it impossible to generate the keysym. in that case we must // override maskIn. this is complicated by caps/shift-lock and // num-lock. maskOut = (maskIn & ~index->second.m_keyMaskMask); log((CLOG_DEBUG2 "maskIn(0x%04x) & ~maskMask(0x%04x) -> 0x%04x", maskIn, index->second.m_keyMaskMask, maskOut)); - if (IsKeypadKey(id) || IsPrivateKeypadKey(id)) { + if (IsKeypadKey(keysym) || IsPrivateKeypadKey(keysym)) { if ((m_mask & m_numLockMask) != 0) { maskOut &= ~index->second.m_keyMask; maskOut |= m_numLockMask; @@ -687,7 +713,7 @@ CXWindowsSecondaryScreen::findKeyCode(KeyCode& keycode, // characters that are not case conversions. see if // case conversion is necessary. KeySym lKey, uKey; - XConvertCase(id, &lKey, &uKey); + XConvertCase(keysym, &lKey, &uKey); if (lKey != uKey) { log((CLOG_DEBUG2 "case convertable, shift && capsLock -> caps lock")); maskShift = m_capsLockMask; diff --git a/server/CXWindowsPrimaryScreen.cpp b/server/CXWindowsPrimaryScreen.cpp index 0dc659e9..ba4e8a39 100644 --- a/server/CXWindowsPrimaryScreen.cpp +++ b/server/CXWindowsPrimaryScreen.cpp @@ -12,6 +12,7 @@ # include # include # define XK_MISCELLANY +# define XK_XKB_KEYS # include #endif @@ -172,10 +173,10 @@ CXWindowsPrimaryScreen::onEvent(CEvent* event) const KeyID key = mapKey(&xevent.xkey); if (key != kKeyNone) { m_receiver->onKeyDown(key, mask); - if (key == XK_Caps_Lock && m_capsLockHalfDuplex) { + if (key == kKeyCapsLock && m_capsLockHalfDuplex) { m_receiver->onKeyUp(key, mask | KeyModifierCapsLock); } - else if (key == XK_Num_Lock && m_numLockHalfDuplex) { + else if (key == kKeyNumLock && m_numLockHalfDuplex) { m_receiver->onKeyUp(key, mask | KeyModifierNumLock); } } @@ -209,10 +210,10 @@ CXWindowsPrimaryScreen::onEvent(CEvent* event) if (!hasPress) { // 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 == XK_Caps_Lock && m_capsLockHalfDuplex) { + if (key == kKeyCapsLock && m_capsLockHalfDuplex) { m_receiver->onKeyDown(key, mask); } - else if (key == XK_Num_Lock && m_numLockHalfDuplex) { + else if (key == kKeyNumLock && m_numLockHalfDuplex) { m_receiver->onKeyDown(key, mask); } m_receiver->onKeyUp(key, mask); @@ -621,12 +622,35 @@ CXWindowsPrimaryScreen::mapModifier(unsigned int state) const KeyID CXWindowsPrimaryScreen::mapKey(XKeyEvent* event) const { + CDisplayLock display(m_screen); + + // convert to a keysym + // FIXME -- we're not properly handling unicode KeySym keysym; char dummy[1]; - - CDisplayLock display(m_screen); XLookupString(event, dummy, 0, &keysym, NULL); - return static_cast(keysym); + + // convert key + switch (keysym & 0xffffff00) { + case 0x0000: + // Latin-1 + return static_cast(keysym); + + case 0xfe00: + // ISO 9995 Function and Modifier Keys + if (keysym == XK_ISO_Left_Tab) { + return kKeyLeftTab; + } + return kKeyNone; + + case 0xff00: + // MISCELLANY + return static_cast(keysym - 0xff00 + 0xef00); + + default: + // FIXME -- support unicode characters + return kKeyNone; + } } ButtonID diff --git a/synergy/KeyTypes.h b/synergy/KeyTypes.h index f9ca8241..947f48f6 100644 --- a/synergy/KeyTypes.h +++ b/synergy/KeyTypes.h @@ -3,15 +3,14 @@ #include "BasicTypes.h" -// type to hold a key identifier +// type to hold a key 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; // type to hold bitmask of key modifiers (e.g. shift keys) typedef UInt32 KeyModifierMask; -// key codes -static const KeyID kKeyNone = 0; - // modifier key bitmasks static const KeyModifierMask KeyModifierShift = 0x0001; static const KeyModifierMask KeyModifierControl = 0x0002; @@ -21,4 +20,145 @@ static const KeyModifierMask KeyModifierCapsLock = 0x1000; static const KeyModifierMask KeyModifierNumLock = 0x2000; static const KeyModifierMask KeyModifierScrollLock = 0x4000; +// +// key codes. all codes except kKeyNone are equal to the corresponding +// X11 keysym - 0x1000. +// + +// no key +static const KeyID kKeyNone = 0x0000; + +// TTY functions +static const KeyID kKeyBackSpace = 0xEF08; /* back space, back char */ +static const KeyID kKeyTab = 0xEF09; +static const KeyID kKeyLinefeed = 0xEF0A; /* Linefeed, LF */ +static const KeyID kKeyClear = 0xEF0B; +static const KeyID kKeyReturn = 0xEF0D; /* Return, enter */ +static const KeyID kKeyPause = 0xEF13; /* Pause, hold */ +static const KeyID kKeyScrollLock = 0xEF14; +static const KeyID kKeySysReq = 0xEF15; +static const KeyID kKeyEscape = 0xEF1B; +static const KeyID kKeyDelete = 0xEFFF; /* Delete, rubout */ + +// cursor control +static const KeyID kKeyHome = 0xEF50; +static const KeyID kKeyLeft = 0xEF51; /* Move left, left arrow */ +static const KeyID kKeyUp = 0xEF52; /* Move up, up arrow */ +static const KeyID kKeyRight = 0xEF53; /* Move right, right arrow */ +static const KeyID kKeyDown = 0xEF54; /* Move down, down arrow */ +static const KeyID kKeyPageUp = 0xEF55; +static const KeyID kKeyPageDown = 0xEF56; +static const KeyID kKeyEnd = 0xEF57; /* EOL */ +static const KeyID kKeyBegin = 0xEF58; /* BOL */ + +// misc functions +static const KeyID kKeySelect = 0xEF60; /* Select, mark */ +static const KeyID kKeyPrint = 0xEF61; +static const KeyID kKeyExecute = 0xEF62; /* Execute, run, do */ +static const KeyID kKeyInsert = 0xEF63; /* Insert, insert here */ +static const KeyID kKeyUndo = 0xEF65; /* Undo, oops */ +static const KeyID kKeyRedo = 0xEF66; /* redo, again */ +static const KeyID kKeyMenu = 0xEF67; +static const KeyID kKeyFind = 0xEF68; /* Find, search */ +static const KeyID kKeyCancel = 0xEF69; /* Cancel, stop, abort, exit */ +static const KeyID kKeyHelp = 0xEF6A; /* Help */ +static const KeyID kKeyBreak = 0xEF6B; +static const KeyID kKeyModeSwitch = 0xEF7E; /* Character set switch */ +static const KeyID kKeyNumLock = 0xEF7F; + +// keypad +static const KeyID kKeyKP_Space = 0xEF80; /* space */ +static const KeyID kKeyKP_Tab = 0xEF89; +static const KeyID kKeyKP_Enter = 0xEF8D; /* enter */ +static const KeyID kKeyKP_F1 = 0xEF91; /* PF1, KP_A, ... */ +static const KeyID kKeyKP_F2 = 0xEF92; +static const KeyID kKeyKP_F3 = 0xEF93; +static const KeyID kKeyKP_F4 = 0xEF94; +static const KeyID kKeyKP_Home = 0xEF95; +static const KeyID kKeyKP_Left = 0xEF96; +static const KeyID kKeyKP_Up = 0xEF97; +static const KeyID kKeyKP_Right = 0xEF98; +static const KeyID kKeyKP_Down = 0xEF99; +static const KeyID kKeyKP_Prior = 0xEF9A; +static const KeyID kKeyKP_PageUp = 0xEF9A; +static const KeyID kKeyKP_Next = 0xEF9B; +static const KeyID kKeyKP_PageDown = 0xEF9B; +static const KeyID kKeyKP_End = 0xEF9C; +static const KeyID kKeyKP_Begin = 0xEF9D; +static const KeyID kKeyKP_Insert = 0xEF9E; +static const KeyID kKeyKP_Delete = 0xEF9F; +static const KeyID kKeyKP_Equal = 0xEFBD; /* equals */ +static const KeyID kKeyKP_Multiply = 0xEFAA; +static const KeyID kKeyKP_Add = 0xEFAB; +static const KeyID kKeyKP_Separator= 0xEFAC; /* separator, often comma */ +static const KeyID kKeyKP_Subtract = 0xEFAD; +static const KeyID kKeyKP_Decimal = 0xEFAE; +static const KeyID kKeyKP_Divide = 0xEFAF; +static const KeyID kKeyKP_0 = 0xEFB0; +static const KeyID kKeyKP_1 = 0xEFB1; +static const KeyID kKeyKP_2 = 0xEFB2; +static const KeyID kKeyKP_3 = 0xEFB3; +static const KeyID kKeyKP_4 = 0xEFB4; +static const KeyID kKeyKP_5 = 0xEFB5; +static const KeyID kKeyKP_6 = 0xEFB6; +static const KeyID kKeyKP_7 = 0xEFB7; +static const KeyID kKeyKP_8 = 0xEFB8; +static const KeyID kKeyKP_9 = 0xEFB9; + +// function keys +static const KeyID kKeyF1 = 0xEFBE; +static const KeyID kKeyF2 = 0xEFBF; +static const KeyID kKeyF3 = 0xEFC0; +static const KeyID kKeyF4 = 0xEFC1; +static const KeyID kKeyF5 = 0xEFC2; +static const KeyID kKeyF6 = 0xEFC3; +static const KeyID kKeyF7 = 0xEFC4; +static const KeyID kKeyF8 = 0xEFC5; +static const KeyID kKeyF9 = 0xEFC6; +static const KeyID kKeyF10 = 0xEFC7; +static const KeyID kKeyF11 = 0xEFC8; +static const KeyID kKeyF12 = 0xEFC9; +static const KeyID kKeyF13 = 0xEFCA; +static const KeyID kKeyF14 = 0xEFCB; +static const KeyID kKeyF15 = 0xEFCC; +static const KeyID kKeyF16 = 0xEFCD; +static const KeyID kKeyF17 = 0xEFCE; +static const KeyID kKeyF18 = 0xEFCF; +static const KeyID kKeyF19 = 0xEFD0; +static const KeyID kKeyF20 = 0xEFD1; +static const KeyID kKeyF21 = 0xEFD2; +static const KeyID kKeyF22 = 0xEFD3; +static const KeyID kKeyF23 = 0xEFD4; +static const KeyID kKeyF24 = 0xEFD5; +static const KeyID kKeyF25 = 0xEFD6; +static const KeyID kKeyF26 = 0xEFD7; +static const KeyID kKeyF27 = 0xEFD8; +static const KeyID kKeyF28 = 0xEFD9; +static const KeyID kKeyF29 = 0xEFDA; +static const KeyID kKeyF30 = 0xEFDB; +static const KeyID kKeyF31 = 0xEFDC; +static const KeyID kKeyF32 = 0xEFDD; +static const KeyID kKeyF33 = 0xEFDE; +static const KeyID kKeyF34 = 0xEFDF; +static const KeyID kKeyF35 = 0xEFE0; + +// modifiers +static const KeyID kKeyShift_L = 0xEFE1; /* Left shift */ +static const KeyID kKeyShift_R = 0xEFE2; /* Right shift */ +static const KeyID kKeyControl_L = 0xEFE3; /* Left control */ +static const KeyID kKeyControl_R = 0xEFE4; /* Right control */ +static const KeyID kKeyCapsLock = 0xEFE5; /* Caps lock */ +static const KeyID kKeyShiftLock = 0xEFE6; /* Shift lock */ +static const KeyID kKeyMeta_L = 0xEFE7; /* Left meta */ +static const KeyID kKeyMeta_R = 0xEFE8; /* Right meta */ +static const KeyID kKeyAlt_L = 0xEFE9; /* Left alt */ +static const KeyID kKeyAlt_R = 0xEFEA; /* Right alt */ +static const KeyID kKeySuper_L = 0xEFEB; /* Left super */ +static const KeyID kKeySuper_R = 0xEFEC; /* Right super */ +static const KeyID kKeyHyper_L = 0xEFED; /* Left hyper */ +static const KeyID kKeyHyper_R = 0xEFEE; /* Right hyper */ + +// more function and modifier keys +static const KeyID kKeyLeftTab = 0xEE20; + #endif