如何子类化QIODevice读取/dev/input/eventX并触发readyRead信号?
继承QIODevice实现KeyBoard类的问题解答
我已查阅QIODevice文档,但仍不清楚如何实现需求。我希望创建一个继承自QIODevice的KeyBoard类,用于打开/dev/input/eventX,且代码可使用KeyBoard类的readyRead()信号(QFile不会触发该信号)。现有类定义如下:
class KeyBoard : public QIODevice { public: KeyBoard(); ~KeyBoard(); protected: qint64 readData(char *data, qint64 size); qint64 writeData(const char *data, qint64 size); };请问需要在readData()和writeData()中实现哪些逻辑?
刚好我之前做过类似的Linux输入设备封装,来给你一步步拆解需要实现的逻辑:
一、readData()的核心实现逻辑
这是读取键盘事件的底层入口,主要做这几件事:
- 首先要在KeyBoard类里新增一个成员变量
int m_fd,用来保存打开/dev/input/eventX后的文件描述符。这个fd可以在构造函数或者自定义的open()方法里通过系统调用open("/dev/input/eventX", O_RDONLY)获取,记得处理打开失败的情况(比如返回-1时要调用setErrorString()设置错误信息)。 - 在readData函数里,直接调用系统的
read()函数,把数据从m_fd读到传入的data缓冲区里,返回实际读取的字节数。如果读取失败(比如返回-1),要设置对应的错误描述,同时返回-1。 - 重点提醒:readData本身不需要触发
readyRead()信号,你得配合QSocketNotifier实现异步通知——当m_fd有可读数据时,QSocketNotifier会触发信号,你在对应的槽函数里手动发出readyRead()信号就行。
示例代码大概是这样:
#include <unistd.h> #include <string.h> qint64 KeyBoard::readData(char *data, qint64 size) { if (m_fd == -1) { setErrorString("Device not opened"); return -1; } ssize_t bytesRead = ::read(m_fd, data, size); if (bytesRead == -1) { setErrorString(strerror(errno)); return -1; } return bytesRead; }
二、writeData()的实现逻辑
对于/dev/input/eventX这类输入设备来说,它通常是只读的,所以writeData可以直接返回-1,表示不支持写入操作,同时设置错误信息说明原因即可。如果你的场景有特殊需求(比如模拟按键输入),可以调用系统的write()函数,但绝大多数场景下不需要额外处理:
qint64 KeyBoard::writeData(const char *data, qint64 size) { Q_UNUSED(data); Q_UNUSED(size); setErrorString("Keyboard device does not support writing"); return -1; }
额外关键步骤(为了触发readyRead())
要让KeyBoard类正常发出readyRead()信号,还需要补充这些代码:
- 在构造函数里,打开设备文件后,创建
QSocketNotifier *m_notifier = new QSocketNotifier(m_fd, QSocketNotifier::Read, this);,然后绑定它的activated信号到自定义槽函数(比如onReadyRead())。 - 在
onReadyRead()槽函数里,直接调用emit readyRead();即可。 - 析构函数里记得关闭m_fd,同时销毁m_notifier。
内容的提问来源于stack exchange,提问作者Timothy Kwok
相关产品推荐
相关产品推荐

