summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/xcb/qxcbkeyboard.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/xcb/qxcbkeyboard.cpp')
-rw-r--r--src/plugins/platforms/xcb/qxcbkeyboard.cpp172
1 files changed, 160 insertions, 12 deletions
diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
index e7dabd3351..f1b26853a1 100644
--- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp
+++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
@@ -673,8 +673,9 @@ void QXcbKeyboard::updateKeymap()
xkb_state_unref(xkb_state);
xkb_state = new_state;
} else {
- // get initial state from the X server (and keep it up-to-date at all times)
xkb_state = new_state;
+#ifndef QT_NO_XKB
+ // get initial state from the X server (and keep it up-to-date at all times)
xcb_xkb_get_state_cookie_t state;
xcb_xkb_get_state_reply_t *init_state;
@@ -695,9 +696,13 @@ void QXcbKeyboard::updateKeymap()
init_state->latchedGroup,
init_state->lockedGroup);
free(init_state);
+#else
+ updateXKBMods();
+#endif
}
}
+#ifndef QT_NO_XKB
void QXcbKeyboard::updateXKBState(xcb_xkb_state_notify_event_t *state)
{
if (!m_config)
@@ -715,11 +720,74 @@ void QXcbKeyboard::updateXKBState(xcb_xkb_state_notify_event_t *state)
state->lockedGroup);
if ((newState & XKB_STATE_LAYOUT_EFFECTIVE) == XKB_STATE_LAYOUT_EFFECTIVE) {
- qWarning("TODO: Support KeyboardLayoutChange on QPA (QTBUG-27681)");
+ //qWarning("TODO: Support KeyboardLayoutChange on QPA (QTBUG-27681)");
}
}
}
+#else
+void QXcbKeyboard::updateXKBStateFromCore(quint16 state)
+{
+ if (!m_config)
+ return;
+
+ quint32 modsDepressed, modsLatched, modsLocked;
+ modsDepressed = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_DEPRESSED);
+ modsLatched = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LATCHED);
+ modsLocked = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LOCKED);
+
+ quint32 xkbMask = xkbModMask(state);
+ xkb_state_component newState;
+ newState = xkb_state_update_mask(xkb_state,
+ modsDepressed & xkbMask,
+ modsLatched & xkbMask,
+ modsLocked & xkbMask,
+ 0,
+ 0,
+ (state >> 13) & 3); // bits 13 and 14 report the state keyboard group
+
+ if ((newState & XKB_STATE_LAYOUT_EFFECTIVE) == XKB_STATE_LAYOUT_EFFECTIVE) {
+ //qWarning("TODO: Support KeyboardLayoutChange on QPA (QTBUG-27681)");
+ }
+}
+
+quint32 QXcbKeyboard::xkbModMask(quint16 state)
+{
+ quint32 xkb_mask = 0;
+
+ if ((state & XCB_MOD_MASK_SHIFT) && xkb_mods.shift != XKB_MOD_INVALID)
+ xkb_mask |= (1 << xkb_mods.shift);
+ if ((state & XCB_MOD_MASK_LOCK) && xkb_mods.lock != XKB_MOD_INVALID)
+ xkb_mask |= (1 << xkb_mods.lock);
+ if ((state & XCB_MOD_MASK_CONTROL) && xkb_mods.control != XKB_MOD_INVALID)
+ xkb_mask |= (1 << xkb_mods.control);
+ if ((state & XCB_MOD_MASK_1) && xkb_mods.mod1 != XKB_MOD_INVALID)
+ xkb_mask |= (1 << xkb_mods.mod1);
+ if ((state & XCB_MOD_MASK_2) && xkb_mods.mod2 != XKB_MOD_INVALID)
+ xkb_mask |= (1 << xkb_mods.mod2);
+ if ((state & XCB_MOD_MASK_3) && xkb_mods.mod3 != XKB_MOD_INVALID)
+ xkb_mask |= (1 << xkb_mods.mod3);
+ if ((state & XCB_MOD_MASK_4) && xkb_mods.mod4 != XKB_MOD_INVALID)
+ xkb_mask |= (1 << xkb_mods.mod4);
+ if ((state & XCB_MOD_MASK_5) && xkb_mods.mod5 != XKB_MOD_INVALID)
+ xkb_mask |= (1 << xkb_mods.mod5);
+
+ return xkb_mask;
+}
+
+void QXcbKeyboard::updateXKBMods()
+{
+ xkb_mods.shift = xkb_map_mod_get_index(xkb_keymap, XKB_MOD_NAME_SHIFT);
+ xkb_mods.lock = xkb_map_mod_get_index(xkb_keymap, XKB_MOD_NAME_CAPS);
+ xkb_mods.control = xkb_map_mod_get_index(xkb_keymap, XKB_MOD_NAME_CTRL);
+ xkb_mods.mod1 = xkb_map_mod_get_index(xkb_keymap, "Mod1");
+ xkb_mods.mod2 = xkb_map_mod_get_index(xkb_keymap, "Mod2");
+ xkb_mods.mod3 = xkb_map_mod_get_index(xkb_keymap, "Mod3");
+ xkb_mods.mod4 = xkb_map_mod_get_index(xkb_keymap, "Mod4");
+ xkb_mods.mod5 = xkb_map_mod_get_index(xkb_keymap, "Mod5");
+}
+#endif
+
QList<int> QXcbKeyboard::possibleKeys(const QKeyEvent *event) const
{
// turn off the modifier bits which doesn't participate in shortcuts
@@ -846,11 +914,14 @@ QXcbKeyboard::QXcbKeyboard(QXcbConnection *connection)
, xkb_context(0)
, xkb_keymap(0)
, xkb_state(0)
+#ifndef QT_NO_XKB
, core_device_id(0)
+#endif
{
+ updateKeymap();
+#ifndef QT_NO_XKB
if (connection->hasXKB()) {
- updateKeymap();
updateVModMapping();
updateVModToRModMapping();
@@ -871,6 +942,10 @@ QXcbKeyboard::QXcbKeyboard(QXcbConnection *connection)
core_device_id = device_id->deviceID;
free(device_id);
}
+#else
+ m_key_symbols = xcb_key_symbols_alloc(xcb_connection());
+ updateModifiers();
+#endif
}
QXcbKeyboard::~QXcbKeyboard()
@@ -881,8 +956,12 @@ QXcbKeyboard::~QXcbKeyboard()
xkb_keymap_unref(xkb_keymap);
if (xkb_context)
xkb_context_unref(xkb_context);
+#ifdef QT_NO_XKB
+ xcb_key_symbols_free(m_key_symbols);
+#endif
}
+#ifndef QT_NO_XKB
void QXcbKeyboard::updateVModMapping()
{
xcb_xkb_get_names_cookie_t names_cookie;
@@ -1004,14 +1083,67 @@ void QXcbKeyboard::updateVModToRModMapping()
rmod_masks.altgr = modmap;
}
-#if 0
- qDebug() << "alt: " << rmod_masks.alt;
- qDebug() << "meta: " << rmod_masks.meta;
- qDebug() << "altgr: " << rmod_masks.altgr;
-#endif
-
free(map_reply);
}
+#else
+void QXcbKeyboard::updateModifiers()
+{
+ // The core protocol does not provide a convenient way to determine the mapping
+ // of modifier bits. Clients must retrieve and search the modifier map to determine
+ // the keycodes bound to each modifier, and then retrieve and search the keyboard
+ // mapping to determine the keysyms bound to the keycodes. They must repeat this
+ // process for all modifiers whenever any part of the modifier mapping is changed.
+ memset(&rmod_masks, 0, sizeof(rmod_masks));
+
+ xcb_generic_error_t *error = 0;
+ xcb_connection_t *conn = xcb_connection();
+ xcb_get_modifier_mapping_cookie_t modMapCookie = xcb_get_modifier_mapping(conn);
+ xcb_get_modifier_mapping_reply_t *modMapReply =
+ xcb_get_modifier_mapping_reply(conn, modMapCookie, &error);
+ if (error) {
+ qWarning("Qt: failed to get modifier mapping");
+ free(error);
+ return;
+ }
+
+ // for Alt and Meta L and R are the same
+ static const xcb_keysym_t symbols[] = {
+ XK_Alt_L, XK_Meta_L, XK_Mode_switch
+ };
+ static const size_t numSymbols = sizeof symbols / sizeof *symbols;
+
+ // Figure out the modifier mapping, ICCCM 6.6
+ xcb_keycode_t* modKeyCodes[numSymbols];
+ for (size_t i = 0; i < numSymbols; ++i)
+ modKeyCodes[i] = xcb_key_symbols_get_keycode(m_key_symbols, symbols[i]);
+
+ xcb_keycode_t *modMap = xcb_get_modifier_mapping_keycodes(modMapReply);
+ const int w = modMapReply->keycodes_per_modifier;
+ for (size_t i = 0; i < numSymbols; ++i) {
+ for (int bit = 0; bit < 8; ++bit) {
+ uint mask = 1 << bit;
+ for (int x = 0; x < w; ++x) {
+ xcb_keycode_t keyCode = modMap[x + bit * w];
+ xcb_keycode_t *itk = modKeyCodes[i];
+ while (itk && *itk != XCB_NO_SYMBOL)
+ if (*itk++ == keyCode) {
+ uint sym = symbols[i];
+ if ((sym == XK_Alt_L || sym == XK_Alt_R))
+ rmod_masks.alt = mask;
+ if ((sym == XK_Meta_L || sym == XK_Meta_R))
+ rmod_masks.meta = mask;
+ if (sym == XK_Mode_switch)
+ rmod_masks.altgr = mask;
+ }
+ }
+ }
+ }
+
+ for (size_t i = 0; i < numSymbols; ++i)
+ free(modKeyCodes[i]);
+ free(modMapReply);
+}
+#endif
class KeyChecker
{
@@ -1076,8 +1208,17 @@ void QXcbKeyboard::handleKeyEvent(QWindow *window, QEvent::Type type, xcb_keycod
if (!m_config)
return;
-
+ // It is crucial the order of xkb_state_key_get_one_sym &
+ // xkb_state_update_key operations is not reversed!
xcb_keysym_t sym = xkb_state_key_get_one_sym(xkb_state, code);
+#ifdef QT_NO_XKB
+ enum xkb_key_direction direction;
+ if (type == QEvent::KeyPress)
+ direction = XKB_KEY_DOWN;
+ else
+ direction = XKB_KEY_UP;
+ xkb_state_update_key(xkb_state, code, direction);
+#endif
QPlatformInputContext *inputContext = QGuiApplicationPrivate::platformIntegration()->inputContext();
QMetaMethod method;
@@ -1194,13 +1335,20 @@ void QXcbKeyboard::handleKeyReleaseEvent(QXcbWindowEventListener *eventListener,
handleKeyEvent(window->window(), QEvent::KeyRelease, event->detail, event->state, event->time);
}
-void QXcbKeyboard::handleMappingNotifyEvent(const xcb_xkb_map_notify_event_t *)
+void QXcbKeyboard::handleMappingNotifyEvent(const void *event)
{
+ updateKeymap();
+#ifdef QT_NO_XKB
+ void *ev = const_cast<void *>(event);
+ xcb_refresh_keyboard_mapping(m_key_symbols, static_cast<xcb_mapping_notify_event_t *>(ev));
+ updateModifiers();
+#else
+ Q_UNUSED(event)
if (connection()->hasXKB()) {
- updateKeymap();
updateVModMapping();
updateVModToRModMapping();
}
+#endif
}
QT_END_NAMESPACE