Evgenii Legotckoi
3 января 2016 г. 22:35

Qt WinAPI - Урок 005. Глобальный HotKey WinAPI в Qt 5

Для работы с глобальными HotKey в Qt 5 присутствует виртуальный метод nativeEvent . Данный метод заменил методы winEvent , x11Event , macEvent из Qt 4.8.

Фишка в работе HotKey с Qt заключается в том, что если окно находится не в фокусе, то есть оно, например, будет свёрнуто в системный трей, то тогда зарегистрированные QShortcut работать просто не будут. Поэтому необходимо работать с глобальными событиями от операционной системы, то есть перейти к реализации платформозависимой части кода в приложении на Qt.

RegisterHotKey

В данном примере разберём вариант работы с WinAPI . Для этого воспользуемся функцией RegisterHotKey.

  1. BOOL WINAPI RegisterHotKey(
  2. _In_opt_ HWND hWnd,
  3. _In_ int id,
  4. _In_ UINT fsModifiers,
  5. _In_ UINT vk
  6. );

Параметры 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

Отключение сочетания горячих клавиш.

  1. BOOL WINAPI UnregisterHotKey(
  2. _In_opt_ HWND hWnd,
  3. _In_ int id
  4. );

Параметры UnregisterHotKey

hWnd [in, optional]

Тип: HWND
Обработчик окна ассоциированный с горячей клавишей, который должен быть освобождён. Этот параметр должен быть NULL, если не ассоциирован с окном.

id [in]

Тип: int
Идентификатор сочетания горячих клавиш, который должен быть освобождён.

Пример работы с HotKey в WinAPI

Создадим проект для работы с HotKey. В данном проекте будет присутствовать объект класса QSystemTrayIcon. Будем скрывать приложение в системный трей и проверять сочетание горячих клавиш. Таким сочетанием будет "ALT+SHIFT+D" , например. В данном проекте обработчиком горячих клавиш будет MainWindow. Обработка сочетания горячих клавиш будет производиться в nativeEvent.

Проверку на сочетание выбранных горячих клавиш будем производить с помощью qDebug().

mainwindow.h

  1. #ifndef MAINWINDOW_H
  2. #define MAINWINDOW_H
  3.  
  4. #include <QMainWindow>
  5. #include <QSystemTrayIcon>
  6. #include "windows.h" // Подключаем библиотеку WinAPI
  7.  
  8. namespace Ui {
  9. class MainWindow;
  10. }
  11.  
  12. class MainWindow : public QMainWindow
  13. {
  14. Q_OBJECT
  15.  
  16. public:
  17. explicit MainWindow(QWidget *parent = 0);
  18. ~MainWindow();
  19.  
  20. protected:
  21. // Метод для обработки native событий от ОС в Qt
  22. bool nativeEvent(const QByteArray &eventType, void *message, long *result);
  23.  
  24. private slots:
  25. void iconActivated(QSystemTrayIcon::ActivationReason reason);
  26.  
  27. private:
  28. Ui::MainWindow *ui;
  29. QSystemTrayIcon *trayIcon;
  30. };
  31.  
  32. #endif // MAINWINDOW_H

mainwindow.cpp

  1. #include "mainwindow.h"
  2. #include "ui_mainwindow.h"
  3. #include <QDebug>
  4.  
  5. MainWindow::MainWindow(QWidget *parent) :
  6. QMainWindow(parent),
  7. ui(new Ui::MainWindow)
  8. {
  9. ui->setupUi(this);
  10. /* Иконка системного трея нужна для того, чтобы
  11. * окно приложения было не в фокусе
  12. * */
  13. trayIcon = new QSystemTrayIcon(this);
  14. trayIcon->setIcon(this->style()->standardIcon(QStyle::SP_ComputerIcon));
  15. trayIcon->show();
  16.  
  17. connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
  18. this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
  19.  
  20. // Регистрируем HotKey "ALT+SHIFT+D"
  21. RegisterHotKey((HWND)MainWindow::winId(), // Устанавливаем системный идентификатор окна виджета, который будет обрабатывать HotKey
  22. 100, // Устанавливаем идентификатор HotKey
  23. MOD_ALT | MOD_SHIFT, // Устанавливаем модификаторы
  24. 'D'); // Определяем Горячую Клавишу для HotKey
  25. }
  26.  
  27. MainWindow::~MainWindow()
  28. {
  29. delete ui;
  30. }
  31.  
  32. bool MainWindow::nativeEvent(const QByteArray &eventType, void *message, long *result)
  33. {
  34. Q_UNUSED(eventType)
  35. Q_UNUSED(result)
  36. // Преобразуем указатель message в MSG WinAPI
  37. MSG* msg = reinterpret_cast<MSG*>(message);
  38.  
  39. // Если сообщение является HotKey, то ...
  40. if(msg->message == WM_HOTKEY){
  41. // ... проверяем идентификатор HotKey
  42. if(msg->wParam == 100){
  43. // Сообщаем об этом в консоль
  44. qDebug() << "HotKey worked";
  45. return true;
  46. }
  47. }
  48. return false;
  49. }
  50.  
  51. void MainWindow::iconActivated(QSystemTrayIcon::ActivationReason reason)
  52. {
  53. switch (reason){
  54. case QSystemTrayIcon::Trigger:
  55. !isVisible() ? show() : hide();
  56. break;
  57. default:
  58. break;
  59. }
  60. }

Примечание

Для того, чтобы проект скомпилировался с комплектом сборки MSVC, добавьте в pro файл проекта следующие строки:

  1. win32-msvc*{
  2. LIBS += -luser32
  3. }

Итог

В результате работы данного программного кода будет производиться обработка глобального сочетания горячих клавиш даже в том случае, если окно приложения будет скрыто в лоток системного трея. Демонстрацию работы приложения можно увидеть в видеоуроке.

Видеоурок

Вам это нравится? Поделитесь в социальных сетях!

Комментарии

Только авторизованные пользователи могут публиковать комментарии.
Пожалуйста, авторизуйтесь или зарегистрируйтесь