diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,7 +49,7 @@ # no X11 stuff on mac if (NOT APPLE) - find_package(XCB MODULE COMPONENTS XCB KEYSYMS XTEST) + find_package(XCB MODULE COMPONENTS XCB KEYSYMS XTEST XKB) set_package_properties(XCB PROPERTIES DESCRIPTION "X protocol C-language Binding" URL "http://xcb.freedesktop.org" TYPE OPTIONAL diff --git a/src/runtime/plugins/CMakeLists.txt b/src/runtime/plugins/CMakeLists.txt --- a/src/runtime/plugins/CMakeLists.txt +++ b/src/runtime/plugins/CMakeLists.txt @@ -1,4 +1,4 @@ -if (${XCB_XCB_FOUND} AND ${XCB_KEYSYMS_FOUND}) +if (${XCB_XCB_FOUND} AND ${XCB_KEYSYMS_FOUND} AND ${XCB_XKB_FOUND}) add_subdirectory(xcb) endif() # if (APPLE) diff --git a/src/runtime/plugins/xcb/CMakeLists.txt b/src/runtime/plugins/xcb/CMakeLists.txt --- a/src/runtime/plugins/xcb/CMakeLists.txt +++ b/src/runtime/plugins/xcb/CMakeLists.txt @@ -8,6 +8,7 @@ KF5GlobalAccelPrivate XCB::XCB XCB::KEYSYMS + XCB::XKB ) install( diff --git a/src/runtime/plugins/xcb/kglobalaccel_x11.h b/src/runtime/plugins/xcb/kglobalaccel_x11.h --- a/src/runtime/plugins/xcb/kglobalaccel_x11.h +++ b/src/runtime/plugins/xcb/kglobalaccel_x11.h @@ -77,6 +77,7 @@ bool x11KeyPress(xcb_key_press_event_t *event); xcb_key_symbols_t *m_keySymbols; + uint8_t m_xkb_first_event; }; #endif // _KGLOBALACCEL_X11_H diff --git a/src/runtime/plugins/xcb/kglobalaccel_x11.cpp b/src/runtime/plugins/xcb/kglobalaccel_x11.cpp --- a/src/runtime/plugins/xcb/kglobalaccel_x11.cpp +++ b/src/runtime/plugins/xcb/kglobalaccel_x11.cpp @@ -33,9 +33,13 @@ #include // xcb + +// It uses "excplicit" as a variable name, which is not allowed in C++ +#define explicit xcb_explicit #include #include - +#include +#undef explicit // g_keyModMaskXAccel // mask of modifiers which can be used in shortcuts @@ -63,11 +67,13 @@ KGlobalAccelImpl::KGlobalAccelImpl(QObject *parent) : KGlobalAccelInterface(parent) , m_keySymbols(nullptr) + , m_xkb_first_event(0) { + const xcb_query_extension_reply_t *reply = xcb_get_extension_data(QX11Info::connection(), &xcb_xkb_id); + if (reply && reply->present) + m_xkb_first_event = reply->first_event; + calculateGrabMasks(); - if (QX11Info::isPlatformX11()) { - m_keySymbols = xcb_key_symbols_alloc(QX11Info::connection()); - } } KGlobalAccelImpl::~KGlobalAccelImpl() @@ -87,8 +93,12 @@ } if (!m_keySymbols) { - return false; + m_keySymbols = xcb_key_symbols_alloc(QX11Info::connection()); + if (!m_keySymbols) { + return false; + } } + if( !keyQt ) { qCDebug(KGLOBALACCELD) << "Tried to grab key with null code."; return false; @@ -193,19 +203,41 @@ xcb_generic_event_t *event = reinterpret_cast(message); const uint8_t responseType = event->response_type & ~0x80; switch (responseType) { + case XCB_MAPPING_NOTIFY: - qCDebug(KGLOBALACCELD) << "Got XMappingNotify event"; - xcb_refresh_keyboard_mapping(m_keySymbols, reinterpret_cast(event)); x11MappingNotify(); - return true; + + // Make sure to let Qt handle it as well + return false; case XCB_KEY_PRESS: #ifdef KDEDGLOBALACCEL_TRACE qCDebug(KGLOBALACCELD) << "Got XKeyPress event"; #endif return x11KeyPress(reinterpret_cast(event)); default: + if(m_xkb_first_event && responseType == m_xkb_first_event) { + const uint8_t xkbEvent = event->pad0; + switch (xkbEvent) { + case XCB_XKB_MAP_NOTIFY: + x11MappingNotify(); + break; + case XCB_XKB_NEW_KEYBOARD_NOTIFY: { + const xcb_xkb_new_keyboard_notify_event_t *ev = + reinterpret_cast(event); + if (ev->changed & XCB_XKB_NKN_DETAIL_KEYCODES) + x11MappingNotify(); + break; + } + default: + break; + } + + // Make sure to let Qt handle it as well + return false; + } + // We get all XEvents. Just ignore them. return false; } @@ -216,6 +248,8 @@ void KGlobalAccelImpl::x11MappingNotify() { + qCDebug(KGLOBALACCELD) << "Got XMappingNotify event"; + // Maybe the X modifier map has been changed. // uint oldKeyModMaskXAccel = g_keyModMaskXAccel; // uint oldKeyModMaskXOnOrOff = g_keyModMaskXOnOrOff; @@ -226,6 +260,9 @@ // different keycodes. ungrabKeys(); + // Force reloading of the keySym mapping + m_keySymbols = nullptr; + KKeyServer::initializeMods(); calculateGrabMasks();