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% ықтималдықпен бұл кілтті ұстай алмайсыз. немесе қалай - оны бұл жылдам пернені басқа жолмен босатуға мәжбүрлемеңіз.