diff --git a/README.md b/README.md index 4f26eabf..99890536 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,8 @@ After installing Zeal go to `Tools->Docsets`, select the ones you want, and clic * [Qt](https://www.qt.io/) version 6.4.2 or above. Required module: Qt WebEngine Widgets. * [libarchive](https://libarchive.org/). * [SQLite](https://sqlite.org/). -* X11 platforms only: `xcb-util-keysyms`. +* Linux/BSD platforms: `extra-cmake-modules`. +* X11 platforms only: `libxkbcommon`, `xcb-util-keysyms`. ### Build instructions diff --git a/src/libs/ui/qxtglobalshortcut/CMakeLists.txt b/src/libs/ui/qxtglobalshortcut/CMakeLists.txt index 99c3a01a..59507680 100644 --- a/src/libs/ui/qxtglobalshortcut/CMakeLists.txt +++ b/src/libs/ui/qxtglobalshortcut/CMakeLists.txt @@ -7,14 +7,8 @@ if(APPLE) qxtglobalshortcut_mac.cpp ) elseif(UNIX) - # ECM provides FindXCB.cmake; neither CMake nor libxcb ships one. - find_package(ECM QUIET NO_MODULE) - if(ECM_FOUND) - list(APPEND CMAKE_MODULE_PATH ${ECM_FIND_MODULE_DIR}) - find_package(XCB COMPONENTS XCB KEYSYMS QUIET) - endif() - - if(XCB_FOUND) + find_package(X11 QUIET COMPONENTS xcb xcb_keysyms xkbcommon) + if(X11_xcb_FOUND AND X11_xcb_keysyms_FOUND AND X11_xkbcommon_FOUND) list(APPEND QxtGlobalShortcut_SOURCES qxtglobalshortcut_x11.cpp ) @@ -41,9 +35,6 @@ target_link_libraries(QxtGlobalShortcut PRIVATE Qt6::Gui) if(APPLE) find_library(CARBON_LIBRARY Carbon) target_link_libraries(QxtGlobalShortcut PRIVATE ${CARBON_LIBRARY}) -elseif(UNIX AND XCB_FOUND) - if(Qt6Core_VERSION VERSION_GREATER_EQUAL 6.10) - find_package(Qt6 COMPONENTS GuiPrivate REQUIRED) - endif() - target_link_libraries(QxtGlobalShortcut PRIVATE Qt6::GuiPrivate XCB::XCB XCB::KEYSYMS) +elseif(UNIX AND X11_xcb_FOUND AND X11_xcb_keysyms_FOUND AND X11_xkbcommon_FOUND) + target_link_libraries(QxtGlobalShortcut PRIVATE X11::xcb X11::xcb_keysyms X11::xkbcommon) endif() diff --git a/src/libs/ui/qxtglobalshortcut/qxtglobalshortcut_x11.cpp b/src/libs/ui/qxtglobalshortcut/qxtglobalshortcut_x11.cpp index 534099a5..83b3213e 100644 --- a/src/libs/ui/qxtglobalshortcut/qxtglobalshortcut_x11.cpp +++ b/src/libs/ui/qxtglobalshortcut/qxtglobalshortcut_x11.cpp @@ -33,14 +33,14 @@ #include "qxtglobalshortcut_p.h" #include -#include #include #include #include -#include #include #include +#include +#include namespace { constexpr quint32 maskModifiers[] = {0, XCB_MOD_MASK_2, XCB_MOD_MASK_LOCK, (XCB_MOD_MASK_2 | XCB_MOD_MASK_LOCK)}; @@ -56,6 +56,120 @@ xcb_window_t rootWindow(xcb_connection_t *xcbConnection) { return xcb_setup_roots_iterator(xcb_get_setup(xcbConnection)).data->root; } + +xcb_keysym_t qtKeyToKeysym(Qt::Key key) +{ + if (key >= Qt::Key_F1 && key <= Qt::Key_F35) { + return XKB_KEY_F1 + (key - Qt::Key_F1); + } + + switch (key) { + case Qt::Key_Escape: + return XKB_KEY_Escape; + case Qt::Key_Tab: + return XKB_KEY_Tab; + case Qt::Key_Backtab: + return XKB_KEY_ISO_Left_Tab; + case Qt::Key_Backspace: + return XKB_KEY_BackSpace; + case Qt::Key_Return: + return XKB_KEY_Return; + case Qt::Key_Enter: + return XKB_KEY_KP_Enter; + case Qt::Key_Insert: + return XKB_KEY_Insert; + case Qt::Key_Delete: + return XKB_KEY_Delete; + case Qt::Key_Pause: + return XKB_KEY_Pause; + case Qt::Key_Print: + return XKB_KEY_Print; + case Qt::Key_ScrollLock: + return XKB_KEY_Scroll_Lock; + case Qt::Key_Home: + return XKB_KEY_Home; + case Qt::Key_End: + return XKB_KEY_End; + case Qt::Key_Left: + return XKB_KEY_Left; + case Qt::Key_Up: + return XKB_KEY_Up; + case Qt::Key_Right: + return XKB_KEY_Right; + case Qt::Key_Down: + return XKB_KEY_Down; + case Qt::Key_PageUp: + return XKB_KEY_Page_Up; + case Qt::Key_PageDown: + return XKB_KEY_Page_Down; + case Qt::Key_Menu: + return XKB_KEY_Menu; + + // Browser keys (XF86 vendor extensions). + case Qt::Key_Back: + return XKB_KEY_XF86Back; + case Qt::Key_Forward: + return XKB_KEY_XF86Forward; + case Qt::Key_Refresh: + return XKB_KEY_XF86Refresh; + case Qt::Key_Stop: + return XKB_KEY_XF86Stop; + case Qt::Key_Reload: + return XKB_KEY_XF86Reload; + case Qt::Key_Search: + return XKB_KEY_XF86Search; + case Qt::Key_HomePage: + return XKB_KEY_XF86HomePage; + case Qt::Key_Favorites: + return XKB_KEY_XF86Favorites; + case Qt::Key_OpenUrl: + return XKB_KEY_XF86OpenURL; + + // Multimedia and system keys (XF86 vendor extensions). + case Qt::Key_VolumeMute: + return XKB_KEY_XF86AudioMute; + case Qt::Key_VolumeDown: + return XKB_KEY_XF86AudioLowerVolume; + case Qt::Key_VolumeUp: + return XKB_KEY_XF86AudioRaiseVolume; + case Qt::Key_MediaPlay: + return XKB_KEY_XF86AudioPlay; + case Qt::Key_MediaStop: + return XKB_KEY_XF86AudioStop; + case Qt::Key_MediaPrevious: + return XKB_KEY_XF86AudioPrev; + case Qt::Key_MediaNext: + return XKB_KEY_XF86AudioNext; + case Qt::Key_MediaPause: + return XKB_KEY_XF86AudioPause; + case Qt::Key_MediaTogglePlayPause: + return XKB_KEY_XF86AudioPlay; + case Qt::Key_MediaRecord: + return XKB_KEY_XF86AudioRecord; + case Qt::Key_MonBrightnessDown: + return XKB_KEY_XF86MonBrightnessDown; + case Qt::Key_MonBrightnessUp: + return XKB_KEY_XF86MonBrightnessUp; + + default: + // ASCII/Latin-1: legacy keysym == codepoint. Lowercase letters so we + // match level-0 of the keymap and avoid spurious Shift inference for + // shortcuts like Ctrl+A. + if (key < 0x100) { + return xkb_keysym_to_lower(static_cast(key)); + } + + // Non-Latin Unicode codepoint: X11 Unicode keysym encoding. + if (key < 0x01000000) { + return key | 0x01000000; + } + + // Unhandled Qt special key (Help, Cancel, modifiers, etc.). Fail + // registration rather than passing a special-key encoding through as + // a Unicode keysym, which would grab the wrong physical key. + return XCB_NO_SYMBOL; + } +} } // namespace X11 } // namespace @@ -125,13 +239,9 @@ quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key, quint32 &extraNativ extraNativeMods = 0; quint32 native = 0; - // Use Qt's complete internal keysym table (covers media, launch, and all special keys). - QKeyEvent dummy(QEvent::KeyPress, key, Qt::NoModifier); - const auto keysyms = QXkbCommon::toKeysym(&dummy); - - xcb_keysym_t keysym = keysyms.isEmpty() ? XCB_NO_SYMBOL : keysyms.first(); + const xcb_keysym_t keysym = X11::qtKeyToKeysym(key); if (keysym == XCB_NO_SYMBOL) { - keysym = static_cast(key); + return 0; } xcb_connection_t *xcbConnection = X11::connection();