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