Evgenii Legotckoi
Evgenii LegotckoiАқп. 28, 2016, 10:17 Т.Ж.

Qt Linux - 002-сабақ. Qt 5 қолданбасындағы Linux жүйесіндегі ғаламдық жылдам кілт

Windows жүйесіндегі ғаламдық жылдам пернелермен жұмыс істеу Linux жүйесіне қарағанда тривиальды тапсырма болып табылады, өйткені WinAPI бұл үшін көп соманы қажет етпейтін әдістерді дайындаған. кодының. Сондай-ақ әрбір жылдам пернеге ID тағайындалады, ол арқылы осы жылдам пернені жоюға болады.

Qt-ге қатысты X11, графикалық серверін пайдаланатын Linux/Unix жүйесінде XLib, кітапханасынан жылдам пернелерді тіркеу/тіркеуден шығару функцияларын пайдалану керек, бірақ нәтиже мәндерін өңдеу керек. XLib кітапханасының аналогы ретінде жасалған, бірақ деңгейі төменірек және C бағдарламалау тілінде жазылған XCB, кітапхана функционалдығын * пайдалану. Windows* жағдайындағыдай, Qt 5.5 жүйесінде жаһандық жылдам пернелерді өңдеу үшін nativeEventFilter әдісі пайдаланылады. Жылдам пернелерді өңдеу үшін QAbstractNativeEventFilter ішінен мұраланған бөлек класс жасауды және осы сүзгіні бүкіл қолданбаға орнатуды ұсынамын.

Жылдам пернелерді орнату үшін XKeysymToKeycode (KeySym тізбегінен кілт кодын алу үшін) және XGrabKey функциялары /post /170/) (жылдам пернені орнату үшін).

Жылдам пернені тіркеуден шығару үшін XUngrabKey функциясы пайдаланылады.

Жоба құрылымы

  • GlobalHotkeyLinux.pro - жоба профилі;
  • mainwindow.h - қолданбаның негізгі терезесінің тақырып файлы;
  • mainwindow.cpp - қолданбаның негізгі терезесі үшін бастапқы код файлы;
  • mainwindow.ui - қолданбаның негізгі терезесінің пішін файлы;
  • main.cpp - негізгі бастапқы код файлы;
  • nativeeventfilter.h - жылдам перне оқиғасы сүзгісінің тақырып файлы;
  • nativeeventfilter.cpp - жылдам перне оқиғасы сүзгісі үшін бастапқы код файлы.

GlobalHotkeyLinux.pro

Qt ішіндегі X11 терезе серверінен оқиғалар туралы ақпаратты алу үшін QX11Info класы пайдаланылатынына және оны пайдалану үшін x11extras модулін қосу керек екеніне назар аударамын, бірақ бұл жеткіліксіз болуы мүмкін. , өйткені стандартты Qt5.5 дистрибутивінде бұл жай ғана кітапхана болмайды, сондықтан оларды келесі пәрменмен орнату қажет:

sudo apt-get install qtx11extras5-dev-tools

Сонымен қатар, xcb және xlib кітапханаларымен жұмыс істеу үшін X11 ескере отырып жоба конфигурациясын көрсету қажет:

CONFIG    += link_pkgconfig
PKGCONFIG += x11

Содан кейін біз келесі мазмұндағы профильді аламыз.

#-------------------------------------------------
#
# 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

жергілікті оқиға сүзгісі.h

Qt-де қолданба терезелеріне, құрамдастарға немесе бүкіл қолданбаға бірден орнатуға болатын оқиға сүзгі сыныптары бар, өйткені біз бұл жолы орындаймыз. Ол үшін Qt қолданбасы іске қосылған операциялық жүйеден оқиғаларды қабылдауға қызмет ететін QAbstractNativeEventFilter ішінен мұрагер класс жасау керек. Жылдам пернені өңдейтін natvieEventFilter әдісін қайта анықтайық, сонымен қатар екі әдісті жасайық: біреуі жылдам пернені орнату үшін, екіншісі оны өшіру үшін.

#ifndef NATIVEEVENTFILTER_H
#define NATIVEEVENTFILTER_H

#include <QObject>
#include <QAbstractNativeEventFilter>

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

    // переопределяем метод nativeEventFilter
    bool nativeEventFilter(const QByteArray &eventType, void *message, long *result);
    void setShortcut();     // Добавляем метод установки хоткея
    void unsetShortcut();   // и метод удаления хоткея для полноты картины

signals:
    void activated();

public slots:
};

#endif // NATIVEEVENTFILTER_H

nativeeventfilter.cpp

Сүзгі жасаудың мәні мынада: біз XLib кітапханасының көмегімен жылдам пернені оңай тіркей аламыз, ал XCB кітапханасы арқылы оқиғаларды талдауға тура келеді, өйткені X11 деректерін алатын Qt олар туралы Xlib тұрғысынан түсінбейді, бірақ бұл деректерді XCB сияқты түсінеді.

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

namespace
{
    Display * m_display;        // Соединение с сервером X11
    Window m_win;               // Захватываемое окно - в данном случае будет вся система
    int keycode;                // код клавиши
    unsigned int modifier;      // код модификаторов

    /* Вектор дополнительных модификаторов Num Lock, Caps lock
     * Они тоже учитываются в X11, поэтому понадобяться все возможные комбинации
     * */
    QVector<quint32> maskModifiers(){
        return QVector<quint32>() << 0 << Mod2Mask << LockMask << (Mod2Mask | LockMask);
    }
}

NativeEventFilter::NativeEventFilter(QObject *parent) : QObject(parent)
{
    m_display = QX11Info::display();        // Создадим подключение к серверу
    m_win = DefaultRootWindow(m_display);   // и вытащим из него захватываемое окно с помощью макроса
}

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

    /* В вот обработка события строится уже на библиотеке XCB вместо Xlib.
     * Вроде как, получая событие Qt знает его в качестве XCB события,
     * но не знает его в качестве события Xlib, хотя использовать более
     * легкий синтаксис Xlib для установки хоткеев нам никто не запрещает
     * */
    xcb_key_press_event_t *keyEvent = 0;

    // Итак проверяем, что это было xcb событие
    if (eventType == "xcb_generic_event_t") {
        // кастуем сообщение собственно в xcb событие
        xcb_generic_event_t *event = static_cast<xcb_generic_event_t *>(message);

        // проверяем, что произошло нажатие клавиши
        if ((event->response_type & 127) == XCB_KEY_PRESS){

            // Если так, то кастуем сообщение в событие нажатия клавиши
            keyEvent = static_cast<xcb_key_press_event_t *>(message);

            // Далее проверям, является ли это событие нужным хоткее
            foreach (quint32 maskMods, maskModifiers()) {
                if((keyEvent->state == (modifier | maskMods ))
                        &&  keyEvent->detail == keycode){
                    emit activated();   // и посылаем сигнал
                    return true;
                }
            }
        }
    }
    return false;
}

void NativeEventFilter::setShortcut()
{
    unsetShortcut();        /* Вначале для перестраховки отключим предполагаемый хоткей,
                             * даже несмотря на то, что будет мусор в первый раз в параметрах хоткея.
                             * */

    // получим код клавиши из KeySym определения и соединения с сервером X11
    keycode = XKeysymToKeycode(m_display, XK_E);
    modifier = ControlMask; // Зададим модификатор

    /* А теперь пройдемся по всем возможным комбинациям с учётом Num Lock и Caps Lock
     * устанавливая хоткеи
     * */
    foreach (quint32 maskMods, maskModifiers()) {
        XGrabKey(m_display,         // указываем соединение с X11
                 keycode ,          // код клавиши
                 modifier | maskMods,   // модификатор со всеми возможными масками
                 m_win,             // Захватываемое окно
                 True,              // Является ли приложение владельцем события. в данном примере не принципиально.
                 GrabModeAsync,     // Обязательно Ассинхронный режим обработки, иначе, рискуете встрять
                 GrabModeAsync);    // с замороженной системой, не реагирующей ни на какие воздействия, если
                                    // заранее не напишите корректную передачу события обратно в систему,
                                    // а скорее всего так и будет
    }
}

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

mainwindow.h

Қолданбаның тақырып файлында ерекше ештеңе көрмейміз. Тек сигналды қабылдауға арналған слот және осы сигналды беретін сүзгінің өзі.

#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

Тек сүзгіні инициализациялау, оны бүкіл қолданбаға орнату, сигналды оқиға өңдегіш ұясына қосу және жылдам пернені орнату қалды. Осылайша, Linux үшін Qt қолданбасы үшін жаһандық жылдам перненің жұмыс нұсқасын аламыз.

#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);    // Инициализируем фильтр
    qApp->installNativeEventFilter(nativeEventFilter);  // Устанавилваем его на приложение
    // подключаем сигнал фильтра к слоту
    connect(nativeEventFilter, &NativeEventFilter::activated, this, &MainWindow::slotGlobalHotkey);
    nativeEventFilter->setShortcut();   // Устанавилваем хоткей
}

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

void MainWindow::slotGlobalHotkey()
{
    // И сообщаем пользователю, если он нажал нужный нам HotKey
    QMessageBox::information(this,"Global Hotkey", "Global Hotkey is worked", QMessageBox::Ok);
}

Жоба мұрағаты: GlobalHotkeyLinux

Барлығы

Нәтижесінде біз Ctrl+E жаһандық жылдам пернелеріне жауап беретін қолданбаны аламыз және қолданбаны кішірейтсеңіз немесе басқа қолданбамен жұмыс істесеңіз де жылдам перне жұмыс істейтіні туралы хабарды көрсетеміз. Тек PrintScreen пернесін басуға тырыспаңыз. Бұл, ең алдымен, жұмыс істемейді. Себебі, кейбір жылдам пернені түсіріп көру үшін XGrabKey пайдаланған кезде, ол кез келген басқа клиент қолданбасы осы жылдам пернені әлі басып алмаған жағдайда ғана түсіріледі. мақсатты түсірілген терезе. Егер сіз сол Ubuntu дистрибутивінде PrintScreen пернесіне ғана әрекет ететін скриншоттарды жасауға арналған қолданба бар деп есептесеңіз, онда сіз бұл бағдарламаны жоймайынша, 100% ықтималдықпен бұл кілтті ұстай алмайсыз. немесе қалай - оны бұл жылдам пернені басқа жолмен босатуға мәжбүрлемеңіз.

Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Ол саған ұнайды ма? Әлеуметтік желілерде бөлісіңіз!

Пікірлер

Тек рұқсаты бар пайдаланушылар ғана пікір қалдыра алады.
Кіріңіз немесе Тіркеліңіз
Г

C++ - Тест 001. Первая программа и типы данных

  • Нәтиже:66ұпай,
  • Бағалау ұпайлары-1
t

C++ - Тест 001. Первая программа и типы данных

  • Нәтиже:33ұпай,
  • Бағалау ұпайлары-10
t

Qt - Тест 001. Сигналы и слоты

  • Нәтиже:52ұпай,
  • Бағалау ұпайлары-4
Соңғы пікірлер
G
GoattRockҚыр. 3, 2024, 10:50 Т.Ж.
Linux жүйесінде файлдарды қалай көшіруге болады Задумывались когда-нибудь о том, как мы привыкли доверять свои вещи службам грузоперевозок? Сейчас такие услуги стали неотъемлемой частью нашей жизни, особенно когда речь идет о переездах между …
d
dblas5Шілде 5, 2024, 8:02 Т.Ж.
QML - Сабақ 016. SQLite деректер қоры және онымен QML Qt-та жұмыс істеу Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
k
kmssrАқп. 8, 2024, 3:43 Т.Қ.
Qt Linux - Сабақ 001. Linux астында Autorun Qt қолданбасы как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
АК
Анатолий КононенкоАқп. 4, 2024, 10:50 Т.Қ.
Qt WinAPI - Сабақ 007. Qt ішінде ICMP Ping арқылы жұмыс істеу Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
Енді форумда талқылаңыз
Evgenii Legotckoi
Evgenii LegotckoiМаусым 24, 2024, 12:11 Т.Қ.
добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
F
FynjyШілде 22, 2024, 1:15 Т.Ж.
при создании qml проекта Kits есть но недоступны для выбора Поставил Qt Creator 11.0.2. Qt 6.4.3 При создании проекта Qml не могу выбрать Kits, они все недоступны, хотя настроены и при создании обычного Qt Widget приложения их можно выбрать. В чем может …
BlinCT
BlinCTМаусым 24, 2024, 10 Т.Қ.
Нарисовать кривую в qml Всем привет. Имеется Лист листов с тосками, точки получаны интерполяцией Лагранжа. Вопрос, как этими точками нарисовать кривую? ChartView отпадает сразу, в qt6.7 появился новый элемент…
BlinCT
BlinCTМамыр 5, 2024, 2:46 Т.Ж.
Написать свой GraphsView Всем привет. В Qt есть давольно старый обьект дял работы с графиками ChartsView и есть в 6.7 новый но очень сырой и со слабым функционалом GraphsView. По этой причине я хочу написать х…
Evgenii Legotckoi
Evgenii LegotckoiМамыр 2, 2024, 11:07 Т.Ж.
Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Добрый день. По моему мнению - да, но то, что будет касаться вызовов к функционалу Андроида, может создать огромные трудности.

Бізді әлеуметтік желілерде бақылаңыз