diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -14,20 +14,7 @@ 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}) @@ -45,9 +32,20 @@ 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} @@ -107,12 +105,14 @@ 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 diff --git a/src/util/kmodifierkeyinfo.cpp b/src/util/kmodifierkeyinfo.cpp --- a/src/util/kmodifierkeyinfo.cpp +++ b/src/util/kmodifierkeyinfo.cpp @@ -20,9 +20,23 @@ #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); diff --git a/src/util/kmodifierkeyinfoprovider.cpp b/src/util/kmodifierkeyinfoprovider.cpp --- a/src/util/kmodifierkeyinfoprovider.cpp +++ b/src/util/kmodifierkeyinfoprovider.cpp @@ -20,6 +20,29 @@ #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)) { @@ -62,4 +85,20 @@ 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 --- 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 --- a/src/util/kmodifierkeyinfoprovider_p.h +++ b/src/util/kmodifierkeyinfoprovider_p.h @@ -24,13 +24,14 @@ #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 @@ -41,6 +42,7 @@ Latched = 0x2, Locked = 0x4 }; + Q_ENUM(ModifierState); Q_DECLARE_FLAGS(ModifierStates, ModifierState) KModifierKeyInfoProvider(); @@ -66,7 +68,7 @@ * @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. @@ -81,7 +83,7 @@ * @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. @@ -103,8 +105,6 @@ */ 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); @@ -114,26 +114,16 @@ 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_xcb.h b/src/util/kmodifierkeyinfoprovider_xcb.h new file mode 100644 --- /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 diff --git a/src/util/kmodifierkeyinfoprovider_x11.cpp b/src/util/kmodifierkeyinfoprovider_xcb.cpp rename from src/util/kmodifierkeyinfoprovider_x11.cpp rename to src/util/kmodifierkeyinfoprovider_xcb.cpp --- a/src/util/kmodifierkeyinfoprovider_x11.cpp +++ b/src/util/kmodifierkeyinfoprovider_xcb.cpp @@ -20,7 +20,7 @@ */ #include "kmodifierkeyinfo.h" -#include "kmodifierkeyinfoprovider_p.h" +#include "kmodifierkeyinfoprovider_xcb.h" #include #include @@ -61,16 +61,15 @@ 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) { @@ -111,14 +110,14 @@ } } -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; @@ -128,7 +127,7 @@ 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; @@ -208,7 +207,7 @@ } _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") { @@ -233,12 +232,11 @@ 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; @@ -248,7 +246,6 @@ continue; } newState = Nothing; - oldState = m_modifierStates[it.key()]; // determine the new state if (mods & it.value()) { @@ -261,23 +258,11 @@ 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; @@ -293,7 +278,7 @@ } } -void KModifierKeyInfoProvider::xkbUpdateModifierMapping() +void KModifierKeyInfoProviderXcb::xkbUpdateModifierMapping() { if (!m_xkbAvailable) { return;