Evgenii Legotckoi
Evgenii LegotckoiFeb. 28, 2016, 10:17 a.m.

Qt Linux - Lesson 002. Global HotKey in Linux

Work with the global keyboard hot keys in Windows is a trivial task than Linux, since this has WinAPI prepared methods that do not require a large amount of code. And each hotkey is set in line ID, in which the hot key can be removed.

In Linux / Unix, which uses the graphics server is the X11, with respect to Qt must use the function to register / unregister hotkeys from XLib library, but the process has to the values ​​obtained using XCB library functionality, which is being developed as an analogue XLib library, but is more low-level and written the C programming language. As in the case of Windows, for processing in the global hotkeys Qt 5 nativeEventFilter used method. I propose to make a separate class, inherited from QAbstractNativeEventFilter for processing hotkeys and set the filter to the entire application.

To set hotkeys to be used XKeysymToKeycode (to get the keys from KeySym sequence of code) and XGrabKey (to set the hotkey).

XUngrabKey function will be used for unregistration hotkey.

Project structure

  • GlobalHotkeyLinux.pro - the profile of the project;
  • mainwindow.h - header file of the main application window;
  • mainwindow.cpp - file source code of the main application window;
  • mainwindow.ui - file forms the main application window;
  • main.cpp - the main source file;
  • nativeeventfilter.h - header event filter file hotkeys;
  • nativeeventfilter.cpp - file source hotkeys event filter.

GlobalHotkeyLinux.pro

I draw your attention to the fact that in order to obtain information about the events of the X11 window server using Qt QX11Info class, and to use it you need to connect x11extras unit, but that may not be enough, as in the standard package Qt5 these libraries simply will not , so they will need to install the following command:

sudo apt-get install qtx11extras5-dev-tools

In addition to work with libraries and xcb xlib you will need to specify the configuration of the project in view of X11:

CONFIG    += link_pkgconfig
PKGCONFIG += x11

Then we get the profile with the following contents.

#-------------------------------------------------
#
# Project created by QtCreator 2016-02-12T23:41:57
#
#-------------------------------------------------

QT       += core gui
QT       += x11extras

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG    += c++11
CONFIG    += link_pkgconfig
PKGCONFIG += x11

TARGET = GlobalHotkeyLinux
TEMPLATE = app


SOURCES += main.cpp\
        mainwindow.cpp \
    nativeeventfilter.cpp

HEADERS  += mainwindow.h \
    nativeeventfilter.h

FORMS    += mainwindow.ui

nativeeventfilter.h

In Qt, there are event filters classes that can be installed on the application window, or components directly on the entire application as we did this time. To do this, you need to create a class inherited from QAbstractNativeEventFilter, which is used to receive events from the operating system, which runs the application on Qt. Override the method natvieEventFilter, which will process and hotkey, and we make two methods: one to set the hotkey, and the second to turn it off.

#ifndef NATIVEEVENTFILTER_H
#define NATIVEEVENTFILTER_H

#include <QObject>
#include <QAbstractNativeEventFilter>

class NativeEventFilter : public QObject, public QAbstractNativeEventFilter
{
    Q_OBJECT
public:
    explicit NativeEventFilter(QObject *parent = 0);

    bool nativeEventFilter(const QByteArray &eventType, void *message, long *result);
    void setShortcut();     
    void unsetShortcut();   

signals:
    void activated();

public slots:
};

#endif // NATIVEEVENTFILTER_H

nativeeventfilter.cpp

The whole point of creating a filter that we easily can register a hotkey using XLib library, while dismantling events have with XCB library because the Qt, receiving data from the X11, has no idea about them in the context of Xlib, and understand this data how XCB.

#include "nativeeventfilter.h"
#include <QVector>
#include <QX11Info>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <xcb/xcb.h>

namespace
{
    Display * m_display;        // Connect to Server X11
    Window m_win;               // Grabing window - in this case, the entire system will be
    int keycode;               
    unsigned int modifier;     

    /* Vector additional modifiers Num Lock, Caps lock
      * They are also taken into account in X11, you therefore need all the possible combinations
     * */
    QVector<quint32> maskModifiers(){
        return QVector<quint32>() << 0 << Mod2Mask << LockMask << (Mod2Mask | LockMask);
    }
}

NativeEventFilter::NativeEventFilter(QObject *parent) : QObject(parent)
{
    m_display = QX11Info::display();        // Create a connection to the server
    m_win = DefaultRootWindow(m_display);   // and pull out of it captured by the window with a macro
}

bool NativeEventFilter::nativeEventFilter(const QByteArray &eventType, void *message, long *result)
{
    Q_UNUSED(eventType)
    Q_UNUSED(result)

    /* But event handling is built on the library instead of Xlib XCB.
     * Kind of like getting Qt event knows it as XCB events,
     * but does not know it as an event Xlib, although used more
     * Xlib easy syntax to set the hotkeys no one forbids us
     * */
    xcb_key_press_event_t *keyEvent = 0;

    //So we check that it was xcb event
    if (eventType == "xcb_generic_event_t") {
        // cast message xcb event
        xcb_generic_event_t *event = static_cast<xcb_generic_event_t *>(message);

        // check that a keystroke occurred
        if ((event->response_type & 127) == XCB_KEY_PRESS){

            // If so, then cast message keypress event
            keyEvent = static_cast<xcb_key_press_event_t *>(message);

            // Next, check whether it is necessary to hotkeys event
            foreach (quint32 maskMods, maskModifiers()) {
                if((keyEvent->state == (modifier | maskMods ))
                        &&  keyEvent->detail == keycode){
                    emit activated();   // and send a signal
                    return true;
                }
            }
        }
    }
    return false;
}

void NativeEventFilter::setShortcut()
{
    unsetShortcut();        /* First to alleged reinsurance disable hotkey,
                             * Despite the fact that the waste will be the first time in the parameters hotkey.
                             * */

    // get the key code of KeySym identify and connect to the X11 server
    keycode = XKeysymToKeycode(m_display, XK_E);
    modifier = ControlMask; // Зададим модификатор

    /* Now we go through all the possible combinations in view of Num Lock and Caps Lock, setting hotkeys
     * */
    foreach (quint32 maskMods, maskModifiers()) {
        XGrabKey(m_display,         // specify the connection to the X11
                 keycode ,          // keycode
                 modifier | maskMods,   // modifier with all the masks
                 m_win,             // grabing window
                 True,              // It is the owner of the application event. in this example it is not essential.
                 GrabModeAsync,     // Be sure to asynchronous processing mode, otherwise, risk of freeze system
                 GrabModeAsync);    
    }
}

void NativeEventFilter::unsetShortcut()
{
    // Проходим по всем возможным комбинациям и удаляем хоткей
    foreach (quint32 maskMods, maskModifiers()) {
        XUngrabKey(m_display,
                   keycode,
                   modifier | maskMods,
                   m_win);
    }
}

mainwindow.h

The header file applications do not see anything special. Only a slot for receiving the signal and the filter itself, which will give the signal.

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "nativeeventfilter.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void slotGlobalHotkey();

private:
    Ui::MainWindow *ui;
    NativeEventFilter *nativeEventFilter;
};

#endif // MAINWINDOW_H

mainwindow.cpp

All that remains to do is to initialize the filter, set it to the entire application, connect the signal to the slot of the event handler and set the hotkey. Thus we get a working version of a global hotkey for Qt apps for linux.

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QApplication>
#include <QMessageBox>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    nativeEventFilter = new NativeEventFilter(this);    // Initialize filter
    qApp->installNativeEventFilter(nativeEventFilter);  // Install it on an application
    // connect the filter signal to a slot
    connect(nativeEventFilter, &NativeEventFilter::activated, this, &MainWindow::slotGlobalHotkey);
    nativeEventFilter->setShortcut();   // Устанавилваем хоткей
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::slotGlobalHotkey()
{
    // And informs the user if he want us to hit HotKey
    QMessageBox::information(this,"Global Hotkey", "Global Hotkey is worked", QMessageBox::Ok);
}

Archive of the project: GlobalHotkeyLinux

Result

The result is an application that will respond to the global hotkey Ctrl + E and display a message that the hot key is working, even if you will roll application or will be working with another application. Just do not try to capture the pressing PrintScreen key. It will not work most likely. The reason is that when using XGrabKey try to capture some hot key, it will be captured only in the case if any other client application that has not captured the gripper hotkey on the target window. And when you consider that in the same distro Ubuntu already have an application to create screenshots, which just reacts to the PrintScreen key, you with 100% probability will not be able to intercept this key until you will kill this program, or any other way not force it to release the hotkey.

We recommend hosting TIMEWEB
We recommend hosting TIMEWEB
Stable hosting, on which the social network EVILEG is located. For projects on Django we recommend VDS hosting.

Do you like it? Share on social networks!

Comments

Only authorized users can post comments.
Please, Log in or Sign up
г
  • ги
  • April 24, 2024, 1:51 a.m.

C++ - Test 005. Structures and Classes

  • Result:41points,
  • Rating points-8
l
  • laei
  • April 23, 2024, 7:19 p.m.

C ++ - Test 004. Pointers, Arrays and Loops

  • Result:10points,
  • Rating points-10
l
  • laei
  • April 23, 2024, 7:17 p.m.

C++ - Тест 003. Условия и циклы

  • Result:50points,
  • Rating points-4
Last comments
k
kmssrFeb. 9, 2024, 5:43 a.m.
Qt Linux - Lesson 001. Autorun Qt application under Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
Qt WinAPI - Lesson 007. Working with ICMP Ping in Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
EVA
EVADec. 25, 2023, 9:30 p.m.
Boost - static linking in CMake project under Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
J
JonnyJoDec. 25, 2023, 7:38 p.m.
Boost - static linking in CMake project under Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
G
GvozdikDec. 19, 2023, 8:01 a.m.
Qt/C++ - Lesson 056. Connecting the Boost library in Qt for MinGW and MSVC compilers Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
Now discuss on the forum
G
GarApril 22, 2024, 3:46 p.m.
Clipboard Как скопировать окно целиком в clipb?
DA
Dr Gangil AcademicsApril 20, 2024, 5:45 p.m.
Unlock Your Aesthetic Potential: Explore MSC in Facial Aesthetics and Cosmetology in India Embark on a transformative journey with an msc in facial aesthetics and cosmetology in india . Delve into the intricate world of beauty and rejuvenation, guided by expert faculty and …
a
a_vlasovApril 14, 2024, 4:41 p.m.
Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Евгений, добрый день! Такой вопрос. Верно ли следующее утверждение: Любое Android-приложение, написанное на Java/Kotlin чисто теоретически (пусть и с большими трудностями) можно написать и на C+…
Павел Дорофеев
Павел ДорофеевApril 14, 2024, 12:35 p.m.
QTableWidget с 2 заголовками Вот тут есть кастомный QTableView с многорядностью проект поддерживается, обращайтесь
f
fastrexApril 4, 2024, 2:47 p.m.
Вернуть старое поведение QComboBox, не менять индекс при resetModel Добрый день! У нас много проектов в которых используется QComboBox, в версии 5.5.1, когда модель испускает сигнал resetModel, currentIndex не менялся. В версии 5.15 при resetModel происходит try…

Follow us in social networks