检测键盘/条形码扫描仪事件的来源
Posted
技术标签:
【中文标题】检测键盘/条形码扫描仪事件的来源【英文标题】:Detect the source of a keyboard/barcode scanner event 【发布时间】:2011-02-25 20:21:35 【问题描述】:我需要读取几个条码扫描器,并根据其来源绑定读取的数据。
换句话说,我的应用程序需要知道从何处击键才能采取正确的操作,例如更新 UI 并将命令发送到专用的外部硬件。
如何将不同键盘/扫描仪的输入“路由”到我的应用中的特定事件,或检索允许我的应用找出输入来源的信息? (我从条形码扫描仪只是系统的键盘这一点开始。)
我知道我可以“打开”特定的“设备”以从中读取原始数据,但这与在我的应用程序中拥有“键盘事件”不同。 (还请考虑我的应用程序是用 Qt 编写的,但我真的不需要与之绑定。)
谢谢。
编辑: 我最好说它必须在 Linux 上运行。没有 Windows 也没有 .NET,也没有嵌入式 Linux。 我还计划用 C++/Qt 编写代码,但对其他框架持开放态度。 很抱歉错过了。
【问题讨论】:
这个问题已经被多次以不同的方式提出:***.com/questions/5088374***.com/questions/4764274***.com/questions/4487153***.com/questions/4464072 链接 1 没有足够的解决方案。链接 3 和 4 是关于 .NET 的,我需要一个 linux 解决方案。链接 2 有一个答案说它很容易,但没有说明更多......不过,它现在是更好的指针。谢谢。 【参考方案1】:其实是个解决办法。
我仍然没有可用的应用程序显示,但这个概念是使用 XI2。
我将消化XI2 Recipes 并尝试将其绑定到QApplication::x11EventFilter()
。
如 XI2 Recipes, Part 3 中所示,我可以通过 XIButtonClassInfo
、XIKeyClassInfo
和 XIValuatorClassInfo
中的字段 sourceid
来确定事件的来源。
Recipes, Part 4 显示如何打印有关事件源的信息(在void print_deviceevent(XIDeviceEvent* event)
中)。这样听起来很容易。
(即使还没有可行的解决方案,我还是决定发布一个答案,以便它可以帮助遇到同样问题的其他人。一旦我取得进展,我将用更好的报告编辑我自己的答案。)
编辑:
正如所承诺的,这是一个打印出键盘事件来源的工作 sn-p:
#include <QDebug>
#include "qxi2application.h"
#include <QX11Info>
#include <X11/extensions/XInput2.h>
// XI2 Event types.
static const char *_xi2_event_names[] =
"Reserved 0",
"XI_DeviceChanged",
"XI_KeyPress",
"XI_KeyRelease",
"XI_ButtonPress",
"XI_ButtonRelease",
"XI_Motion",
"XI_Enter",
"XI_Leave",
"XI_FocusIn",
"XI_FocusOut",
"XI_HierarchyChanged",
"XI_PropertyEvent",
"XI_RawKeyPress",
"XI_RawKeyRelease",
"XI_RawButtonPress",
"XI_RawButtonRelease",
"XI_RawMotion"
;
#include <QMainWindow>
QXI2Application::QXI2Application( int &argc, char **argv, int qt_version )
: QApplication( argc, argv, qt_version )
int event, error;
_display = QX11Info::display( );
if ( !XQueryExtension( _display, "XInputExtension", &xi_opcode, &event, &error ) )
qDebug( ) << "X Input extension not available.\n";
// We support XI 2.0.
int major = 2;
int minor = 0;
int rc = XIQueryVersion( _display, &major, &minor );
if ( rc == BadRequest )
qDebug( ) << "No XI2 support. Server supports version " << major << "." << minor << " only.\n";
else if ( rc != Success )
qDebug( ) << "Internal Error! This is a bug in Xlib.\n";
else
qDebug( ) << "XI2 supported. Server provides version " << major << "." << minor;
void QXI2Application::setMainWindow( QMainWindow *wnd )
XIEventMask evmasks[ 1 ];
unsigned char mask1[ ( XI_LASTEVENT + 7 ) / 8 ];
memset( mask1, 0, sizeof( mask1 ) );
// Select for key events from all master devices.
XISetMask( mask1, XI_KeyPress );
XISetMask( mask1, XI_KeyRelease );
evmasks[ 0 ].deviceid = XIAllMasterDevices;
evmasks[ 0 ].mask_len = sizeof( mask1 );
evmasks[ 0 ].mask = mask1;
XISelectEvents( _display, wnd->winId( ), evmasks, 1 );
XFlush( _display );
bool QXI2Application::x11EventFilter( XEvent *event )
XGenericEventCookie *cookie = &event->xcookie;
if ( event->type != GenericEvent
|| cookie->extension != xi_opcode
|| !XGetEventData( _display, cookie ) )
return false;
qDebug( ) << "cookie->evtype = " << cookie->evtype << " ("
<< _xi2_event_names[ cookie->evtype < XI_LASTEVENT ? cookie->evtype : XI_LASTEVENT ] << ")";
switch( cookie->evtype )
case XI_KeyPress:
qDebug( ) << "\tXI_KeyPress";
XIDeviceEvent *dev_ev = ( XIDeviceEvent * )event->xcookie.data;
qDebug( ) << "\tdev_ev->deviceid = " << dev_ev->deviceid;
qDebug( ) << "\tdev_ev->sourceid = " << dev_ev->sourceid;
break;
case XI_KeyRelease:
qDebug( ) << "\tXI_KeyRelease";
XIDeviceEvent *dev_ev = ( XIDeviceEvent * )event->xcookie.data;
qDebug( ) << "\tdev_ev->deviceid = " << dev_ev->deviceid;
qDebug( ) << "\tdev_ev->sourceid = " << dev_ev->sourceid;
break;
default:
qDebug( ) << "\tcookie->evtype = " << cookie->evtype;
break;
XFreeEventData( _display, cookie );
return false;
它输出类似(注释):
-------------------------------------------
XI2 supported. Server provides version 2 . 0
-------------------------------------------
[Keyboard] ↳ Dell Dell USB Keyboard id=8 [slave keyboard (3)]
cookie->evtype = 2 ( XI_KeyPress )
XI_KeyPress
dev_ev->deviceid = 3
dev_ev->sourceid = 8
cookie->evtype = 3 ( XI_KeyRelease )
XI_KeyRelease
dev_ev->deviceid = 3
dev_ev->sourceid = 8
-------------------------------------------
[Barcode] ↳ Cypress-Weikeng USB Adapter id=10 [slave keyboard (3)]
cookie->evtype = 2 ( XI_KeyPress )
XI_KeyPress
dev_ev->deviceid = 3
dev_ev->sourceid = 10
cookie->evtype = 3 ( XI_KeyRelease )
XI_KeyRelease
dev_ev->deviceid = 3
dev_ev->sourceid = 10
xinput list
的输出是:
# xinput list
⎡ Virtual core pointer id=2 [master pointer (3)]
⎜ ↳ Virtual core XTEST pointer id=4 [slave pointer (2)]
⎜ ↳ Dell Dell USB Optical Mouse id=9 [slave pointer (2)]
⎣ Virtual core keyboard id=3 [master keyboard (2)]
↳ Virtual core XTEST keyboard id=5 [slave keyboard (3)]
↳ Power Button id=6 [slave keyboard (3)]
↳ Power Button id=7 [slave keyboard (3)]
↳ Dell Dell USB Keyboard id=8 [slave keyboard (3)]
↳ Cypress-Weikeng USB Adapter id=10 [slave keyboard (3)]
这个超简单的测试表明,虽然所有的事件都来自masterdev_ev->deviceid = 3
,但是slave可以通过dev_ev->sourceid
来区分。
我想现在我可以根据应用程序上配置的dev_ev->sourceid
将传入事件路由到相应的“客户端”。
【讨论】:
【参考方案2】:我正在处理一个非常相似的问题,发现这个答案非常有帮助。只是为了扩充所提供的代码示例,这里是创建可执行文件所需的标头和主要代码。请注意,int qt_version
参数从类构造函数中省略,因为它在类实现中未使用。还需要在 qxi2application.cpp 文件中添加一个简单的析构函数。
qxi2application.h
#ifndef QXI2APPLICATION_H
#define QXI2APPLICATION_H
#include <QApplication>
#include <QMainWindow>
class QXI2Application : public QApplication
Q_OBJECT
public:
QXI2Application(int &argc, char **argv);
~QXI2Application();
void setMainWindow( QMainWindow *wnd );
bool x11EventFilter( XEvent *event );
private:
Display* _display;
int xi_opcode;
;
#endif // QXI2APPLICATION_H
main.cpp
#include "qxi2application.h"
#include <QApplication>
#include <QMainWindow>
int main(int argc, char *argv[])
QXI2Application a(argc, argv);
QMainWindow* wind = new QMainWindow;
a.setMainWindow(wind);
wind->show();
return a.exec();
【讨论】:
以上是关于检测键盘/条形码扫描仪事件的来源的主要内容,如果未能解决你的问题,请参考以下文章