Keyboard / Barcode Scanner Event Source Detection

I need to read several barcode scanners and link the read data according to its source.

In other words, my application needs to know where the keystrokes came from in order to be able to take the right actions, such as updating the interface and sending commands to dedicated external equipment.

How can I “route” the inputs of various keyboards / scanners to certain events in my application or receive information that allows my application to find out where from the input? (I start by saying that a barcode scanner is just a keyboard for the system.)

I know that I can “open” a specific “device” to read raw data, but this is not the same as having a “keyboard event” in my application. (Note also that my application is written in Qt, but I do not need to get attached to it.)

Thanks.

EDIT: I would say that it should work on Linux. No windows, no .NET, no embedded Linux either. I also plan to code it in C ++ / Qt, but I am open to other frameworks. Sorry for the miss.

+4
source share
2 answers

This is actually a solution.

I do not have a working application for display, but the concept uses XI2. I am going to digest XI2 Recipes and try to bind it to QApplication::x11EventFilter() .

As shown in XI2 Recipes, Part 3 , I can determine the event source with the sourceid field present in XIButtonClassInfo , XIKeyClassInfo and XIValuatorClassInfo .

Recipes, Part 4 shows how to print event source information (in void print_deviceevent(XIDeviceEvent* event) ). It just sounds like that.

(Even if you don’t have a working solution yet, I decided to post an answer so that it would help someone else with the same problem. As soon as I have time, I will edit my own answer with the best reports.)


EDIT:

As promised, here is a working snippet that prints the source of keyboard events:

 #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; } 

He outputs something like (commented):

 ------------------------------------------- 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 

The output of 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)] 

This ultra- dev_ev->deviceid = 3 test shows that although all events come from master dev_ev->deviceid = 3 , the slave is recognized by dev_ev->sourceid .

I think now I can direct incoming events to the corresponding "clients" based on dev_ev->sourceid configured for the application.

+4
source

I am working on a very similar problem and found this answer very useful. To enlarge the above code example, here is the header and main code needed to create the executable. Note that the int qt_version was omitted in the class constructor, since it was not used in the class implementation. A trivial destructor must also be added to the qxi2application.cpp file.

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(); } 
+1
source

Source: https://habr.com/ru/post/1341358/


All Articles