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