c++ - 我们可以在 Linux 中使用 C++ 使用原始 ASCII 值生成击键吗?

标签 c++ linux usb ascii keystroke

我从条形码扫描仪接收到 ASCII 格式的条形码数据。我需要编写一个程序来使用通过 Linux 中的条形码扫描仪接收到计算机的数据来模拟键盘。我也阅读了适用于 Linux 的 USB-HIDKB 驱动程序的源代码 (http://lxr.free-electrons.com/source/drivers/hid/usbhid/usbkbd.c),但我觉得我必须反其道而行之。 我真正想要做的是从扫描仪接收数据作为 ASCII 格式的数据流,并且需要使用扫描数据生成击键。数据读取部分快完成了,需要找到一种方法将 ASCII 数据转换为击键。

示例操作:

CTRL + z(撤消操作的键盘快捷键)有一个条形码,一旦扫描就会收到条形码数据,08 10 03 00 1a 00 18 0b 被接收为十六进制数据,然后数据为 1a 00 18 0b。这里前 4 个字节是标题,剩下的是数据部分。 现在我需要做的是执行撤销操作而不是打印数据。

欢迎任何代码示例或建议开始编码。谢谢。

最佳答案

找到了一段有用的代码 [1]: http://www.doctort.org/adam/nerd-notes/x11-fake-keypress-event.html ,帮助我开始使用已处理的数据模拟击键。

但这仅适用于具有 xwindowing 系统的系统。这不适用于仅基于终端的系统。在这种情况下,我们需要使用 uinput 子系统来生成软件按键。

关于如何在 Linux 中使用 uinput 的示例程序可以在这里找到 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;
}

执行程序并切换到文本编辑器。你会看到那里正在打印文本。

关于c++ - 我们可以在 Linux 中使用 C++ 使用原始 ASCII 值生成击键吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40238050/

相关文章:

c++ - 使用 C++ 在 Linux 0.01 中为 "Semaphore"添加系统调用

ruby - 是否可以有多个 STDIN 流?

c++ - 如何在 C++ (VS2010) 中设置超时读取 USB 端口?

c++ - 函数在 C++ 中返回一个结构?

c++ - 为什么 std::regex_match 不支持 "zero-length assertions"?

c++ - 指针和架构的大小

c - xfrm 实现 IPsec

linux - 如何在删除前检查文件是否存在?

linux - 在 Linux 中查找哪个驱动器对应哪个 USB 大容量存储设备

android - 为什么原生 Android 应用程序崩溃后会立即重新启动?