Определить источник события сканера клавиатуры / штрих-кода - PullRequest
4 голосов
/ 25 февраля 2011

Мне нужно прочитать несколько сканеров штрих-кода и связать прочитанные данные в соответствии с их источником.

Другими словами, моему приложению необходимо знать, откуда при нажатии клавиш можно было выполнять правильные действия, такие как обновление интерфейса и отправка команд на выделенное внешнее оборудование.

Как я могу "направить" входы различных клавиатур / сканеров на определенные события в моем приложении ИЛИ получить информацию, которая позволяет моему приложению выяснить, откуда поступил ввод? (Я начинаю с того, что сканер штрих-кода - это просто клавиатура для системы.)

Я знаю, что могу «открыть» определенное «устройство» для чтения необработанных данных с него, но это не то же самое, что иметь «событие клавиатуры» в моем приложении. (Учтите также, что мое приложение написано на Qt, но мне не нужно привязываться к нему.)

Спасибо.

EDIT: Я бы лучше сказал, что он должен работать на Linux. Ни Windows, ни .NET, ни встроенный Linux тоже. Я также планирую кодировать его в C ++ / Qt, но я открыт для других платформ. Извините за мисс.

Ответы [ 2 ]

4 голосов
/ 02 марта 2011

На самом деле это решение.

У меня еще нет рабочего приложения, которое можно показать, но концепция использует XI2. Я собираюсь переварить XI2 Recipes и попытаться связать его с QApplication::x11EventFilter().

Как показано в рецептах XI2 , часть 3 , я могу определить источник события с полем sourceid, присутствующим в XIButtonClassInfo, XIKeyClassInfo и XIValuatorClassInfo.

Рецепты, часть 4 показывает, как распечатать информацию об источнике события (в void print_deviceevent(XIDeviceEvent* event)). Звучит просто так.

(Даже не имея рабочего решения, я решил опубликовать ответ, чтобы он мог помочь кому-то еще, имеющему ту же проблему. Как только я добьюсь прогресса, я отредактирую свой собственный ответ с лучшими отчетами.)


EDIT:

Как и было обещано, вот рабочий фрагмент, который распечатывает источник событий клавиатуры:

#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 голос
/ 11 марта 2017

Я работаю над очень похожей проблемой и нашел этот ответ очень полезным.Просто для дополнения приведенного примера кода здесь есть заголовок и основной код, необходимые для создания исполняемого файла.Обратите внимание, что параметр 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();
}
...