00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
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
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
00185
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
00261 static const int maxKeysyms = 4;
00262
00263 LOG((CLOG_DEBUG1 "non-XKB mapping"));
00264
00265
00266
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
00278 m_keyCodeFromKey.clear();
00279
00280
00281 int minKeycode, maxKeycode;
00282 XDisplayKeycodes(m_display, &minKeycode, &maxKeycode);
00283 int numKeycodes = maxKeycode - minKeycode + 1;
00284
00285
00286 int keysymsPerKeycode;
00287 KeySym* allKeysyms = XGetKeyboardMapping(m_display,
00288 minKeycode, numKeycodes,
00289 &keysymsPerKeycode);
00290
00291
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
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
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
00339
00340
00341
00342
00343
00344
00345 if (!modifierButtons.empty()) {
00346 m_lastGoodNonXKBModifiers = modifierButtons;
00347 }
00348 else {
00349 modifierButtons = m_lastGoodNonXKBModifiers;
00350 }
00351
00352
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
00361 item.m_sensitive = 0;
00362
00363
00364
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
00371
00372
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
00402
00403
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
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
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
00428
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
00442 item.m_group = (j >= 2) ? 1 : 0;
00443
00444
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
00457 CKeyMap::initModifierKey(item);
00458
00459
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
00470 keyMap.addKeyEntry(item);
00471 m_keyCodeFromKey.insert(std::make_pair(item.m_id, keycode));
00472
00473
00474 if ((j & 1) != 0) {
00475
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
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,
00509 0,
00510 {
00511 0,
00512 0,
00513 0
00514 }
00515 };
00516
00517 LOG((CLOG_DEBUG1 "XKB mapping"));
00518
00519
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
00529 std::vector<int> modifierLevel(maxNumGroups * 8, 4);
00530 m_modifierFromX.clear();
00531 m_modifierFromX.resize(maxNumGroups * 8);
00532 m_modifierToX.clear();
00533
00534
00535 m_keyCodeFromKey.clear();
00536
00537
00538
00539
00540
00541
00542
00543
00544 bool useLastGoodModifiers = !hasModifiersXKB();
00545 if (!useLastGoodModifiers) {
00546 m_lastGoodXKBModifiers.clear();
00547 }
00548
00549
00550
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
00558 if (XkbKeyNumGroups(m_xkb, keycode) == 0) {
00559 continue;
00560 }
00561
00562
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
00569 for (int group = 0; group < maxNumGroups; ++group) {
00570 item.m_group = group;
00571 int eGroup = getEffectiveGroup(keycode, group);
00572
00573
00574 XkbKeyTypePtr type = XkbKeyKeyType(m_xkb, keycode, eGroup);
00575
00576
00577 item.m_sensitive = type->mods.mask;
00578
00579
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
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
00594
00595
00596
00597 if ((level ^ 1) < type->num_levels) {
00598 level ^= 1;
00599 }
00600 }
00601
00602
00603 KeySym keysym = XkbKeySymEntry(m_xkb, keycode, level, eGroup);
00604
00605
00606
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
00618 item.m_lock = (action->type == XkbSA_LockMods);
00619
00620
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
00629 continue;
00630 }
00631 }
00632 level = mapEntry->level;
00633
00634
00635 if (useLastGoodModifiers) {
00636 XKBModifierMap::const_iterator k =
00637 m_lastGoodXKBModifiers.find(eGroup * 256 + keycode);
00638 if (k != m_lastGoodXKBModifiers.end()) {
00639
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
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
00656
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
00664 if ((modifierMask & (1u << j)) == 0) {
00665 continue;
00666 }
00667
00668
00669
00670
00671
00672
00673
00674 if (level >= modifierLevel[8 * group + j]) {
00675 continue;
00676 }
00677 modifierLevel[8 * group + j] = level;
00678
00679
00680 m_modifierFromX[8 * group + j] |= (1u << modifierBit);
00681 m_modifierToX.insert(std::make_pair(
00682 1u << modifierBit, 1u << j));
00683 }
00684 }
00685
00686
00687 if (type->num_levels == 1) {
00688
00689
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
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
00736 keyMap.foreachKey(&CXWindowsKeyState::remapKeyModifiers, this);
00737
00738
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
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
00763 int numGroups = XkbKeyNumGroups(m_xkb, keycode);
00764 for (int group = 0; group < numGroups; ++group) {
00765
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
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
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 }