Created
April 1, 2022 08:42
-
-
Save pedrolcl/f26d6388657165b16434f4fb1a0c62b5 to your computer and use it in GitHub Desktop.
Native Event Filters for Keyboard Events in C++ Qt Application
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Native Event Filters for Keyboard Events | |
* Copyright © 2022 Pedro López-Cabanillas | |
* | |
* testnativefilters.pro: | |
* TEMPLATE = app | |
* QT += core gui widgets | |
* | |
* SOURCES += \ | |
* testnativefilters.cpp | |
* | |
* linux { | |
* CONFIG += link_pkgconfig | |
* PKGCONFIG += xcb | |
* } | |
*/ | |
#include <QAbstractNativeEventFilter> | |
#include <QApplication> | |
#include <QCheckBox> | |
#include <QDebug> | |
#include <QMainWindow> | |
#include <QKeyEvent> | |
#include <QLabel> | |
#include <QVBoxLayout> | |
#include <QWidget> | |
#if defined(Q_OS_WIN) | |
#include <windows.h> | |
#elif defined(Q_OS_LINUX) | |
#include <xcb/xcb.h> | |
#endif | |
class NativeFilter : public QAbstractNativeEventFilter | |
{ | |
public: | |
#if QT_VERSION < QT_VERSION_CHECK(6,0,0) | |
virtual bool nativeEventFilter(const QByteArray &eventType, void *message, long*) override | |
#else | |
virtual bool nativeEventFilter(const QByteArray &eventType, void *message, qintptr*) override | |
#endif | |
{ | |
if (eventType == "xcb_generic_event_t") { | |
#if defined(Q_OS_LINUX) | |
xcb_generic_event_t* ev = static_cast<xcb_generic_event_t *>(message); | |
switch (ev->response_type & ~0x80) { | |
case XCB_KEY_PRESS: | |
{ | |
xcb_key_press_event_t *kp = reinterpret_cast<xcb_key_press_event_t *>(ev); | |
qDebug() << "filtered key pressed:" << kp->detail; | |
} | |
return true; | |
case XCB_KEY_RELEASE: | |
{ | |
xcb_key_release_event_t *kr = reinterpret_cast<xcb_key_release_event_t *>(ev); | |
qDebug() << "filtered key released:" << kr->detail; | |
} | |
return true; | |
default: | |
break; | |
} | |
#endif | |
} else if (eventType == "windows_dispatcher_MSG" || eventType == "windows_generic_MSG") { | |
#if defined(Q_OS_WIN) | |
bool isRepeat = false; | |
MSG* msg = static_cast<MSG *>(message); | |
int scanCode = LOBYTE(HIWORD(msg->lParam)); | |
switch (msg->message) { | |
case WM_KEYDOWN: | |
qDebug() << "filtered key pressed:" << scanCode; | |
return true; | |
case WM_KEYUP: | |
qDebug() << "filtered key released:" << scanCode; | |
return true; | |
default: | |
break; | |
} | |
#endif | |
} | |
return false; | |
} | |
}; | |
class MainWindow : public QMainWindow | |
{ | |
public: | |
MainWindow(QWidget *parent = 0) : QMainWindow(parent) | |
{ | |
QWidget *widget = new QWidget(this); | |
this->setCentralWidget(widget); | |
QVBoxLayout *layout = new QVBoxLayout(widget); | |
QLabel *lbl = new QLabel(this); | |
layout->addWidget(lbl); | |
lbl->setAlignment(Qt::AlignCenter | Qt::AlignVCenter); | |
lbl->setText(QString("Qt: %1<br/>platform: %2").arg(qVersion(), qApp->platformName())); | |
QCheckBox *chk = new QCheckBox(this); | |
layout->addWidget(chk); | |
chk->setText("Use app level event filter"); | |
connect(chk, &QCheckBox::stateChanged, qApp, [=](int state){ | |
if (state == Qt::Checked) { | |
qApp->installNativeEventFilter(&m_filter); | |
} else { | |
qApp->removeNativeEventFilter(&m_filter); | |
} | |
}); | |
} | |
protected: | |
void keyPressEvent(QKeyEvent *event) override | |
{ | |
qDebug() << "unfiltered key pressed:" | |
<< event->nativeScanCode(); | |
} | |
void keyReleaseEvent(QKeyEvent *event) override | |
{ | |
qDebug() << "unfiltered key released:" | |
<< event->nativeScanCode(); | |
} | |
private: | |
NativeFilter m_filter; | |
}; | |
int main(int argc, char *argv[]) | |
{ | |
QApplication a(argc, argv); | |
MainWindow w; | |
w.show(); | |
return a.exec(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment