If your application needs a global hotkey support, QT will leave you hanging. Fortunately, on high-level this is a rather simple function:
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:
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);
}
But this alone is nothing without actual QAbstractNativeEventFilter-based event filter. Here we need to intercept message and emit the signal:
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:
_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.