1 /*
2  * barrier -- mouse and keyboard sharing utility
3  * Copyright (C) 2012-2016 Symless Ltd.
4  * Copyright (C) 2003 Chris Schoeneman
5  *
6  * This package is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * found in the file LICENSE that should have accompanied this file.
9  *
10  * This package is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "platform/XWindowsKeyState.h"
20 
21 #include "platform/XWindowsUtil.h"
22 #include "base/Log.h"
23 #include "common/stdmap.h"
24 
25 #include <cstddef>
26 #include <algorithm>
27 #if X_DISPLAY_MISSING
28 #    error X11 is required to build barrier
29 #else
30 #    include <X11/X.h>
31 #    include <X11/Xutil.h>
32 #    define XK_MISCELLANY
33 #    define XK_XKB_KEYS
34 #    include <X11/keysymdef.h>
35 #if HAVE_XKB_EXTENSION
36 #    include <X11/XKBlib.h>
37 #endif
38 #endif
39 
40 static const size_t ModifiersFromXDefaultSize = 32;
41 
XWindowsKeyState(IXWindowsImpl * impl,Display * display,bool useXKB,IEventQueue * events)42 XWindowsKeyState::XWindowsKeyState(IXWindowsImpl* impl,
43         Display* display, bool useXKB,
44         IEventQueue* events) :
45     KeyState(events),
46     m_display(display),
47     m_modifierFromX(ModifiersFromXDefaultSize)
48 {
49      m_impl = impl;
50 
51     init(display, useXKB);
52 }
53 
XWindowsKeyState(IXWindowsImpl * impl,Display * display,bool useXKB,IEventQueue * events,barrier::KeyMap & keyMap)54 XWindowsKeyState::XWindowsKeyState(IXWindowsImpl* impl,
55     Display* display, bool useXKB,
56     IEventQueue* events, barrier::KeyMap& keyMap) :
57     KeyState(events, keyMap),
58     m_display(display),
59     m_modifierFromX(ModifiersFromXDefaultSize)
60 {
61     m_impl = impl;
62     init(display, useXKB);
63 }
64 
~XWindowsKeyState()65 XWindowsKeyState::~XWindowsKeyState()
66 {
67 #if HAVE_XKB_EXTENSION
68     if (m_xkb != NULL) {
69         m_impl->XkbFreeKeyboard(m_xkb, 0, True);
70     }
71 #endif
72 }
73 
74 void
init(Display * display,bool useXKB)75 XWindowsKeyState::init(Display* display, bool useXKB)
76 {
77     XGetKeyboardControl(m_display, &m_keyboardState);
78 #if HAVE_XKB_EXTENSION
79     if (useXKB) {
80         m_xkb = m_impl->XkbGetMap(m_display,
81                                   XkbKeyActionsMask | XkbKeyBehaviorsMask |
82                                   XkbAllClientInfoMask, XkbUseCoreKbd);
83     }
84     else {
85         m_xkb = NULL;
86     }
87 #endif
88     setActiveGroup(kGroupPollAndSet);
89 }
90 
91 void
setActiveGroup(SInt32 group)92 XWindowsKeyState::setActiveGroup(SInt32 group)
93 {
94     if (group == kGroupPollAndSet) {
95         // we need to set the group to -1 in order for pollActiveGroup() to
96         // actually poll for the group
97         m_group = -1;
98         m_group = pollActiveGroup();
99     }
100     else if (group == kGroupPoll) {
101         m_group = -1;
102     }
103     else {
104         assert(group >= 0);
105         m_group = group;
106     }
107 }
108 
109 void
setAutoRepeat(const XKeyboardState & state)110 XWindowsKeyState::setAutoRepeat(const XKeyboardState& state)
111 {
112     m_keyboardState = state;
113 }
114 
115 KeyModifierMask
mapModifiersFromX(unsigned int state) const116 XWindowsKeyState::mapModifiersFromX(unsigned int state) const
117 {
118     LOG((CLOG_DEBUG2 "mapping state: %i", state));
119     UInt32 offset = 8 * getGroupFromState(state);
120     KeyModifierMask mask = 0;
121     for (int i = 0; i < 8; ++i) {
122         if ((state & (1u << i)) != 0) {
123             LOG((CLOG_DEBUG2 "|= modifier: %i", offset + i));
124             if (offset + i >= m_modifierFromX.size()) {
125                 LOG((CLOG_ERR "m_modifierFromX is too small (%d) for the "
126                     "requested offset (%d)", m_modifierFromX.size(), offset+i));
127             } else {
128                 mask |= m_modifierFromX[offset + i];
129             }
130         }
131     }
132     return mask;
133 }
134 
135 bool
mapModifiersToX(KeyModifierMask mask,unsigned int & modifiers) const136 XWindowsKeyState::mapModifiersToX(KeyModifierMask mask,
137                 unsigned int& modifiers) const
138 {
139     modifiers = 0;
140 
141     for (SInt32 i = 0; i < kKeyModifierNumBits; ++i) {
142         KeyModifierMask bit = (1u << i);
143         if ((mask & bit) != 0) {
144             KeyModifierToXMask::const_iterator j = m_modifierToX.find(bit);
145             if (j == m_modifierToX.end()) {
146                 return false;
147             }
148             else {
149                 modifiers |= j->second;
150             }
151         }
152     }
153 
154     return true;
155 }
156 
157 void
mapKeyToKeycodes(KeyID key,KeycodeList & keycodes) const158 XWindowsKeyState::mapKeyToKeycodes(KeyID key, KeycodeList& keycodes) const
159 {
160     keycodes.clear();
161     std::pair<KeyToKeyCodeMap::const_iterator,
162         KeyToKeyCodeMap::const_iterator> range =
163             m_keyCodeFromKey.equal_range(key);
164     for (KeyToKeyCodeMap::const_iterator i = range.first;
165                                 i != range.second; ++i) {
166         keycodes.push_back(i->second);
167     }
168 }
169 
170 bool
fakeCtrlAltDel()171 XWindowsKeyState::fakeCtrlAltDel()
172 {
173     // pass keys through unchanged
174     return false;
175 }
176 
177 KeyModifierMask
pollActiveModifiers() const178 XWindowsKeyState::pollActiveModifiers() const
179 {
180     Window root = DefaultRootWindow(m_display), window;
181     int xRoot, yRoot, xWindow, yWindow;
182     unsigned int state = 0;
183     if (m_impl->XQueryPointer(m_display, root, &root, &window,
184                               &xRoot, &yRoot, &xWindow, &yWindow, &state
185                               ) == False) {
186         state = 0;
187     }
188     return mapModifiersFromX(state);
189 }
190 
191 SInt32
pollActiveGroup() const192 XWindowsKeyState::pollActiveGroup() const
193 {
194     // fixed condition where any group < -1 would have undetermined behaviour
195     if (m_group >= 0) {
196         return m_group;
197     }
198 
199 #if HAVE_XKB_EXTENSION
200     if (m_xkb != NULL) {
201         XkbStateRec state;
202         if (m_impl->XkbGetState(m_display, XkbUseCoreKbd, &state) == Success) {
203             return state.group;
204         }
205     }
206 #endif
207     return 0;
208 }
209 
210 void
pollPressedKeys(KeyButtonSet & pressedKeys) const211 XWindowsKeyState::pollPressedKeys(KeyButtonSet& pressedKeys) const
212 {
213     char keys[32];
214     m_impl->XQueryKeymap(m_display, keys);
215     for (UInt32 i = 0; i < 32; ++i) {
216         for (UInt32 j = 0; j < 8; ++j) {
217             if ((keys[i] & (1u << j)) != 0) {
218                 pressedKeys.insert(8 * i + j);
219             }
220         }
221     }
222 }
223 
224 void
getKeyMap(barrier::KeyMap & keyMap)225 XWindowsKeyState::getKeyMap(barrier::KeyMap& keyMap)
226 {
227     // get autorepeat info.  we must use the global_auto_repeat told to
228     // us because it may have modified by barrier.
229     int oldGlobalAutoRepeat = m_keyboardState.global_auto_repeat;
230     XGetKeyboardControl(m_display, &m_keyboardState);
231     m_keyboardState.global_auto_repeat = oldGlobalAutoRepeat;
232 
233 #if HAVE_XKB_EXTENSION
234     if (m_xkb != NULL) {
235         unsigned mask = XkbKeyActionsMask | XkbKeyBehaviorsMask |
236                         XkbAllClientInfoMask;
237         if (m_impl->XkbGetUpdatedMap(m_display, mask, m_xkb) == Success) {
238             updateKeysymMapXKB(keyMap);
239             return;
240         }
241     }
242 #endif
243     updateKeysymMap(keyMap);
244 }
245 
246 void
fakeKey(const Keystroke & keystroke)247 XWindowsKeyState::fakeKey(const Keystroke& keystroke)
248 {
249     switch (keystroke.m_type) {
250     case Keystroke::kButton:
251         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"));
252         if (keystroke.m_data.m_button.m_repeat) {
253             int c = keystroke.m_data.m_button.m_button;
254             int i = (c >> 3);
255             int b = 1 << (c & 7);
256             if (m_keyboardState.global_auto_repeat == AutoRepeatModeOff ||
257                 (c!=113 && c!=116 && (m_keyboardState.auto_repeats[i] & b) == 0)) {
258                 LOG((CLOG_DEBUG1 "  discard autorepeat"));
259                 break;
260             }
261         }
262         m_impl->XTestFakeKeyEvent(m_display, keystroke.m_data.m_button.m_button,
263                                   keystroke.m_data.m_button.m_press,
264                                   CurrentTime);
265         break;
266 
267     case Keystroke::kGroup:
268         if (keystroke.m_data.m_group.m_absolute) {
269             LOG((CLOG_DEBUG1 "  group %d", keystroke.m_data.m_group.m_group));
270 #if HAVE_XKB_EXTENSION
271             if (m_xkb != NULL) {
272                 if (m_impl->XkbLockGroup(m_display, XkbUseCoreKbd,
273                                          keystroke.m_data.m_group.m_group
274                                          ) == False) {
275                     LOG((CLOG_DEBUG1 "XkbLockGroup request not sent"));
276                 }
277             }
278             else
279 #endif
280             {
281                 LOG((CLOG_DEBUG1 "  ignored"));
282             }
283         }
284         else {
285             LOG((CLOG_DEBUG1 "  group %+d", keystroke.m_data.m_group.m_group));
286 #if HAVE_XKB_EXTENSION
287             if (m_xkb != NULL) {
288                 if (m_impl->XkbLockGroup(m_display, XkbUseCoreKbd,
289                                          getEffectiveGroup(pollActiveGroup(),
290                                          keystroke.m_data.m_group.m_group)
291                                          ) == False) {
292                     LOG((CLOG_DEBUG1 "XkbLockGroup request not sent"));
293                 }
294             }
295             else
296 #endif
297             {
298                 LOG((CLOG_DEBUG1 "  ignored"));
299             }
300         }
301         break;
302     }
303     XFlush(m_display);
304 }
305 
306 void
updateKeysymMap(barrier::KeyMap & keyMap)307 XWindowsKeyState::updateKeysymMap(barrier::KeyMap& keyMap)
308 {
309     // there are up to 4 keysyms per keycode
310     static const int maxKeysyms = 4;
311 
312     LOG((CLOG_DEBUG1 "non-XKB mapping"));
313 
314     // prepare map from X modifier to KeyModifierMask.  certain bits
315     // are predefined.
316     std::fill(m_modifierFromX.begin(), m_modifierFromX.end(), 0);
317     m_modifierFromX[ShiftMapIndex]   = KeyModifierShift;
318     m_modifierFromX[LockMapIndex]    = KeyModifierCapsLock;
319     m_modifierFromX[ControlMapIndex] = KeyModifierControl;
320     m_modifierToX.clear();
321     m_modifierToX[KeyModifierShift]    = ShiftMask;
322     m_modifierToX[KeyModifierCapsLock] = LockMask;
323     m_modifierToX[KeyModifierControl]  = ControlMask;
324 
325     // prepare map from KeyID to KeyCode
326     m_keyCodeFromKey.clear();
327 
328     // get the number of keycodes
329     int minKeycode, maxKeycode;
330     m_impl->XDisplayKeycodes(m_display, &minKeycode, &maxKeycode);
331     int numKeycodes = maxKeycode - minKeycode + 1;
332 
333     // get the keyboard mapping for all keys
334     int keysymsPerKeycode;
335     KeySym* allKeysyms = m_impl->XGetKeyboardMapping(m_display,
336                                                      minKeycode, numKeycodes,
337                                                      &keysymsPerKeycode);
338 
339     // it's more convenient to always have maxKeysyms KeySyms per key
340     {
341         KeySym* tmpKeysyms = new KeySym[maxKeysyms * numKeycodes];
342         for (int i = 0; i < numKeycodes; ++i) {
343             for (int j = 0; j < maxKeysyms; ++j) {
344                 if (j < keysymsPerKeycode) {
345                     tmpKeysyms[maxKeysyms * i + j] =
346                         allKeysyms[keysymsPerKeycode * i + j];
347                 }
348                 else {
349                     tmpKeysyms[maxKeysyms * i + j] = NoSymbol;
350                 }
351             }
352         }
353         m_impl->XFree(allKeysyms);
354         allKeysyms = tmpKeysyms;
355     }
356 
357     // get the buttons assigned to modifiers.  X11 does not predefine
358     // the meaning of any modifiers except shift, caps lock, and the
359     // control key.  the meaning of a modifier bit (other than those)
360     // depends entirely on the KeySyms mapped to that bit.  unfortunately
361     // you cannot map a bit back to the KeySym used to produce it.
362     // for example, let's say button 1 maps to Alt_L without shift and
363     // Meta_L with shift.  now if mod1 is mapped to button 1 that could
364     // mean the user used Alt or Meta to turn on that modifier and there's
365     // no way to know which.  it's also possible for one button to be
366     // mapped to multiple bits so both mod1 and mod2 could be generated
367     // by button 1.
368     //
369     // we're going to ignore any modifier for a button except the first.
370     // with the above example, that means we'll ignore the mod2 modifier
371     // bit unless it's also mapped to some other button.  we're also
372     // going to ignore all KeySyms except the first modifier KeySym,
373     // which means button 1 above won't map to Meta, just Alt.
374     std::map<KeyCode, unsigned int> modifierButtons;
375     XModifierKeymap* modifiers = m_impl->XGetModifierMapping(m_display);
376     for (unsigned int i = 0; i < 8; ++i) {
377         const KeyCode* buttons =
378             modifiers->modifiermap + i * modifiers->max_keypermod;
379         for (int j = 0; j < modifiers->max_keypermod; ++j) {
380             modifierButtons.insert(std::make_pair(buttons[j], i));
381         }
382     }
383     XFreeModifiermap(modifiers);
384     modifierButtons.erase(0);
385 
386     // Hack to deal with VMware.  When a VMware client grabs input the
387     // player clears out the X modifier map for whatever reason.  We're
388     // notified of the change and arrive here to discover that there
389     // are no modifiers at all.  Since this prevents the modifiers from
390     // working in the VMware client we'll use the last known good set
391     // of modifiers when there are no modifiers.  If there are modifiers
392     // we update the last known good set.
393     if (!modifierButtons.empty()) {
394         m_lastGoodNonXKBModifiers = modifierButtons;
395     }
396     else {
397         modifierButtons = m_lastGoodNonXKBModifiers;
398     }
399 
400     // add entries for each keycode
401     barrier::KeyMap::KeyItem item;
402     for (int i = 0; i < numKeycodes; ++i) {
403         KeySym* keysyms = allKeysyms + maxKeysyms * i;
404         KeyCode keycode = static_cast<KeyCode>(i + minKeycode);
405         item.m_button   = static_cast<KeyButton>(keycode);
406         item.m_client   = 0;
407 
408         // determine modifier sensitivity
409         item.m_sensitive = 0;
410 
411         // if the keysyms in levels 2 or 3 exist and differ from levels
412         // 0 and 1 then the key is sensitive AltGr (Mode_switch)
413         if ((keysyms[2] != NoSymbol && keysyms[2] != keysyms[0]) ||
414             (keysyms[3] != NoSymbol && keysyms[2] != keysyms[1])) {
415             item.m_sensitive |= KeyModifierAltGr;
416         }
417 
418         // check if the key is caps-lock sensitive.  some systems only
419         // provide one keysym for keys sensitive to caps-lock.  if we
420         // find that then fill in the missing keysym.
421         if (keysyms[0] != NoSymbol && keysyms[1] == NoSymbol &&
422             keysyms[2] == NoSymbol && keysyms[3] == NoSymbol) {
423             KeySym lKeysym, uKeysym;
424             XConvertCase(keysyms[0], &lKeysym, &uKeysym);
425             if (lKeysym != uKeysym) {
426                 keysyms[0] = lKeysym;
427                 keysyms[1] = uKeysym;
428                 item.m_sensitive |= KeyModifierCapsLock;
429             }
430         }
431         else if (keysyms[0] != NoSymbol && keysyms[1] != NoSymbol) {
432             KeySym lKeysym, uKeysym;
433             XConvertCase(keysyms[0], &lKeysym, &uKeysym);
434             if (lKeysym != uKeysym &&
435                 lKeysym == keysyms[0] &&
436                 uKeysym == keysyms[1]) {
437                 item.m_sensitive |= KeyModifierCapsLock;
438             }
439             else if (keysyms[2] != NoSymbol && keysyms[3] != NoSymbol) {
440                 XConvertCase(keysyms[2], &lKeysym, &uKeysym);
441                 if (lKeysym != uKeysym &&
442                     lKeysym == keysyms[2] &&
443                     uKeysym == keysyms[3]) {
444                     item.m_sensitive |= KeyModifierCapsLock;
445                 }
446             }
447         }
448 
449         // key is sensitive to shift if keysyms in levels 0 and 1 or
450         // levels 2 and 3 don't match.  it's also sensitive to shift
451         // if it's sensitive to caps-lock.
452         if ((item.m_sensitive & KeyModifierCapsLock) != 0) {
453             item.m_sensitive |= KeyModifierShift;
454         }
455         else if ((keysyms[0] != NoSymbol && keysyms[1] != NoSymbol &&
456                 keysyms[0] != keysyms[1]) ||
457                 (keysyms[2] != NoSymbol && keysyms[3] != NoSymbol &&
458                 keysyms[2] != keysyms[3])) {
459             item.m_sensitive |= KeyModifierShift;
460         }
461 
462         // key is sensitive to numlock if any keysym on it is
463         if (IsKeypadKey(keysyms[0]) || IsPrivateKeypadKey(keysyms[0]) ||
464             IsKeypadKey(keysyms[1]) || IsPrivateKeypadKey(keysyms[1]) ||
465             IsKeypadKey(keysyms[2]) || IsPrivateKeypadKey(keysyms[2]) ||
466             IsKeypadKey(keysyms[3]) || IsPrivateKeypadKey(keysyms[3])) {
467             item.m_sensitive |= KeyModifierNumLock;
468         }
469 
470         // do each keysym (shift level)
471         for (int j = 0; j < maxKeysyms; ++j) {
472             item.m_id = XWindowsUtil::mapKeySymToKeyID(keysyms[j]);
473             if (item.m_id == kKeyNone) {
474                 if (j != 0 && modifierButtons.count(keycode) > 0) {
475                     // pretend the modifier works in other shift levels
476                     // because it probably does.
477                     if (keysyms[1] == NoSymbol || j != 3) {
478                         item.m_id = XWindowsUtil::mapKeySymToKeyID(keysyms[0]);
479                     }
480                     else {
481                         item.m_id = XWindowsUtil::mapKeySymToKeyID(keysyms[1]);
482                     }
483                 }
484                 if (item.m_id == kKeyNone) {
485                     continue;
486                 }
487             }
488 
489             // group is 0 for levels 0 and 1 and 1 for levels 2 and 3
490             item.m_group = (j >= 2) ? 1 : 0;
491 
492             // compute required modifiers
493             item.m_required = 0;
494             if ((j & 1) != 0) {
495                 item.m_required |= KeyModifierShift;
496             }
497             if ((j & 2) != 0) {
498                 item.m_required |= KeyModifierAltGr;
499             }
500 
501             item.m_generates = 0;
502             item.m_lock      = false;
503             if (modifierButtons.count(keycode) > 0) {
504                 // get flags for modifier keys
505                 barrier::KeyMap::initModifierKey(item);
506 
507                 // add mapping from X (unless we already have)
508                 if (item.m_generates != 0) {
509                     unsigned int bit = modifierButtons[keycode];
510                     if (m_modifierFromX[bit] == 0) {
511                         m_modifierFromX[bit] = item.m_generates;
512                         m_modifierToX[item.m_generates] = (1u << bit);
513                     }
514                 }
515             }
516 
517             // add key
518             keyMap.addKeyEntry(item);
519             m_keyCodeFromKey.insert(std::make_pair(item.m_id, keycode));
520 
521             // add other ways to synthesize the key
522             if ((j & 1) != 0) {
523                 // add capslock version of key is sensitive to capslock
524                 KeySym lKeysym, uKeysym;
525                 XConvertCase(keysyms[j], &lKeysym, &uKeysym);
526                 if (lKeysym != uKeysym &&
527                     lKeysym == keysyms[j - 1] &&
528                     uKeysym == keysyms[j]) {
529                     item.m_required &= ~KeyModifierShift;
530                     item.m_required |=  KeyModifierCapsLock;
531                     keyMap.addKeyEntry(item);
532                     item.m_required |=  KeyModifierShift;
533                     item.m_required &= ~KeyModifierCapsLock;
534                 }
535 
536                 // add numlock version of key if sensitive to numlock
537                 if (IsKeypadKey(keysyms[j]) || IsPrivateKeypadKey(keysyms[j])) {
538                     item.m_required &= ~KeyModifierShift;
539                     item.m_required |=  KeyModifierNumLock;
540                     keyMap.addKeyEntry(item);
541                     item.m_required |=  KeyModifierShift;
542                     item.m_required &= ~KeyModifierNumLock;
543                 }
544             }
545         }
546     }
547 
548     delete[] allKeysyms;
549 }
550 
551 #if HAVE_XKB_EXTENSION
552 void
updateKeysymMapXKB(barrier::KeyMap & keyMap)553 XWindowsKeyState::updateKeysymMapXKB(barrier::KeyMap& keyMap)
554 {
555     static const XkbKTMapEntryRec defMapEntry = {
556         True,        // active
557         0,            // level
558         {
559             0,        // mods.mask
560             0,        // mods.real_mods
561             0        // mods.vmods
562         }
563     };
564 
565     LOG((CLOG_DEBUG1 "XKB mapping"));
566 
567     // find the number of groups
568     int maxNumGroups = 0;
569     for (int i = m_xkb->min_key_code; i <= m_xkb->max_key_code; ++i) {
570         int numGroups = m_impl->do_XkbKeyNumGroups(m_xkb, static_cast<KeyCode>(i));
571         if (numGroups > maxNumGroups) {
572             maxNumGroups = numGroups;
573         }
574     }
575 
576     // prepare map from X modifier to KeyModifierMask
577     std::vector<int> modifierLevel(maxNumGroups * 8, 4);
578     m_modifierFromX.clear();
579     m_modifierFromX.resize(maxNumGroups * 8);
580     m_modifierToX.clear();
581 
582     // prepare map from KeyID to KeyCode
583     m_keyCodeFromKey.clear();
584 
585     // Hack to deal with VMware.  When a VMware client grabs input the
586     // player clears out the X modifier map for whatever reason.  We're
587     // notified of the change and arrive here to discover that there
588     // are no modifiers at all.  Since this prevents the modifiers from
589     // working in the VMware client we'll use the last known good set
590     // of modifiers when there are no modifiers.  If there are modifiers
591     // we update the last known good set.
592     bool useLastGoodModifiers = !hasModifiersXKB();
593     if (!useLastGoodModifiers) {
594         m_lastGoodXKBModifiers.clear();
595     }
596 
597     // check every button.  on this pass we save all modifiers as native
598     // X modifier masks.
599     barrier::KeyMap::KeyItem item;
600     for (int i = m_xkb->min_key_code; i <= m_xkb->max_key_code; ++i) {
601         KeyCode keycode = static_cast<KeyCode>(i);
602         item.m_button   = static_cast<KeyButton>(keycode);
603         item.m_client   = 0;
604 
605         // skip keys with no groups (they generate no symbols)
606         if (m_impl->do_XkbKeyNumGroups(m_xkb, keycode) == 0) {
607             continue;
608         }
609 
610         // note half-duplex keys
611         const XkbBehavior& b = m_xkb->server->behaviors[keycode];
612         if ((b.type & XkbKB_OpMask) == XkbKB_Lock) {
613             keyMap.addHalfDuplexButton(item.m_button);
614         }
615 
616         // iterate over all groups
617         for (int group = 0; group < maxNumGroups; ++group) {
618             item.m_group = group;
619             int eGroup   = getEffectiveGroup(keycode, group);
620 
621             // get key info
622             XkbKeyTypePtr type = m_impl->do_XkbKeyKeyType(m_xkb, keycode,
623                                                           eGroup);
624 
625             // set modifiers the item is sensitive to
626             item.m_sensitive = type->mods.mask;
627 
628             // iterate over all shift levels for the button (including none)
629             for (int j = -1; j < type->map_count; ++j) {
630                 const XkbKTMapEntryRec* mapEntry =
631                     ((j == -1) ? &defMapEntry : type->map + j);
632                 if (!mapEntry->active) {
633                     continue;
634                 }
635                 int level = mapEntry->level;
636 
637                 // set required modifiers for this item
638                 item.m_required = mapEntry->mods.mask;
639                 if ((item.m_required & LockMask) != 0 &&
640                     j != -1 && type->preserve != NULL &&
641                     (type->preserve[j].mask & LockMask) != 0) {
642                     // sensitive caps lock and we preserve caps-lock.
643                     // preserving caps-lock means we Xlib functions would
644                     // yield the capitialized KeySym so we'll adjust the
645                     // level accordingly.
646                     if ((level ^ 1) < type->num_levels) {
647                         level ^= 1;
648                     }
649                 }
650 
651                 // get the keysym for this item
652                 KeySym keysym = m_impl->do_XkbKeySymEntry(m_xkb, keycode, level,
653                                                           eGroup);
654 
655                 // check for group change actions, locking modifiers, and
656                 // modifier masks.
657                 item.m_lock         = false;
658                 bool isModifier     = false;
659                 UInt32 modifierMask = m_xkb->map->modmap[keycode];
660                 if (m_impl->do_XkbKeyHasActions(m_xkb, keycode) == True) {
661                     XkbAction* action =
662                         m_impl->do_XkbKeyActionEntry(m_xkb, keycode, level,
663                                                      eGroup);
664                     if (action->type == XkbSA_SetMods ||
665                         action->type == XkbSA_LockMods) {
666                         isModifier  = true;
667 
668                         // note toggles
669                         item.m_lock = (action->type == XkbSA_LockMods);
670 
671                         // maybe use action's mask
672                         if ((action->mods.flags & XkbSA_UseModMapMods) == 0) {
673                             modifierMask = action->mods.mask;
674                         }
675                     }
676                     else if (action->type == XkbSA_SetGroup ||
677                             action->type == XkbSA_LatchGroup ||
678                             action->type == XkbSA_LockGroup) {
679                         // ignore group change key
680                         continue;
681                     }
682                 }
683                 level = mapEntry->level;
684 
685                 // VMware modifier hack
686                 if (useLastGoodModifiers) {
687                     XKBModifierMap::const_iterator k =
688                         m_lastGoodXKBModifiers.find(eGroup * 256 + keycode);
689                     if (k != m_lastGoodXKBModifiers.end()) {
690                         // Use last known good modifier
691                         isModifier   = true;
692                         level        = k->second.m_level;
693                         modifierMask = k->second.m_mask;
694                         item.m_lock  = k->second.m_lock;
695                     }
696                 }
697                 else if (isModifier) {
698                     // Save known good modifier
699                     XKBModifierInfo& info =
700                         m_lastGoodXKBModifiers[eGroup * 256 + keycode];
701                     info.m_level = level;
702                     info.m_mask  = modifierMask;
703                     info.m_lock  = item.m_lock;
704                 }
705 
706                 // record the modifier mask for this key.  don't bother
707                 // for keys that change the group.
708                 item.m_generates = 0;
709                 UInt32 modifierBit =
710                     XWindowsUtil::getModifierBitForKeySym(keysym);
711                 if (isModifier && modifierBit != kKeyModifierBitNone) {
712                     item.m_generates = (1u << modifierBit);
713                     for (SInt32 j = 0; j < 8; ++j) {
714                         // skip modifiers this key doesn't generate
715                         if ((modifierMask & (1u << j)) == 0) {
716                             continue;
717                         }
718 
719                         // skip keys that map to a modifier that we've
720                         // already seen using fewer modifiers.  that is
721                         // if this key must combine with other modifiers
722                         // and we know of a key that combines with fewer
723                         // modifiers (or no modifiers) then prefer the
724                         // other key.
725                         if (level >= modifierLevel[8 * group + j]) {
726                             continue;
727                         }
728                         modifierLevel[8 * group + j] = level;
729 
730                         // save modifier
731                         m_modifierFromX[8 * group + j] |= (1u << modifierBit);
732                         m_modifierToX.insert(std::make_pair(
733                                 1u << modifierBit, 1u << j));
734                     }
735                 }
736 
737                 // handle special cases of just one keysym for the keycode
738                 if (type->num_levels == 1) {
739                     // if there are upper- and lowercase versions of the
740                     // keysym then add both.
741                     KeySym lKeysym, uKeysym;
742                     XConvertCase(keysym, &lKeysym, &uKeysym);
743                     if (lKeysym != uKeysym) {
744                         if (j != -1) {
745                             continue;
746                         }
747 
748                         item.m_sensitive |= ShiftMask | LockMask;
749 
750                         KeyID lKeyID = XWindowsUtil::mapKeySymToKeyID(lKeysym);
751                         KeyID uKeyID = XWindowsUtil::mapKeySymToKeyID(uKeysym);
752                         if (lKeyID == kKeyNone || uKeyID == kKeyNone) {
753                             continue;
754                         }
755 
756                         item.m_id       = lKeyID;
757                         item.m_required = 0;
758                         keyMap.addKeyEntry(item);
759 
760                         item.m_id       = uKeyID;
761                         item.m_required = ShiftMask;
762                         keyMap.addKeyEntry(item);
763                         item.m_required = LockMask;
764                         keyMap.addKeyEntry(item);
765 
766                         if (group == 0) {
767                             m_keyCodeFromKey.insert(
768                                     std::make_pair(lKeyID, keycode));
769                             m_keyCodeFromKey.insert(
770                                     std::make_pair(uKeyID, keycode));
771                         }
772                         continue;
773                     }
774                 }
775 
776                 // add entry
777                 item.m_id = XWindowsUtil::mapKeySymToKeyID(keysym);
778                 keyMap.addKeyEntry(item);
779                 if (group == 0) {
780                     m_keyCodeFromKey.insert(std::make_pair(item.m_id, keycode));
781                 }
782             }
783         }
784     }
785 
786     // change all modifier masks to barrier masks from X masks
787     keyMap.foreachKey(&XWindowsKeyState::remapKeyModifiers, this);
788 
789     // allow composition across groups
790     keyMap.allowGroupSwitchDuringCompose();
791 }
792 #endif
793 
794 void
remapKeyModifiers(KeyID id,SInt32 group,barrier::KeyMap::KeyItem & item,void * vself)795 XWindowsKeyState::remapKeyModifiers(KeyID id, SInt32 group,
796                             barrier::KeyMap::KeyItem& item, void* vself)
797 {
798     XWindowsKeyState* self = static_cast<XWindowsKeyState*>(vself);
799     item.m_required  =
800         self->mapModifiersFromX(XkbBuildCoreState(item.m_required, group));
801     item.m_sensitive =
802         self->mapModifiersFromX(XkbBuildCoreState(item.m_sensitive, group));
803 }
804 
805 bool
hasModifiersXKB() const806 XWindowsKeyState::hasModifiersXKB() const
807 {
808 #if HAVE_XKB_EXTENSION
809     // iterate over all keycodes
810     for (int i = m_xkb->min_key_code; i <= m_xkb->max_key_code; ++i) {
811         KeyCode keycode = static_cast<KeyCode>(i);
812         if (m_impl->do_XkbKeyHasActions(m_xkb, keycode) == True) {
813             // iterate over all groups
814             int numGroups = m_impl->do_XkbKeyNumGroups(m_xkb, keycode);
815             for (int group = 0; group < numGroups; ++group) {
816                 // iterate over all shift levels for the button (including none)
817                 XkbKeyTypePtr type = m_impl->do_XkbKeyKeyType(m_xkb, keycode, group);
818                 for (int j = -1; j < type->map_count; ++j) {
819                     if (j != -1 && !type->map[j].active) {
820                         continue;
821                     }
822                     int level = ((j == -1) ? 0 : type->map[j].level);
823                     XkbAction* action =
824                         m_impl->do_XkbKeyActionEntry(m_xkb, keycode, level, group);
825                     if (action->type == XkbSA_SetMods ||
826                         action->type == XkbSA_LockMods) {
827                         return true;
828                     }
829                 }
830             }
831         }
832     }
833 #endif
834     return false;
835 }
836 
837 int
getEffectiveGroup(KeyCode keycode,int group) const838 XWindowsKeyState::getEffectiveGroup(KeyCode keycode, int group) const
839 {
840     (void)keycode;
841 #if HAVE_XKB_EXTENSION
842     // get effective group for key
843     int numGroups = m_impl->do_XkbKeyNumGroups(m_xkb, keycode);
844     if (group >= numGroups) {
845         unsigned char groupInfo = m_impl->do_XkbKeyGroupInfo(m_xkb, keycode);
846         switch (XkbOutOfRangeGroupAction(groupInfo)) {
847         case XkbClampIntoRange:
848             group = numGroups - 1;
849             break;
850 
851         case XkbRedirectIntoRange:
852             group = XkbOutOfRangeGroupNumber(groupInfo);
853             if (group >= numGroups) {
854                 group = 0;
855             }
856             break;
857 
858         default:
859             // wrap
860             group %= numGroups;
861             break;
862         }
863     }
864 #endif
865     return group;
866 }
867 
868 UInt32
getGroupFromState(unsigned int state) const869 XWindowsKeyState::getGroupFromState(unsigned int state) const
870 {
871 #if HAVE_XKB_EXTENSION
872     if (m_xkb != NULL) {
873         return XkbGroupForCoreState(state);
874     }
875 #endif
876     return 0;
877 }
878