我正在开发一个基于 Qt5 的小型 GUI,它将显示来自 Linux 文件设备的数据流。
为此,我选择了操纵杆输入。使用 cat/dev/input/js0
可以在终端上看到传入的流。
使用 C,您可以使用带有阻塞读取或处理设备信号的循环来读取此设备文件。但我没有用 Qt 得到这个。
使用 Qt 与设备文件交互的典型方法是什么?
基于@rodrigo 的回答,这里有一个新的实现:
joystick.h
#ifndef JOYSTICK_H
#define JOYSTICK_H
#include <QObject>
#include <QFile>
#include <QSocketNotifier>
class Joystick
: public QObject
{
Q_OBJECT
QString fileName = "/dev/input/js0";
QFile *file;
QSocketNotifier *notifier;
public:
explicit Joystick(QObject *parent = nullptr);
~Joystick();
signals:
public slots:
void handle_readNotification(int socket);
};
#endif // JOYSTICK_H
游戏杆.cpp
#include "joystick.h"
Joystick::Joystick(QObject *parent)
: QObject(parent)
{
file = new QFile();
file->setFileName(fileName);
if( !file->exists() ){
qWarning("file does not exist");
return;
}
if( !file->open(QFile::ReadOnly) ){
qWarning("can not open file");
return;
}
notifier = new QSocketNotifier( file->handle(),
QSocketNotifier::Read,
this);
connect( notifier,
&QSocketNotifier::activated,
this,
&Joystick::handle_readNotification );
if( !notifier->isEnabled() ){
qInfo("enable notifier");
notifier->setEnabled(true);
}
qInfo("Joystick init ready");
}
void
Joystick::handle_readNotification(int /*socket*/)
{
static quint64 cnt=0;
qInfo("cnt: %d",cnt++);
if( !(file->isOpen()) ){
qWarning("file closed");
return;
}
char buf[16]; /* tested with different sizes */
if( file->read(buf,sizeof(buf)) ){
qInfo("read: %s",buf);
}
// QByteArray ba = file->readAll();
// qInfo("Data: %s", ba.data());
}
然后我运行它,最后输出的是 cnt: 0
。看来,read
或 readAll
调用现在会阻塞。如果我注释掉读取调用,计数器运行得非常快。 here a similiar post哪里错了?
最终解决方案
感谢罗德里戈!
joystick.h
#ifndef JOYSTICK_H
#define JOYSTICK_H
#include <QObject>
#include <QFile>
#include <QSocketNotifier>
class Joystick
: public QObject
{
Q_OBJECT
QString fileName = "/dev/input/js0";
QSocketNotifier *notifier;
int fd;
public:
explicit Joystick(QObject *parent = nullptr);
~Joystick();
signals:
void buttonPressed(quint8 number, qint16 value);
void axisMoved(quint8 number, qint16 value);
public slots:
void handle_readNotification(int socket);
};
#endif // JOYSTICK_H
游戏杆.cpp
#include "joystick.h"
#include <fcntl.h>
#include <unistd.h>
#include <linux/joystick.h>
Joystick::Joystick(QObject *parent)
: QObject(parent)
{
auto file = new QFile();
file->setFileName(fileName);
if( !file->exists() ){
qWarning("file does not exist");
return;
}
fd = open(fileName.toUtf8().data(), O_RDONLY|O_NONBLOCK);
if( fd==-1 ){
qWarning("can not open file");
return;
}
notifier = new QSocketNotifier( fd,
QSocketNotifier::Read,
this);
connect( notifier,
&QSocketNotifier::activated,
this,
&Joystick::handle_readNotification );
}
Joystick::~Joystick()
{
if( fd>=0 ){
close(fd);
}
}
void
Joystick::handle_readNotification(int /*socket*/)
{
struct js_event buf;
while( read(fd,&buf,sizeof(buf))>0 ){
switch (buf.type) {
case JS_EVENT_BUTTON:
emit buttonPressed(buf.number, buf.value);
break;
case JS_EVENT_AXIS:
emit axisMoved(buf.number, buf.value);
break;
}
}
}
最佳答案
这个问题通常可以通过工具包的轮询源来解决。对于 Qt,这是 QSocketNotifier
.尽管它的名字(历史事故?),它可用于轮询任何文件描述符,而不仅仅是套接字。
所以你只要打开设备,用open()
获取文件描述符,然后在上面创建一个QSocketNotifier
,类型为QSocketNotifier::阅读
。当有事件要读取时,您会收到 activate()
信号。
关于c++ - 如何使用 Qt 在 Linux 中读取文件设备?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48734421/