diff options
-rw-r--r-- | src/plugins/platforms/xcb/qxcbconnection.cpp | 34 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbkeyboard.cpp | 172 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbkeyboard.h | 44 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/xcb-plugin.pro | 6 |
4 files changed, 236 insertions, 20 deletions
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 34508260d9..7381c8c886 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -299,7 +299,10 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra } xcb_extension_t *extensions[] = { - &xcb_shm_id, &xcb_xfixes_id, &xcb_randr_id, &xcb_shape_id, &xcb_sync_id, &xcb_xkb_id, + &xcb_shm_id, &xcb_xfixes_id, &xcb_randr_id, &xcb_shape_id, &xcb_sync_id, +#ifndef QT_NO_XKB + &xcb_xkb_id, +#endif #ifdef XCB_USE_RENDER &xcb_render_id, #endif @@ -747,6 +750,7 @@ void QXcbConnection::handleButtonRelease(xcb_generic_event_t *ev) m_buttons &= ~translateMouseButton(event->detail); } +#ifndef QT_NO_XKB namespace { typedef union { /* All XKB events share these fields. */ @@ -761,6 +765,7 @@ namespace { xcb_xkb_state_notify_event_t state_notify; } _xkb_event; } +#endif void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event) { @@ -786,12 +791,21 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event) case XCB_EXPOSE: HANDLE_PLATFORM_WINDOW_EVENT(xcb_expose_event_t, window, handleExposeEvent); case XCB_BUTTON_PRESS: +#ifdef QT_NO_XKB + m_keyboard->updateXKBStateFromCore(((xcb_button_press_event_t *)event)->state); +#endif handleButtonPress(event); HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_press_event_t, event, handleButtonPressEvent); case XCB_BUTTON_RELEASE: +#ifdef QT_NO_XKB + m_keyboard->updateXKBStateFromCore(((xcb_button_release_event_t *)event)->state); +#endif handleButtonRelease(event); HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_release_event_t, event, handleButtonReleaseEvent); case XCB_MOTION_NOTIFY: +#ifdef QT_NO_XKB + m_keyboard->updateXKBStateFromCore(((xcb_motion_notify_event_t *)event)->state); +#endif HANDLE_PLATFORM_WINDOW_EVENT(xcb_motion_notify_event_t, event, handleMotionNotifyEvent); case XCB_CONFIGURE_NOTIFY: HANDLE_PLATFORM_WINDOW_EVENT(xcb_configure_notify_event_t, event, handleConfigureNotifyEvent); @@ -805,15 +819,29 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event) case XCB_ENTER_NOTIFY: HANDLE_PLATFORM_WINDOW_EVENT(xcb_enter_notify_event_t, event, handleEnterNotifyEvent); case XCB_LEAVE_NOTIFY: +#ifdef QT_NO_XKB + m_keyboard->updateXKBStateFromCore(((xcb_leave_notify_event_t *)event)->state); +#endif HANDLE_PLATFORM_WINDOW_EVENT(xcb_leave_notify_event_t, event, handleLeaveNotifyEvent); case XCB_FOCUS_IN: HANDLE_PLATFORM_WINDOW_EVENT(xcb_focus_in_event_t, event, handleFocusInEvent); case XCB_FOCUS_OUT: HANDLE_PLATFORM_WINDOW_EVENT(xcb_focus_out_event_t, event, handleFocusOutEvent); case XCB_KEY_PRESS: +#ifdef QT_NO_XKB + m_keyboard->updateXKBStateFromCore(((xcb_key_press_event_t *)event)->state); +#endif HANDLE_KEYBOARD_EVENT(xcb_key_press_event_t, handleKeyPressEvent); case XCB_KEY_RELEASE: +#ifdef QT_NO_XKB + m_keyboard->updateXKBStateFromCore(((xcb_key_release_event_t *)event)->state); +#endif HANDLE_KEYBOARD_EVENT(xcb_key_release_event_t, handleKeyReleaseEvent); +#ifdef QT_NO_XKB + case XCB_MAPPING_NOTIFY: + m_keyboard->handleMappingNotifyEvent((xcb_mapping_notify_event_t *)event); + break; +#endif case XCB_SELECTION_REQUEST: { xcb_selection_request_event_t *sr = (xcb_selection_request_event_t *)event; @@ -876,6 +904,7 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event) } } handled = true; +#ifndef QT_NO_XKB } else if (response_type == xkb_first_event) { // https://bugs.freedesktop.org/show_bug.cgi?id=51295 _xkb_event *xkb_event = reinterpret_cast<_xkb_event *>(event); if (xkb_event->any.deviceID == m_keyboard->coreDeviceId()) { @@ -892,6 +921,7 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event) break; } } +#endif } } @@ -1574,6 +1604,7 @@ void QXcbConnection::initializeXShape() void QXcbConnection::initializeXKB() { +#ifndef QT_NO_XKB const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_connection, &xcb_xkb_id); if (!reply || !reply->present) { xkb_first_event = 0; @@ -1629,6 +1660,7 @@ void QXcbConnection::initializeXKB() qWarning() << "Qt: failed to select notify events from xcb-xkb"; return; } +#endif } #if defined(XCB_USE_EGL) 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 diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.h b/src/plugins/platforms/xcb/qxcbkeyboard.h index 9c278eeb8c..af6677c20f 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.h +++ b/src/plugins/platforms/xcb/qxcbkeyboard.h @@ -44,6 +44,10 @@ #include "qxcbobject.h" +#ifdef QT_NO_XKB +#include <xcb/xcb_keysyms.h> +#endif + #include <xkbcommon/xkbcommon.h> #include <QEvent> @@ -62,14 +66,21 @@ public: void handleKeyPressEvent(QXcbWindowEventListener *eventListener, const xcb_key_press_event_t *event); void handleKeyReleaseEvent(QXcbWindowEventListener *eventListener, const xcb_key_release_event_t *event); - void handleMappingNotifyEvent(const xcb_xkb_map_notify_event_t *event); + void handleMappingNotifyEvent(const void *event); Qt::KeyboardModifiers translateModifiers(int s) const; - QList<int> possibleKeys(const QKeyEvent *e) const; void updateKeymap(); - void updateXKBState(xcb_xkb_state_notify_event_t *state); + QList<int> possibleKeys(const QKeyEvent *e) const; + +#ifdef QT_NO_XKB + void updateXKBStateFromCore(quint16 state); + void updateXKBMods(); + quint32 xkbModMask(quint16 state); +#else int coreDeviceId() { return core_device_id; } + void updateXKBState(xcb_xkb_state_notify_event_t *state); +#endif protected: void handleKeyEvent(QWindow *window, QEvent::Type type, xcb_keycode_t code, quint16 state, xcb_timestamp_t time); @@ -80,10 +91,16 @@ protected: int keysymToQtKey(xcb_keysym_t keysym, Qt::KeyboardModifiers &modifiers, QString text) const; void readXKBConfig(struct xkb_rule_names *names); + +#ifdef QT_NO_XKB + void updateModifiers(); +#else void updateVModMapping(); void updateVModToRModMapping(); +#endif private: + bool m_config; xcb_keycode_t m_autorepeat_code; struct xkb_context *xkb_context; @@ -96,12 +113,27 @@ private: uint meta; }; - _mod_masks vmod_masks; _mod_masks rmod_masks; - int core_device_id; +#ifdef QT_NO_XKB + xcb_key_symbols_t *m_key_symbols; + + struct _xkb_mods { + xkb_mod_index_t shift; + xkb_mod_index_t lock; + xkb_mod_index_t control; + xkb_mod_index_t mod1; + xkb_mod_index_t mod2; + xkb_mod_index_t mod3; + xkb_mod_index_t mod4; + xkb_mod_index_t mod5; + }; - bool m_config; + _xkb_mods xkb_mods; +#else + _mod_masks vmod_masks; + int core_device_id; +#endif }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/xcb-plugin.pro b/src/plugins/platforms/xcb/xcb-plugin.pro index e7d8802021..e8d52ebf2f 100644 --- a/src/plugins/platforms/xcb/xcb-plugin.pro +++ b/src/plugins/platforms/xcb/xcb-plugin.pro @@ -111,7 +111,11 @@ contains(QT_CONFIG, xcb-qt) { } else { LIBS += -lxcb -lxcb-image -lxcb-icccm -lxcb-sync -lxcb-xfixes -lxcb-shm -lxcb-randr !contains(DEFINES, QT_NO_SHAPE):LIBS += -lxcb-shape - !contains(DEFINES, QT_NO_XKB):LIBS += -lxcb-xkb + contains(DEFINES, QT_NO_XKB) { + LIBS += -lxcb-keysyms + } else { + LIBS += -lxcb-xkb + } } # libxkbcommon |