检测键盘/条码扫描器事件的来源

我需要阅读几个条形码扫描仪,并根据其来源绑定读取的数据。

换句话说,我的应用程序需要知道哪些按键能够采取正确的操作,例如更新UI并将命令发送到专用的外部硬件。

如何将不同的键盘/扫描器的input“路由”到我的应用程序中的特定事件,或者检索允许我的应用程序从input中找出哪里来的信息? (我从条码扫描器只是系统的键盘开始。)

我知道我可以“打开”特定的“设备”,从它读取原始数据,但它不同于我的应用程序中的“键盘事件”。 (也考虑到我的应用程序是用Qt编写的,但是我并不需要被绑定到它。)

谢谢。

编辑:我最好说,它必须在Linux上运行。 没有Windows和.NET,也没有embedded式Linux。 我也打算在C ++ / Qt中编写代码,但是可以向其他框架开放。 对不起,错过了。

其实这是一个解决方案。

我仍然没有工作的应用程序来显示,但这个概念正在使用XI2。 我将消化XI2食谱,并尝试将其绑定到QApplication::x11EventFilter()

如XI2 食谱第3部分所述 ,我可以使用XIButtonClassInfoXIKeyClassInfoXIValuatorClassInfo的字段sourceid来确定事件的来源。

食谱,第4部分显示如何打印有关事件源的信息(在void print_deviceevent(XIDeviceEvent* event) )。 听起来很容易这样。

(即使还没有工作的解决方案,我决定发表一个答案,以便它可以帮助其他人有同样的问题。只要我取得进展,我会编辑自己的答案,更好的报告。)


编辑:

如所承诺的,这是一个工作片段,可以打印出键盘事件的来源:

 #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)] 

这个超简单的测试表明,尽管所有的事件都来自dev_ev->deviceid = 3 ,但是slave可以通过dev_ev->sourceid区分开来。

我想现在我可以根据应用程序上配置的dev_ev->sourceid将传入的事件路由到相应的“客户端”。

我正在处理一个非常类似的问题,发现这个答案非常有帮助。 只是为了扩大提供的代码示例,这里是创建可执行文件所需的头文件和主代码。 请注意, 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(); }