Skip to content

Commit

Permalink
add keyboard-monitor
Browse files Browse the repository at this point in the history
  • Loading branch information
eightplus committed Apr 2, 2020
1 parent 84704de commit 3163ad6
Show file tree
Hide file tree
Showing 7 changed files with 364 additions and 0 deletions.
5 changes: 5 additions & 0 deletions code/Qt/keyboard-monitor/ReadMe
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
sudo apt install qtbase5-dev qt5-qmake qt5-default qtscript5-dev qttools5-dev-tools libqt5x11extras5-dev pkg-config libxcb1-dev libx11-dev

1)获取CapsLock大小写键状态(使用X11,在pro文件里添加 LIBS += -lX11)
2)获取按键事件,如windows键(Qt::Key_Meta)
3)输入法数据QEvent::InputMethod
49 changes: 49 additions & 0 deletions code/Qt/keyboard-monitor/keyboard-monitor.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
isEqual(QT_MAJOR_VERSION, 5) {
QT += widgets gui core x11extras
}

TARGET = keyboard-monitor
TEMPLATE = app

target.path = /usr/bin
target.source += $$TARGET

CONFIG += c++14
CONFIG += qt warn_on
CONFIG += release
CONFIG += link_pkgconfig
PKGCONFIG += xcb

LIBS += -lX11

# The following define makes your compiler emit warnings if you use
# any feature of Qt which has been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0

QMAKE_CFLAGS += -D_GNU_SOURCE
QMAKE_CPPFLAGS *= $(shell dpkg-buildflags --get CPPFLAGS)
QMAKE_CFLAGS *= $(shell dpkg-buildflags --get CFLAGS)
QMAKE_CXXFLAGS *= $(shell dpkg-buildflags --get CXXFLAGS)
QMAKE_LFLAGS *= $(shell dpkg-buildflags --get LDFLAGS)

unix {
UI_DIR = .ui
MOC_DIR = .moc
OBJECTS_DIR = .obj
}

SOURCES += \
main.cpp \
widget.cpp \
native-event-filter-factory.cpp

HEADERS += \
widget.h \
native-event-filter-factory.h
13 changes: 13 additions & 0 deletions code/Qt/keyboard-monitor/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#include "widget.h"
#include "native-event-filter-factory.h"
#include <QApplication>

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// a.installNativeEventFilter(NativeEventFilterFactory::getEventFilter());
Widget w;
w.show();

return a.exec();
}
69 changes: 69 additions & 0 deletions code/Qt/keyboard-monitor/native-event-filter-factory.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#include "native-event-filter-factory.h"

#include <QByteArray>
#include <QAbstractNativeEventFilter>
#include <QString>
#include <QObject>
#include <QDebug>

#include <X11/XKBlib.h>
#include <xcb/xcb.h>
#include <xcb/xproto.h> //xcb_button_release_event_t xcb_button_release_event_t xcb_key_press_event_t


class NativeEventFilter : public QAbstractNativeEventFilter {
public:

NativeEventFilter() : entered(false) {


}

bool nativeEventFilter(const QByteArray& eventType,
void* message,
long*) override {
QString event_type = QString(eventType);

if (event_type == "xcb_generic_event_t") {//XCB(Linux) 这里只处理了键盘事件XCB_KEY_PRESS
// if (eventType.compare("xcb_generic_event_t") == 0) {
xcb_generic_event_t* ev = static_cast<xcb_generic_event_t*>(message);

int evType = (ev->response_type & ~0x80);
// qDebug() << "xcb_generic_event_t===========" << evType;

if (evType == XCB_ENTER_NOTIFY) {
qDebug() << "XCB_ENTER_NOTIFY===========";
entered = true;
}
else if (evType == XCB_LEAVE_NOTIFY) {
qDebug() << "XCB_LEAVE_NOTIFY===========";
entered = false;
}
else if (evType == XCB_BUTTON_PRESS) {
qDebug() << "XCB_BUTTON_PRESS===========";
}
}
return false;
}

/*NativeEventFilter *getInstance(void)
{
static NativeEventFilter m_instance;
return &m_instance;
// const NativeEventFilter* m_instance = static_cast<const NativeEventFilter*>();
// return const_cast<NativeEventFilter*>(m_instance);
}*/

private:
bool entered;
};


QAbstractNativeEventFilter* NativeEventFilterFactory::getEventFilter()
{
// return NativeEventFilter::getInstance();
NativeEventFilter *m_instance = new NativeEventFilter();
return m_instance;
}
8 changes: 8 additions & 0 deletions code/Qt/keyboard-monitor/native-event-filter-factory.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#pragma once

#include <QAbstractNativeEventFilter>

class NativeEventFilterFactory {
public:
static QAbstractNativeEventFilter *getEventFilter();
};
188 changes: 188 additions & 0 deletions code/Qt/keyboard-monitor/widget.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
#include "widget.h"

#include <QEvent>
#include <QGuiApplication>
#include <QInputMethodEvent>
#include <QInputMethod>
#include <QTransform>
#include <QPoint>
#include <QCursor>
#include <QClipboard>
#include <QVBoxLayout>
#include <QLineEdit>
#include <QLabel>
#include <QDebug>

#include <X11/XKBlib.h>
//解决QEvent::Type中enum和Xlib中#defines同名的冲突,比如Qt中的QEvent::KeyPress与Xlib中的#define KeyPress 2(定义在X.h文件中)
#undef KeyPress
#undef KeyRelease
#undef FocusIn
#undef FocusOut

Widget::Widget(QWidget *parent)
: QWidget(parent)
, m_lineEdit(new QLineEdit(this))
, m_label(new QLabel(this))
{
this->setAttribute(Qt::WA_InputMethodEnabled);
this->setFocusPolicy(Qt::StrongFocus);
this->setFixedSize(400, 300);
installEventFilter(this);

m_lineEdit->setEchoMode(QLineEdit::Password);
connect(m_lineEdit, &QLineEdit::textChanged, this, &Widget::onLineEditTextChanged);

QVBoxLayout *layout = new QVBoxLayout;
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(20);
layout->addWidget(m_lineEdit);
layout->addWidget(m_label);
this->setLayout(layout);

checkStatus();
}

Widget::~Widget()
{

}

// http://stackoverflow.com/questions/2968336/qt-password-field-warn-about-caps-lock
bool Widget::checkStatusStatus()
{
Display* d = XOpenDisplay((char*)0);
bool caps_state = false;
if (d) {
unsigned n;
XkbGetIndicatorState(d, XkbUseCoreKbd, &n);
caps_state = (n & 0x01) == 1;
}
return caps_state;
}

void Widget::checkStatus()
{
if (checkStatusStatus()) {
m_label->setText("Caps Lock is on");
}
else {
m_label->setText("Caps Lock is off");
}
}

void Widget::onLineEditTextChanged(const QString &text)
{
Q_UNUSED(text);

checkStatus();
}

bool Widget::eventFilter(QObject *watched, QEvent *event)
{
if (event->type() == QEvent::InputMethod) {//让QLineEdit失去焦点后进行输入法测试
QInputMethodEvent* e = (QInputMethodEvent*) event;
if(!hasFocus()) {//失去焦点时,输入法事件优先于FocusOut事件被处理
e->setCommitString("");
}
else {
qDebug() << "InputMethod preeditString:" << e->preeditString() << ", commitString:" << e->commitString();
QInputMethod* im = QGuiApplication::inputMethod();
QTransform t;
//QPoint p((0 - this->width()) / 2 + 20, 0 - this->height());
QPoint p(0, 0);
QCursor cursor;
QPoint position(this->mapToGlobal(QPoint(20, 0)));
cursor.setPos(position);
this->setCursor(cursor);
t.translate(p.x(), p.y());

QGuiApplication::inputMethod()->setInputItemTransform(t);
QGuiApplication::inputMethod()->setInputItemRectangle(this->rect());
QGuiApplication::inputMethod()->update(Qt::ImQueryInput);

// qDebug() << "anchor " << im->anchorRectangle();
// qDebug() << "cursor " << im->cursorRectangle();
// qDebug() << "direction " << im->inputDirection();
// qDebug() << "itemclip " << im->inputItemClipRectangle();
// qDebug() << "itemrectangle " << im->inputItemRectangle();
// qDebug() << "animating " << im->isAnimating();
// qDebug() << "visible " << im->isVisible();
// qDebug() << "keyboard " << im->keyboardRectangle();
// qDebug() << this->inputMethodQuery(Qt::ImAnchorPosition);
// qDebug() << this->inputMethodQuery(Qt::ImAnchorRectangle);
}
}
else if (event->type() == QEvent::KeyPress) {
//qDebug() << "QEvent::KeyPress";
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
if (keyEvent) {
qDebug() << "keyEvent->text():" << keyEvent->text() << ",key():" << keyEvent->key();

if (keyEvent->key() == Qt::Key_Meta) {//windows key
qDebug() << "Key_Meta";
}
else if (keyEvent->key() == Qt::Key_Home) {
qDebug() << "Key_Home";
}
else if (keyEvent->key() == Qt::Key_CapsLock) {
qDebug() << "Key_CapsLock";
}
else if (keyEvent->key() == Qt::Key_NumLock) {
qDebug() << "Key_NumLock";
}
else if (keyEvent->key() == Qt::Key_Left) {
qDebug() << "Key_Left";
}
else if (keyEvent->key() == Qt::Key_Right) {
qDebug() << "Key_Right";
}
else if (keyEvent->key() == Qt::Key_Up) {
qDebug() << "Key_Up";
}
else if (keyEvent->key() == Qt::Key_Down) {
qDebug() << "Key_Down";
}
else if (keyEvent->key() == Qt::Key_End) {
qDebug() << "Key_End";
}
else if (keyEvent->key() == Qt::Key_7) {
qDebug() << "7";
}
else if (keyEvent->key() == Qt::Key_4) {
qDebug() << "4";
}
else if (keyEvent->key() == Qt::Key_6) {
qDebug() << "6";
}
else if (keyEvent->key() == Qt::Key_8) {
qDebug() << "8";
}
else if (keyEvent->key() == Qt::Key_2) {
qDebug() << "2";
}
else if (keyEvent->key() == Qt::Key_1) {
qDebug() << "1";
}
}
}
else if (event->type() == QEvent::KeyRelease) {
//qDebug() << "QEvent::KeyRelease";
}
else if (event->type() == QEvent::MouseButtonPress) {
qDebug() << "QEvent::MouseButtonPress";
}
else if (event->type() == QEvent::MouseButtonRelease) {
qDebug() << "QEvent::MouseButtonRelease";
}
else if (event->type() == QEvent::MouseMove) {
qDebug() << "QEvent::MouseMove";
}
else if (event->type() == QEvent::FocusIn) {
//qDebug() << "QEvent::FocusIn";
}
else if (event->type() == QEvent::FocusOut) {
//qDebug() << "QEvent::FocusOut";
}
return QWidget::eventFilter(watched, event);
}
32 changes: 32 additions & 0 deletions code/Qt/keyboard-monitor/widget.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QKeyEvent>

class QLineEdit;
class QLabel;

class Widget : public QWidget
{
Q_OBJECT

public:
Widget(QWidget *parent = 0);
~Widget();

bool checkStatusStatus();
void checkStatus();

public slots:
void onLineEditTextChanged(const QString &text);

protected:
bool eventFilter(QObject *watched, QEvent *event) Q_DECL_OVERRIDE;

private:
QLineEdit *m_lineEdit;
QLabel *m_label;
};

#endif // WIDGET_H

0 comments on commit 3163ad6

Please sign in to comment.