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

时间:2011-02-25 20:21:35

标签: c++ linux qt x11 barcode-scanner

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

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

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

我知道我可以“打开”特定的“设备”来从中读取原始数据,但这与在我的应用程序中输入“键盘事件”不同。 (还要考虑我的应用程序是用Qt编写的,但我并不需要依赖它。)

感谢。

编辑: 我最好说它必须在Linux上运行。没有Windows也没有.NET,也没有嵌入式Linux。 我还打算用C ++ / Qt编写代码,但我对其他框架开放。 对不起,对不起。

2 个答案:

答案 0 :(得分:4)

实际上这是一个解决方案。

我仍然没有可用的应用程序显示,但概念是使用XI2。 我要摘要XI2 Recipes并尝试将其绑定到QApplication::x11EventFilter()

如XI2 Recipes, Part 3所示,我可以确定sourceidXIButtonClassInfoXIKeyClassInfo中包含字段XIValuatorClassInfo的事件来源。

Recipes, Part 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,但奴隶可以通过dev_ev->sourceid区分。

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

答案 1 :(得分:1)

我正在研究一个非常类似的问题,发现这个答案非常有用。只是为了扩充提供的代码示例,这里是创建可执行文件所需的标头和主要代码。请注意,类构造函数中省略了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();
}