diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp index 28de86b8ba..e0fcc01fb4 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp +++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp @@ -742,8 +742,7 @@ void QXcbKeyboard::updateKeymap() // update xkb state object xkb_state_unref(xkb_state); xkb_state = new_state; - if (!connection()->hasXKB()) - updateXKBMods(); + updateXKBMods(); checkForLatinLayout(); } @@ -768,32 +767,37 @@ void QXcbKeyboard::updateXKBState(xcb_xkb_state_notify_event_t *state) } #endif +void QXcbKeyboard::updateXKBStateFromState(struct xkb_state *kb_state, quint16 state) +{ + const quint32 modsDepressed = xkb_state_serialize_mods(kb_state, XKB_STATE_MODS_DEPRESSED); + const quint32 modsLatched = xkb_state_serialize_mods(kb_state, XKB_STATE_MODS_LATCHED); + const quint32 modsLocked = xkb_state_serialize_mods(kb_state, XKB_STATE_MODS_LOCKED); + const quint32 xkbMask = xkbModMask(state); + + const quint32 latched = modsLatched & xkbMask; + const quint32 locked = modsLocked & xkbMask; + quint32 depressed = modsDepressed & xkbMask; + // set modifiers in depressed if they don't appear in any of the final masks + depressed |= ~(depressed | latched | locked) & xkbMask; + + const xkb_state_component newState + = xkb_state_update_mask(kb_state, + depressed, + latched, + locked, + 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)"); + } +} + void QXcbKeyboard::updateXKBStateFromCore(quint16 state) { if (m_config && !connection()->hasXKB()) { - const quint32 modsDepressed = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_DEPRESSED); - const quint32 modsLatched = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LATCHED); - const quint32 modsLocked = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LOCKED); - const quint32 xkbMask = xkbModMask(state); - - const quint32 latched = modsLatched & xkbMask; - const quint32 locked = modsLocked & xkbMask; - quint32 depressed = modsDepressed & xkbMask; - // set modifiers in depressed if they don't appear in any of the final masks - depressed |= ~(depressed | latched | locked) & xkbMask; - - const xkb_state_component newState - = xkb_state_update_mask(xkb_state, - depressed, - latched, - locked, - 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)"); - } + updateXKBStateFromState(xkb_state, state); } } @@ -1455,7 +1459,16 @@ void QXcbKeyboard::handleKeyEvent(xcb_window_t sourceWindow, QEvent::Type type, if (type == QEvent::KeyPress) targetWindow->updateNetWmUserTime(time); - xcb_keysym_t sym = xkb_state_key_get_one_sym(xkb_state, code); + // Have a temporary keyboard state filled in from state + // this way we allow for synthetic events to have different state + // from the current state i.e. you can have Alt+Ctrl pressed + // and receive a synthetic key event that has neither Alt nor Ctrl pressed + struct xkb_state *kb_state = xkb_state_new(xkb_keymap); + if (!kb_state) + return; + updateXKBStateFromState(kb_state, state); + + xcb_keysym_t sym = xkb_state_key_get_one_sym(kb_state, code); QPlatformInputContext *inputContext = QGuiApplicationPrivate::platformIntegration()->inputContext(); QMetaMethod method; @@ -1474,11 +1487,13 @@ void QXcbKeyboard::handleKeyEvent(xcb_window_t sourceWindow, QEvent::Type type, Q_ARG(uint, code), Q_ARG(uint, state), Q_ARG(bool, type == QEvent::KeyPress)); - if (retval) + if (retval) { + xkb_state_unref(kb_state); return; + } } - QString string = lookupString(xkb_state, code); + QString string = lookupString(kb_state, code); // Ιf control modifier is set we should prefer latin character, this is // used for standard shortcuts in checks like "key == QKeySequence::Copy", @@ -1547,6 +1562,7 @@ void QXcbKeyboard::handleKeyEvent(xcb_window_t sourceWindow, QEvent::Type type, QWindowSystemInterface::handleExtendedKeyEvent(window, time, QEvent::KeyPress, qtcode, modifiers, code, sym, state, string, isAutoRepeat); } + xkb_state_unref(kb_state); } QString QXcbKeyboard::lookupString(struct xkb_state *state, xcb_keycode_t code) const diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.h b/src/plugins/platforms/xcb/qxcbkeyboard.h index 457a27affb..dc27511b56 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.h +++ b/src/plugins/platforms/xcb/qxcbkeyboard.h @@ -98,6 +98,8 @@ protected: void checkForLatinLayout(); private: + void updateXKBStateFromState(struct xkb_state *kb_state, quint16 state); + bool m_config; xcb_keycode_t m_autorepeat_code;