MyTetra Share
Делитесь знаниями!
Гадания. Коррекция судьбы: толкование снов.
C++ и Qt - Глобальные клавиши (hotkeys) в X11, Windows, MacOS
20.03.2016
22:41
Текстовые метки: qt, c++, клавиши, клавиатура
Раздел: Компьютер - Программирование - Язык C++ - Библиотека Qt - Принципы написания кода

Эта тема очень интересная, поэтому именно ей я посвящу этот топик после длительного молчания =). Думаю, за свою практику программисту не может не потребоваться использование глобальных клавиш (hotkeys, shortcuts) в приложении. Благодаря им пользователь может сэкономить своё бессценное время, да и функционал программы повышается. Моей задачей было найти способ регистрирования в системе комбанации клавиш и их дальнейшее транслирование. Задача не очень тяжелая, если выполнять под конретную ОС, а вот сделать кроссплатформенность уже не так легко, нужно учесть некоторые факторы.

Давайте возьмемся за X11.


Существует функция XGrabKey, с помощью которой и можно зарегистрировать сочетания клавиш в X11. Для её использования нужно подключить X11-headers. Вот пример кода, который должен работать:

01.#include <QtGui>

02.#include <QX11Info>

03.  

04.#include <X11/X.h>

05.#include <X11/Xlib.h>

06.#include <X11/keysym.h>

07.  

08.#ifdef KeyPress

09.const int XKeyPress   = KeyPress;

10.const int XKeyRelease = KeyRelease;

11.#undef KeyPress

12.#undef KeyRelease

13.#endif

14.  

15.class X11ShortCut :QMainWindow

16.{

17.    Q_OBJECT

18.  

19.public:

20.    X11ShortCut(QWidget *parent)

21.     : QMainWindow(parent)

22.    {

23.        qApp->installEventFilter(this);

24.  

25.        m_keyCode = XKeysymToKeycode(QX11Info::display(), XK_F11);

26.        XGrabKey(QX11Info::display(), m_keyCode, ControlMask|ShiftMask, QX11Info::appRootWindow(), False, GrabModeAsync, GrabModeAsync);

27.        XFlush(QX11Info::display());

28.    }

29.  

30.    ~X11ShortCut()

31.    {

32.        XUngrabKey(QX11Info::display(), m_keyCode, ControlMask|ShiftMask, QX11Info::appRootWindow());

33.    }

34.  

35.    bool X11ShortCut::eventFilter(QObject *, QEvent *event)

36.    {

37.        if(event->type() == QEvent::KeyPress) {

38.            QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);

39.            int qtKey = keyEvent->key();

40.            if(keyEvent->modifiers() == (Qt::ControlModifier|Qt::ShiftModifier) && qtKey == Qt::Key_F11) {

41.                insertPlainText("Ctrl+Shift+F11 pressed!\n");

42.                return false;

43.            }

44.        }

45.        return true;

46.    }

47.  

48.private:

49.    int m_keyCode;

50.};

Здесь и нечего комментировать.

m_keyCode = XkeysymToKeycode(QX11Info::display(), XK_F11);

Получаем код клавиши F11.

Далее регистрируем клавишу в системе с помощью главной функции — XGrabKey
В деструкторе сниманием хоткей. А далее у нас идет фильтр событий, где мы ожидаем известия о нажатии нужного нам сочетания. Более подробнее можно почитать здесь: http://www.xfree.org/current/XGrabKey.3.html

Теперь о регистрации «горячих» клавиш в OS Windows. Будем использовать WinApi. Суть та же, мы регистрируем комбинацию с помощью ф-ции WinApi RegisterHotKey() и ожидаем прибытия сообщения WM_HOTKEY (http://msdn.microsoft.com/en-us/library/ms646279(VS.85).aspx)

1.BOOL RegisterHotKey

2.(

3.        HWND hWnd,

4.        int id,

5.        UINT fsModifiers,

6.        UINT vk

7.);

hWnd — окно, которое должно получать сообщения о активировании глобальной комбинации

  • id — уникальный идентификатор, чтобы различать hotkeys между собой
    fsModifiers — модификаторы: MOD_ALT, MOD_CONTROL, MOD_SHIFT
  • vk — код виртуальной клавиши

1.#DEFINE HOTKEYHIDE 0x000001

2.RegisterHotKey(hwndMain,HOTKEYHIDE,MOD_CONTROL,VK_F12);

Как отлавливать сообщения я уже и не помню, это будет Вашим домашним заданием :D.

Ещё есть популярная ОС — MacOS, но под неё я ни разу ничего не программировал, поэтому и не раскажу. Читайте далее о кроссплатформенном решении.

-----8<-----

Так вот, понадобилось мне в одном проекте использовать hotkeys +программа кроссплатформенная, поэтому желательно было найти соответственный фреймворк. Гугл, как всегда, помог мне (хоть и потратил я немало времени). Есть отличное дополнение для Qt, которое называется libQxt (http://libqxt.org). Качаем от туда архив, ставим. Устанавливается это «сокровище» довольно легко:

./configure && make && make install

Единственное, я использую QtCreator. В его поставке идет «своя» утилита qmake, поэтому вам нужно её явно указать. Установка немного изменяется:

./configure -qmake-bin /home/%user%/%QtSDk%/qt/bin/qmake
make && make install

Для интеграции в проект нужно в .pro-файл дописать:

CONFIG += qxt
QXT += core gui

Документация здесь: http://doc.libqxt.org/.

Переходим к делу.

В версии 0.5, для использования глобальных клавиш, вам надо создавать объект QxtApplication, а не Qapplication. По словам разработчиков, в версии 0.6 они уберут эту зависимость. Поэтому файл main.cpp изменяется:

01.#include <QtGui/QApplication>

02.#include "mainwindow.h"

03.#include <QxtApplication>

04.int main(int argc, char *argv[])

05.{

06.    QxtApplication a(argc, argv);

07.    MainWindow w;

08.    w.show();

09.    return a.exec();

10.}

Далее переходим в класс MainWindow. В .h-файле дописываем:

01.#include <QxtGlobalShortcut>

02. 

03.class MainWindow : public QMainWindow

04.{

05. …

06.private:

07.   QString m_shortcutDef;

08.   QxtGlobalShortcut m_hotkeyHandle;

09. …

10.private slots:

11.   void hotkeyPressed();

12.}

в .cpp-файле:
В конструкторе инициализируем все:

1.m_shortcutDef = QString("Ctrl+Shift+X");

2.m_hotkeyHandle.setShortcut( QKeySequence(m_shortcutDef) );

3.m_hotkeyHandle.setEnabled(true);

4.connect( &m_hotkeyHandle, SIGNAL(activated()), this, SLOT(hotkeyPressed()) );

И, собственно, сам обработчик сообщения:

1.void MainWindow::hotkeyPressed()

2.{

3.  // Achtung

4.}

Вот и всё =). Этот код вы можете использовать для X11, Windows, MacOS.

Coach

Чёто как-то мудрёно у вас, мы использовали следующую комбинацию:

#ifndef _HOTKEYS_H
#define _HOTKEYS_H

#include

#define SHORTCUT_SHOW_HELP “F1″
#define SHORTCUT_SHOW_RUBRICATOR “Ctrl+1″

#endif

в отдельном *.h файле а в коде так:

createShortcut(shortCutHelp, “shortCutHelp”, SHORTCUT_SHOW_HELP, SLOT(on_shortCutHelp()));

писали на винде, но должно работать везде.

Так же в этом разделе:
← Содержание ...
 
MyTetra Share v.0.35
Яндекс индекс цитирования