C++ 如何使用输入子系统生成击键事件

C++ 如何使用输入子系统生成击键事件,c++,c,keyboard,keyboard-events,uinput,C++,C,Keyboard,Keyboard Events,Uinput,我正在Linux中编写一个键盘模拟器程序,首先我能够在X11窗口中渲染按键,但这在虚拟终端中不起作用,并尝试不同的方法。我参考了uinput内核模块并尝试了它。根据教程,击键可以作为uinput事件注入,我相应地编写了下面的代码 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #includ

我正在Linux中编写一个键盘模拟器程序,首先我能够在X11窗口中渲染按键,但这在虚拟终端中不起作用,并尝试不同的方法。我参考了uinput内核模块并尝试了它。根据教程,击键可以作为uinput事件注入,我相应地编写了下面的代码

#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>
#define die(str, args...) do { \
perror(str); \
exit(EXIT_FAILURE); \
} while(0)

int main(void)
{
    int                    fd_keyEmulator;
    struct uinput_user_dev uidev;
    struct input_event     ev;
    int                    dx, dy;
    int                    i;

    fd_keyEmulator = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
    if(fd_keyEmulator < 0)
    {
        std::cout << "error: open : " <<  strerror(errno) << std::endl;
    }

    int ret;
    //ret = ioctl(fd_keyEmulator, UI_SET_EVBIT, EV_KEY);
    //ret = ioctl(fd_keyEmulator, UI_SET_KEYBIT, KEY_D);
    //ret = ioctl(fd_keyEmulator, UI_SET_EVBIT, EV_SYN);
    sleep(5);
    if (ioctl(fd_keyEmulator, UI_SET_EVBIT, EV_KEY) < 0)
    {
        std::cout << "test 1 ..." << std::endl;
        die("error: ioctl");
    }
    if (ioctl(fd_keyEmulator, UI_SET_KEYBIT, KEY_D) < 0)
    {
        std::cout << "test 2 ..." << std::endl;
        die("error: ioctl");
    }
    if (ioctl(fd_keyEmulator, UI_SET_EVBIT, EV_REL) < 0)
    {
        std::cout << "test 3 ..." << std::endl;
        die("error: ioctl");
    }


    memset(&uidev, 0, sizeof(uidev));
    snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "keyboard-emulator");
    uidev.id.bustype = BUS_USB;
    uidev.id.vendor  = 0x1;
    uidev.id.product = 0x1;
    uidev.id.version = 1;

    std::cout << "Writing key press..." << std::endl;
    if(write(fd_keyEmulator, &uidev, sizeof(uidev)) < 0)
        std::cout << "error: write" <<  strerror(errno) << std::endl;

    if(ioctl(fd_keyEmulator, UI_DEV_CREATE) < 0)
        std::cout << "error: ioctl" <<  strerror(errno) << std::endl;


    memset(&ev, 0, sizeof(ev));
    ev.type = EV_REL;
    ev.code = KEY_D;
    ev.value = 1;

    //ret = write(fd_keyEmulator, &ev, sizeof(ev));
    if (write(fd_keyEmulator, &ev, sizeof (struct input_event)) < 0)
                die("error: write");
    if (write(fd_keyEmulator, &ev, sizeof (struct input_event)) < 0)
                die("error: write");
    if (write(fd_keyEmulator, &ev, sizeof (struct input_event)) < 0)
                die("error: write");
    if (write(fd_keyEmulator, &ev, sizeof (struct input_event)) < 0)
                die("error: write");


    if(ioctl(fd_keyEmulator, UI_DEV_DESTROY) < 0)
        std::cout << "error: ioctl" <<  strerror(errno) << std::endl;

    close(fd_keyEmulator);

}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#定义die(str,args…)do{\
perror(str)\
退出(退出失败)\
}而(0)
内部主(空)
{
int fd_键仿真器;
结构uinput_user_dev uidev;
结构输入\事件ev;
int-dx,dy;
int i;
fd_keyEmulator=open(“/dev/uinput”,O_WRONLY | O_NONBLOCK);
如果(fd_键仿真器<0)
{

std::cout以上两个程序没有问题。这里的问题是,这个程序创建了一个新的输入设备(可能在“/dev/input”中的某个地方),而X无法足够快地注册输入设备,以便它能够获取输入。一个简单的“sleep(1)”(带有适当的“#include”)在创建输入设备之后,问题就解决了。具体来说(可能是不必要的),在更改代码之后,程序将按预期运行,因为现在X有足够的时间来实现新的输入设备。在下面的代码段之后添加sleep()语句

    // create the device via an IOCTL call 
    if(ioctl(fd_key_emulator, UI_DEV_CREATE))
    {
        std::cout << "Error in ioctl : UI_DEV_CREATE : " << strerror(errno) << std::endl;
    }
    // add 1 second sleep.
    sleep (1);

    // now fd_key_emulator represents the end-point file descriptor of the new input device.
//通过IOCTL调用创建设备
if(ioctl(fd_-key_-emulator,UI_-DEV_-CREATE))
{
标准::cout
    // create the device via an IOCTL call 
    if(ioctl(fd_key_emulator, UI_DEV_CREATE))
    {
        std::cout << "Error in ioctl : UI_DEV_CREATE : " << strerror(errno) << std::endl;
    }
    // add 1 second sleep.
    sleep (1);

    // now fd_key_emulator represents the end-point file descriptor of the new input device.