Для работы с глобальными HotKey в Qt 5 присутствует виртуальный метод nativeEvent . Данный метод заменил методы winEvent , x11Event , macEvent из Qt 4.8.
Фишка в работе HotKey с Qt заключается в том, что если окно находится не в фокусе, то есть оно, например, будет свёрнуто в системный трей, то тогда зарегистрированные QShortcut работать просто не будут. Поэтому необходимо работать с глобальными событиями от операционной системы, то есть перейти к реализации платформозависимой части кода в приложении на Qt.
RegisterHotKey
В данном примере разберём вариант работы с WinAPI . Для этого воспользуемся функцией RegisterHotKey.
BOOL WINAPI RegisterHotKey( _In_opt_ HWND hWnd, _In_ int id, _In_ UINT fsModifiers, _In_ UINT vk );
Параметры RegisterHotKey
hWnd [in, optional]
Тип:
HWND
Обработчик окна, которое будет принимать сообщения
WM_HOTKEY
, которые будут генерироваться горячей клавишей.
id [in]
Тип:
int
Идентификатор горячих клавиш. Если
hWnd
параметр является NULL, тогда горячие клавиши ассоциируются с текущим потоком, а не с конкретным окном.
fsModifiers [in]
Тип:
UINT
Клавиши модификаторы, которые должны быть нажаты в сочетании с указанной клавишей в
uVirtKey
параметре для создания сообщения
WM_HOTKEY.
fsModifiers
параметр может быть комбинацией следующих значений.
- MOD_ALT 0x0001 - Должна удерживаться клавиша ALT;
- MOD_CONTROL 0x0002 - Должна удерживаться клавиша CTRL;
- MOD_NOREPEAT 0x4000 - Изменяет поведение HotKey, чтобы клавиатура не генерировала несколько сообщений HotKey. В Windows Vista данный флаг не поддерживается.
- MOD_SHIFT 0x0004 - Должна удерживаться клавиша SHIFT;
- MOD_WIN 0x0008 - Должна удерживаться клавиша WINDOWS. Это клавиша с логотипом Windows.
vk [in]
Тип:
UINT
Код виртуальных клавиш для HotKey.
UnregisterHotKey
Отключение сочетания горячих клавиш.
BOOL WINAPI UnregisterHotKey( _In_opt_ HWND hWnd, _In_ int id );
Параметры UnregisterHotKey
hWnd [in, optional]
Тип:
HWND
Обработчик окна ассоциированный с горячей клавишей, который должен быть освобождён. Этот параметр должен быть NULL, если не ассоциирован с окном.
id [in]
Тип:
int
Идентификатор сочетания горячих клавиш, который должен быть освобождён.
Пример работы с HotKey в WinAPI
Создадим проект для работы с HotKey. В данном проекте будет присутствовать объект класса QSystemTrayIcon. Будем скрывать приложение в системный трей и проверять сочетание горячих клавиш. Таким сочетанием будет "ALT+SHIFT+D" , например. В данном проекте обработчиком горячих клавиш будет MainWindow. Обработка сочетания горячих клавиш будет производиться в nativeEvent.
Проверку на сочетание выбранных горячих клавиш будем производить с помощью qDebug().
mainwindow.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QSystemTrayIcon> #include "windows.h" // Подключаем библиотеку WinAPI namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); protected: // Метод для обработки native событий от ОС в Qt bool nativeEvent(const QByteArray &eventType, void *message, long *result); private slots: void iconActivated(QSystemTrayIcon::ActivationReason reason); private: Ui::MainWindow *ui; QSystemTrayIcon *trayIcon; }; #endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h" #include "ui_mainwindow.h" #include <QDebug> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); /* Иконка системного трея нужна для того, чтобы * окно приложения было не в фокусе * */ trayIcon = new QSystemTrayIcon(this); trayIcon->setIcon(this->style()->standardIcon(QStyle::SP_ComputerIcon)); trayIcon->show(); connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason))); // Регистрируем HotKey "ALT+SHIFT+D" RegisterHotKey((HWND)MainWindow::winId(), // Устанавливаем системный идентификатор окна виджета, который будет обрабатывать HotKey 100, // Устанавливаем идентификатор HotKey MOD_ALT | MOD_SHIFT, // Устанавливаем модификаторы 'D'); // Определяем Горячую Клавишу для HotKey } MainWindow::~MainWindow() { delete ui; } bool MainWindow::nativeEvent(const QByteArray &eventType, void *message, long *result) { Q_UNUSED(eventType) Q_UNUSED(result) // Преобразуем указатель message в MSG WinAPI MSG* msg = reinterpret_cast<MSG*>(message); // Если сообщение является HotKey, то ... if(msg->message == WM_HOTKEY){ // ... проверяем идентификатор HotKey if(msg->wParam == 100){ // Сообщаем об этом в консоль qDebug() << "HotKey worked"; return true; } } return false; } void MainWindow::iconActivated(QSystemTrayIcon::ActivationReason reason) { switch (reason){ case QSystemTrayIcon::Trigger: !isVisible() ? show() : hide(); break; default: break; } }
Примечание
Для того, чтобы проект скомпилировался с комплектом сборки MSVC, добавьте в pro файл проекта следующие строки:
win32-msvc*{ LIBS += -luser32 }
Итог
В результате работы данного программного кода будет производиться обработка глобального сочетания горячих клавиш даже в том случае, если окно приложения будет скрыто в лоток системного трея. Демонстрацию работы приложения можно увидеть в видеоуроке.