目录
步骤
keylistener.cpp
keylistener.h
使用方法
linux中键盘和鼠标事件都是在/dev/input中,名字为eventX或者mouse
步骤
- 创建一个继承线程类的KeyListener类
- 重写run函数
- 定义一个键盘的信号和一个鼠标的信号
- 创建对象关联信号使用
keylistener.cpp
#include "keylistener.h"
#include <QDebug>
#include <fcntl.h>
#include <unistd.h>
#include <linux/input.h>
#include <QPoint>KeyListener::KeyListener(const QString &devicePath, QObject *parent): QThread(parent), devicePath(devicePath) {}KeyListener::~KeyListener() {running = true;// 等待线程安全退出wait();
}void KeyListener::run() {// 初始化鼠标在左上角坐标QPoint point(0,0);// 打开键盘事件文件int keyboardFd = open(devicePath.toStdString().c_str(), O_RDONLY);if (keyboardFd < 0) {qWarning() << "无法打开设备文件:" << devicePath;return;}// 打开鼠标事件文件mouseDevice = "/dev/input/event0";int mouseFd = open(mouseDevice.toStdString().c_str(), O_RDONLY);if (mouseFd < 0) {qWarning() << "无法打开鼠标设备文件:" << mouseDevice;close(keyboardFd);return;}// input事件结构体struct input_event ev;// 记录 Alt 键状态bool altPressed = false;// 一直循环while (running) {// 定义文件描述符集合fd_set readFds;// 将文件描述符集合清零FD_ZERO(&readFds);// 将键盘描述符写入集合FD_SET(keyboardFd, &readFds);// 将鼠标描述符写入集合FD_SET(mouseFd, &readFds);// 获取较大值int maxFd = std::max(keyboardFd, mouseFd);// 使用 select() 监听多个文件描述符 需要检查的文件描述符范围是 [0, maxFd-1]int ret = select(maxFd + 1, &readFds, nullptr, nullptr, nullptr);if (ret < 0) {qWarning() << "select() 失败";break;}// 处理键盘事件 检查 keyboardFd(键盘文件描述符)是否就绪。如果就绪,说明键盘有输入数据可读取if (FD_ISSET(keyboardFd, &readFds)) {// 从键盘文件描述符中读取输入事件结构体数据ssize_t bytes = read(keyboardFd, &ev, sizeof(struct input_event));// 检查读取的数据是否完整,并确认事件类型为键盘按键事件(EV_KEY 表示按键事件)if (bytes == sizeof(struct input_event) && ev.type == EV_KEY) {// 检查是否是左Alt键(KEY_LEFTALT)或右Alt键(KEY_RIGHTALT)的按键事件if (ev.code == KEY_LEFTALT || ev.code == KEY_RIGHTALT) {// 更新 Alt 键状态altPressed = ev.value == 1;}if (ev.code == KEY_B && ev.value == 1 && altPressed) {// 触发 Alt+B 信号emit altBPressed();}}}// 处理鼠标事件 检查 mouseFd 鼠标文件描述符是否就绪if (FD_ISSET(mouseFd, &readFds)) {// 从鼠标文件描述符中读取输入事件结构体数据ssize_t bytes = read(mouseFd, &ev, sizeof(struct input_event));// 检查读取的数据是否完整,并根据事件类型处理鼠标事件if (bytes == sizeof(struct input_event) && ev.type == EV_REL) {qDebug() << "鼠标移动事件,X、Y轴:" << ev.code << ", 移动量:" << ev.value;// 根据事件代码(ev.code)确定是 X 轴还是 Y 轴的移动if (ev.code == REL_X) {// 累加 X 轴的移动值point.setX(point.x() + ev.value);} else if (ev.code == REL_Y) {// 累加 Y 轴的移动值point.setY(point.y() + ev.value);}// 发送鼠标移动事件传递鼠标坐标emit mouseMove(point);}// 鼠标按键事件else if (bytes == sizeof(struct input_event) && ev.type == EV_KEY){qDebug() << "鼠标按键事件,按键:" << ev.code << ", 状态:" << ev.value;}}}close(keyboardFd);close(mouseFd);
}
keylistener.h
#ifndef KEYLISTENER_H
#define KEYLISTENER_H#include <QObject>
#include <QThread>
#include <QString>
#include <linux/input.h>
#include <fcntl.h>
#include <unistd.h>
#include <QDebug>
#include <QPoint>class KeyListener : public QThread {Q_OBJECTpublic:explicit KeyListener(const QString &devicePath, QObject *parent = nullptr);~KeyListener();void run() override; // 重写 QThread 的 run 方法signals:void altBPressed(); // 触发 Alt+B 的信号void mouseMove(const QPoint &globalPos); // 发送鼠标坐标信号private:QString devicePath;// 键盘事件驱动路径QString mouseDevice;// 鼠标事件驱动路径bool running = true;
};#endif // KEYLISTENER_H
使用方法
// 需要启用鼠标跟踪this.setMouseTracking(true); // 创建线程监听键盘事件const QString devicePath = "/dev/input/event1";m_listener = new KeyListener(devicePath, this);// 键盘监听触发截图connect(m_listener, &KeyListener::altBPressed,this, 键盘处理时间,Qt::QueuedConnection);connect(m_listener, &KeyListener::mouseMove,this, 鼠标处理事件,Qt::QueuedConnection);// 开始监听m_listener->start();