CXWindowsKeyState.cpp

00001 /*
00002  * synergy -- mouse and keyboard sharing utility
00003  * Copyright (C) 2003 Chris Schoeneman
00004  * 
00005  * This package is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU General Public License
00007  * found in the file COPYING that should have accompanied this file.
00008  * 
00009  * This package is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  */
00014 
00015 #include "CXWindowsKeyState.h"
00016 #include "CXWindowsUtil.h"
00017 #include "CLog.h"
00018 #include "CStringUtil.h"
00019 #include "stdmap.h"
00020 #if X_DISPLAY_MISSING
00021 #   error X11 is required to build synergy
00022 #else
00023 #   include <X11/X.h>
00024 #   include <X11/Xutil.h>
00025 #   define XK_MISCELLANY
00026 #   define XK_XKB_KEYS
00027 #   include <X11/keysymdef.h>
00028 #if HAVE_XKB_EXTENSION
00029 #   include <X11/XKBlib.h>
00030 #endif
00031 #endif
00032 
00033 CXWindowsKeyState::CXWindowsKeyState(Display* display, bool useXKB) :
00034     m_display(display)
00035 {
00036     XGetKeyboardControl(m_display, &m_keyboardState);
00037 #if HAVE_XKB_EXTENSION
00038     if (useXKB) {
00039         m_xkb = XkbGetMap(m_display, XkbKeyActionsMask | XkbKeyBehaviorsMask |
00040                                 XkbAllClientInfoMask, XkbUseCoreKbd);
00041     }
00042     else {
00043         m_xkb = NULL;
00044     }
00045 #endif
00046     setActiveGroup(kGroupPollAndSet);
00047 }
00048 
00049 CXWindowsKeyState::~CXWindowsKeyState()
00050 {
00051 #if HAVE_XKB_EXTENSION
00052     if (m_xkb != NULL) {
00053         XkbFreeKeyboard(m_xkb, 0, True);
00054     }
00055 #endif
00056 }
00057 
00058 void
00059 CXWindowsKeyState::setActiveGroup(SInt32 group)
00060 {
00061     if (group == kGroupPollAndSet) {
00062         m_group = -1;
00063         m_group = pollActiveGroup();
00064     }
00065     else if (group == kGroupPoll) {
00066         m_group = -1;
00067     }
00068     else {
00069         assert(group >= 0);
00070         m_group = group;
00071     }
00072 }
00073 
00074 void
00075 CXWindowsKeyState::setAutoRepeat(const XKeyboardState& state)
00076 {
00077     m_keyboardState = state;
00078 }
00079 
00080 KeyModifierMask
00081 CXWindowsKeyState::mapModifiersFromX(unsigned int state) const
00082 {
00083     UInt32 offset = 8 * getGroupFromState(state);
00084     KeyModifierMask mask = 0;
00085     for (int i = 0; i < 8; ++i) {
00086         if ((state & (1u << i)) != 0) {
00087             mask |= m_modifierFromX[offset + i];
00088         }
00089     }
00090     return mask;
00091 }
00092 
00093 bool
00094 CXWindowsKeyState::mapModifiersToX(KeyModifierMask mask,
00095                 unsigned int& modifiers) const
00096 {
00097     modifiers = 0;
00098 
00099     for (SInt32 i = 0; i < kKeyModifierNumBits; ++i) {
00100         KeyModifierMask bit = (1u << i);
00101         if ((mask & bit) != 0) {
00102             KeyModifierToXMask::const_iterator j = m_modifierToX.find(bit);
00103             if (j == m_modifierToX.end()) {
00104                 return false;
00105             }
00106             else {
00107                 modifiers |= j->second;
00108             }
00109         }
00110     }
00111 
00112     return true;
00113 }
00114 
00115 void
00116 CXWindowsKeyState::mapKeyToKeycodes(KeyID key, CKeycodeList& keycodes) const
00117 {
00118     keycodes.clear();
00119     std::pair<KeyToKeyCodeMap::const_iterator,
00120         KeyToKeyCodeMap::const_iterator> range =
00121             m_keyCodeFromKey.equal_range(key);
00122     for (KeyToKeyCodeMap::const_iterator i = range.first;
00123                                 i != range.second; ++i) {
00124         keycodes.push_back(i->second);
00125     }
00126 }
00127 
00128 bool
00129 CXWindowsKeyState::fakeCtrlAltDel()
00130 {
00131     // pass keys through unchanged
00132     return false;
00133 }
00134 
00135 KeyModifierMask
00136 CXWindowsKeyState::pollActiveModifiers() const
00137 {
00138     Window root = DefaultRootWindow(m_display), window;
00139     int xRoot, yRoot, xWindow, yWindow;
00140     unsigned int state;
00141     if (!XQueryPointer(m_display, root, &root, &window,
00142                                 &xRoot, &yRoot, &xWindow, &yWindow, &state)) {
00143         state = 0;
00144     }
00145     return mapModifiersFromX(state);
00146 }
00147 
00148 SInt32
00149 CXWindowsKeyState::pollActiveGroup() const
00150 {
00151     if (m_group != -1) {
00152         assert(m_group >= 0);
00153         return m_group;
00154     }
00155 
00156 #if HAVE_XKB_EXTENSION
00157     if (m_xkb != NULL) {
00158         XkbStateRec state;
00159         if (XkbGetState(m_display, XkbUseCoreKbd, &state)) {
00160             return state.group;
00161         }
00162     }
00163 #endif
00164     return 0;
00165 }
00166 
00167 void
00168 CXWindowsKeyState::pollPressedKeys(KeyButtonSet& pressedKeys) const
00169 {
00170     char keys[32];
00171     XQueryKeymap(m_display, keys);
00172     for (UInt32 i = 0; i < 32; ++i) {
00173         for (UInt32 j = 0; j < 8; ++j) {
00174             if ((keys[i] & (1u << j)) != 0) {
00175                 pressedKeys.insert(8 * i + j);
00176             }
00177         }
00178     }
00179 }
00180 
00181 void
00182 CXWindowsKeyState::getKeyMap(CKeyMap& keyMap)
00183 {
00184     // get autorepeat info.  we must use the global_auto_repeat told to
00185     // us because it may have modified by synergy.
00186     int oldGlobalAutoRepeat = m_keyboardState.global_auto_repeat;
00187     XGetKeyboardControl(m_display, &m_keyboardState);
00188     m_keyboardState.global_auto_repeat = oldGlobalAutoRepeat;
00189 
00190 #if HAVE_XKB_EXTENSION
00191     if (m_xkb != NULL) {
00192         XkbGetUpdatedMap(m_display, XkbKeyActionsMask | XkbKeyBehaviorsMask |
00193                                 XkbAllClientInfoMask, m_xkb);
00194         updateKeysymMapXKB(keyMap);
00195     }
00196     else
00197 #endif
00198     {
00199         updateKeysymMap(keyMap);
00200     }
00201 }
00202 
00203 void
00204 CXWindowsKeyState::fakeKey(const Keystroke& keystroke)
00205 {
00206     switch (keystroke.m_type) {
00207     case Keystroke::kButton:
00208         LOG((CLOG_DEBUG1 "  %03x (%08x) %s", keystroke.m_data.m_button.m_button, keystroke.m_data.m_button.m_client, keystroke.m_data.m_button.m_press ? "down" : "up"));
00209         if (keystroke.m_data.m_button.m_repeat) {
00210             int c = keystroke.m_data.m_button.m_button;
00211             int i = (c >> 3);
00212             int b = 1 << (c & 7);
00213             if (m_keyboardState.global_auto_repeat == AutoRepeatModeOff ||
00214                 (c!=113 && c!=116 && (m_keyboardState.auto_repeats[i] & b) == 0)) {
00215                 LOG((CLOG_DEBUG1 "  discard autorepeat"));
00216                 break;
00217             }
00218         }
00219         XTestFakeKeyEvent(m_display, keystroke.m_data.m_button.m_button,
00220                             keystroke.m_data.m_button.m_press ? True : False,
00221                             CurrentTime);
00222         break;
00223 
00224     case Keystroke::kGroup:
00225         if (keystroke.m_data.m_group.m_absolute) {
00226             LOG((CLOG_DEBUG1 "  group %d", keystroke.m_data.m_group.m_group));
00227 #if HAVE_XKB_EXTENSION
00228             if (m_xkb != NULL) {
00229                 XkbLockGroup(m_display, XkbUseCoreKbd,
00230                             keystroke.m_data.m_group.m_group);
00231             }
00232             else
00233 #endif
00234             {
00235                 LOG((CLOG_DEBUG1 "  ignored"));
00236             }
00237         }
00238         else {
00239             LOG((CLOG_DEBUG1 "  group %+d", keystroke.m_data.m_group.m_group));
00240 #if HAVE_XKB_EXTENSION
00241             if (m_xkb != NULL) {
00242                 XkbLockGroup(m_display, XkbUseCoreKbd,
00243                             getEffectiveGroup(pollActiveGroup(),
00244                                 keystroke.m_data.m_group.m_group));
00245             }
00246             else
00247 #endif
00248             {
00249                 LOG((CLOG_DEBUG1 "  ignored"));
00250             }
00251         }
00252         break;
00253     }
00254     XFlush(m_display);
00255 }
00256 
00257 void
00258 CXWindowsKeyState::updateKeysymMap(CKeyMap& keyMap)
00259 {
00260     // there are up to 4 keysyms per keycode
00261     static const int maxKeysyms = 4;
00262 
00263     LOG((CLOG_DEBUG1 "non-XKB mapping"));
00264 
00265     // prepare map from X modifier to KeyModifierMask.  certain bits
00266     // are predefined.
00267     m_modifierFromX.clear();
00268     m_modifierFromX.resize(8);
00269     m_modifierFromX[ShiftMapIndex]   = KeyModifierShift;
00270     m_modifierFromX[LockMapIndex]    = KeyModifierCapsLock;
00271     m_modifierFromX[ControlMapIndex] = KeyModifierControl;
00272     m_modifierToX.clear();
00273     m_modifierToX[KeyModifierShift]    = ShiftMask;
00274     m_modifierToX[KeyModifierCapsLock] = LockMask;
00275     m_modifierToX[KeyModifierControl]  = ControlMask;
00276 
00277     // prepare map from KeyID to KeyCode
00278     m_keyCodeFromKey.clear();
00279 
00280     // get the number of keycodes
00281     int minKeycode, maxKeycode;
00282     XDisplayKeycodes(m_display, &minKeycode, &maxKeycode);
00283     int numKeycodes = maxKeycode - minKeycode + 1;
00284 
00285     // get the keyboard mapping for all keys
00286     int keysymsPerKeycode;
00287     KeySym* allKeysyms = XGetKeyboardMapping(m_display,
00288                                 minKeycode, numKeycodes,
00289                                 &keysymsPerKeycode);
00290 
00291     // it's more convenient to always have maxKeysyms KeySyms per key
00292     {
00293         KeySym* tmpKeysyms = new KeySym[maxKeysyms * numKeycodes];
00294         for (int i = 0; i < numKeycodes; ++i) {
00295             for (int j = 0; j < maxKeysyms; ++j) {
00296                 if (j < keysymsPerKeycode) {
00297                     tmpKeysyms[maxKeysyms * i + j] =
00298                         allKeysyms[keysymsPerKeycode * i + j];
00299                 }
00300                 else {
00301                     tmpKeysyms[maxKeysyms * i + j] = NoSymbol;
00302                 }
00303             }   
00304         }
00305         XFree(allKeysyms);
00306         allKeysyms = tmpKeysyms;
00307     }
00308 
00309     // get the buttons assigned to modifiers.  X11 does not predefine
00310     // the meaning of any modifiers except shift, caps lock, and the
00311     // control key.  the meaning of a modifier bit (other than those)
00312     // depends entirely on the KeySyms mapped to that bit.  unfortunately
00313     // you cannot map a bit back to the KeySym used to produce it.
00314     // for example, let's say button 1 maps to Alt_L without shift and
00315     // Meta_L with shift.  now if mod1 is mapped to button 1 that could
00316     // mean the user used Alt or Meta to turn on that modifier and there's
00317     // no way to know which.  it's also possible for one button to be
00318     // mapped to multiple bits so both mod1 and mod2 could be generated
00319     // by button 1.
00320     //
00321     // we're going to ignore any modifier for a button except the first.
00322     // with the above example, that means we'll ignore the mod2 modifier
00323     // bit unless it's also mapped to some other button.  we're also
00324     // going to ignore all KeySyms except the first modifier KeySym,
00325     // which means button 1 above won't map to Meta, just Alt.
00326     std::map<KeyCode, unsigned int> modifierButtons;
00327     XModifierKeymap* modifiers = XGetModifierMapping(m_display);
00328     for (unsigned int i = 0; i < 8; ++i) {
00329         const KeyCode* buttons =
00330             modifiers->modifiermap + i * modifiers->max_keypermod;
00331         for (int j = 0; j < modifiers->max_keypermod; ++j) {
00332             modifierButtons.insert(std::make_pair(buttons[j], i));
00333         }
00334     }
00335     XFreeModifiermap(modifiers);
00336     modifierButtons.erase(0);
00337 
00338     // Hack to deal with VMware.  When a VMware client grabs input the
00339     // player clears out the X modifier map for whatever reason.  We're
00340     // notified of the change and arrive here to discover that there
00341     // are no modifiers at all.  Since this prevents the modifiers from
00342     // working in the VMware client we'll use the last known good set
00343     // of modifiers when there are no modifiers.  If there are modifiers
00344     // we update the last known good set.
00345     if (!modifierButtons.empty()) {
00346         m_lastGoodNonXKBModifiers = modifierButtons;
00347     }
00348     else {
00349         modifierButtons = m_lastGoodNonXKBModifiers;
00350     }
00351 
00352     // add entries for each keycode
00353     CKeyMap::KeyItem item;
00354     for (int i = 0; i < numKeycodes; ++i) {
00355         KeySym* keysyms = allKeysyms + maxKeysyms * i;
00356         KeyCode keycode = static_cast<KeyCode>(i + minKeycode);
00357         item.m_button   = static_cast<KeyButton>(keycode);
00358         item.m_client   = 0;
00359 
00360         // determine modifier sensitivity
00361         item.m_sensitive = 0;
00362 
00363         // if the keysyms in levels 2 or 3 exist and differ from levels
00364         // 0 and 1 then the key is sensitive AltGr (Mode_switch)
00365         if ((keysyms[2] != NoSymbol && keysyms[2] != keysyms[0]) ||
00366             (keysyms[3] != NoSymbol && keysyms[2] != keysyms[1])) {
00367             item.m_sensitive |= KeyModifierAltGr;
00368         }
00369 
00370         // check if the key is caps-lock sensitive.  some systems only
00371         // provide one keysym for keys sensitive to caps-lock.  if we
00372         // find that then fill in the missing keysym.
00373         if (keysyms[0] != NoSymbol && keysyms[1] == NoSymbol &&
00374             keysyms[2] == NoSymbol && keysyms[3] == NoSymbol) {
00375             KeySym lKeysym, uKeysym;
00376             XConvertCase(keysyms[0], &lKeysym, &uKeysym);
00377             if (lKeysym != uKeysym) {
00378                 keysyms[0] = lKeysym;
00379                 keysyms[1] = uKeysym;
00380                 item.m_sensitive |= KeyModifierCapsLock;
00381             }
00382         }
00383         else if (keysyms[0] != NoSymbol && keysyms[1] != NoSymbol) {
00384             KeySym lKeysym, uKeysym;
00385             XConvertCase(keysyms[0], &lKeysym, &uKeysym);
00386             if (lKeysym != uKeysym &&
00387                 lKeysym == keysyms[0] &&
00388                 uKeysym == keysyms[1]) {
00389                 item.m_sensitive |= KeyModifierCapsLock;
00390             }
00391             else if (keysyms[2] != NoSymbol && keysyms[3] != NoSymbol) {
00392                 XConvertCase(keysyms[2], &lKeysym, &uKeysym);
00393                 if (lKeysym != uKeysym &&
00394                     lKeysym == keysyms[2] &&
00395                     uKeysym == keysyms[3]) {
00396                     item.m_sensitive |= KeyModifierCapsLock;
00397                 }
00398             }
00399         }
00400 
00401         // key is sensitive to shift if keysyms in levels 0 and 1 or
00402         // levels 2 and 3 don't match.  it's also sensitive to shift
00403         // if it's sensitive to caps-lock.
00404         if ((item.m_sensitive & KeyModifierCapsLock) != 0) {
00405             item.m_sensitive |= KeyModifierShift;
00406         }
00407         else if ((keysyms[0] != NoSymbol && keysyms[1] != NoSymbol &&
00408                 keysyms[0] != keysyms[1]) ||
00409                 (keysyms[2] != NoSymbol && keysyms[3] != NoSymbol &&
00410                 keysyms[2] != keysyms[3])) {
00411             item.m_sensitive |= KeyModifierShift;
00412         }
00413 
00414         // key is sensitive to numlock if any keysym on it is
00415         if (IsKeypadKey(keysyms[0]) || IsPrivateKeypadKey(keysyms[0]) ||
00416             IsKeypadKey(keysyms[1]) || IsPrivateKeypadKey(keysyms[1]) ||
00417             IsKeypadKey(keysyms[2]) || IsPrivateKeypadKey(keysyms[2]) ||
00418             IsKeypadKey(keysyms[3]) || IsPrivateKeypadKey(keysyms[3])) {
00419             item.m_sensitive |= KeyModifierNumLock;
00420         }
00421 
00422         // do each keysym (shift level)
00423         for (int j = 0; j < maxKeysyms; ++j) {
00424             item.m_id = CXWindowsUtil::mapKeySymToKeyID(keysyms[j]);
00425             if (item.m_id == kKeyNone) {
00426                 if (j != 0 && modifierButtons.count(keycode) > 0) {
00427                     // pretend the modifier works in other shift levels
00428                     // because it probably does.
00429                     if (keysyms[1] == NoSymbol || j != 3) {
00430                         item.m_id = CXWindowsUtil::mapKeySymToKeyID(keysyms[0]);
00431                     }
00432                     else {
00433                         item.m_id = CXWindowsUtil::mapKeySymToKeyID(keysyms[1]);
00434                     }
00435                 }
00436                 if (item.m_id == kKeyNone) {
00437                     continue;
00438                 }
00439             }
00440 
00441             // group is 0 for levels 0 and 1 and 1 for levels 2 and 3
00442             item.m_group = (j >= 2) ? 1 : 0;
00443 
00444             // compute required modifiers
00445             item.m_required = 0;
00446             if ((j & 1) != 0) {
00447                 item.m_required |= KeyModifierShift;
00448             }
00449             if ((j & 2) != 0) {
00450                 item.m_required |= KeyModifierAltGr;
00451             }
00452 
00453             item.m_generates = 0;
00454             item.m_lock      = false;
00455             if (modifierButtons.count(keycode) > 0) {
00456                 // get flags for modifier keys
00457                 CKeyMap::initModifierKey(item);
00458 
00459                 // add mapping from X (unless we already have)
00460                 if (item.m_generates != 0) {
00461                     unsigned int bit = modifierButtons[keycode];
00462                     if (m_modifierFromX[bit] == 0) {
00463                         m_modifierFromX[bit] = item.m_generates;
00464                         m_modifierToX[item.m_generates] = (1u << bit);
00465                     }
00466                 }
00467             }
00468 
00469             // add key
00470             keyMap.addKeyEntry(item);
00471             m_keyCodeFromKey.insert(std::make_pair(item.m_id, keycode));
00472 
00473             // add other ways to synthesize the key
00474             if ((j & 1) != 0) {
00475                 // add capslock version of key is sensitive to capslock
00476                 KeySym lKeysym, uKeysym;
00477                 XConvertCase(keysyms[j], &lKeysym, &uKeysym);
00478                 if (lKeysym != uKeysym &&
00479                     lKeysym == keysyms[j - 1] &&
00480                     uKeysym == keysyms[j]) {
00481                     item.m_required &= ~KeyModifierShift;
00482                     item.m_required |=  KeyModifierCapsLock;
00483                     keyMap.addKeyEntry(item);
00484                     item.m_required |=  KeyModifierShift;
00485                     item.m_required &= ~KeyModifierCapsLock;
00486                 }
00487 
00488                 // add numlock version of key if sensitive to numlock
00489                 if (IsKeypadKey(keysyms[j]) || IsPrivateKeypadKey(keysyms[j])) {
00490                     item.m_required &= ~KeyModifierShift;
00491                     item.m_required |=  KeyModifierNumLock;
00492                     keyMap.addKeyEntry(item);
00493                     item.m_required |=  KeyModifierShift;
00494                     item.m_required &= ~KeyModifierNumLock;
00495                 }
00496             }
00497         }
00498     }
00499 
00500     delete[] allKeysyms;
00501 }
00502 
00503 #if HAVE_XKB_EXTENSION
00504 void
00505 CXWindowsKeyState::updateKeysymMapXKB(CKeyMap& keyMap)
00506 {
00507     static const XkbKTMapEntryRec defMapEntry = {
00508         True,       // active
00509         0,          // level
00510         {
00511             0,      // mods.mask
00512             0,      // mods.real_mods
00513             0       // mods.vmods
00514         }
00515     };
00516 
00517     LOG((CLOG_DEBUG1 "XKB mapping"));
00518 
00519     // find the number of groups
00520     int maxNumGroups = 0;
00521     for (int i = m_xkb->min_key_code; i <= m_xkb->max_key_code; ++i) {
00522         int numGroups = XkbKeyNumGroups(m_xkb, static_cast<KeyCode>(i));
00523         if (numGroups > maxNumGroups) {
00524             maxNumGroups = numGroups;
00525         }
00526     }
00527 
00528     // prepare map from X modifier to KeyModifierMask
00529     std::vector<int> modifierLevel(maxNumGroups * 8, 4);
00530     m_modifierFromX.clear();
00531     m_modifierFromX.resize(maxNumGroups * 8);
00532     m_modifierToX.clear();
00533 
00534     // prepare map from KeyID to KeyCode
00535     m_keyCodeFromKey.clear();
00536 
00537     // Hack to deal with VMware.  When a VMware client grabs input the
00538     // player clears out the X modifier map for whatever reason.  We're
00539     // notified of the change and arrive here to discover that there
00540     // are no modifiers at all.  Since this prevents the modifiers from
00541     // working in the VMware client we'll use the last known good set
00542     // of modifiers when there are no modifiers.  If there are modifiers
00543     // we update the last known good set.
00544     bool useLastGoodModifiers = !hasModifiersXKB();
00545     if (!useLastGoodModifiers) {
00546         m_lastGoodXKBModifiers.clear();
00547     }
00548 
00549     // check every button.  on this pass we save all modifiers as native
00550     // X modifier masks.
00551     CKeyMap::KeyItem item;
00552     for (int i = m_xkb->min_key_code; i <= m_xkb->max_key_code; ++i) {
00553         KeyCode keycode = static_cast<KeyCode>(i);
00554         item.m_button   = static_cast<KeyButton>(keycode);
00555         item.m_client   = 0;
00556 
00557         // skip keys with no groups (they generate no symbols)
00558         if (XkbKeyNumGroups(m_xkb, keycode) == 0) {
00559             continue;
00560         }
00561 
00562         // note half-duplex keys
00563         const XkbBehavior& b = m_xkb->server->behaviors[keycode];
00564         if ((b.type & XkbKB_OpMask) == XkbKB_Lock) {
00565             keyMap.addHalfDuplexButton(item.m_button);
00566         }
00567 
00568         // iterate over all groups
00569         for (int group = 0; group < maxNumGroups; ++group) {
00570             item.m_group = group;
00571             int eGroup   = getEffectiveGroup(keycode, group);
00572 
00573             // get key info
00574             XkbKeyTypePtr type = XkbKeyKeyType(m_xkb, keycode, eGroup);
00575 
00576             // set modifiers the item is sensitive to
00577             item.m_sensitive = type->mods.mask;
00578 
00579             // iterate over all shift levels for the button (including none)
00580             for (int j = -1; j < type->map_count; ++j) {
00581                 const XkbKTMapEntryRec* mapEntry =
00582                     ((j == -1) ? &defMapEntry : type->map + j);
00583                 if (!mapEntry->active) {
00584                     continue;
00585                 }
00586                 int level = mapEntry->level;
00587 
00588                 // set required modifiers for this item
00589                 item.m_required = mapEntry->mods.mask;
00590                 if ((item.m_required & LockMask) != 0 &&
00591                     j != -1 && type->preserve != NULL &&
00592                     (type->preserve[j].mask & LockMask) != 0) {
00593                     // sensitive caps lock and we preserve caps-lock.
00594                     // preserving caps-lock means we Xlib functions would
00595                     // yield the capitialized KeySym so we'll adjust the
00596                     // level accordingly.
00597                     if ((level ^ 1) < type->num_levels) {
00598                         level ^= 1;
00599                     }
00600                 }
00601 
00602                 // get the keysym for this item
00603                 KeySym keysym = XkbKeySymEntry(m_xkb, keycode, level, eGroup);
00604 
00605                 // check for group change actions, locking modifiers, and
00606                 // modifier masks.
00607                 item.m_lock         = false;
00608                 bool isModifier     = false;
00609                 UInt32 modifierMask = m_xkb->map->modmap[keycode];
00610                 if (XkbKeyHasActions(m_xkb, keycode)) {
00611                     XkbAction* action =
00612                         XkbKeyActionEntry(m_xkb, keycode, level, eGroup);
00613                     if (action->type == XkbSA_SetMods ||
00614                         action->type == XkbSA_LockMods) {
00615                         isModifier  = true;
00616 
00617                         // note toggles
00618                         item.m_lock = (action->type == XkbSA_LockMods);
00619 
00620                         // maybe use action's mask
00621                         if ((action->mods.flags & XkbSA_UseModMapMods) == 0) {
00622                             modifierMask = action->mods.mask;
00623                         }
00624                     }
00625                     else if (action->type == XkbSA_SetGroup ||
00626                             action->type == XkbSA_LatchGroup ||
00627                             action->type == XkbSA_LockGroup) {
00628                         // ignore group change key
00629                         continue;
00630                     }
00631                 }
00632                 level = mapEntry->level;
00633 
00634                 // VMware modifier hack
00635                 if (useLastGoodModifiers) {
00636                     XKBModifierMap::const_iterator k =
00637                         m_lastGoodXKBModifiers.find(eGroup * 256 + keycode);
00638                     if (k != m_lastGoodXKBModifiers.end()) {
00639                         // Use last known good modifier
00640                         isModifier   = true;
00641                         level        = k->second.m_level;
00642                         modifierMask = k->second.m_mask;
00643                         item.m_lock  = k->second.m_lock;
00644                     }
00645                 }
00646                 else if (isModifier) {
00647                     // Save known good modifier
00648                     XKBModifierInfo& info =
00649                         m_lastGoodXKBModifiers[eGroup * 256 + keycode];
00650                     info.m_level = level;
00651                     info.m_mask  = modifierMask;
00652                     info.m_lock  = item.m_lock;
00653                 }
00654 
00655                 // record the modifier mask for this key.  don't bother
00656                 // for keys that change the group.
00657                 item.m_generates = 0;
00658                 UInt32 modifierBit =
00659                     CXWindowsUtil::getModifierBitForKeySym(keysym);
00660                 if (isModifier && modifierBit != kKeyModifierBitNone) {
00661                     item.m_generates = (1u << modifierBit);
00662                     for (SInt32 j = 0; j < 8; ++j) {
00663                         // skip modifiers this key doesn't generate
00664                         if ((modifierMask & (1u << j)) == 0) {
00665                             continue;
00666                         }
00667 
00668                         // skip keys that map to a modifier that we've
00669                         // already seen using fewer modifiers.  that is
00670                         // if this key must combine with other modifiers
00671                         // and we know of a key that combines with fewer
00672                         // modifiers (or no modifiers) then prefer the
00673                         // other key.
00674                         if (level >= modifierLevel[8 * group + j]) {
00675                             continue;
00676                         }
00677                         modifierLevel[8 * group + j] = level;
00678 
00679                         // save modifier
00680                         m_modifierFromX[8 * group + j] |= (1u << modifierBit);
00681                         m_modifierToX.insert(std::make_pair(
00682                                 1u << modifierBit, 1u << j));
00683                     }
00684                 }
00685 
00686                 // handle special cases of just one keysym for the keycode
00687                 if (type->num_levels == 1) {
00688                     // if there are upper- and lowercase versions of the
00689                     // keysym then add both.
00690                     KeySym lKeysym, uKeysym;
00691                     XConvertCase(keysym, &lKeysym, &uKeysym);
00692                     if (lKeysym != uKeysym) {
00693                         if (j != -1) {
00694                             continue;
00695                         }
00696 
00697                         item.m_sensitive |= ShiftMask | LockMask;
00698 
00699                         KeyID lKeyID = CXWindowsUtil::mapKeySymToKeyID(lKeysym);
00700                         KeyID uKeyID = CXWindowsUtil::mapKeySymToKeyID(uKeysym);
00701                         if (lKeyID == kKeyNone || uKeyID == kKeyNone) {
00702                             continue;
00703                         }
00704 
00705                         item.m_id       = lKeyID;
00706                         item.m_required = 0;
00707                         keyMap.addKeyEntry(item);
00708 
00709                         item.m_id       = uKeyID;
00710                         item.m_required = ShiftMask;
00711                         keyMap.addKeyEntry(item);
00712                         item.m_required = LockMask;
00713                         keyMap.addKeyEntry(item);
00714 
00715                         if (group == 0) {
00716                             m_keyCodeFromKey.insert(
00717                                     std::make_pair(lKeyID, keycode));
00718                             m_keyCodeFromKey.insert(
00719                                     std::make_pair(uKeyID, keycode));
00720                         }
00721                         continue;
00722                     }
00723                 }
00724 
00725                 // add entry
00726                 item.m_id = CXWindowsUtil::mapKeySymToKeyID(keysym);
00727                 keyMap.addKeyEntry(item);
00728                 if (group == 0) {
00729                     m_keyCodeFromKey.insert(std::make_pair(item.m_id, keycode));
00730                 }
00731             }
00732         }
00733     }
00734 
00735     // change all modifier masks to synergy masks from X masks
00736     keyMap.foreachKey(&CXWindowsKeyState::remapKeyModifiers, this);
00737 
00738     // allow composition across groups
00739     keyMap.allowGroupSwitchDuringCompose();
00740 }
00741 #endif
00742 
00743 void
00744 CXWindowsKeyState::remapKeyModifiers(KeyID id, SInt32 group,
00745                             CKeyMap::KeyItem& item, void* vself)
00746 {
00747     CXWindowsKeyState* self = reinterpret_cast<CXWindowsKeyState*>(vself);
00748     item.m_required  =
00749         self->mapModifiersFromX(XkbBuildCoreState(item.m_required, group));
00750     item.m_sensitive =
00751         self->mapModifiersFromX(XkbBuildCoreState(item.m_sensitive, group));
00752 }
00753 
00754 bool
00755 CXWindowsKeyState::hasModifiersXKB() const
00756 {
00757 #if HAVE_XKB_EXTENSION
00758     // iterate over all keycodes
00759     for (int i = m_xkb->min_key_code; i <= m_xkb->max_key_code; ++i) {
00760         KeyCode keycode = static_cast<KeyCode>(i);
00761         if (XkbKeyHasActions(m_xkb, keycode)) {
00762             // iterate over all groups
00763             int numGroups = XkbKeyNumGroups(m_xkb, keycode);
00764             for (int group = 0; group < numGroups; ++group) {
00765                 // iterate over all shift levels for the button (including none)
00766                 XkbKeyTypePtr type = XkbKeyKeyType(m_xkb, keycode, group);
00767                 for (int j = -1; j < type->map_count; ++j) {
00768                     if (j != -1 && !type->map[j].active) {
00769                         continue;
00770                     }
00771                     int level = ((j == -1) ? 0 : type->map[j].level);
00772                     XkbAction* action =
00773                         XkbKeyActionEntry(m_xkb, keycode, level, group);
00774                     if (action->type == XkbSA_SetMods ||
00775                         action->type == XkbSA_LockMods) {
00776                         return true;
00777                     }
00778                 }
00779             }
00780         }
00781     }
00782 #endif
00783     return false;
00784 }
00785 
00786 int
00787 CXWindowsKeyState::getEffectiveGroup(KeyCode keycode, int group) const
00788 {
00789     (void)keycode;
00790 #if HAVE_XKB_EXTENSION
00791     // get effective group for key
00792     int numGroups = XkbKeyNumGroups(m_xkb, keycode);
00793     if (group >= numGroups) {
00794         unsigned char groupInfo = XkbKeyGroupInfo(m_xkb, keycode);
00795         switch (XkbOutOfRangeGroupAction(groupInfo)) {
00796         case XkbClampIntoRange:
00797             group = numGroups - 1;
00798             break;
00799 
00800         case XkbRedirectIntoRange:
00801             group = XkbOutOfRangeGroupNumber(groupInfo);
00802             if (group >= numGroups) {
00803                 group = 0;
00804             }
00805             break;
00806 
00807         default:
00808             // wrap
00809             group %= numGroups;
00810             break;
00811         }
00812     }
00813 #endif
00814     return group;
00815 }
00816 
00817 UInt32
00818 CXWindowsKeyState::getGroupFromState(unsigned int state) const
00819 {
00820 #if HAVE_XKB_EXTENSION
00821     if (m_xkb != NULL) {
00822         return XkbGroupForCoreState(state);
00823     }
00824 #endif
00825     return 0;
00826 }

Generated on Fri Nov 6 00:18:45 2009 for synergy-plus by  doxygen 1.4.7