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
AD

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

  • Result:50points,
  • Rating points-4
m

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

  • Result:80points,
  • Rating points4
m

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

  • Result:20points,
  • Rating points-10
Last comments
Evgenii Legotckoi
Evgenii LegotckoiNov. 1, 2024, 12:37 a.m.
Django - Lesson 064. How to write a Python Markdown extension Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
A
ALO1ZEOct. 19, 2024, 6:19 p.m.
Fb3 file reader on Qt Creator Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
ИМ
Игорь МаксимовOct. 5, 2024, 5:51 p.m.
Django - Lesson 064. How to write a Python Markdown extension Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas5July 5, 2024, 9:02 p.m.
QML - Lesson 016. SQLite database and the working with it in QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
k
kmssrFeb. 9, 2024, 5:43 a.m.
Qt Linux - Lesson 001. Autorun Qt application under Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
Now discuss on the forum
Evgenii Legotckoi
Evgenii LegotckoiJune 25, 2024, 1:11 a.m.
добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
t
tonypeachey1Nov. 15, 2024, 5:04 p.m.
google domain [url=https://google.com/]domain[/url] domain [http://www.example.com link title]
NSProject
NSProjectJune 4, 2022, 1:49 p.m.
Всё ещё разбираюсь с кешем. В следствии прочтения данной статьи. Я принял для себя решение сделать кеширование свойств менеджера модели LikeDislike. И так как установка evileg_core для меня не была возможна, ибо он писался…
9
9AnonimOct. 25, 2024, 7:10 p.m.
Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…

Follow us in social networks