Skip to content

Instantly share code, notes, and snippets.

@pedrolcl
Created April 1, 2022 08:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pedrolcl/f26d6388657165b16434f4fb1a0c62b5 to your computer and use it in GitHub Desktop.
Save pedrolcl/f26d6388657165b16434f4fb1a0c62b5 to your computer and use it in GitHub Desktop.
Native Event Filters for Keyboard Events in C++ Qt Application
/* 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