如何检查键盘是否已连接并在运行时连接时使用它?
How to check if keyboard is connected or or not and use it if it is connected during runtime?
所以我有一个 QT 项目,我想在其中检查是否连接了键盘。如果未连接,我希望在程序 运行 期间连接时仍能使用它。我环顾四周,发现了一些可能合适的图书馆,但我不确定他们是否能做我想做的。有问题的库:libinput
、libusb
或 Solid
与 KDE。我的问题是,这些库中的一个会做我想让它做的事还是完全不同?如果它是上述库之一,那么任何示例都会有很大帮助,因为我无法从文档中真正得到任何东西。我可能还应该提到我使用 linux,或者更准确地说是 openSUSE Leap 15.2
好吧,事实证明它并不像我想象的那么复杂,并且需要我谈到的 none 个库。这是我的解决方案,以防将来有人在寻找类似的东西。
scanner.h
#ifndef SCANNER_H
#define SCANNER_H
#include <QObject>
#include <QThread>
#include <QTimer>
#include <QDebug>
#include <QString>
#include <QFile>
#include <QSocketNotifier>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/input.h>
class Scanner : public QThread
{
Q_OBJECT
public:
static Scanner* getInstance(void);
int saveInCorrectFormat(int code);
protected:
void run() override;
signals:
void ChipScanned(QString rfid);
private slots:
void handleNotification(int socket);
void checkScannerData();
private:
Scanner(QObject *parent = 0);
~Scanner();
void initScanner(void);
static Scanner* sInstance;
QString defaultPath = "/dev/input/event2";
QString rfid;
QTimer* sCheckScanner;
QFile *sScannerFile;
QSocketNotifier *sNotifier;
int fd;
bool notificationEnabled;
struct input_event event;
int RFID[10];
int i = 0;
int buffer = 0;
};
#endif // SCANNER_H
scanner.cpp
#include "scanner.h"
Scanner* Scanner::sInstance = new Scanner();
Scanner* Scanner::getInstance(void){
return sInstance;
}
Scanner::Scanner(QObject *parent) : QThread(parent){
moveToThread(this);
start();
}
Scanner::~Scanner(){
}
void Scanner::run(){
initScanner();
QThread::exec();
}
/**
* @brief Scanner::initScanner
* initialize the timer to check up on the keyboard event file
*/
void Scanner::initScanner(void){
notificationEnabled = false;
sScannerFile = new QFile(defaultPath);
sCheckScanner = new QTimer(this);
sCheckScanner->setInterval(100);
sCheckScanner->setSingleShot(false);
connect(sCheckScanner, SIGNAL(timeout()), this, SLOT(checkScannerData()));
sCheckScanner->start();
}
/**
* @brief Scanner::checkScannerData
* check if the keyboard is connected or not
* if it is connected, activate event handling
*/
void Scanner::checkScannerData(){
if(sScannerFile->exists()){
if(notificationEnabled){
return;
}
fd = open(defaultPath.toUtf8().data(), O_RDONLY | O_NONBLOCK);
if(-1 != fd){
sNotifier = new QSocketNotifier(fd, QSocketNotifier::Read, this);
connect(sNotifier, SIGNAL(activated(int)), this, SLOT(handleNotification(int)));
qDebug() << "Scanner connected";
notificationEnabled = true;
}
}else{
if(notificationEnabled){
sNotifier->setEnabled(false);
disconnect(sNotifier, SIGNAL(activated(int)), this, SLOT(handleNotification(int)));
delete sNotifier;
close(fd);
qDebug() << "Scanner disconnect";
notificationEnabled = false;
}
}
}
/**
* @brief Scanner::handleNotification
* check if the keyboard is still connected or if the event was the disconnect
* if still connected than read the data and save it
* @param socket
*/
void Scanner::handleNotification(int socket){
if(!sScannerFile->exists()){
if(notificationEnabled){
sNotifier->setEnabled(false);
disconnect(sNotifier, SIGNAL(activated(int)), this, SLOT(handleNotification(int)));
delete sNotifier;
close(fd);
qDebug() << "Scanner disconnect";
notificationEnabled = false;
}
return;
}
if(read(fd, &event, sizeof(event)) == sizeof(event)){
if(event.type != EV_SYN){
if(event.value == 1 && event.code != 28){
RFID[i] = saveInCorrectFormat(event.code);
rfid.append(QString("%1").arg(saveInCorrectFormat(event.code)));
i++;
}
}
}
if(rfid.size() == 10){
buffer++;
if(buffer == 10){
emit ChipScanned(rfid);
qDebug() << rfid;
i = 0;
buffer = 0;
rfid.clear();
}
}
}
/**
* @brief Scanner::saveInCorrectFormat
* correct the raw data in the it's right format
* @param code
* current data to convert
* @return
* converted data
*/
int Scanner::saveInCorrectFormat(int code){
switch(code){
case 11:
return 0;
case 28:
return -1;
default:
return code-1;
}
}
一些额外的信息:
我的设备并不是真正的键盘,但输入的处理方式就好像它是键盘一样,这就是为什么我必须在原始数据成为预期格式之前对其进行一些调整。其他人很可能不需要这些调整,例如读取数据后的 int saveInCorrectFormat
或 if
条件。我相信此代码相当通用,这意味着更改 defaultPath
并在读取原始数据时进行一些调整可能也可以将其用于其他设备。
所以我有一个 QT 项目,我想在其中检查是否连接了键盘。如果未连接,我希望在程序 运行 期间连接时仍能使用它。我环顾四周,发现了一些可能合适的图书馆,但我不确定他们是否能做我想做的。有问题的库:libinput
、libusb
或 Solid
与 KDE。我的问题是,这些库中的一个会做我想让它做的事还是完全不同?如果它是上述库之一,那么任何示例都会有很大帮助,因为我无法从文档中真正得到任何东西。我可能还应该提到我使用 linux,或者更准确地说是 openSUSE Leap 15.2
好吧,事实证明它并不像我想象的那么复杂,并且需要我谈到的 none 个库。这是我的解决方案,以防将来有人在寻找类似的东西。
scanner.h
#ifndef SCANNER_H
#define SCANNER_H
#include <QObject>
#include <QThread>
#include <QTimer>
#include <QDebug>
#include <QString>
#include <QFile>
#include <QSocketNotifier>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/input.h>
class Scanner : public QThread
{
Q_OBJECT
public:
static Scanner* getInstance(void);
int saveInCorrectFormat(int code);
protected:
void run() override;
signals:
void ChipScanned(QString rfid);
private slots:
void handleNotification(int socket);
void checkScannerData();
private:
Scanner(QObject *parent = 0);
~Scanner();
void initScanner(void);
static Scanner* sInstance;
QString defaultPath = "/dev/input/event2";
QString rfid;
QTimer* sCheckScanner;
QFile *sScannerFile;
QSocketNotifier *sNotifier;
int fd;
bool notificationEnabled;
struct input_event event;
int RFID[10];
int i = 0;
int buffer = 0;
};
#endif // SCANNER_H
scanner.cpp
#include "scanner.h"
Scanner* Scanner::sInstance = new Scanner();
Scanner* Scanner::getInstance(void){
return sInstance;
}
Scanner::Scanner(QObject *parent) : QThread(parent){
moveToThread(this);
start();
}
Scanner::~Scanner(){
}
void Scanner::run(){
initScanner();
QThread::exec();
}
/**
* @brief Scanner::initScanner
* initialize the timer to check up on the keyboard event file
*/
void Scanner::initScanner(void){
notificationEnabled = false;
sScannerFile = new QFile(defaultPath);
sCheckScanner = new QTimer(this);
sCheckScanner->setInterval(100);
sCheckScanner->setSingleShot(false);
connect(sCheckScanner, SIGNAL(timeout()), this, SLOT(checkScannerData()));
sCheckScanner->start();
}
/**
* @brief Scanner::checkScannerData
* check if the keyboard is connected or not
* if it is connected, activate event handling
*/
void Scanner::checkScannerData(){
if(sScannerFile->exists()){
if(notificationEnabled){
return;
}
fd = open(defaultPath.toUtf8().data(), O_RDONLY | O_NONBLOCK);
if(-1 != fd){
sNotifier = new QSocketNotifier(fd, QSocketNotifier::Read, this);
connect(sNotifier, SIGNAL(activated(int)), this, SLOT(handleNotification(int)));
qDebug() << "Scanner connected";
notificationEnabled = true;
}
}else{
if(notificationEnabled){
sNotifier->setEnabled(false);
disconnect(sNotifier, SIGNAL(activated(int)), this, SLOT(handleNotification(int)));
delete sNotifier;
close(fd);
qDebug() << "Scanner disconnect";
notificationEnabled = false;
}
}
}
/**
* @brief Scanner::handleNotification
* check if the keyboard is still connected or if the event was the disconnect
* if still connected than read the data and save it
* @param socket
*/
void Scanner::handleNotification(int socket){
if(!sScannerFile->exists()){
if(notificationEnabled){
sNotifier->setEnabled(false);
disconnect(sNotifier, SIGNAL(activated(int)), this, SLOT(handleNotification(int)));
delete sNotifier;
close(fd);
qDebug() << "Scanner disconnect";
notificationEnabled = false;
}
return;
}
if(read(fd, &event, sizeof(event)) == sizeof(event)){
if(event.type != EV_SYN){
if(event.value == 1 && event.code != 28){
RFID[i] = saveInCorrectFormat(event.code);
rfid.append(QString("%1").arg(saveInCorrectFormat(event.code)));
i++;
}
}
}
if(rfid.size() == 10){
buffer++;
if(buffer == 10){
emit ChipScanned(rfid);
qDebug() << rfid;
i = 0;
buffer = 0;
rfid.clear();
}
}
}
/**
* @brief Scanner::saveInCorrectFormat
* correct the raw data in the it's right format
* @param code
* current data to convert
* @return
* converted data
*/
int Scanner::saveInCorrectFormat(int code){
switch(code){
case 11:
return 0;
case 28:
return -1;
default:
return code-1;
}
}
一些额外的信息:
我的设备并不是真正的键盘,但输入的处理方式就好像它是键盘一样,这就是为什么我必须在原始数据成为预期格式之前对其进行一些调整。其他人很可能不需要这些调整,例如读取数据后的 int saveInCorrectFormat
或 if
条件。我相信此代码相当通用,这意味着更改 defaultPath
并在读取原始数据时进行一些调整可能也可以将其用于其他设备。