1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the plugins of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 #include "qxcbkeyboard.h"
40 #include "qxcbwindow.h"
41 #include "qxcbscreen.h"
42 
43 #include <qpa/qwindowsysteminterface.h>
44 #include <qpa/qplatforminputcontext.h>
45 #include <qpa/qplatformintegration.h>
46 #include <qpa/qplatformcursor.h>
47 
48 #include <QtCore/QMetaEnum>
49 
50 #include <private/qguiapplication_p.h>
51 
52 #include <xcb/xinput.h>
53 
54 QT_BEGIN_NAMESPACE
55 
translateModifiers(int s) const56 Qt::KeyboardModifiers QXcbKeyboard::translateModifiers(int s) const
57 {
58     Qt::KeyboardModifiers ret = Qt::NoModifier;
59     if (s & XCB_MOD_MASK_SHIFT)
60         ret |= Qt::ShiftModifier;
61     if (s & XCB_MOD_MASK_CONTROL)
62         ret |= Qt::ControlModifier;
63     if (s & rmod_masks.alt)
64         ret |= Qt::AltModifier;
65     if (s & rmod_masks.meta)
66         ret |= Qt::MetaModifier;
67     if (s & rmod_masks.altgr)
68         ret |= Qt::GroupSwitchModifier;
69     return ret;
70 }
71 
72 /* Look at a pair of unshifted and shifted key symbols.
73  * If the 'unshifted' symbol is uppercase and there is no shifted symbol,
74  * return the matching lowercase symbol; otherwise return 0.
75  * The caller can then use the previously 'unshifted' symbol as the new
76  * 'shifted' (uppercase) symbol and the symbol returned by the function
77  * as the new 'unshifted' (lowercase) symbol.) */
getUnshiftedXKey(xcb_keysym_t unshifted,xcb_keysym_t shifted)78 static xcb_keysym_t getUnshiftedXKey(xcb_keysym_t unshifted, xcb_keysym_t shifted)
79 {
80     if (shifted != XKB_KEY_NoSymbol) // Has a shifted symbol
81         return 0;
82 
83     xcb_keysym_t xlower;
84     xcb_keysym_t xupper;
85     QXkbCommon::xkbcommon_XConvertCase(unshifted, &xlower, &xupper);
86 
87     if (xlower != xupper          // Check if symbol is cased
88         && unshifted == xupper) { // Unshifted must be upper case
89         return xlower;
90     }
91 
92     return 0;
93 }
94 
symbolsGroupString(const xcb_keysym_t * symbols,int count)95 static QByteArray symbolsGroupString(const xcb_keysym_t *symbols, int count)
96 {
97     // Don't output trailing NoSymbols
98     while (count > 0 && symbols[count - 1] == XKB_KEY_NoSymbol)
99         count--;
100 
101     QByteArray groupString;
102     for (int symIndex = 0; symIndex < count; symIndex++) {
103         xcb_keysym_t sym = symbols[symIndex];
104         char symString[64];
105         if (sym == XKB_KEY_NoSymbol)
106             strcpy(symString, "NoSymbol");
107         else
108             xkb_keysym_get_name(sym, symString, sizeof(symString));
109 
110         if (!groupString.isEmpty())
111             groupString += ", ";
112         groupString += symString;
113     }
114     return groupString;
115 }
116 
keymapFromCore(const KeysymModifierMap & keysymMods)117 struct xkb_keymap *QXcbKeyboard::keymapFromCore(const KeysymModifierMap &keysymMods)
118 {
119     /* Construct an XKB keymap string from information queried from
120      * the X server */
121     QByteArray keymap;
122     keymap += "xkb_keymap {\n";
123 
124     const xcb_keycode_t minKeycode = connection()->setup()->min_keycode;
125     const xcb_keycode_t maxKeycode = connection()->setup()->max_keycode;
126 
127     // Generate symbolic names from keycodes
128     {
129         keymap +=
130             "xkb_keycodes \"core\" {\n"
131             "\tminimum = " + QByteArray::number(minKeycode) + ";\n"
132             "\tmaximum = " + QByteArray::number(maxKeycode) + ";\n";
133         for (int code = minKeycode; code <= maxKeycode; code++) {
134             auto codeStr = QByteArray::number(code);
135             keymap += "<K" + codeStr + "> = " + codeStr + ";\n";
136         }
137         /* TODO: indicators?
138          */
139         keymap += "};\n"; // xkb_keycodes
140     }
141 
142     /* Set up default types (xkbcommon automatically assigns these to
143      * symbols, but doesn't have shift info) */
144     keymap +=
145         "xkb_types \"core\" {\n"
146         "virtual_modifiers NumLock,Alt,LevelThree;\n"
147         "type \"ONE_LEVEL\" {\n"
148             "modifiers= none;\n"
149             "level_name[Level1] = \"Any\";\n"
150         "};\n"
151         "type \"TWO_LEVEL\" {\n"
152             "modifiers= Shift;\n"
153             "map[Shift]= Level2;\n"
154             "level_name[Level1] = \"Base\";\n"
155             "level_name[Level2] = \"Shift\";\n"
156         "};\n"
157         "type \"ALPHABETIC\" {\n"
158             "modifiers= Shift+Lock;\n"
159             "map[Shift]= Level2;\n"
160             "map[Lock]= Level2;\n"
161             "level_name[Level1] = \"Base\";\n"
162             "level_name[Level2] = \"Caps\";\n"
163         "};\n"
164         "type \"KEYPAD\" {\n"
165             "modifiers= Shift+NumLock;\n"
166             "map[Shift]= Level2;\n"
167             "map[NumLock]= Level2;\n"
168             "level_name[Level1] = \"Base\";\n"
169             "level_name[Level2] = \"Number\";\n"
170         "};\n"
171         "type \"FOUR_LEVEL\" {\n"
172             "modifiers= Shift+LevelThree;\n"
173             "map[Shift]= Level2;\n"
174             "map[LevelThree]= Level3;\n"
175             "map[Shift+LevelThree]= Level4;\n"
176             "level_name[Level1] = \"Base\";\n"
177             "level_name[Level2] = \"Shift\";\n"
178             "level_name[Level3] = \"Alt Base\";\n"
179             "level_name[Level4] = \"Shift Alt\";\n"
180         "};\n"
181         "type \"FOUR_LEVEL_ALPHABETIC\" {\n"
182             "modifiers= Shift+Lock+LevelThree;\n"
183             "map[Shift]= Level2;\n"
184             "map[Lock]= Level2;\n"
185             "map[LevelThree]= Level3;\n"
186             "map[Shift+LevelThree]= Level4;\n"
187             "map[Lock+LevelThree]= Level4;\n"
188             "map[Shift+Lock+LevelThree]= Level3;\n"
189             "level_name[Level1] = \"Base\";\n"
190             "level_name[Level2] = \"Shift\";\n"
191             "level_name[Level3] = \"Alt Base\";\n"
192             "level_name[Level4] = \"Shift Alt\";\n"
193         "};\n"
194         "type \"FOUR_LEVEL_SEMIALPHABETIC\" {\n"
195             "modifiers= Shift+Lock+LevelThree;\n"
196             "map[Shift]= Level2;\n"
197             "map[Lock]= Level2;\n"
198             "map[LevelThree]= Level3;\n"
199             "map[Shift+LevelThree]= Level4;\n"
200             "map[Lock+LevelThree]= Level3;\n"
201             "preserve[Lock+LevelThree]= Lock;\n"
202             "map[Shift+Lock+LevelThree]= Level4;\n"
203             "preserve[Shift+Lock+LevelThree]= Lock;\n"
204             "level_name[Level1] = \"Base\";\n"
205             "level_name[Level2] = \"Shift\";\n"
206             "level_name[Level3] = \"Alt Base\";\n"
207             "level_name[Level4] = \"Shift Alt\";\n"
208         "};\n"
209         "type \"FOUR_LEVEL_KEYPAD\" {\n"
210             "modifiers= Shift+NumLock+LevelThree;\n"
211             "map[Shift]= Level2;\n"
212             "map[NumLock]= Level2;\n"
213             "map[LevelThree]= Level3;\n"
214             "map[Shift+LevelThree]= Level4;\n"
215             "map[NumLock+LevelThree]= Level4;\n"
216             "map[Shift+NumLock+LevelThree]= Level3;\n"
217             "level_name[Level1] = \"Base\";\n"
218             "level_name[Level2] = \"Number\";\n"
219             "level_name[Level3] = \"Alt Base\";\n"
220             "level_name[Level4] = \"Alt Number\";\n"
221         "};\n"
222         "};\n"; // xkb_types
223 
224     // Generate mapping between symbolic names and keysyms
225     {
226         QVector<xcb_keysym_t> xkeymap;
227         int keysymsPerKeycode = 0;
228         {
229             int keycodeCount = maxKeycode - minKeycode + 1;
230             if (auto keymapReply = Q_XCB_REPLY(xcb_get_keyboard_mapping, xcb_connection(),
231                                                minKeycode, keycodeCount)) {
232                 keysymsPerKeycode = keymapReply->keysyms_per_keycode;
233                 int numSyms = keycodeCount * keysymsPerKeycode;
234                 auto keymapPtr = xcb_get_keyboard_mapping_keysyms(keymapReply.get());
235                 xkeymap.resize(numSyms);
236                 for (int i = 0; i < numSyms; i++)
237                     xkeymap[i] = keymapPtr[i];
238             }
239         }
240         if (xkeymap.isEmpty())
241             return nullptr;
242 
243         static const char *const builtinModifiers[] =
244         { "Shift", "Lock", "Control", "Mod1", "Mod2", "Mod3", "Mod4", "Mod5" };
245 
246         /* Level 3 symbols (e.g. AltGr+something) seem to come in two flavors:
247          * - as a proper level 3 in group 1, at least on recent X.org versions
248          * - 'disguised' as group 2, on 'legacy' X servers
249          * In the 2nd case, remap group 2 to level 3, that seems to work better
250          * in practice */
251         bool mapGroup2ToLevel3 = keysymsPerKeycode < 5;
252 
253         keymap += "xkb_symbols \"core\" {\n";
254         for (int code = minKeycode; code <= maxKeycode; code++) {
255             auto codeMap = xkeymap.constData() + (code - minKeycode) * keysymsPerKeycode;
256 
257             const int maxGroup1 = 4; // We only support 4 shift states anyway
258             const int maxGroup2 = 2; // Only 3rd and 4th keysym are group 2
259             xcb_keysym_t symbolsGroup1[maxGroup1];
260             xcb_keysym_t symbolsGroup2[maxGroup2];
261             for (int i = 0; i < maxGroup1 + maxGroup2; i++) {
262                 xcb_keysym_t sym = i < keysymsPerKeycode ? codeMap[i] : XKB_KEY_NoSymbol;
263                 if (mapGroup2ToLevel3) {
264                     // Merge into single group
265                     if (i < maxGroup1)
266                         symbolsGroup1[i] = sym;
267                 } else {
268                     // Preserve groups
269                     if (i < 2)
270                         symbolsGroup1[i] = sym;
271                     else if (i < 4)
272                         symbolsGroup2[i - 2] = sym;
273                     else
274                         symbolsGroup1[i - 2] = sym;
275                 }
276             }
277 
278             /* Fix symbols so the unshifted and shifted symbols have
279              * lower resp. upper case */
280             if (auto lowered = getUnshiftedXKey(symbolsGroup1[0], symbolsGroup1[1])) {
281                 symbolsGroup1[1] = symbolsGroup1[0];
282                 symbolsGroup1[0] = lowered;
283             }
284             if (auto lowered = getUnshiftedXKey(symbolsGroup2[0], symbolsGroup2[1])) {
285                 symbolsGroup2[1] = symbolsGroup2[0];
286                 symbolsGroup2[0] = lowered;
287             }
288 
289             QByteArray groupStr1 = symbolsGroupString(symbolsGroup1, maxGroup1);
290             if (groupStr1.isEmpty())
291                 continue;
292 
293             keymap += "key <K" + QByteArray::number(code) + "> { ";
294             keymap += "symbols[Group1] = [ " + groupStr1 + " ]";
295             QByteArray groupStr2 = symbolsGroupString(symbolsGroup2, maxGroup2);
296             if (!groupStr2.isEmpty())
297                 keymap += ", symbols[Group2] = [ " + groupStr2 + " ]";
298 
299             // See if this key code is for a modifier
300             xcb_keysym_t modifierSym = XKB_KEY_NoSymbol;
301             for (int symIndex = 0; symIndex < keysymsPerKeycode; symIndex++) {
302                 xcb_keysym_t sym = codeMap[symIndex];
303 
304                 if (sym == XKB_KEY_Alt_L
305                     || sym == XKB_KEY_Meta_L
306                     || sym == XKB_KEY_Mode_switch
307                     || sym == XKB_KEY_Super_L
308                     || sym == XKB_KEY_Super_R
309                     || sym == XKB_KEY_Hyper_L
310                     || sym == XKB_KEY_Hyper_R) {
311                     modifierSym = sym;
312                     break;
313                 }
314             }
315 
316             // AltGr
317             if (modifierSym == XKB_KEY_Mode_switch)
318                 keymap += ", virtualMods=LevelThree";
319             keymap += " };\n"; // key
320 
321             // Generate modifier mappings
322             int modNum = keysymMods.value(modifierSym, -1);
323             if (modNum != -1) {
324                 // Here modNum is always < 8 (see keysymsToModifiers())
325                 keymap += QByteArray("modifier_map ") + builtinModifiers[modNum]
326                     + " { <K" + QByteArray::number(code) + "> };\n";
327             }
328         }
329         // TODO: indicators?
330         keymap += "};\n"; // xkb_symbols
331     }
332 
333     // We need an "Alt" modifier, provide via the xkb_compatibility section
334     keymap +=
335         "xkb_compatibility \"core\" {\n"
336         "virtual_modifiers NumLock,Alt,LevelThree;\n"
337         "interpret Alt_L+AnyOf(all) {\n"
338             "virtualModifier= Alt;\n"
339             "action= SetMods(modifiers=modMapMods,clearLocks);\n"
340         "};\n"
341         "interpret Alt_R+AnyOf(all) {\n"
342             "virtualModifier= Alt;\n"
343             "action= SetMods(modifiers=modMapMods,clearLocks);\n"
344         "};\n"
345         "};\n";
346 
347     /* TODO: There is an issue with modifier state not being handled
348      * correctly if using Xming with XKEYBOARD disabled. */
349 
350     keymap += "};\n"; // xkb_keymap
351 
352     return xkb_keymap_new_from_buffer(m_xkbContext.get(),
353                                       keymap.constData(),
354                                       keymap.size(),
355                                       XKB_KEYMAP_FORMAT_TEXT_V1,
356                                       XKB_KEYMAP_COMPILE_NO_FLAGS);
357 }
358 
updateKeymap(xcb_mapping_notify_event_t * event)359 void QXcbKeyboard::updateKeymap(xcb_mapping_notify_event_t *event)
360 {
361     if (connection()->hasXKB() || event->request == XCB_MAPPING_POINTER)
362         return;
363 
364     xcb_refresh_keyboard_mapping(m_key_symbols, event);
365     updateKeymap();
366 }
367 
updateKeymap()368 void QXcbKeyboard::updateKeymap()
369 {
370     KeysymModifierMap keysymMods;
371     if (!connection()->hasXKB())
372         keysymMods = keysymsToModifiers();
373     updateModifiers(keysymMods);
374 
375     m_config = true;
376 
377     if (!m_xkbContext) {
378         m_xkbContext.reset(xkb_context_new(XKB_CONTEXT_NO_DEFAULT_INCLUDES));
379         if (!m_xkbContext) {
380             qCWarning(lcQpaKeyboard, "failed to create XKB context");
381             m_config = false;
382             return;
383         }
384         xkb_log_level logLevel = lcQpaKeyboard().isDebugEnabled() ?
385                                  XKB_LOG_LEVEL_DEBUG : XKB_LOG_LEVEL_CRITICAL;
386         xkb_context_set_log_level(m_xkbContext.get(), logLevel);
387     }
388 
389     if (connection()->hasXKB()) {
390         m_xkbKeymap.reset(xkb_x11_keymap_new_from_device(m_xkbContext.get(), xcb_connection(),
391                                                          core_device_id, XKB_KEYMAP_COMPILE_NO_FLAGS));
392         if (m_xkbKeymap)
393             m_xkbState.reset(xkb_x11_state_new_from_device(m_xkbKeymap.get(), xcb_connection(), core_device_id));
394     } else {
395         m_xkbKeymap.reset(keymapFromCore(keysymMods));
396         if (m_xkbKeymap)
397             m_xkbState.reset(xkb_state_new(m_xkbKeymap.get()));
398     }
399 
400     if (!m_xkbKeymap) {
401         qCWarning(lcQpaKeyboard, "failed to compile a keymap");
402         m_config = false;
403         return;
404     }
405     if (!m_xkbState) {
406         qCWarning(lcQpaKeyboard, "failed to create XKB state");
407         m_config = false;
408         return;
409     }
410 
411     updateXKBMods();
412 
413     QXkbCommon::verifyHasLatinLayout(m_xkbKeymap.get());
414 }
415 
possibleKeys(const QKeyEvent * event) const416 QList<int> QXcbKeyboard::possibleKeys(const QKeyEvent *event) const
417 {
418     return QXkbCommon::possibleKeys(m_xkbState.get(), event, m_superAsMeta, m_hyperAsMeta);
419 }
420 
updateXKBState(xcb_xkb_state_notify_event_t * state)421 void QXcbKeyboard::updateXKBState(xcb_xkb_state_notify_event_t *state)
422 {
423     if (m_config && connection()->hasXKB()) {
424         const xkb_state_component changedComponents
425                 = xkb_state_update_mask(m_xkbState.get(),
426                                   state->baseMods,
427                                   state->latchedMods,
428                                   state->lockedMods,
429                                   state->baseGroup,
430                                   state->latchedGroup,
431                                   state->lockedGroup);
432 
433         handleStateChanges(changedComponents);
434     }
435 }
436 
lockedGroup(quint16 state)437 static xkb_layout_index_t lockedGroup(quint16 state)
438 {
439     return (state >> 13) & 3; // bits 13 and 14 report the state keyboard group
440 }
441 
updateXKBStateFromCore(quint16 state)442 void QXcbKeyboard::updateXKBStateFromCore(quint16 state)
443 {
444     if (m_config && !connection()->hasXKB()) {
445         struct xkb_state *xkbState = m_xkbState.get();
446         xkb_mod_mask_t modsDepressed = xkb_state_serialize_mods(xkbState, XKB_STATE_MODS_DEPRESSED);
447         xkb_mod_mask_t modsLatched = xkb_state_serialize_mods(xkbState, XKB_STATE_MODS_LATCHED);
448         xkb_mod_mask_t modsLocked = xkb_state_serialize_mods(xkbState, XKB_STATE_MODS_LOCKED);
449         xkb_mod_mask_t xkbMask = xkbModMask(state);
450 
451         xkb_mod_mask_t latched = modsLatched & xkbMask;
452         xkb_mod_mask_t locked = modsLocked & xkbMask;
453         xkb_mod_mask_t depressed = modsDepressed & xkbMask;
454         // set modifiers in depressed if they don't appear in any of the final masks
455         depressed |= ~(depressed | latched | locked) & xkbMask;
456 
457         xkb_state_component changedComponents = xkb_state_update_mask(
458                     xkbState, depressed, latched, locked, 0, 0, lockedGroup(state));
459 
460         handleStateChanges(changedComponents);
461     }
462 }
463 
updateXKBStateFromXI(void * modInfo,void * groupInfo)464 void QXcbKeyboard::updateXKBStateFromXI(void *modInfo, void *groupInfo)
465 {
466     if (m_config && !connection()->hasXKB()) {
467         auto *mods = static_cast<xcb_input_modifier_info_t *>(modInfo);
468         auto *group = static_cast<xcb_input_group_info_t *>(groupInfo);
469         const xkb_state_component changedComponents
470                 = xkb_state_update_mask(m_xkbState.get(),
471                                         mods->base,
472                                         mods->latched,
473                                         mods->locked,
474                                         group->base,
475                                         group->latched,
476                                         group->locked);
477 
478         handleStateChanges(changedComponents);
479     }
480 }
481 
handleStateChanges(xkb_state_component changedComponents)482 void QXcbKeyboard::handleStateChanges(xkb_state_component changedComponents)
483 {
484     // Note: Ubuntu (with Unity) always creates a new keymap when layout is changed
485     // via system settings, which means that the layout change would not be detected
486     // by this code. That can be solved by emitting KeyboardLayoutChange also from updateKeymap().
487     if ((changedComponents & XKB_STATE_LAYOUT_EFFECTIVE) == XKB_STATE_LAYOUT_EFFECTIVE)
488         qCDebug(lcQpaKeyboard, "TODO: Support KeyboardLayoutChange on QPA (QTBUG-27681)");
489 }
490 
xkbModMask(quint16 state)491 xkb_mod_mask_t QXcbKeyboard::xkbModMask(quint16 state)
492 {
493     xkb_mod_mask_t xkb_mask = 0;
494 
495     if ((state & XCB_MOD_MASK_SHIFT) && xkb_mods.shift != XKB_MOD_INVALID)
496         xkb_mask |= (1 << xkb_mods.shift);
497     if ((state & XCB_MOD_MASK_LOCK) && xkb_mods.lock != XKB_MOD_INVALID)
498         xkb_mask |= (1 << xkb_mods.lock);
499     if ((state & XCB_MOD_MASK_CONTROL) && xkb_mods.control != XKB_MOD_INVALID)
500         xkb_mask |= (1 << xkb_mods.control);
501     if ((state & XCB_MOD_MASK_1) && xkb_mods.mod1 != XKB_MOD_INVALID)
502         xkb_mask |= (1 << xkb_mods.mod1);
503     if ((state & XCB_MOD_MASK_2) && xkb_mods.mod2 != XKB_MOD_INVALID)
504         xkb_mask |= (1 << xkb_mods.mod2);
505     if ((state & XCB_MOD_MASK_3) && xkb_mods.mod3 != XKB_MOD_INVALID)
506         xkb_mask |= (1 << xkb_mods.mod3);
507     if ((state & XCB_MOD_MASK_4) && xkb_mods.mod4 != XKB_MOD_INVALID)
508         xkb_mask |= (1 << xkb_mods.mod4);
509     if ((state & XCB_MOD_MASK_5) && xkb_mods.mod5 != XKB_MOD_INVALID)
510         xkb_mask |= (1 << xkb_mods.mod5);
511 
512     return xkb_mask;
513 }
514 
updateXKBMods()515 void QXcbKeyboard::updateXKBMods()
516 {
517     xkb_mods.shift = xkb_keymap_mod_get_index(m_xkbKeymap.get(), XKB_MOD_NAME_SHIFT);
518     xkb_mods.lock = xkb_keymap_mod_get_index(m_xkbKeymap.get(), XKB_MOD_NAME_CAPS);
519     xkb_mods.control = xkb_keymap_mod_get_index(m_xkbKeymap.get(), XKB_MOD_NAME_CTRL);
520     xkb_mods.mod1 = xkb_keymap_mod_get_index(m_xkbKeymap.get(), "Mod1");
521     xkb_mods.mod2 = xkb_keymap_mod_get_index(m_xkbKeymap.get(), "Mod2");
522     xkb_mods.mod3 = xkb_keymap_mod_get_index(m_xkbKeymap.get(), "Mod3");
523     xkb_mods.mod4 = xkb_keymap_mod_get_index(m_xkbKeymap.get(), "Mod4");
524     xkb_mods.mod5 = xkb_keymap_mod_get_index(m_xkbKeymap.get(), "Mod5");
525 }
526 
QXcbKeyboard(QXcbConnection * connection)527 QXcbKeyboard::QXcbKeyboard(QXcbConnection *connection)
528     : QXcbObject(connection)
529 {
530     core_device_id = 0;
531     if (connection->hasXKB()) {
532         selectEvents();
533         core_device_id = xkb_x11_get_core_keyboard_device_id(xcb_connection());
534         if (core_device_id == -1) {
535             qCWarning(lcQpaXcb, "failed to get core keyboard device info");
536             return;
537         }
538     } else {
539         m_key_symbols = xcb_key_symbols_alloc(xcb_connection());
540     }
541 
542     updateKeymap();
543 }
544 
~QXcbKeyboard()545 QXcbKeyboard::~QXcbKeyboard()
546 {
547     if (m_key_symbols)
548         xcb_key_symbols_free(m_key_symbols);
549 }
550 
initialize()551 void QXcbKeyboard::initialize()
552 {
553     auto inputContext = QGuiApplicationPrivate::platformIntegration()->inputContext();
554     QXkbCommon::setXkbContext(inputContext, m_xkbContext.get());
555 }
556 
selectEvents()557 void QXcbKeyboard::selectEvents()
558 {
559     const uint16_t required_map_parts = (XCB_XKB_MAP_PART_KEY_TYPES |
560         XCB_XKB_MAP_PART_KEY_SYMS |
561         XCB_XKB_MAP_PART_MODIFIER_MAP |
562         XCB_XKB_MAP_PART_EXPLICIT_COMPONENTS |
563         XCB_XKB_MAP_PART_KEY_ACTIONS |
564         XCB_XKB_MAP_PART_KEY_BEHAVIORS |
565         XCB_XKB_MAP_PART_VIRTUAL_MODS |
566         XCB_XKB_MAP_PART_VIRTUAL_MOD_MAP);
567 
568     const uint16_t required_events = (XCB_XKB_EVENT_TYPE_NEW_KEYBOARD_NOTIFY |
569         XCB_XKB_EVENT_TYPE_MAP_NOTIFY |
570         XCB_XKB_EVENT_TYPE_STATE_NOTIFY);
571 
572     // XKB events are reported to all interested clients without regard
573     // to the current keyboard input focus or grab state
574     xcb_void_cookie_t select = xcb_xkb_select_events_checked(
575                 xcb_connection(),
576                 XCB_XKB_ID_USE_CORE_KBD,
577                 required_events,
578                 0,
579                 required_events,
580                 required_map_parts,
581                 required_map_parts,
582                 nullptr);
583 
584     xcb_generic_error_t *error = xcb_request_check(xcb_connection(), select);
585     if (error) {
586         free(error);
587         qCWarning(lcQpaXcb, "failed to select notify events from XKB");
588     }
589 }
590 
updateVModMapping()591 void QXcbKeyboard::updateVModMapping()
592 {
593     xcb_xkb_get_names_value_list_t names_list;
594 
595     memset(&vmod_masks, 0, sizeof(vmod_masks));
596 
597     auto name_reply = Q_XCB_REPLY(xcb_xkb_get_names, xcb_connection(),
598                                   XCB_XKB_ID_USE_CORE_KBD,
599                                   XCB_XKB_NAME_DETAIL_VIRTUAL_MOD_NAMES);
600     if (!name_reply) {
601         qWarning("Qt: failed to retrieve the virtual modifier names from XKB");
602         return;
603     }
604 
605     const void *buffer = xcb_xkb_get_names_value_list(name_reply.get());
606     xcb_xkb_get_names_value_list_unpack(buffer,
607                                         name_reply->nTypes,
608                                         name_reply->indicators,
609                                         name_reply->virtualMods,
610                                         name_reply->groupNames,
611                                         name_reply->nKeys,
612                                         name_reply->nKeyAliases,
613                                         name_reply->nRadioGroups,
614                                         name_reply->which,
615                                         &names_list);
616 
617     int count = 0;
618     uint vmod_mask, bit;
619     char *vmod_name;
620     vmod_mask = name_reply->virtualMods;
621     // find the virtual modifiers for which names are defined.
622     for (bit = 1; vmod_mask; bit <<= 1) {
623         vmod_name = nullptr;
624 
625         if (!(vmod_mask & bit))
626             continue;
627 
628         vmod_mask &= ~bit;
629         // virtualModNames - the list of virtual modifier atoms beginning with the lowest-numbered
630         // virtual modifier for which a name is defined and proceeding to the highest.
631         QByteArray atomName = connection()->atomName(names_list.virtualModNames[count]);
632         vmod_name = atomName.data();
633         count++;
634 
635         if (!vmod_name)
636             continue;
637 
638         // similarly we could retrieve NumLock, Super, Hyper modifiers if needed.
639         if (qstrcmp(vmod_name, "Alt") == 0)
640             vmod_masks.alt = bit;
641         else if (qstrcmp(vmod_name, "Meta") == 0)
642             vmod_masks.meta = bit;
643         else if (qstrcmp(vmod_name, "AltGr") == 0)
644             vmod_masks.altgr = bit;
645         else if (qstrcmp(vmod_name, "Super") == 0)
646             vmod_masks.super = bit;
647         else if (qstrcmp(vmod_name, "Hyper") == 0)
648             vmod_masks.hyper = bit;
649     }
650 }
651 
updateVModToRModMapping()652 void QXcbKeyboard::updateVModToRModMapping()
653 {
654     xcb_xkb_get_map_map_t map;
655 
656     memset(&rmod_masks, 0, sizeof(rmod_masks));
657 
658     auto map_reply = Q_XCB_REPLY(xcb_xkb_get_map,
659                                  xcb_connection(),
660                                  XCB_XKB_ID_USE_CORE_KBD,
661                                  XCB_XKB_MAP_PART_VIRTUAL_MODS,
662                                  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
663     if (!map_reply) {
664         qWarning("Qt: failed to retrieve the virtual modifier map from XKB");
665         return;
666     }
667 
668     const void *buffer = xcb_xkb_get_map_map(map_reply.get());
669     xcb_xkb_get_map_map_unpack(buffer,
670                                map_reply->nTypes,
671                                map_reply->nKeySyms,
672                                map_reply->nKeyActions,
673                                map_reply->totalActions,
674                                map_reply->totalKeyBehaviors,
675                                map_reply->nVModMapKeys,
676                                map_reply->totalKeyExplicit,
677                                map_reply->totalModMapKeys,
678                                map_reply->totalVModMapKeys,
679                                map_reply->present,
680                                &map);
681 
682     uint vmod_mask, bit;
683     // the virtual modifiers mask for which a set of corresponding
684     // real modifiers is to be returned
685     vmod_mask = map_reply->virtualMods;
686     int count = 0;
687 
688     for (bit = 1; vmod_mask; bit <<= 1) {
689         uint modmap;
690 
691         if (!(vmod_mask & bit))
692             continue;
693 
694         vmod_mask &= ~bit;
695         // real modifier bindings for the specified virtual modifiers
696         modmap = map.vmods_rtrn[count];
697         count++;
698 
699         if (vmod_masks.alt == bit)
700             rmod_masks.alt = modmap;
701         else if (vmod_masks.meta == bit)
702             rmod_masks.meta = modmap;
703         else if (vmod_masks.altgr == bit)
704             rmod_masks.altgr = modmap;
705         else if (vmod_masks.super == bit)
706             rmod_masks.super = modmap;
707         else if (vmod_masks.hyper == bit)
708             rmod_masks.hyper = modmap;
709     }
710 }
711 
712 // Small helper: set modifier bit, if modifier position is valid
applyModifier(uint * mask,int modifierBit)713 static inline void applyModifier(uint *mask, int modifierBit)
714 {
715     if (modifierBit >= 0 && modifierBit < 8)
716         *mask |= 1 << modifierBit;
717 }
718 
updateModifiers(const KeysymModifierMap & keysymMods)719 void QXcbKeyboard::updateModifiers(const KeysymModifierMap &keysymMods)
720 {
721     if (connection()->hasXKB()) {
722         updateVModMapping();
723         updateVModToRModMapping();
724     } else {
725         memset(&rmod_masks, 0, sizeof(rmod_masks));
726         // Compute X modifier bits for Qt modifiers
727         applyModifier(&rmod_masks.alt,   keysymMods.value(XKB_KEY_Alt_L,       -1));
728         applyModifier(&rmod_masks.alt,   keysymMods.value(XKB_KEY_Alt_R,       -1));
729         applyModifier(&rmod_masks.meta,  keysymMods.value(XKB_KEY_Meta_L,      -1));
730         applyModifier(&rmod_masks.meta,  keysymMods.value(XKB_KEY_Meta_R,      -1));
731         applyModifier(&rmod_masks.altgr, keysymMods.value(XKB_KEY_Mode_switch, -1));
732         applyModifier(&rmod_masks.super, keysymMods.value(XKB_KEY_Super_L,     -1));
733         applyModifier(&rmod_masks.super, keysymMods.value(XKB_KEY_Super_R,     -1));
734         applyModifier(&rmod_masks.hyper, keysymMods.value(XKB_KEY_Hyper_L,     -1));
735         applyModifier(&rmod_masks.hyper, keysymMods.value(XKB_KEY_Hyper_R,     -1));
736     }
737 
738     resolveMaskConflicts();
739 }
740 
741 // Small helper: check if an array of xcb_keycode_t contains a certain code
keycodes_contains(xcb_keycode_t * codes,xcb_keycode_t which)742 static inline bool keycodes_contains(xcb_keycode_t *codes, xcb_keycode_t which)
743 {
744     while (*codes != XCB_NO_SYMBOL) {
745         if (*codes == which) return true;
746         codes++;
747     }
748     return false;
749 }
750 
keysymsToModifiers()751 QXcbKeyboard::KeysymModifierMap QXcbKeyboard::keysymsToModifiers()
752 {
753     // The core protocol does not provide a convenient way to determine the mapping
754     // of modifier bits. Clients must retrieve and search the modifier map to determine
755     // the keycodes bound to each modifier, and then retrieve and search the keyboard
756     // mapping to determine the keysyms bound to the keycodes. They must repeat this
757     // process for all modifiers whenever any part of the modifier mapping is changed.
758 
759     KeysymModifierMap map;
760 
761     auto modMapReply = Q_XCB_REPLY(xcb_get_modifier_mapping, xcb_connection());
762     if (!modMapReply) {
763         qWarning("Qt: failed to get modifier mapping");
764         return map;
765     }
766 
767     // for Alt and Meta L and R are the same
768     static const xcb_keysym_t symbols[] = {
769         XKB_KEY_Alt_L, XKB_KEY_Meta_L, XKB_KEY_Mode_switch, XKB_KEY_Super_L, XKB_KEY_Super_R,
770         XKB_KEY_Hyper_L, XKB_KEY_Hyper_R
771     };
772     static const size_t numSymbols = sizeof symbols / sizeof *symbols;
773 
774     // Figure out the modifier mapping, ICCCM 6.6
775     xcb_keycode_t* modKeyCodes[numSymbols];
776     for (size_t i = 0; i < numSymbols; ++i)
777         modKeyCodes[i] = xcb_key_symbols_get_keycode(m_key_symbols, symbols[i]);
778 
779     xcb_keycode_t *modMap = xcb_get_modifier_mapping_keycodes(modMapReply.get());
780     const int modMapLength = xcb_get_modifier_mapping_keycodes_length(modMapReply.get());
781     /* For each modifier of "Shift, Lock, Control, Mod1, Mod2, Mod3,
782      * Mod4, and Mod5" the modifier map contains keycodes_per_modifier
783      * key codes that are associated with a modifier.
784      *
785      * As an example, take this 'xmodmap' output:
786      *   xmodmap: up to 4 keys per modifier, (keycodes in parentheses):
787      *
788      *   shift       Shift_L (0x32),  Shift_R (0x3e)
789      *   lock        Caps_Lock (0x42)
790      *   control     Control_L (0x25),  Control_R (0x69)
791      *   mod1        Alt_L (0x40),  Alt_R (0x6c),  Meta_L (0xcd)
792      *   mod2        Num_Lock (0x4d)
793      *   mod3
794      *   mod4        Super_L (0x85),  Super_R (0x86),  Super_L (0xce),  Hyper_L (0xcf)
795      *   mod5        ISO_Level3_Shift (0x5c),  Mode_switch (0xcb)
796      *
797      * The corresponding raw modifier map would contain keycodes for:
798      *   Shift_L (0x32), Shift_R (0x3e), 0, 0,
799      *   Caps_Lock (0x42), 0, 0, 0,
800      *   Control_L (0x25), Control_R (0x69), 0, 0,
801      *   Alt_L (0x40), Alt_R (0x6c), Meta_L (0xcd), 0,
802      *   Num_Lock (0x4d), 0, 0, 0,
803      *   0,0,0,0,
804      *   Super_L (0x85),  Super_R (0x86),  Super_L (0xce),  Hyper_L (0xcf),
805      *   ISO_Level3_Shift (0x5c),  Mode_switch (0xcb), 0, 0
806      */
807 
808     /* Create a map between a modifier keysym (as per the symbols array)
809      * and the modifier bit it's associated with (if any).
810      * As modMap contains key codes, search modKeyCodes for a match;
811      * if one is found we can look up the associated keysym.
812      * Together with the modifier index this will be used
813      * to compute a mapping between X modifier bits and Qt's
814      * modifiers (Alt, Ctrl etc). */
815     for (int i = 0; i < modMapLength; i++) {
816         if (modMap[i] == XCB_NO_SYMBOL)
817             continue;
818         // Get key symbol for key code
819         for (size_t k = 0; k < numSymbols; k++) {
820             if (modKeyCodes[k] && keycodes_contains(modKeyCodes[k], modMap[i])) {
821                 // Key code is for modifier. Record mapping
822                 xcb_keysym_t sym = symbols[k];
823                 /* As per modMap layout explanation above, dividing
824                  * by keycodes_per_modifier gives the 'row' in the
825                  * modifier map, which in turn is the modifier bit. */
826                 map[sym] = i / modMapReply->keycodes_per_modifier;
827                 break;
828             }
829         }
830     }
831 
832     for (size_t i = 0; i < numSymbols; ++i)
833         free(modKeyCodes[i]);
834 
835     return map;
836 }
837 
resolveMaskConflicts()838 void QXcbKeyboard::resolveMaskConflicts()
839 {
840     // if we don't have a meta key (or it's hidden behind alt), use super or hyper to generate
841     // Qt::Key_Meta and Qt::MetaModifier, since most newer XFree86/Xorg installations map the Windows
842     // key to Super
843     if (rmod_masks.alt == rmod_masks.meta)
844         rmod_masks.meta = 0;
845 
846     if (rmod_masks.meta == 0) {
847         // no meta keys... s/meta/super,
848         rmod_masks.meta = rmod_masks.super;
849         if (rmod_masks.meta == 0) {
850             // no super keys either? guess we'll use hyper then
851             rmod_masks.meta = rmod_masks.hyper;
852         }
853     }
854 
855     // translate Super/Hyper keys to Meta if we're using them as the MetaModifier
856     if (rmod_masks.meta && rmod_masks.meta == rmod_masks.super)
857         m_superAsMeta = true;
858     if (rmod_masks.meta && rmod_masks.meta == rmod_masks.hyper)
859         m_hyperAsMeta = true;
860 }
861 
handleKeyEvent(xcb_window_t sourceWindow,QEvent::Type type,xcb_keycode_t code,quint16 state,xcb_timestamp_t time,bool fromSendEvent)862 void QXcbKeyboard::handleKeyEvent(xcb_window_t sourceWindow, QEvent::Type type, xcb_keycode_t code,
863                                   quint16 state, xcb_timestamp_t time, bool fromSendEvent)
864 {
865     if (!m_config)
866         return;
867 
868     QXcbWindow *source = connection()->platformWindowFromId(sourceWindow);
869     QXcbWindow *targetWindow = connection()->focusWindow() ? connection()->focusWindow() : source;
870     if (!targetWindow || !source)
871         return;
872     if (type == QEvent::KeyPress)
873         targetWindow->updateNetWmUserTime(time);
874 
875     QXkbCommon::ScopedXKBState sendEventState;
876     if (fromSendEvent) {
877         // Have a temporary keyboard state filled in from state
878         // this way we allow for synthetic events to have different state
879         // from the current state i.e. you can have Alt+Ctrl pressed
880         // and receive a synthetic key event that has neither Alt nor Ctrl pressed
881         sendEventState.reset(xkb_state_new(m_xkbKeymap.get()));
882         if (!sendEventState)
883             return;
884 
885         xkb_mod_mask_t depressed = xkbModMask(state);
886         xkb_state_update_mask(sendEventState.get(), depressed, 0, 0, 0, 0, lockedGroup(state));
887     }
888 
889     struct xkb_state *xkbState = fromSendEvent ? sendEventState.get() : m_xkbState.get();
890 
891     xcb_keysym_t sym = xkb_state_key_get_one_sym(xkbState, code);
892     QString text = QXkbCommon::lookupString(xkbState, code);
893 
894     Qt::KeyboardModifiers modifiers = translateModifiers(state);
895     if (QXkbCommon::isKeypad(sym))
896         modifiers |= Qt::KeypadModifier;
897 
898     int qtcode = QXkbCommon::keysymToQtKey(sym, modifiers, xkbState, code, m_superAsMeta, m_hyperAsMeta);
899 
900     if (type == QEvent::KeyPress) {
901         if (m_isAutoRepeat && m_autoRepeatCode != code)
902             // Some other key was pressed while we are auto-repeating on a different key.
903             m_isAutoRepeat = false;
904     } else {
905         m_isAutoRepeat = false;
906         // Look at the next event in the queue to see if we are auto-repeating.
907         connection()->eventQueue()->peek(QXcbEventQueue::PeekRetainMatch,
908                                          [this, time, code](xcb_generic_event_t *event, int type) {
909             if (type == XCB_KEY_PRESS) {
910                 auto keyPress = reinterpret_cast<xcb_key_press_event_t *>(event);
911                 m_isAutoRepeat = keyPress->time == time && keyPress->detail == code;
912                 if (m_isAutoRepeat)
913                     m_autoRepeatCode = code;
914             }
915             return true;
916         });
917     }
918 
919     bool filtered = false;
920     if (auto inputContext = QGuiApplicationPrivate::platformIntegration()->inputContext()) {
921         QKeyEvent event(type, qtcode, modifiers, code, sym, state, text, m_isAutoRepeat, text.size());
922         event.setTimestamp(time);
923         filtered = inputContext->filterEvent(&event);
924     }
925 
926     if (!filtered) {
927         QWindow *window = targetWindow->window();
928 #ifndef QT_NO_CONTEXTMENU
929         if (type == QEvent::KeyPress && qtcode == Qt::Key_Menu) {
930             const QPoint globalPos = window->screen()->handle()->cursor()->pos();
931             const QPoint pos = window->mapFromGlobal(globalPos);
932             QWindowSystemInterface::handleContextMenuEvent(window, false, pos, globalPos, modifiers);
933         }
934 #endif
935         QWindowSystemInterface::handleExtendedKeyEvent(window, time, type, qtcode, modifiers,
936                                                        code, sym, state, text, m_isAutoRepeat);
937     }
938 }
939 
fromSendEvent(const void * event)940 static bool fromSendEvent(const void *event)
941 {
942     // From X11 protocol: Every event contains an 8-bit type code. The most
943     // significant bit in this code is set if the event was generated from
944     // a SendEvent request.
945     const xcb_generic_event_t *e = reinterpret_cast<const xcb_generic_event_t *>(event);
946     return (e->response_type & 0x80) != 0;
947 }
948 
handleKeyPressEvent(const xcb_key_press_event_t * e)949 void QXcbKeyboard::handleKeyPressEvent(const xcb_key_press_event_t *e)
950 {
951     handleKeyEvent(e->event, QEvent::KeyPress, e->detail, e->state, e->time, fromSendEvent(e));
952 }
953 
handleKeyReleaseEvent(const xcb_key_release_event_t * e)954 void QXcbKeyboard::handleKeyReleaseEvent(const xcb_key_release_event_t *e)
955 {
956     handleKeyEvent(e->event, QEvent::KeyRelease, e->detail, e->state, e->time, fromSendEvent(e));
957 }
958 
959 QT_END_NAMESPACE
960