Для роботи з глобальними HotKey у Qt 5 присутній віртуальний метод nativeEvent . Цей метод замінив методи winEvent , x11Event , macEvent з Qt 4.8.
Фішка в роботі HotKey з Qt полягає в тому, що якщо вікно знаходиться не у фокусі, тобто воно, наприклад, буде згорнуто в системний трей, тоді зареєстровані QShortcut працювати просто не будуть . Тому необхідно працювати з глобальними подіями від операційної системи, тобто перейти до реалізації платформозалежної частини коду у додатку на Qt.
Зареєструвати HotKey
У цьому прикладі розберемо варіант роботи з WinAPI . Для цього скористаємося функцією RegisterHotKey.
BOOL WINAPI RegisterHotKey( _In_opt_ HWND hWnd, _In_ int id, _In_ UINT fsModifiers, _In_ UINT vk );
Параметри RegisterHotKey
hWnd [в, необов'язково]
Тип:
HWND
Обробник вікна, яке прийматиме повідомлення
WM_HOTKEY
, які генеруватимуться гарячою клавішею.
id [в]
Тип:
int
Ідентифікатор гарячих кнопок. Якщо
hWnd
параметр є NULL, тоді гарячі клавіші асоціюються з потоком, а не з конкретним вікном.
fsModifiers [в]
Тип:
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 [в]
Тип:
UINT
Код віртуальних кнопок для HotKey.
Скасувати реєстрацію HotKey
Вимкнення поєднання гарячих клавіш.
BOOL WINAPI UnregisterHotKey( _In_opt_ HWND hWnd, _In_ int id );
Параметри UnregisterHotKey
hWnd [в, необов'язково]
Тип:
HWND
Обробник вікна асоційований із гарячою клавішею, який має бути звільнений. Цей параметр має бути NULL, якщо не асоційований із вікном.
id [в]
Тип:
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, додайте до файлу проекту наступні рядки:
win32-msvc*{ LIBS += -luser32 }
Підсумок
В результаті роботи даного програмного коду буде оброблятися глобальне поєднання гарячих клавіш навіть у тому випадку, якщо вікно програми буде приховано в лоток системного трею. Демонстрацію роботи програми можна побачити у відеоуроці.