├── .github └── FUNDING.yml ├── src ├── qhotkey.cpp ├── helper.h ├── qhotkey_osx.cpp ├── qhotkey_linux.cpp ├── qhotkey_win.cpp └── qhotkey.h ├── QHotkeys.pri ├── .gitignore ├── QHotkeys.pro ├── README.md └── LICENSE /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: mrousavy 2 | ko_fi: mrousavy 3 | custom: ["https://paypal.me/mrousavy"] 4 | -------------------------------------------------------------------------------- /src/qhotkey.cpp: -------------------------------------------------------------------------------- 1 | #include "qhotkey.h" 2 | #include 3 | 4 | #if !defined(Q_OS_WIN) && !defined(Q_OS_LINUX) && !defined(Q_OS_MACOS) 5 | #error This OS is not yet implemented. You can help at https://github.com/mrousavy/QHotkeys 6 | #endif 7 | -------------------------------------------------------------------------------- /QHotkeys.pri: -------------------------------------------------------------------------------- 1 | DEFINES += QHOTKEYS 2 | 3 | HEADERS += \ 4 | $$PWD/src/qhotkey.h \ 5 | $$PWD/src/helper.h 6 | 7 | msvc { 8 | SOURCES += $$PWD/src/qhotkey_win.cpp 9 | LIBS += -luser32 10 | } else:linux { 11 | SOURCES += $$PWD/src/qhotkey_linux.cpp 12 | } else:macx { 13 | SOURCES += $$PWD/src/qhotkey_osx.cpp 14 | } else { 15 | SOURCES += $$PWD/src/qhotkey.cpp 16 | } 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # C++ objects and libs 2 | 3 | *.slo 4 | *.lo 5 | *.o 6 | *.a 7 | *.la 8 | *.lai 9 | *.so 10 | *.dll 11 | *.dylib 12 | 13 | # Qt-es 14 | 15 | /.qmake.cache 16 | /.qmake.stash 17 | *.pro.user 18 | *.pro.user.* 19 | *.qbs.user 20 | *.qbs.user.* 21 | *.moc 22 | moc_*.cpp 23 | moc_*.h 24 | qrc_*.cpp 25 | ui_*.h 26 | Makefile* 27 | *build-* 28 | 29 | # QtCreator 30 | 31 | *.autosave 32 | 33 | # QtCtreator Qml 34 | *.qmlproject.user 35 | *.qmlproject.user.* 36 | 37 | # QtCtreator CMake 38 | CMakeLists.txt.user* 39 | 40 | # Output 41 | debug/ 42 | release/ 43 | -------------------------------------------------------------------------------- /QHotkeys.pro: -------------------------------------------------------------------------------- 1 | QT -= gui 2 | 3 | TARGET = QHotkeys 4 | TEMPLATE = lib 5 | CONFIG += staticlib 6 | 7 | DEFINES += QT_DEPRECATED_WARNINGS 8 | 9 | # If compiling .dll (shared library): 10 | # DEFINES += QHOTKEYS_SHAREDLIB 11 | # DEFINES += QHOTKEYS_EXPORT 12 | 13 | HEADERS += \ 14 | src/qhotkey.h \ 15 | src/helper.h 16 | 17 | msvc { 18 | SOURCES += src/qhotkey_win.cpp 19 | LIBS += -luser32 20 | } else:linux { 21 | SOURCES += src/qhotkey_linux.cpp 22 | } else:mingw { 23 | SOURCES += src/qhotkey_linux.cpp 24 | } else:macx { 25 | SOURCES += src/qhotkey_osx.cpp 26 | } else { 27 | SOURCES += src/qhotkey.cpp 28 | } 29 | -------------------------------------------------------------------------------- /src/helper.h: -------------------------------------------------------------------------------- 1 | #ifndef HELPER_H 2 | #define HELPER_H 3 | #include "qhotkey.h" 4 | 5 | /*! 6 | * \brief getKey Convert the given modifier to a platform specific modifier ID 7 | * \param modifier The given Modifier 8 | * \return A platform specific modifier ID for OS calls 9 | */ 10 | inline int getMod(const Qt::ModifierKey& modifier) noexcept 11 | { 12 | return static_cast(modifier); 13 | } 14 | /*! 15 | * \brief getKey Convert the given Qt key to a platform specific key ID 16 | * \param key The given Qt::Key 17 | * \return A platform specific key ID for OS calls 18 | */ 19 | inline int getKey(const Qt::Key& key) noexcept 20 | { 21 | return static_cast(key); 22 | } 23 | 24 | #endif // HELPER_H 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # QHotkeys 2 | 🔠 A small and lightweight cross platform C++ library implementing a system-wide hotkey system for Qt 3 | 4 | There are implementations available for the following compilers/platforms: 5 | * msvc - Windows 6 | * linux - Linux/X11 7 | * macx - MacOSX 8 | 9 | ## Usage 10 | #### Install 11 | Run this command in your project's directory: 12 | ```sh 13 | git submodule add https://github.com/mrousavy/QHotkeys 14 | ``` 15 | 16 | Add these lines to your Qt Project file (`.pro`): 17 | ```qmake 18 | include(QHotkeys/QHotkeys.pri) 19 | DEPENDPATH += QHotkeys/src/ 20 | INCLUDEPATH += QHotkeys/src/ 21 | ``` 22 | 23 | #### Code 24 | ```cpp 25 | #include 26 | using namespace Qt; 27 | 28 | // ... 29 | 30 | void myCallback(const QHotkey& hotkey) { 31 | // This is executed on a seperate thread! 32 | cout << "Hotkey pressed!"; 33 | } 34 | 35 | // ... 36 | 37 | // Register the hotkey 38 | QHotkey hotkey(ModifierKey::Control | ModifierKey::Alt, Key_I); 39 | // Connect pressed signal to one or more callback slots 40 | QObject::connect(&hotkey, &QHotkey::pressed, &myCallback); 41 | ``` 42 | -------------------------------------------------------------------------------- /src/qhotkey_osx.cpp: -------------------------------------------------------------------------------- 1 | #ifndef QHOTKEY_OSX_H 2 | #define QHOTKEY_OSX_H 3 | #include 4 | 5 | #ifdef Q_OS_MACOS 6 | #include "qhotkey.h" 7 | #include "helper.h" 8 | #include 9 | 10 | int Qt::QHotkey::_ghkid = 0; 11 | struct Qt::QHotkey::PlatformData 12 | { 13 | int _thrId; 14 | // TODO: PLATFORMDATA 15 | }; 16 | 17 | Qt::QHotkey::QHotkey(const Qt::ModifierKey modifiers, const Qt::Key key) 18 | : _modifiers(modifiers), _key(key), 19 | _hkid(_ghkid++), _registered(false), 20 | _loop(&Qt::QHotkey::registerHotkey, this), 21 | _pData(new PlatformData) 22 | {} 23 | 24 | Qt::QHotkey::~QHotkey() 25 | { 26 | // TODO: OSX IMPLEMENTATION 27 | } 28 | 29 | void Qt::QHotkey::registerHotkey() 30 | { 31 | qDebug() << _registered; 32 | if (_registered) 33 | throw std::runtime_error("This QHotkey instance is already registered!"); 34 | 35 | // TODO: OSX IMPLEMENTATION 36 | _registered = result == 0; 37 | messageLoop(); 38 | } 39 | 40 | void Qt::QHotkey::messageLoop() const 41 | { 42 | // TODO: OSX IMPLEMENTATION 43 | } 44 | #endif // Q_OS_MACOS 45 | 46 | #endif // QHOTKEY_OSX_H 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Marc Rousavy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/qhotkey_linux.cpp: -------------------------------------------------------------------------------- 1 | #ifndef QHOTKEY_LINUX_H 2 | #define QHOTKEY_LINUX_H 3 | #include 4 | 5 | #ifdef Q_OS_LINUX 6 | #include "qhotkey.h" 7 | #include "helper.h" 8 | #include 9 | 10 | int Qt::QHotkey::_ghkid = 0; 11 | struct Qt::QHotkey::PlatformData 12 | { 13 | int _thrId; 14 | // TODO: PLATFORMDATA 15 | }; 16 | 17 | Qt::QHotkey::QHotkey(const Qt::ModifierKey modifiers, const Qt::Key key) 18 | : _modifiers(modifiers), _key(key), 19 | _hkid(_ghkid++), _registered(false), 20 | _loop(&Qt::QHotkey::registerHotkey, this), 21 | _pData(new PlatformData) 22 | {} 23 | 24 | Qt::QHotkey::~QHotkey() 25 | { 26 | // TODO: LINUX IMPLEMENTATION 27 | int XUngrabKey(Display *display, int keycode, unsigned int 28 | modifiers, Window grab_window); 29 | } 30 | 31 | void Qt::QHotkey::registerHotkey() 32 | { 33 | qDebug() << _registered; 34 | if (_registered) 35 | throw std::runtime_error("This QHotkey instance is already registered!"); 36 | 37 | // TODO: LINUX IMPLEMENTATION 38 | int XGrabKey(Display *display, int keycode, unsigned int 39 | modifiers, Window grab_window, Bool owner_events, int pointer_mode, int keyboard_mode); 40 | _registered = result == 0; 41 | messageLoop(); 42 | } 43 | 44 | void Qt::QHotkey::messageLoop() const 45 | { 46 | // TODO: LINUX IMPLEMENTATION 47 | } 48 | #endif // Q_OS_LINUX 49 | 50 | #endif // QHOTKEY_LINUX_H 51 | -------------------------------------------------------------------------------- /src/qhotkey_win.cpp: -------------------------------------------------------------------------------- 1 | #ifndef QHOTKEY_WIN_H 2 | #define QHOTKEY_WIN_H 3 | #include 4 | 5 | #ifdef Q_OS_WIN 6 | #include "qhotkey.h" 7 | #include "helper.h" 8 | #include 9 | 10 | int Qt::QHotkey::_ghkid = 0; 11 | struct Qt::QHotkey::PlatformData 12 | { 13 | int thrId; 14 | UINT wmId; 15 | }; 16 | 17 | Qt::QHotkey::QHotkey(const Qt::ModifierKey modifiers, const Qt::Key key) 18 | : _modifiers(modifiers), _key(key), 19 | _hkid(_ghkid++), _registered(false), 20 | _loop(&Qt::QHotkey::registerHotkey, this), 21 | _pData(new PlatformData) 22 | {} 23 | 24 | Qt::QHotkey::~QHotkey() 25 | { 26 | // Send WM_QHOTKEY_UNHOOK message to messageLoop() 27 | PostThreadMessage(_pData->thrId, _pData->wmId, NULL, NULL); 28 | _loop.join(); 29 | UnregisterHotKey(NULL, _hkid); 30 | delete _pData; 31 | } 32 | 33 | void Qt::QHotkey::registerHotkey() 34 | { 35 | _pData->wmId = RegisterWindowMessage(L"WM_QHOTKEY_UNHOOK"); 36 | _pData->thrId = GetCurrentThreadId(); 37 | 38 | if (_registered) 39 | throw std::runtime_error("This QHotkey instance is already registered!"); 40 | 41 | auto result = RegisterHotKey(NULL, _hkid, getMod(_modifiers), getKey(_key)); 42 | if (result == FALSE) 43 | throw std::runtime_error("Could not register hotkey! #" + GetLastError()); 44 | 45 | _registered = result == 0; 46 | messageLoop(); 47 | } 48 | 49 | void Qt::QHotkey::messageLoop() const 50 | { 51 | MSG msg; 52 | while (GetMessage(&msg, NULL, NULL, NULL)) { 53 | if (msg.message == _pData->wmId) return; 54 | if (msg.message == WM_HOTKEY && 55 | msg.wParam == _hkid) { 56 | if (msg.wParam == _hkid) { 57 | emit pressed(*this); // Qt callback slot 58 | } 59 | } 60 | } 61 | } 62 | #endif // Q_OS_WIN 63 | 64 | #endif // QHOTKEY_WIN_H 65 | -------------------------------------------------------------------------------- /src/qhotkey.h: -------------------------------------------------------------------------------- 1 | #ifndef QHOTKEY_H 2 | #define QHOTKEY_H 3 | #include 4 | #include 5 | #include 6 | 7 | #ifdef QHOTKEYS_SHAREDLIB 8 | #ifdef QHOTKEYS_EXPORT 9 | #define QHOTKEYS_DLLSPEC Q_DECL_EXPORT 10 | #else 11 | #define QHOTKEYS_DLLSPEC Q_DECL_IMPORT 12 | #endif 13 | #else 14 | #define QHOTKEYS_DLLSPEC 15 | #endif 16 | 17 | namespace Qt 18 | { 19 | /*! 20 | * \brief An enum representing modifier keys on the keyboard 21 | */ 22 | enum class QHOTKEYS_DLLSPEC ModifierKey 23 | { 24 | None = 1 << 0, 25 | Control = 1 << 1, 26 | Shift = 1 << 2, 27 | Alt = 1 << 3, 28 | Meta = 1 << 4 29 | }; 30 | inline ModifierKey operator|(ModifierKey a, ModifierKey b) 31 | { 32 | return static_cast(static_cast(a) | static_cast(b)); 33 | } 34 | 35 | /*! 36 | * \brief A hooked global hotkey 37 | */ 38 | class QHOTKEYS_DLLSPEC QHotkey : public QObject 39 | { 40 | Q_OBJECT 41 | using callback_t = std::function; 42 | 43 | ///////////////// 44 | /// FUNCTIONS /// 45 | ///////////////// 46 | public: 47 | /*! 48 | * \brief QHotkey Create and hook a new Global Hotkey 49 | * \param modifiers The modifier keys for the hotkey (e.g. ::Control | ::Alt) 50 | * \param key The actual key to be registered as a hotkey 51 | */ 52 | QHotkey(const ModifierKey modifiers, const Key key); 53 | /*! 54 | * \brief ~QHotkey Destroy and unhook the Hotkey 55 | */ 56 | ~QHotkey(); 57 | 58 | signals: 59 | /*! 60 | * \brief pressed The Callback function which gets emitted 61 | * once the hotkey has been pressed. Connect this function 62 | * to a valid SLOT to handle this event. 63 | */ 64 | void pressed(const QHotkey&) const; 65 | 66 | ///////////////// 67 | /// MEMBER /// 68 | ///////////////// 69 | private: 70 | const ModifierKey _modifiers; 71 | const Key _key; 72 | const int _hkid; 73 | bool _registered; 74 | std::thread _loop; 75 | 76 | struct PlatformData; 77 | PlatformData* _pData; 78 | 79 | static int _ghkid; 80 | 81 | ///////////////// 82 | /// FUNCTIONS /// 83 | ///////////////// 84 | private: 85 | void registerHotkey(); 86 | void messageLoop() const; 87 | }; 88 | } 89 | #endif // QHOTKEY_H 90 | --------------------------------------------------------------------------------