diff options
author | Gatis Paeglis <gatis.paeglis@qt.io> | 2018-02-01 16:04:43 +0100 |
---|---|---|
committer | Gatis Paeglis <gatis.paeglis@qt.io> | 2018-02-25 09:49:58 +0000 |
commit | 7c01c759aef565162e4d5f04527a8946857c56ff (patch) | |
tree | ff99ef9916d0df90bf0bc1e5ace39df74c06627f /src/plugins/platforms/xcb/qxcbkeyboard.cpp | |
parent | 1219fc26a041164dd4cb362b25f3d097501c9371 (diff) |
xcb: have a proper detection of key events originating from SendEvent
This is a more correct fix for QTBUG-48795. The original fix
was unnecessarily using non-XKB code path for updating state
for all incoming key events. This would result in losing some
valuable bits from xkb state.
Task-number: QTBUG-48795
Change-Id: Ic4fb28b2d834272f1db2cbf5888cafb209707847
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'src/plugins/platforms/xcb/qxcbkeyboard.cpp')
-rw-r--r-- | src/plugins/platforms/xcb/qxcbkeyboard.cpp | 98 |
1 files changed, 55 insertions, 43 deletions
diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp index 8781969521..7428e419db 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp +++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp @@ -786,37 +786,32 @@ void QXcbKeyboard::updateXKBState(xcb_xkb_state_notify_event_t *state) } #endif -void QXcbKeyboard::updateXKBStateFromState(struct xkb_state *kb_state, quint16 state) +static xkb_layout_index_t lockedGroup(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)"); - } + return (state >> 13) & 3; // bits 13 and 14 report the state keyboard group } void QXcbKeyboard::updateXKBStateFromCore(quint16 state) { if (m_config && !connection()->hasXKB()) { - updateXKBStateFromState(m_xkbState.get(), state); + struct xkb_state *xkbState = m_xkbState.get(); + xkb_mod_mask_t modsDepressed = xkb_state_serialize_mods(xkbState, XKB_STATE_MODS_DEPRESSED); + xkb_mod_mask_t modsLatched = xkb_state_serialize_mods(xkbState, XKB_STATE_MODS_LATCHED); + xkb_mod_mask_t modsLocked = xkb_state_serialize_mods(xkbState, XKB_STATE_MODS_LOCKED); + xkb_mod_mask_t xkbMask = xkbModMask(state); + + xkb_mod_mask_t latched = modsLatched & xkbMask; + xkb_mod_mask_t locked = modsLocked & xkbMask; + xkb_mod_mask_t depressed = modsDepressed & xkbMask; + // set modifiers in depressed if they don't appear in any of the final masks + depressed |= ~(depressed | latched | locked) & xkbMask; + + xkb_state_component changedComponents = xkb_state_update_mask( + xkbState, depressed, latched, locked, 0, 0, lockedGroup(state)); + + if ((changedComponents & XKB_STATE_LAYOUT_EFFECTIVE) == XKB_STATE_LAYOUT_EFFECTIVE) { + //qWarning("TODO: Support KeyboardLayoutChange on QPA (QTBUG-27681)"); + } } } @@ -841,9 +836,9 @@ void QXcbKeyboard::updateXKBStateFromXI(void *modInfo, void *groupInfo) } #endif -quint32 QXcbKeyboard::xkbModMask(quint16 state) +xkb_mod_mask_t QXcbKeyboard::xkbModMask(quint16 state) { - quint32 xkb_mask = 0; + xkb_mod_mask_t xkb_mask = 0; if ((state & XCB_MOD_MASK_SHIFT) && xkb_mods.shift != XKB_MOD_INVALID) xkb_mask |= (1 << xkb_mods.shift); @@ -1503,7 +1498,7 @@ private: }; void QXcbKeyboard::handleKeyEvent(xcb_window_t sourceWindow, QEvent::Type type, xcb_keycode_t code, - quint16 state, xcb_timestamp_t time) + quint16 state, xcb_timestamp_t time, bool fromSendEvent) { if (!m_config) return; @@ -1515,17 +1510,25 @@ void QXcbKeyboard::handleKeyEvent(xcb_window_t sourceWindow, QEvent::Type type, if (type == QEvent::KeyPress) targetWindow->updateNetWmUserTime(time); - // 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 - ScopedXKBState xkbState(xkb_state_new(m_xkbKeymap.get())); - if (!xkbState) - return; - updateXKBStateFromState(xkbState.get(), state); - xcb_keysym_t sym = xkb_state_key_get_one_sym(xkbState.get(), code); - QString string = lookupString(xkbState.get(), code); + ScopedXKBState sendEventState; + if (fromSendEvent) { + // 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 + sendEventState.reset(xkb_state_new(m_xkbKeymap.get())); + if (!sendEventState) + return; + + xkb_mod_mask_t depressed = xkbModMask(state); + xkb_state_update_mask(sendEventState.get(), depressed, 0, 0, 0, 0, lockedGroup(state)); + } + + struct xkb_state *xkbState = fromSendEvent ? sendEventState.get() : m_xkbState.get(); + + xcb_keysym_t sym = xkb_state_key_get_one_sym(xkbState, code); + QString string = lookupString(xkbState, code); Qt::KeyboardModifiers modifiers = translateModifiers(state); if (sym >= XKB_KEY_KP_Space && sym <= XKB_KEY_KP_9) @@ -1548,7 +1551,7 @@ void QXcbKeyboard::handleKeyEvent(xcb_window_t sourceWindow, QEvent::Type type, } int qtcode = keysymToQtKey(latinKeysym != XKB_KEY_NoSymbol ? latinKeysym : sym, - modifiers, xkbState.get(), code); + modifiers, xkbState, code); bool isAutoRepeat = false; if (type == QEvent::KeyPress) { @@ -1624,14 +1627,23 @@ QString QXcbKeyboard::lookupStringNoKeysymTransformations(xkb_keysym_t keysym) c return QString::fromUtf8(chars.constData(), size); } -void QXcbKeyboard::handleKeyPressEvent(const xcb_key_press_event_t *event) +static bool fromSendEvent(const void *event) +{ + // From X11 protocol: Every event contains an 8-bit type code. The most + // significant bit in this code is set if the event was generated from + // a SendEvent request. + const xcb_generic_event_t *e = reinterpret_cast<const xcb_generic_event_t *>(event); + return (e->response_type & 0x80) != 0; +} + +void QXcbKeyboard::handleKeyPressEvent(const xcb_key_press_event_t *e) { - handleKeyEvent(event->event, QEvent::KeyPress, event->detail, event->state, event->time); + handleKeyEvent(e->event, QEvent::KeyPress, e->detail, e->state, e->time, fromSendEvent(e)); } -void QXcbKeyboard::handleKeyReleaseEvent(const xcb_key_release_event_t *event) +void QXcbKeyboard::handleKeyReleaseEvent(const xcb_key_release_event_t *e) { - handleKeyEvent(event->event, QEvent::KeyRelease, event->detail, event->state, event->time); + handleKeyEvent(e->event, QEvent::KeyRelease, e->detail, e->state, e->time, fromSendEvent(e)); } void QXcbKeyboard::handleMappingNotifyEvent(const void *event) |