Implementing Global Hotkey Support in QT on Windows

If your application needs a global hotkey support, QT will leave you hanging. Fortunately, on high-level this is a rather simple function:

Code
bool registerHotkey(QKeySequence keySequence) {
auto key = Qt::Key(keySequence[0] & static_cast<int>(~Qt::KeyboardModifierMask));
auto modifiers = Qt::KeyboardModifiers(keySequence[0] & static_cast<int>(Qt::KeyboardModifierMask));

return nativeRegisterHotkey(key, modifiers);
}

Essentially the only work is splitting key and modifiers into their own variables and then having platform-specific code handling the nasty bits.

For Windows, this is just a simple conversion of modifiers and keys followed by a call to RegisterHotKey API:

Code
bool nativeRegisterHotkey(Qt::Key key, Qt::KeyboardModifiers modifiers) {
uint modValue = 0;
if (modifiers & Qt::AltModifier) { modValue += MOD_ALT; }
if (modifiers & Qt::ControlModifier) { modValue += MOD_CONTROL; }
if (modifiers & Qt::ShiftModifier) { modValue += MOD_SHIFT; }

uint keyValue;
if (((key >= Qt::Key_A) && (key <= Qt::Key_Z)) || ((key >= Qt::Key_0) && (key <= Qt::Key_9))) {
keyValue = key;
} else if ((key >= Qt::Key_F1) && (key <= Qt::Key_F24)) {
keyValue = VK_F1 + (key - Qt::Key_F1);
} else {
return false; //unsupported key
}

return RegisterHotKey(nullptr, _hotkeyId, modValue, keyValue);
}
&#91;/type&#93;

But this alone is nothing without actual <a href="https://doc.qt.io/qt-5/qabstractnativeeventfilter.html">QAbstractNativeEventFilter</a>-based event filter. Here we need to intercept message and emit the signal:
[type title="Code"]
bool nativeEventFilter(const QByteArray&, void* message, long*) {
MSG* msg = static_cast<MSG*>(message);
if (msg->message == WM_HOTKEY) {
if (msg->wParam == static_cast<WPARAM>(_hotkeyId)) {
emit activated();
return true;
}
}
return false;
}

Mind you, this is a rather incomplete and simplified example. Full code (supporting both Windows and Linux) is available for download.

To use it, just assign instance to a long living variable, register a key sequence, and hook into activated signal:

Code
_hotkey = new Hotkey();
_hotkey->registerHotkey(QKeySequence { "Ctrl+Shift+F1" });
connect(_hotkey, SIGNAL(activated()), this, SLOT(onActivated()));

PS: X11 variant of this code is available here.

One thought to “Implementing Global Hotkey Support in QT on Windows”

  1. Hello Jossip,

    Thx for the code.
    I’m not a programer and I got three error message when using your .cpp and .h
    1) In the .h

    protected:
    bool nativeEventFilter(const QByteArray& eventType, void* message, long* result) override;

    Got this message : Non-virtual member function marked ‘override’ hides virtual member function

    2) In .cpp :

    auto key = Qt::Key(keySequence[0] & static_cast(~Qt::KeyboardModifierMask));
    auto modifiers = Qt::KeyboardModifiers(keySequence[0] & static_cast(Qt::KeyboardModifierMask));

    Got this message for the two declaration : ‘operator int’ is deprecated: Use QKeyCombination instead of int

    I will really appreciate if you could update this, or give me the solution.
    Best wishes.

Leave a Reply

Your email address will not be published. Required fields are marked *