diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 31c4ca3..1220bca 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,143 +1,143 @@ set(kguiaddons_LIB_SRCS colors/kcolorspaces.cpp colors/kcolorutils.cpp colors/kcolorcollection.cpp colors/kcolormimedata.cpp text/kdatevalidator.cpp text/kwordwrap.cpp fonts/kfontutils.cpp util/kiconutils.cpp util/klocalimagecacheimpl.cpp util/kmodifierkeyinfo.cpp util/kmodifierkeyinfoprovider.cpp util/urlhandler.cpp ) -set (kmodifierkeyinfoprovider_impl "dummy") -if (NOT APPLE AND X11_FOUND AND X11_Xkb_FOUND AND XCB_XCB_FOUND) - find_package(Qt5X11Extras ${REQUIRED_QT_VERSION} NO_MODULE) - if (Qt5X11Extras_FOUND) - include_directories ( - ${X11_Xkb_INCLUDE_PATH} - ${X11_Xlib_INCLUDE_PATH} - ${XCB_XCB_INCLUDE_DIR} - ) - set (kmodifierkeyinfoprovider_impl "x11") - endif() -endif () - -set (kguiaddons_LIB_SRCS ${kguiaddons_LIB_SRCS} util/kmodifierkeyinfoprovider_${kmodifierkeyinfoprovider_impl}.cpp) +set (kguiaddons_LIB_SRCS ${kguiaddons_LIB_SRCS} util/kmodifierkeyinfoprovider.cpp) add_library(KF5GuiAddons ${kguiaddons_LIB_SRCS}) generate_export_header(KF5GuiAddons BASE_NAME KGuiAddons) add_library(KF5::GuiAddons ALIAS KF5GuiAddons) set(kguiaddons_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/colors ${CMAKE_CURRENT_SOURCE_DIR}/fonts ${CMAKE_CURRENT_SOURCE_DIR}/text ${CMAKE_CURRENT_SOURCE_DIR}/util ) target_include_directories(KF5GuiAddons PUBLIC "$") target_include_directories(KF5GuiAddons INTERFACE "$" ) target_compile_definitions(KF5GuiAddons INTERFACE "$") target_link_libraries(KF5GuiAddons PUBLIC Qt5::Gui) -if (kmodifierkeyinfoprovider_impl STREQUAL "x11") - target_link_libraries(KF5GuiAddons LINK_PRIVATE ${X11_LIBRARIES} ${XCB_XCB_LIBRARY} Qt5::X11Extras) -endif() +set(WITH_XCB) +if (NOT APPLE AND X11_FOUND AND X11_Xkb_FOUND AND XCB_XCB_FOUND) + find_package(Qt5X11Extras ${REQUIRED_QT_VERSION} NO_MODULE) + if (Qt5X11Extras_FOUND) + add_library(kmodifierkey_xcb MODULE util/kmodifierkeyinfoprovider_xcb.cpp) + target_include_directories (kmodifierkey_xcb PRIVATE + ${X11_Xkb_INCLUDE_PATH} + ${X11_Xlib_INCLUDE_PATH} + ${XCB_XCB_INCLUDE_DIR} + ) + target_link_libraries(kmodifierkey_xcb PRIVATE ${X11_LIBRARIES} ${XCB_XCB_LIBRARY} Qt5::X11Extras KF5::GuiAddons) + install( TARGETS kmodifierkey_xcb DESTINATION ${PLUGIN_INSTALL_DIR}/kf5/kguiaddons/kmodifierkey/) + endif() +endif () set_target_properties(KF5GuiAddons PROPERTIES VERSION ${KGUIADDONS_VERSION_STRING} SOVERSION ${KGUIADDONS_SOVERSION} EXPORT_NAME GuiAddons ) ecm_generate_headers(KGuiAddons_HEADERS HEADER_NAMES KColorUtils KColorCollection KColorMimeData RELATIVE colors REQUIRED_HEADERS KGuiAddons_HEADERS ) ecm_generate_headers(KGuiAddons_HEADERS HEADER_NAMES KDateValidator KWordWrap RELATIVE text REQUIRED_HEADERS KGuiAddons_HEADERS ) ecm_generate_headers(KGuiAddons_HEADERS HEADER_NAMES KFontUtils RELATIVE fonts REQUIRED_HEADERS KGuiAddons_HEADERS ) ecm_generate_headers(KGuiAddons_HEADERS HEADER_NAMES KIconUtils KImageCache KModifierKeyInfo RELATIVE util REQUIRED_HEADERS KGuiAddons_HEADERS ) find_package(PythonModuleGeneration) if (PythonModuleGeneration_FOUND) ecm_generate_python_binding( TARGET KF5::GuiAddons PYTHONNAMESPACE PyKF5 MODULENAME KGuiAddons SIP_DEPENDS QtGui/QtGuimod.sip HEADERS colors/kcolorutils.h colors/kcolorcollection.h colors/kcolormimedata.h text/kdatevalidator.h text/kwordwrap.h fonts/kfontutils.h util/kiconutils.h util/kimagecache.h util/kmodifierkeyinfo.h + util/kmodifierkeyinfoprovider_p.h ) endif() install(TARGETS KF5GuiAddons EXPORT KF5GuiAddonsTargets ${KF5_INSTALL_TARGETS_DEFAULT_ARGS}) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/kguiaddons_export.h + util/kmodifierkeyinfoprovider_p.h util/klocalimagecacheimpl.h # implementation detail, no forwarding header ${KGuiAddons_HEADERS} DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/KGuiAddons COMPONENT Devel ) if(BUILD_QCH) ecm_add_qch( KF5GuiAddons_QCH NAME KGuiAddons BASE_NAME KF5GuiAddons VERSION ${KF5_VERSION} ORG_DOMAIN org.kde SOURCES # using only public headers, to cover only public API ${KGuiAddons_HEADERS} MD_MAINPAGE "${CMAKE_SOURCE_DIR}/README.md" LINK_QCHS Qt5Gui_QCH BLANK_MACROS KGUIADDONS_EXPORT TAGFILE_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR} QCH_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR} COMPONENT Devel ) endif() include(ECMGeneratePriFile) ecm_generate_pri_file(BASE_NAME KGuiAddons LIB_NAME KF5GuiAddons DEPS "gui" FILENAME_VAR PRI_FILENAME INCLUDE_INSTALL_DIR ${KDE_INSTALL_INCLUDEDIR_KF5}/KGuiAddons) install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR}) diff --git a/src/util/kmodifierkeyinfo.cpp b/src/util/kmodifierkeyinfo.cpp index b8f97ae..3579da8 100644 --- a/src/util/kmodifierkeyinfo.cpp +++ b/src/util/kmodifierkeyinfo.cpp @@ -1,85 +1,99 @@ /* Copyright 2009 Michael Leupold This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include "kmodifierkeyinfo.h" #include "kmodifierkeyinfoprovider_p.h" +#include + +#include +#include + +KModifierKeyInfoProvider* createProvider() +{ + QPluginLoader loader(QStringLiteral("kf5/kguiaddons/kmodifierkey/kmodifierkey_")+qGuiApp->platformName()); + auto instance = dynamic_cast(loader.instance()); + if (instance) + return instance; + qWarning() << "Error: could not load plugin for platform" << loader.fileName() << "error:" << loader.errorString() << loader.instance(); + return new KModifierKeyInfoProvider; +} KModifierKeyInfo::KModifierKeyInfo(QObject *parent) - : QObject(parent), p(new KModifierKeyInfoProvider) + : QObject(parent), p(createProvider()) { connect(p, &KModifierKeyInfoProvider::keyPressed, this, &KModifierKeyInfo::keyPressed); connect(p, &KModifierKeyInfoProvider::keyLatched, this, &KModifierKeyInfo::keyLatched); connect(p, &KModifierKeyInfoProvider::keyLocked, this, &KModifierKeyInfo::keyLocked); connect(p, &KModifierKeyInfoProvider::buttonPressed, this, &KModifierKeyInfo::buttonPressed); connect(p, &KModifierKeyInfoProvider::keyAdded, this, &KModifierKeyInfo::keyAdded); connect(p, &KModifierKeyInfoProvider::keyRemoved, this, &KModifierKeyInfo::keyRemoved); } KModifierKeyInfo::~KModifierKeyInfo() { delete p; } bool KModifierKeyInfo::knowsKey(Qt::Key key) const { return p->knowsKey(key); } const QList KModifierKeyInfo::knownKeys() const { return p->knownKeys(); } bool KModifierKeyInfo::isKeyPressed(Qt::Key key) const { return p->isKeyPressed(key); } bool KModifierKeyInfo::isKeyLatched(Qt::Key key) const { return p->isKeyLatched(key); } bool KModifierKeyInfo::setKeyLatched(Qt::Key key, bool latched) { return p->setKeyLatched(key, latched); } bool KModifierKeyInfo::isKeyLocked(Qt::Key key) const { return p->isKeyLocked(key); } bool KModifierKeyInfo::setKeyLocked(Qt::Key key, bool locked) { return p->setKeyLocked(key, locked); } bool KModifierKeyInfo::isButtonPressed(Qt::MouseButton button) const { return p->isButtonPressed(button); } diff --git a/src/util/kmodifierkeyinfoprovider.cpp b/src/util/kmodifierkeyinfoprovider.cpp index 24c9a77..c619ee6 100644 --- a/src/util/kmodifierkeyinfoprovider.cpp +++ b/src/util/kmodifierkeyinfoprovider.cpp @@ -1,65 +1,104 @@ /* Copyright 2009 Michael Leupold This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include "kmodifierkeyinfoprovider_p.h" +KModifierKeyInfoProvider::KModifierKeyInfoProvider() + : QObject(nullptr) +{ +} + +KModifierKeyInfoProvider::~KModifierKeyInfoProvider() +{ +} + +bool KModifierKeyInfoProvider::setKeyLatched(Qt::Key key, bool latched) +{ + Q_UNUSED(key); + Q_UNUSED(latched); + return false; +} + +bool KModifierKeyInfoProvider::setKeyLocked(Qt::Key key, bool locked) +{ + Q_UNUSED(key); + Q_UNUSED(locked); + return false; +} + bool KModifierKeyInfoProvider::isKeyPressed(Qt::Key key) const { if (m_modifierStates.contains(key)) { return m_modifierStates[key] & Pressed; } return false; } bool KModifierKeyInfoProvider::isKeyLatched(Qt::Key key) const { if (m_modifierStates.contains(key)) { return m_modifierStates[key] & Latched; } return false; } bool KModifierKeyInfoProvider::isKeyLocked(Qt::Key key) const { if (m_modifierStates.contains(key)) { return m_modifierStates[key] & Locked; } return false; } bool KModifierKeyInfoProvider::isButtonPressed(Qt::MouseButton button) const { if (m_buttonStates.contains(button)) { return m_buttonStates[button]; } return false; } bool KModifierKeyInfoProvider::knowsKey(Qt::Key key) const { return m_modifierStates.contains(key); } const QList KModifierKeyInfoProvider::knownKeys() const { return m_modifierStates.keys(); } -#include "moc_kmodifierkeyinfoprovider_p.cpp" +void KModifierKeyInfoProvider::stateUpdated(Qt::Key key, KModifierKeyInfoProvider::ModifierStates newState) +{ + auto &state = m_modifierStates[key]; + if (newState != state) { + const auto difference = (newState ^ state); + state = newState; + if (difference & Pressed) { + emit keyPressed(key, newState & Pressed); + } + if (difference & Latched) { + emit keyLatched(key, newState & Latched); + } + if (difference & Locked) { + emit keyLocked(key, newState & Locked); + } + } +} diff --git a/src/util/kmodifierkeyinfoprovider_dummy.cpp b/src/util/kmodifierkeyinfoprovider_dummy.cpp deleted file mode 100644 index 860e769..0000000 --- a/src/util/kmodifierkeyinfoprovider_dummy.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* - Copyright 2009 Michael Leupold - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) version 3, or any - later version accepted by the membership of KDE e.V. (or its - successor approved by the membership of KDE e.V.), which shall - act as a proxy defined in Section 6 of version 3 of the license. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. If not, see . -*/ - -#include "kmodifierkeyinfo.h" -#include "kmodifierkeyinfoprovider_p.h" - -KModifierKeyInfoProvider::KModifierKeyInfoProvider() - : QObject(0) -{ -} - -KModifierKeyInfoProvider::~KModifierKeyInfoProvider() -{ -} - -bool KModifierKeyInfoProvider::setKeyLatched(Qt::Key key, bool latched) -{ - Q_UNUSED(key); - Q_UNUSED(latched); - return false; -} - -bool KModifierKeyInfoProvider::setKeyLocked(Qt::Key key, bool locked) -{ - Q_UNUSED(key); - Q_UNUSED(locked); - return false; -} - -bool KModifierKeyInfoProvider::nativeEventFilter(const QByteArray &eventType, void *message, long int *result) -{ - Q_UNUSED(eventType) - Q_UNUSED(message) - Q_UNUSED(result) - return false; -} diff --git a/src/util/kmodifierkeyinfoprovider_p.h b/src/util/kmodifierkeyinfoprovider_p.h index c90d873..0e760a4 100644 --- a/src/util/kmodifierkeyinfoprovider_p.h +++ b/src/util/kmodifierkeyinfoprovider_p.h @@ -1,139 +1,129 @@ /* Copyright 2009 Michael Leupold This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #ifndef KMODIFIERKEYINFOPROVIDER_P_H #define KMODIFIERKEYINFOPROVIDER_P_H #include #include #include +#include "kguiaddons_export.h" /** * Background class that implements the behaviour of KModifierKeyInfo for * the different supported platforms. * @internal */ -class KModifierKeyInfoProvider : public QObject, public QAbstractNativeEventFilter +class KGUIADDONS_EXPORT KModifierKeyInfoProvider : public QObject { Q_OBJECT public: enum ModifierState { Nothing = 0x0, Pressed = 0x1, Latched = 0x2, Locked = 0x4 }; + Q_ENUM(ModifierState); Q_DECLARE_FLAGS(ModifierStates, ModifierState) KModifierKeyInfoProvider(); ~KModifierKeyInfoProvider() override; /** * Detect if a key is pressed. * @param key Modifier key to query * @return true if the key is pressed, false if it isn't. */ bool isKeyPressed(Qt::Key key) const; /** * Detect if a key is latched. * @param key Modifier key to query * @return true if the key is latched, false if it isn't. */ bool isKeyLatched(Qt::Key key) const; /** * Set the latched state of a key. * @param key Modifier to set the latched state for * @param latched true to latch the key, false to unlatch it * @return true if the key is known, false else */ - bool setKeyLatched(Qt::Key key, bool latched); + virtual bool setKeyLatched(Qt::Key key, bool latched); /** * Detect if a key is locked. * @param key Modifier key to query * @return true if the key is locked, false if it isn't. */ bool isKeyLocked(Qt::Key key) const; /** * Set the locked state of a key. * @param key Modifier to set the locked state for * @param latched true to lock the key, false to unlock it * @return true if the key is known, false else */ - bool setKeyLocked(Qt::Key key, bool locked); + virtual bool setKeyLocked(Qt::Key key, bool locked); /** * Check if a mouse button is pressed. * @param button Mouse button to check * @return true if pressed, false else */ bool isButtonPressed(Qt::MouseButton button) const; /** * Check if a key is known/can be queried * @param key Modifier key to check * @return true if the key is known, false if it isn't. */ bool knowsKey(Qt::Key key) const; /** * Get a list of known keys * @return List of known keys. */ const QList knownKeys() const; - bool nativeEventFilter(const QByteArray &eventType, void *message, long int *result) override; - Q_SIGNALS: void keyLatched(Qt::Key key, bool state); void keyLocked(Qt::Key key, bool state); void keyPressed(Qt::Key key, bool state); void buttonPressed(Qt::MouseButton button, bool state); void keyAdded(Qt::Key key); void keyRemoved(Qt::Key key); protected: - void xkbUpdateModifierMapping(); - void xkbModifierStateChanged(unsigned char mods, unsigned char latched_mods, - unsigned char locked_mods); - void xkbButtonStateChanged(unsigned short ptr_buttons); + void stateUpdated(Qt::Key key, KModifierKeyInfoProvider::ModifierStates state); -private: // the state of each known modifier QHash m_modifierStates; + // the state of each known mouse button QHash m_buttonStates; - - int m_xkbEv; - bool m_xkbAvailable; - - // maps a Qt::Key to a modifier mask - QHash m_xkbModifiers; - // maps a Qt::MouseButton to a button mask - QHash m_xkbButtons; }; +Q_DECLARE_INTERFACE(KModifierKeyInfoProvider, "org.kde.kguiaddons.KModifierKeyInfoProvider") Q_DECLARE_OPERATORS_FOR_FLAGS(KModifierKeyInfoProvider::ModifierStates) #endif diff --git a/src/util/kmodifierkeyinfoprovider_x11.cpp b/src/util/kmodifierkeyinfoprovider_xcb.cpp similarity index 90% rename from src/util/kmodifierkeyinfoprovider_x11.cpp rename to src/util/kmodifierkeyinfoprovider_xcb.cpp index 0d0a289..9b66bd6 100644 --- a/src/util/kmodifierkeyinfoprovider_x11.cpp +++ b/src/util/kmodifierkeyinfoprovider_xcb.cpp @@ -1,362 +1,347 @@ /* Copyright 2009 Michael Leupold Copyright 2013 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include "kmodifierkeyinfo.h" -#include "kmodifierkeyinfoprovider_p.h" +#include "kmodifierkeyinfoprovider_xcb.h" #include #include #define XK_MISCELLANY #define XK_XKB_KEYS #include #include #include struct ModifierDefinition { ModifierDefinition(Qt::Key _key, unsigned int _mask, const char *_name, KeySym _keysym) { key = _key; mask = _mask; name = _name; keysym = _keysym; } Qt::Key key; unsigned int mask; const char *name; // virtual modifier name KeySym keysym; }; /* * Get the real modifiers related to a virtual modifier. */ unsigned int xkbVirtualModifier(XkbDescPtr xkb, const char *name) { Q_ASSERT(xkb != nullptr); unsigned int mask = 0; bool nameEqual; for (int i = 0; i < XkbNumVirtualMods; ++i) { char *modStr = XGetAtomName(xkb->dpy, xkb->names->vmods[i]); if (modStr != nullptr) { nameEqual = (strcmp(name, modStr) == 0); XFree(modStr); if (nameEqual) { XkbVirtualModsToReal(xkb, 1 << i, &mask); - break; + break; } } } return mask; } -KModifierKeyInfoProvider::KModifierKeyInfoProvider() - : QObject(nullptr) - , QAbstractNativeEventFilter() +KModifierKeyInfoProviderXcb::KModifierKeyInfoProviderXcb() + : KModifierKeyInfoProvider() , m_xkbEv(0) , m_xkbAvailable(false) { if (qApp) { if (qApp->platformName() == QStringLiteral("xcb")) { int code, xkberr, maj, min; m_xkbAvailable = XkbQueryExtension(QX11Info::display(), &code, &m_xkbEv, &xkberr, &maj, &min); } } if (m_xkbAvailable) { XkbSelectEvents(QX11Info::display(), XkbUseCoreKbd, XkbStateNotifyMask | XkbMapNotifyMask, XkbStateNotifyMask | XkbMapNotifyMask); unsigned long int stateMask = XkbModifierStateMask | XkbModifierBaseMask | XkbModifierLatchMask | XkbModifierLockMask | XkbPointerButtonMask; XkbSelectEventDetails(QX11Info::display(), XkbUseCoreKbd, XkbStateNotifyMask, stateMask, stateMask); } xkbUpdateModifierMapping(); // add known pointer buttons m_xkbButtons.insert(Qt::LeftButton, Button1Mask); m_xkbButtons.insert(Qt::MidButton, Button2Mask); m_xkbButtons.insert(Qt::RightButton, Button3Mask); m_xkbButtons.insert(Qt::XButton1, Button4Mask); m_xkbButtons.insert(Qt::XButton2, Button5Mask); // get the initial state if (m_xkbAvailable) { XkbStateRec state; XkbGetState(QX11Info::display(), XkbUseCoreKbd, &state); xkbModifierStateChanged(state.mods, state.latched_mods, state.locked_mods); xkbButtonStateChanged(state.ptr_buttons); QCoreApplication::instance()->installNativeEventFilter(this); } } -KModifierKeyInfoProvider::~KModifierKeyInfoProvider() +KModifierKeyInfoProviderXcb::~KModifierKeyInfoProviderXcb() { if (m_xkbAvailable) { QCoreApplication::instance()->removeNativeEventFilter(this); } } -bool KModifierKeyInfoProvider::setKeyLatched(Qt::Key key, bool latched) +bool KModifierKeyInfoProviderXcb::setKeyLatched(Qt::Key key, bool latched) { if (!m_xkbModifiers.contains(key)) { return false; } return XkbLatchModifiers(QX11Info::display(), XkbUseCoreKbd, m_xkbModifiers[key], latched ? m_xkbModifiers[key] : 0); } -bool KModifierKeyInfoProvider::setKeyLocked(Qt::Key key, bool locked) +bool KModifierKeyInfoProviderXcb::setKeyLocked(Qt::Key key, bool locked) { if (!m_xkbModifiers.contains(key)) { return false; } return XkbLockModifiers(QX11Info::display(), XkbUseCoreKbd, m_xkbModifiers[key], locked ? m_xkbModifiers[key] : 0); } // HACK: xcb-xkb is not yet a public part of xcb. Because of that we have to include the event structure. namespace { typedef struct _xcb_xkb_map_notify_event_t { uint8_t response_type; uint8_t xkbType; uint16_t sequence; xcb_timestamp_t time; uint8_t deviceID; uint8_t ptrBtnActions; uint16_t changed; xcb_keycode_t minKeyCode; xcb_keycode_t maxKeyCode; uint8_t firstType; uint8_t nTypes; xcb_keycode_t firstKeySym; uint8_t nKeySyms; xcb_keycode_t firstKeyAct; uint8_t nKeyActs; xcb_keycode_t firstKeyBehavior; uint8_t nKeyBehavior; xcb_keycode_t firstKeyExplicit; uint8_t nKeyExplicit; xcb_keycode_t firstModMapKey; uint8_t nModMapKeys; xcb_keycode_t firstVModMapKey; uint8_t nVModMapKeys; uint16_t virtualMods; uint8_t pad0[2]; } _xcb_xkb_map_notify_event_t; typedef struct _xcb_xkb_state_notify_event_t { uint8_t response_type; uint8_t xkbType; uint16_t sequence; xcb_timestamp_t time; uint8_t deviceID; uint8_t mods; uint8_t baseMods; uint8_t latchedMods; uint8_t lockedMods; uint8_t group; int16_t baseGroup; int16_t latchedGroup; uint8_t lockedGroup; uint8_t compatState; uint8_t grabMods; uint8_t compatGrabMods; uint8_t lookupMods; uint8_t compatLoockupMods; uint16_t ptrBtnState; uint16_t changed; xcb_keycode_t keycode; uint8_t eventType; uint8_t requestMajor; uint8_t requestMinor; } _xcb_xkb_state_notify_event_t; typedef union { /* All XKB events share these fields. */ struct { uint8_t response_type; uint8_t xkbType; uint16_t sequence; xcb_timestamp_t time; uint8_t deviceID; } any; _xcb_xkb_map_notify_event_t map_notify; _xcb_xkb_state_notify_event_t state_notify; } _xkb_event; } -bool KModifierKeyInfoProvider::nativeEventFilter(const QByteArray &eventType, void *message, long int *result) +bool KModifierKeyInfoProviderXcb::nativeEventFilter(const QByteArray &eventType, void *message, long int *result) { Q_UNUSED(result) if (!m_xkbAvailable || eventType != "xcb_generic_event_t") { return false; } xcb_generic_event_t *event = static_cast(message); if ((event->response_type & ~0x80) == m_xkbEv + XkbEventCode) { _xkb_event *kbevt = reinterpret_cast<_xkb_event *>(event); unsigned int stateMask = XkbModifierStateMask | XkbModifierBaseMask | XkbModifierLatchMask | XkbModifierLockMask; if (kbevt->any.xkbType == XkbMapNotify) { xkbUpdateModifierMapping(); } else if (kbevt->any.xkbType == XkbStateNotify) { if (kbevt->state_notify.changed & stateMask) { xkbModifierStateChanged(kbevt->state_notify.mods, kbevt->state_notify.latchedMods, kbevt->state_notify.lockedMods); } else if (kbevt->state_notify.changed & XkbPointerButtonMask) { xkbButtonStateChanged(kbevt->state_notify.ptrBtnState); } } } return false; } -void KModifierKeyInfoProvider::xkbModifierStateChanged(unsigned char mods, +void KModifierKeyInfoProviderXcb::xkbModifierStateChanged(unsigned char mods, unsigned char latched_mods, unsigned char locked_mods) { // detect keyboard modifiers - ModifierStates oldState; ModifierStates newState; QHash::const_iterator it; QHash::const_iterator end = m_xkbModifiers.constEnd(); for (it = m_xkbModifiers.constBegin(); it != end; ++it) { if (!m_modifierStates.contains(it.key())) { continue; } newState = Nothing; - oldState = m_modifierStates[it.key()]; // determine the new state if (mods & it.value()) { newState |= Pressed; } if (latched_mods & it.value()) { newState |= Latched; } if (locked_mods & it.value()) { newState |= Locked; } - if (newState != oldState) { - m_modifierStates[it.key()] = newState; - - if ((newState ^ oldState) & Pressed) { - emit keyPressed(it.key(), newState & Pressed); - } - if ((newState ^ oldState) & Latched) { - emit keyLatched(it.key(), newState & Latched); - } - if ((newState ^ oldState) & Locked) { - emit keyLocked(it.key(), newState & Locked); - } - } + stateUpdated(it.key(), newState); } } -void KModifierKeyInfoProvider::xkbButtonStateChanged(unsigned short ptr_buttons) +void KModifierKeyInfoProviderXcb::xkbButtonStateChanged(unsigned short ptr_buttons) { // detect mouse button states bool newButtonState; QHash::const_iterator it; QHash::const_iterator end = m_xkbButtons.constEnd(); for (it = m_xkbButtons.constBegin(); it != end; ++it) { newButtonState = (ptr_buttons & it.value()); if (newButtonState != m_buttonStates[it.key()]) { m_buttonStates[it.key()] = newButtonState; emit buttonPressed(it.key(), newButtonState); } } } -void KModifierKeyInfoProvider::xkbUpdateModifierMapping() +void KModifierKeyInfoProviderXcb::xkbUpdateModifierMapping() { if (!m_xkbAvailable) { return; } m_xkbModifiers.clear(); QList srcModifiers; srcModifiers << ModifierDefinition(Qt::Key_Shift, ShiftMask, nullptr, 0) << ModifierDefinition(Qt::Key_Control, ControlMask, nullptr, 0) << ModifierDefinition(Qt::Key_Alt, 0, "Alt", XK_Alt_L) // << { 0, 0, I18N_NOOP("Win"), "superkey", "" } << ModifierDefinition(Qt::Key_Meta, 0, "Meta", XK_Meta_L) << ModifierDefinition(Qt::Key_Super_L, 0, "Super", XK_Super_L) << ModifierDefinition(Qt::Key_Hyper_L, 0, "Hyper", XK_Hyper_L) << ModifierDefinition(Qt::Key_AltGr, 0, "AltGr", 0) << ModifierDefinition(Qt::Key_NumLock, 0, "NumLock", XK_Num_Lock) << ModifierDefinition(Qt::Key_CapsLock, LockMask, nullptr, 0) << ModifierDefinition(Qt::Key_ScrollLock, 0, "ScrollLock", XK_Scroll_Lock); XkbDescPtr xkb = XkbGetKeyboard(QX11Info::display(), XkbAllComponentsMask, XkbUseCoreKbd); QList::const_iterator it; QList::const_iterator end = srcModifiers.constEnd(); for (it = srcModifiers.constBegin(); it != end; ++it) { unsigned int mask = it->mask; if (mask == 0 && xkb != nullptr) { // try virtual modifier first if (it->name != nullptr) { mask = xkbVirtualModifier(xkb, it->name); } if (mask == 0 && it->keysym != 0) { mask = XkbKeysymToModifiers(QX11Info::display(), it->keysym); } else if (mask == 0) { // special case for AltGr mask = XkbKeysymToModifiers(QX11Info::display(), XK_Mode_switch) | XkbKeysymToModifiers(QX11Info::display(), XK_ISO_Level3_Shift) | XkbKeysymToModifiers(QX11Info::display(), XK_ISO_Level3_Latch) | XkbKeysymToModifiers(QX11Info::display(), XK_ISO_Level3_Lock); } } if (mask != 0) { m_xkbModifiers.insert(it->key, mask); // previously unknown modifier if (!m_modifierStates.contains(it->key)) { m_modifierStates.insert(it->key, Nothing); emit keyAdded(it->key); } } } // remove modifiers which are no longer available QMutableHashIterator i(m_modifierStates); while (i.hasNext()) { i.next(); if (!m_xkbModifiers.contains(i.key())) { Qt::Key key = i.key(); i.remove(); emit keyRemoved(key); } } if (xkb != nullptr) { XkbFreeKeyboard(xkb, 0, true); } } diff --git a/src/util/kmodifierkeyinfoprovider_xcb.h b/src/util/kmodifierkeyinfoprovider_xcb.h new file mode 100644 index 0000000..accdfa3 --- /dev/null +++ b/src/util/kmodifierkeyinfoprovider_xcb.h @@ -0,0 +1,55 @@ +/* + Copyright 2009 Michael Leupold + Copyright 2013 Martin Gräßlin + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see . +*/ + +#ifndef KMODIFIERKEYINFOPROVIDERXCB_H +#define KMODIFIERKEYINFOPROVIDERXCB_H + +#include "kmodifierkeyinfoprovider_p.h" + +class KModifierKeyInfoProviderXcb : public KModifierKeyInfoProvider, public QAbstractNativeEventFilter +{ +Q_OBJECT +Q_PLUGIN_METADATA(IID "org.kde.kguiaddons.KModifierKeyInfoProvider.XCB") +public: + KModifierKeyInfoProviderXcb(); + ~KModifierKeyInfoProviderXcb(); + + bool setKeyLatched(Qt::Key key, bool latched) override; + bool setKeyLocked(Qt::Key key, bool locked) override; + + bool nativeEventFilter(const QByteArray &eventType, void *message, long int *result) override; + + void xkbUpdateModifierMapping(); + void xkbModifierStateChanged(unsigned char mods, unsigned char latched_mods, + unsigned char locked_mods); + void xkbButtonStateChanged(unsigned short ptr_buttons); + +private: + int m_xkbEv; + bool m_xkbAvailable; + + // maps a Qt::Key to a modifier mask + QHash m_xkbModifiers; + // maps a Qt::MouseButton to a button mask + QHash m_xkbButtons; +}; + +#endif