Можем ли мы генерировать нажатия клавиш, используя необработанные значения ASCII, используя C++ в Linux?

У меня есть данные штрих-кода, полученные от сканера штрих-кода в формате ASCII. Мне нужно написать программу для эмуляции клавиатуры с использованием данных, полученных на компьютер через сканер штрих-кода в Linux. Я также прочитал исходный код драйвера USB-HIDKB для Linux (http://lxr.free-electrons.com/source/drivers/hid/usbhid/usbkbd.c), но я чувствую, что должен сделать наоборот. Именно то, что я хочу сделать, это данные, полученные от сканера в виде потока данных в формате ASCII, и мне нужно генерировать нажатия клавиш с использованием отсканированных данных. Часть чтения данных почти завершена, и нужно найти способ преобразовать данные ASCII в нажатия клавиш.

пример операции:

Существует штрих-код для CTRL + z (сочетание клавиш для операции undo), после сканирования будут получены данные штрих-кода, 08 10 03 00 1a 00 18 0b будут получены как данные в HEX, затем данные 1a 00 18 0b. здесь первые 4 байта — это заголовок, а остальные — часть данных. теперь мне нужно выполнить операцию отмены вместо печати данных.

Я приветствую любой пример кода или предложения для начала кодирования. Спасибо.


person Dig The Code    schedule 25.10.2016    source источник
comment
Вы имеете в виду, что буквально получаете строку ASCII "08 10 03 03 00 1a 00 18 0b", то есть 23 символа ASCII, включая 14 цифр, две буквы и 7 пробелов? Поскольку 8-байтовый поток 08 10 03 03 00 1a 00 18 0b не является ASCII.   -  person MSalters    schedule 25.10.2016
comment
Нет, данные в посте генерируются после преобразования ASCII-потока в HEX-формат. что мне нужно сделать, это сгенерировать нажатия клавиш для вышеуказанного потока данных перед печатью в выходном потоке.   -  person Dig The Code    schedule 27.10.2016
comment
Ну, в ASCII нет ни управляющей клавиши, ни Ctrl-Z, ни отмены. ASCII - это один байт на символ, а 4 байта 1a 00 18 0b - это SUB NUL CAN VT (замена, нуль, отмена, вертикальная табуляция)   -  person MSalters    schedule 27.10.2016
comment
это касается не только событий, вызываемых клавишей Ctrl. простое преобразование последовательности шестнадцатеричного потока в нажатия клавиш.   -  person Dig The Code    schedule 08.11.2016


Ответы (1)


Найден полезный фрагмент кода http://%20%20%20[1]:%20http://www.doctort.org/adam/nerd-notes/x11-fake-keypress-event.html помог мне начать эмулировать нажатие клавиш, используя уже обработанные данные.

но это работает только в системах с xwindowing системами. Это не будет работать в системах, основанных только на терминалах. В этом случае нам нужно использовать подсистему uinput для генерации нажатия клавиши программного обеспечения.

образец программы о том, как использовать uinput в Linux, можно найти здесь http://thiemonge.org/getting-started-with-uinput

Я написал простую программу, используя uinput. Это работает.

пример кода:

#include <cstdlib>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/input.h>
#include <linux/uinput.h>
#include <iostream>

#include <time.h>
#include <string>

using namespace std;

int SetupUinputDevice()
{
    //  file descriptor for input subsystem device
    int fd_uinput_device;
    // read only, non-blocking, no delay file descriptor
    fd_uinput_device = open("/dev/uinput", O_WRONLY | O_NONBLOCK | O_NDELAY);
    if(fd_uinput_device < 0)
    {
        std::cout << "Error : open file descriptor /dev/uinput : " << strerror(errno) << std::endl; 
        return -1;
    }

    // create and initiate uinput_user_dev struct for KeyboardEmulator device
    struct uinput_user_dev dev_key_board_emulator;
    memset(&dev_key_board_emulator, 0, sizeof(uinput_user_dev));
    snprintf(dev_key_board_emulator.name, UINPUT_MAX_NAME_SIZE, "zebra-scanner-hidkb-emulator");
    dev_key_board_emulator.id.bustype = BUS_USB;
    dev_key_board_emulator.id.vendor = 0x01;
    dev_key_board_emulator.id.product = 0x02;
    dev_key_board_emulator.id.version = 1;

    /** configure the uinput device to key board events, these will inform to 
     * subsystem  via ioctl calls which type of events will be handled by 
     * the device
     */
    // configure/set key press and release events
    if(ioctl(fd_uinput_device, UI_SET_EVBIT, EV_KEY) < 0)
    {
        std::cout << "Error : ioctl : UI_SET_EVBIT for EV_KEY " << strerror(errno) << std::endl;
        return -1;
    }

    // enable set of key board events
    for(int iEvent=0; iEvent < 254; iEvent++)
    {
        if(ioctl(fd_uinput_device, UI_SET_KEYBIT, iEvent) < 0)
        {
            std::cout << "Error : ioctl : UI_SET_KEYBIT for event ID: " << iEvent << " : " << strerror(errno) << std::endl;
        }
    }

    // enable synchronization events
    if(ioctl(fd_uinput_device, UI_SET_EVBIT, EV_SYN) < 0)
    {
        std::cout << "Error : ioctl : UI_SET_EVBIT for EV_SYN: " << strerror(errno) << std::endl;
        return -1;
    }

    // write the uinput_user_dev structure into the device file descriptor
    if(write(fd_uinput_device, &dev_key_board_emulator, sizeof(uinput_user_dev)) < 0)
    {
        std::cout << "Error : failed to write uinput_user_dev structure into the device file descriptor: " << strerror(errno) << std::endl;
        return -1;
    }

    // Create the end point file descriptor for user input device descriptor.
    if(ioctl(fd_uinput_device, UI_DEV_CREATE) < 0)
    {
        std::cout << "Error : failed to create end point for user input device: " << strerror(errno) << std::endl;
        return -1;
    }

    return fd_uinput_device;
}

int CloseUinputDevice(int fd_dev)
{
    if(ioctl(fd_dev, UI_DEV_DESTROY) < 0)
    {
        std::cout << "Error : ioctl failed: UI_DEV_DESTROY : " << strerror(errno) << std::endl;
        return -1;
    }

    if(close(fd_dev) < 0)
    {
        std::cout << "Error : close device file descriptor : " << strerror(errno) << std::endl;
        return -1;
    }
}

int SendKeyboardEvents(int fd_dev, int event_type, int key_code, int value)
{
    // input_event struct member for input events
    struct input_event key_input_event;
    memset(&key_input_event, 0, sizeof(input_event));

    // set event values
    key_input_event.type = event_type;
    key_input_event.code = key_code;
    key_input_event.value = value;

    if(write(fd_dev, &key_input_event, sizeof(input_event)) < 0)
    {
        std::cout << "Error writing input events to the device descriptor: " << strerror(errno) << std::endl;
        return -1;
    }
    return 0;
}

int main(int argc, char** argv) {

    std::cout << "------------key - emulator------------" << std::endl;
    int fd_keyEmulator = SetupUinputDevice();
    sleep(3);
    if(fd_keyEmulator < 0)
    {
        std::cout << "Error in setup file descriptor for uinput device..." << std::endl;
        return 0;
    }

    // start to send events
    int returnValue;
    returnValue = SendKeyboardEvents(fd_keyEmulator, EV_KEY, KEY_A, 1);
    returnValue = SendKeyboardEvents(fd_keyEmulator, EV_KEY, KEY_A, 0);
    returnValue = SendKeyboardEvents(fd_keyEmulator, EV_KEY, KEY_B, 1);
    returnValue = SendKeyboardEvents(fd_keyEmulator, EV_KEY, KEY_B, 0);
    returnValue = SendKeyboardEvents(fd_keyEmulator, EV_KEY, KEY_C, 1);
    returnValue = SendKeyboardEvents(fd_keyEmulator, EV_KEY, KEY_C, 0);
    returnValue = SendKeyboardEvents(fd_keyEmulator, EV_KEY, KEY_D, 1);
    returnValue = SendKeyboardEvents(fd_keyEmulator, EV_KEY, KEY_D, 0);
    returnValue = SendKeyboardEvents(fd_keyEmulator, EV_KEY, KEY_E, 1);
    returnValue = SendKeyboardEvents(fd_keyEmulator, EV_KEY, KEY_E, 0);
    returnValue = SendKeyboardEvents(fd_keyEmulator, EV_KEY, KEY_F, 1);
    returnValue = SendKeyboardEvents(fd_keyEmulator, EV_KEY, KEY_F, 0);
    returnValue = SendKeyboardEvents(fd_keyEmulator, EV_KEY, KEY_G, 1);
    returnValue = SendKeyboardEvents(fd_keyEmulator, EV_KEY, KEY_G, 0);
    returnValue = SendKeyboardEvents(fd_keyEmulator, EV_KEY, KEY_H, 1);
    returnValue = SendKeyboardEvents(fd_keyEmulator, EV_KEY, KEY_H, 0);

    CloseUinputDevice(fd_keyEmulator);

    std::cout << "------------end of program------------" << std::endl;

    return 0;
}

выполнить программу и переключиться в текстовый редактор. вы увидите печать текста там.

person Dig The Code    schedule 03.11.2016