84struct xkb_keymap *QXcbKeyboard::keymapFromCore(
const KeysymModifierMap &keysymMods)
87
89 keymap +=
"xkb_keymap {\n";
91 const xcb_keycode_t minKeycode =
connection()->setup()->min_keycode;
92 const xcb_keycode_t maxKeycode =
connection()->setup()->max_keycode;
97 "xkb_keycodes \"core\" {\n"
98 "\tminimum = " + QByteArray::number(minKeycode) +
";\n"
99 "\tmaximum = " + QByteArray::number(maxKeycode) +
";\n";
100 for (
int code = minKeycode; code <= maxKeycode; code++) {
101 auto codeStr = QByteArray::number(code);
102 keymap +=
"<K" + codeStr +
"> = " + codeStr +
";\n";
105
110
112 "xkb_types \"core\" {\n"
113 "virtual_modifiers NumLock,Alt,LevelThree;\n"
114 "type \"ONE_LEVEL\" {\n"
116 "level_name[Level1] = \"Any\";\n"
118 "type \"TWO_LEVEL\" {\n"
119 "modifiers= Shift;\n"
120 "map[Shift]= Level2;\n"
121 "level_name[Level1] = \"Base\";\n"
122 "level_name[Level2] = \"Shift\";\n"
124 "type \"ALPHABETIC\" {\n"
125 "modifiers= Shift+Lock;\n"
126 "map[Shift]= Level2;\n"
127 "map[Lock]= Level2;\n"
128 "level_name[Level1] = \"Base\";\n"
129 "level_name[Level2] = \"Caps\";\n"
131 "type \"KEYPAD\" {\n"
132 "modifiers= Shift+NumLock;\n"
133 "map[Shift]= Level2;\n"
134 "map[NumLock]= Level2;\n"
135 "level_name[Level1] = \"Base\";\n"
136 "level_name[Level2] = \"Number\";\n"
138 "type \"FOUR_LEVEL\" {\n"
139 "modifiers= Shift+LevelThree;\n"
140 "map[Shift]= Level2;\n"
141 "map[LevelThree]= Level3;\n"
142 "map[Shift+LevelThree]= Level4;\n"
143 "level_name[Level1] = \"Base\";\n"
144 "level_name[Level2] = \"Shift\";\n"
145 "level_name[Level3] = \"Alt Base\";\n"
146 "level_name[Level4] = \"Shift Alt\";\n"
148 "type \"FOUR_LEVEL_ALPHABETIC\" {\n"
149 "modifiers= Shift+Lock+LevelThree;\n"
150 "map[Shift]= Level2;\n"
151 "map[Lock]= Level2;\n"
152 "map[LevelThree]= Level3;\n"
153 "map[Shift+LevelThree]= Level4;\n"
154 "map[Lock+LevelThree]= Level4;\n"
155 "map[Shift+Lock+LevelThree]= Level3;\n"
156 "level_name[Level1] = \"Base\";\n"
157 "level_name[Level2] = \"Shift\";\n"
158 "level_name[Level3] = \"Alt Base\";\n"
159 "level_name[Level4] = \"Shift Alt\";\n"
161 "type \"FOUR_LEVEL_SEMIALPHABETIC\" {\n"
162 "modifiers= Shift+Lock+LevelThree;\n"
163 "map[Shift]= Level2;\n"
164 "map[Lock]= Level2;\n"
165 "map[LevelThree]= Level3;\n"
166 "map[Shift+LevelThree]= Level4;\n"
167 "map[Lock+LevelThree]= Level3;\n"
168 "preserve[Lock+LevelThree]= Lock;\n"
169 "map[Shift+Lock+LevelThree]= Level4;\n"
170 "preserve[Shift+Lock+LevelThree]= Lock;\n"
171 "level_name[Level1] = \"Base\";\n"
172 "level_name[Level2] = \"Shift\";\n"
173 "level_name[Level3] = \"Alt Base\";\n"
174 "level_name[Level4] = \"Shift Alt\";\n"
176 "type \"FOUR_LEVEL_KEYPAD\" {\n"
177 "modifiers= Shift+NumLock+LevelThree;\n"
178 "map[Shift]= Level2;\n"
179 "map[NumLock]= Level2;\n"
180 "map[LevelThree]= Level3;\n"
181 "map[Shift+LevelThree]= Level4;\n"
182 "map[NumLock+LevelThree]= Level4;\n"
183 "map[Shift+NumLock+LevelThree]= Level3;\n"
184 "level_name[Level1] = \"Base\";\n"
185 "level_name[Level2] = \"Number\";\n"
186 "level_name[Level3] = \"Alt Base\";\n"
187 "level_name[Level4] = \"Alt Number\";\n"
193 QList<xcb_keysym_t> xkeymap;
194 int keysymsPerKeycode = 0;
196 int keycodeCount = maxKeycode - minKeycode + 1;
197 if (
auto keymapReply =
Q_XCB_REPLY(xcb_get_keyboard_mapping, xcb_connection(),
198 minKeycode, keycodeCount)) {
199 keysymsPerKeycode = keymapReply->keysyms_per_keycode;
200 int numSyms = keycodeCount * keysymsPerKeycode;
201 auto keymapPtr = xcb_get_keyboard_mapping_keysyms(keymapReply.get());
202 xkeymap.resize(numSyms);
203 for (
int i = 0; i < numSyms; i++)
204 xkeymap[i] = keymapPtr[i];
207 if (xkeymap.isEmpty())
210 static const char *
const builtinModifiers[] =
211 {
"Shift",
"Lock",
"Control",
"Mod1",
"Mod2",
"Mod3",
"Mod4",
"Mod5" };
214
215
216
217
218 bool mapGroup2ToLevel3 = keysymsPerKeycode < 5;
220 keymap +=
"xkb_symbols \"core\" {\n";
221 for (
int code = minKeycode; code <= maxKeycode; code++) {
222 auto codeMap = xkeymap.constData() + (code - minKeycode) * keysymsPerKeycode;
224 const int maxGroup1 = 4;
225 const int maxGroup2 = 2;
226 xcb_keysym_t symbolsGroup1[maxGroup1];
227 xcb_keysym_t symbolsGroup2[maxGroup2] = { XKB_KEY_NoSymbol, XKB_KEY_NoSymbol };
228 for (
int i = 0; i < maxGroup1 + maxGroup2; i++) {
229 xcb_keysym_t sym = i < keysymsPerKeycode ? codeMap[i] : XKB_KEY_NoSymbol;
230 if (mapGroup2ToLevel3) {
233 symbolsGroup1[i] = sym;
237 symbolsGroup1[i] = sym;
239 symbolsGroup2[i - 2] = sym;
241 symbolsGroup1[i - 2] = sym;
246
248 symbolsGroup1[1] = symbolsGroup1[0];
249 symbolsGroup1[0] = lowered;
252 symbolsGroup2[1] = symbolsGroup2[0];
253 symbolsGroup2[0] = lowered;
256 QByteArray groupStr1 = symbolsGroupString(symbolsGroup1, maxGroup1);
257 if (groupStr1.isEmpty())
260 keymap +=
"key <K" + QByteArray::number(code) +
"> { ";
261 keymap +=
"symbols[Group1] = [ " + groupStr1 +
" ]";
262 QByteArray groupStr2 = symbolsGroupString(symbolsGroup2, maxGroup2);
263 if (!groupStr2.isEmpty())
264 keymap +=
", symbols[Group2] = [ " + groupStr2 +
" ]";
267 xcb_keysym_t modifierSym = XKB_KEY_NoSymbol;
268 for (
int symIndex = 0; symIndex < keysymsPerKeycode; symIndex++) {
269 xcb_keysym_t sym = codeMap[symIndex];
271 if (sym == XKB_KEY_Alt_L
272 || sym == XKB_KEY_Meta_L
273 || sym == XKB_KEY_Mode_switch
274 || sym == XKB_KEY_Super_L
275 || sym == XKB_KEY_Super_R
276 || sym == XKB_KEY_Hyper_L
277 || sym == XKB_KEY_Hyper_R) {
284 if (modifierSym == XKB_KEY_Mode_switch)
285 keymap +=
", virtualMods=LevelThree";
289 int modNum = keysymMods.value(modifierSym, -1);
292 keymap += QByteArray(
"modifier_map ") + builtinModifiers[modNum]
293 +
" { <K" + QByteArray::number(code) +
"> };\n";
302 "xkb_compatibility \"core\" {\n"
303 "virtual_modifiers NumLock,Alt,LevelThree;\n"
304 "interpret Alt_L+AnyOf(all) {\n"
305 "virtualModifier= Alt;\n"
306 "action= SetMods(modifiers=modMapMods,clearLocks);\n"
308 "interpret Alt_R+AnyOf(all) {\n"
309 "virtualModifier= Alt;\n"
310 "action= SetMods(modifiers=modMapMods,clearLocks);\n"
315
319 return xkb_keymap_new_from_buffer(m_xkbContext.get(),
322 XKB_KEYMAP_FORMAT_TEXT_V1,
323 XKB_KEYMAP_COMPILE_NO_FLAGS);
335void QXcbKeyboard::updateKeymap()
337 KeysymModifierMap keysymMods;
339 keysymMods = keysymsToModifiers();
340 updateModifiers(keysymMods);
345 m_xkbContext.reset(xkb_context_new(XKB_CONTEXT_NO_DEFAULT_INCLUDES));
347 qCWarning(lcQpaKeyboard,
"failed to create XKB context");
351 xkb_log_level logLevel = lcQpaKeyboard().isDebugEnabled() ?
352 XKB_LOG_LEVEL_DEBUG : XKB_LOG_LEVEL_CRITICAL;
353 xkb_context_set_log_level(m_xkbContext.get(), logLevel);
357 m_xkbKeymap.reset(xkb_x11_keymap_new_from_device(m_xkbContext.get(), xcb_connection(),
358 core_device_id, XKB_KEYMAP_COMPILE_NO_FLAGS));
360 m_xkbState.reset(xkb_x11_state_new_from_device(m_xkbKeymap.get(), xcb_connection(), core_device_id));
362 m_xkbKeymap.reset(keymapFromCore(keysymMods));
364 m_xkbState.reset(xkb_state_new(m_xkbKeymap.get()));
368 qCWarning(lcQpaKeyboard,
"failed to compile a keymap");
373 qCWarning(lcQpaKeyboard,
"failed to create XKB state");
380 QXkbCommon::verifyHasLatinLayout(m_xkbKeymap.get());
418void QXcbKeyboard::updateXKBStateFromCore(quint16 state)
421 struct xkb_state *xkbState = m_xkbState.get();
422 xkb_mod_mask_t modsDepressed = xkb_state_serialize_mods(xkbState, XKB_STATE_MODS_DEPRESSED);
423 xkb_mod_mask_t modsLatched = xkb_state_serialize_mods(xkbState, XKB_STATE_MODS_LATCHED);
424 xkb_mod_mask_t modsLocked = xkb_state_serialize_mods(xkbState, XKB_STATE_MODS_LOCKED);
425 xkb_mod_mask_t xkbMask = xkbModMask(state);
427 xkb_mod_mask_t latched = modsLatched & xkbMask;
428 xkb_mod_mask_t locked = modsLocked & xkbMask;
429 xkb_mod_mask_t depressed = modsDepressed & xkbMask;
431 depressed |= ~(depressed | latched | locked) & xkbMask;
433 xkb_state_component changedComponents = xkb_state_update_mask(
434 xkbState, depressed, latched, locked, 0, 0, lockedGroup(state));
436 handleStateChanges(changedComponents);
467xkb_mod_mask_t QXcbKeyboard::xkbModMask(quint16 state)
469 xkb_mod_mask_t xkb_mask = 0;
471 if ((state & XCB_MOD_MASK_SHIFT) && xkb_mods.shift != XKB_MOD_INVALID)
472 xkb_mask |= (1 << xkb_mods.shift);
473 if ((state & XCB_MOD_MASK_LOCK) && xkb_mods.lock != XKB_MOD_INVALID)
474 xkb_mask |= (1 << xkb_mods.lock);
475 if ((state & XCB_MOD_MASK_CONTROL) && xkb_mods.control != XKB_MOD_INVALID)
476 xkb_mask |= (1 << xkb_mods.control);
477 if ((state & XCB_MOD_MASK_1) && xkb_mods.mod1 != XKB_MOD_INVALID)
478 xkb_mask |= (1 << xkb_mods.mod1);
479 if ((state & XCB_MOD_MASK_2) && xkb_mods.mod2 != XKB_MOD_INVALID)
480 xkb_mask |= (1 << xkb_mods.mod2);
481 if ((state & XCB_MOD_MASK_3) && xkb_mods.mod3 != XKB_MOD_INVALID)
482 xkb_mask |= (1 << xkb_mods.mod3);
483 if ((state & XCB_MOD_MASK_4) && xkb_mods.mod4 != XKB_MOD_INVALID)
484 xkb_mask |= (1 << xkb_mods.mod4);
485 if ((state & XCB_MOD_MASK_5) && xkb_mods.mod5 != XKB_MOD_INVALID)
486 xkb_mask |= (1 << xkb_mods.mod5);
491void QXcbKeyboard::updateXKBMods()
494 xkb_mods.lock = xkb_keymap_mod_get_index(m_xkbKeymap.get(), XKB_MOD_NAME_CAPS);
495 xkb_mods.control = xkb_keymap_mod_get_index(m_xkbKeymap.get(),
XKB_MOD_NAME_CTRL);
496 xkb_mods.mod1 = xkb_keymap_mod_get_index(m_xkbKeymap.get(),
"Mod1");
497 xkb_mods.mod2 = xkb_keymap_mod_get_index(m_xkbKeymap.get(),
"Mod2");
498 xkb_mods.mod3 = xkb_keymap_mod_get_index(m_xkbKeymap.get(),
"Mod3");
499 xkb_mods.mod4 = xkb_keymap_mod_get_index(m_xkbKeymap.get(),
"Mod4");
500 xkb_mods.mod5 = xkb_keymap_mod_get_index(m_xkbKeymap.get(),
"Mod5");
533void QXcbKeyboard::selectEvents()
535 const uint16_t required_map_parts = (XCB_XKB_MAP_PART_KEY_TYPES |
536 XCB_XKB_MAP_PART_KEY_SYMS |
537 XCB_XKB_MAP_PART_MODIFIER_MAP |
538 XCB_XKB_MAP_PART_EXPLICIT_COMPONENTS |
539 XCB_XKB_MAP_PART_KEY_ACTIONS |
540 XCB_XKB_MAP_PART_KEY_BEHAVIORS |
541 XCB_XKB_MAP_PART_VIRTUAL_MODS |
542 XCB_XKB_MAP_PART_VIRTUAL_MOD_MAP);
544 const uint16_t required_events = (XCB_XKB_EVENT_TYPE_NEW_KEYBOARD_NOTIFY |
545 XCB_XKB_EVENT_TYPE_MAP_NOTIFY |
546 XCB_XKB_EVENT_TYPE_STATE_NOTIFY);
550 xcb_void_cookie_t select = xcb_xkb_select_events_checked(
552 XCB_XKB_ID_USE_CORE_KBD,
560 xcb_generic_error_t *error = xcb_request_check(
xcb_connection(), select);
563 qCWarning(lcQpaXcb,
"failed to select notify events from XKB");
567void QXcbKeyboard::updateVModMapping()
569 xcb_xkb_get_names_value_list_t names_list;
571 memset(&vmod_masks, 0,
sizeof(vmod_masks));
574 XCB_XKB_ID_USE_CORE_KBD,
575 XCB_XKB_NAME_DETAIL_VIRTUAL_MOD_NAMES);
577 qWarning(
"Qt: failed to retrieve the virtual modifier names from XKB");
581 const void *buffer = xcb_xkb_get_names_value_list(name_reply.get());
582 xcb_xkb_get_names_value_list_unpack(buffer,
584 name_reply->indicators,
585 name_reply->virtualMods,
586 name_reply->groupNames,
588 name_reply->nKeyAliases,
589 name_reply->nRadioGroups,
596 vmod_mask = name_reply->virtualMods;
598 for (bit = 1; vmod_mask; bit <<= 1) {
601 if (!(vmod_mask & bit))
607 QByteArray atomName =
connection()->atomName(names_list.virtualModNames[count]);
608 vmod_name = atomName.data();
615 if (qstrcmp(vmod_name,
"Alt") == 0)
616 vmod_masks.alt = bit;
617 else if (qstrcmp(vmod_name,
"Meta") == 0)
618 vmod_masks.meta = bit;
619 else if (qstrcmp(vmod_name,
"AltGr") == 0)
620 vmod_masks.altgr = bit;
621 else if (qstrcmp(vmod_name,
"Super") == 0)
622 vmod_masks.super = bit;
623 else if (qstrcmp(vmod_name,
"Hyper") == 0)
624 vmod_masks.hyper = bit;
628void QXcbKeyboard::updateVModToRModMapping()
630 xcb_xkb_get_map_map_t map;
632 memset(&rmod_masks, 0,
sizeof(rmod_masks));
636 XCB_XKB_ID_USE_CORE_KBD,
637 XCB_XKB_MAP_PART_VIRTUAL_MODS,
638 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
640 qWarning(
"Qt: failed to retrieve the virtual modifier map from XKB");
644 const void *buffer = xcb_xkb_get_map_map(map_reply.get());
645 xcb_xkb_get_map_map_unpack(buffer,
648 map_reply->nKeyActions,
649 map_reply->totalActions,
650 map_reply->totalKeyBehaviors,
651 map_reply->nVModMapKeys,
652 map_reply->totalKeyExplicit,
653 map_reply->totalModMapKeys,
654 map_reply->totalVModMapKeys,
661 vmod_mask = map_reply->virtualMods;
664 for (bit = 1; vmod_mask; bit <<= 1) {
667 if (!(vmod_mask & bit))
672 modmap = map.vmods_rtrn[count];
675 if (vmod_masks.alt == bit)
676 rmod_masks.alt = modmap;
677 else if (vmod_masks.meta == bit)
678 rmod_masks.meta = modmap;
679 else if (vmod_masks.altgr == bit)
680 rmod_masks.altgr = modmap;
681 else if (vmod_masks.super == bit)
682 rmod_masks.super = modmap;
683 else if (vmod_masks.hyper == bit)
684 rmod_masks.hyper = modmap;
695void QXcbKeyboard::updateModifiers(
const KeysymModifierMap &keysymMods)
699 updateVModToRModMapping();
701 memset(&rmod_masks, 0,
sizeof(rmod_masks));
703 applyModifier(&rmod_masks.alt, keysymMods.value(XKB_KEY_Alt_L, -1));
704 applyModifier(&rmod_masks.alt, keysymMods.value(XKB_KEY_Alt_R, -1));
705 applyModifier(&rmod_masks.meta, keysymMods.value(XKB_KEY_Meta_L, -1));
706 applyModifier(&rmod_masks.meta, keysymMods.value(XKB_KEY_Meta_R, -1));
707 applyModifier(&rmod_masks.altgr, keysymMods.value(XKB_KEY_Mode_switch, -1));
708 applyModifier(&rmod_masks.super, keysymMods.value(XKB_KEY_Super_L, -1));
709 applyModifier(&rmod_masks.super, keysymMods.value(XKB_KEY_Super_R, -1));
710 applyModifier(&rmod_masks.hyper, keysymMods.value(XKB_KEY_Hyper_L, -1));
711 applyModifier(&rmod_masks.hyper, keysymMods.value(XKB_KEY_Hyper_R, -1));
714 resolveMaskConflicts();
727QXcbKeyboard::KeysymModifierMap QXcbKeyboard::keysymsToModifiers()
735 KeysymModifierMap map;
739 qWarning(
"Qt: failed to get modifier mapping");
744 static const xcb_keysym_t symbols[] = {
745 XKB_KEY_Alt_L, XKB_KEY_Meta_L, XKB_KEY_Mode_switch, XKB_KEY_Super_L, XKB_KEY_Super_R,
746 XKB_KEY_Hyper_L, XKB_KEY_Hyper_R
748 static const size_t numSymbols =
sizeof symbols /
sizeof *symbols;
751 xcb_keycode_t* modKeyCodes[numSymbols];
752 for (size_t i = 0; i < numSymbols; ++i)
753 modKeyCodes[i] = xcb_key_symbols_get_keycode(m_key_symbols, symbols[i]);
755 xcb_keycode_t *modMap = xcb_get_modifier_mapping_keycodes(modMapReply.get());
756 const int modMapLength = xcb_get_modifier_mapping_keycodes_length(modMapReply.get());
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
785
786
787
788
789
790
791 for (
int i = 0; i < modMapLength; i++) {
792 if (modMap[i] == XCB_NO_SYMBOL)
795 for (size_t k = 0; k < numSymbols; k++) {
796 if (modKeyCodes[k] && keycodes_contains(modKeyCodes[k], modMap[i])) {
798 xcb_keysym_t sym = symbols[k];
800
801
802 map[sym] = i / modMapReply->keycodes_per_modifier;
808 for (size_t i = 0; i < numSymbols; ++i)
809 free(modKeyCodes[i]);
838void QXcbKeyboard::handleKeyEvent(xcb_window_t sourceWindow, QEvent::Type type, xcb_keycode_t code,
839 quint16 state, xcb_timestamp_t time,
bool fromSendEvent)
844 QXcbWindow *source =
connection()->platformWindowFromId(sourceWindow);
846 if (!targetWindow || !source)
848 if (type == QEvent::KeyPress)
849 targetWindow->updateNetWmUserTime(time);
851 QXkbCommon::ScopedXKBState sendEventState;
857 sendEventState.reset(xkb_state_new(m_xkbKeymap.get()));
861 xkb_mod_mask_t depressed = xkbModMask(state);
862 xkb_state_update_mask(sendEventState.get(), depressed, 0, 0, 0, 0, lockedGroup(state));
865 struct xkb_state *xkbState = fromSendEvent ? sendEventState.get() : m_xkbState.get();
867 xcb_keysym_t sym = xkb_state_key_get_one_sym(xkbState, code);
868 QString text = QXkbCommon::lookupString(xkbState, code);
870 Qt::KeyboardModifiers modifiers = translateModifiers(state);
871 if (QXkbCommon::isKeypad(sym))
872 modifiers |= Qt::KeypadModifier;
874 int qtcode = QXkbCommon::keysymToQtKey(sym, modifiers, xkbState, code, m_superAsMeta, m_hyperAsMeta);
876 if (type == QEvent::KeyPress) {
877 if (m_isAutoRepeat && m_autoRepeatCode != code)
879 m_isAutoRepeat =
false;
881 m_isAutoRepeat =
false;
884 [
this, time, code](xcb_generic_event_t *event,
int type) {
885 if (type == XCB_KEY_PRESS) {
886 auto keyPress =
reinterpret_cast<xcb_key_press_event_t *>(event);
887 m_isAutoRepeat = keyPress->time == time && keyPress->detail == code;
889 m_autoRepeatCode = code;
895 bool filtered =
false;
896 if (
auto inputContext = QGuiApplicationPrivate::platformIntegration()->inputContext()) {
897 QKeyEvent event(type, qtcode, modifiers, code, sym, state, text, m_isAutoRepeat, text.size());
898 event.setTimestamp(time);
899 filtered = inputContext->filterEvent(&event);
903 QWindow *window = targetWindow->window();
904#ifndef QT_NO_CONTEXTMENU
905 if (type == QEvent::KeyPress && qtcode == Qt::Key_Menu) {
906 const QPoint globalPos = window->screen()->handle()->cursor()->pos();
907 const QPoint pos = window->mapFromGlobal(globalPos);
908 QWindowSystemInterface::handleContextMenuEvent(window,
false, pos, globalPos, modifiers);
911 QWindowSystemInterface::handleExtendedKeyEvent(window, time, type, qtcode, modifiers,
912 code, sym, state, text, m_isAutoRepeat);