centos 在Linux中使用C语言和uinput库模拟击键

j5fpnvbx  于 2022-11-07  发布在  Linux
关注(0)|答案(2)|浏览(223)

我一直在使用下面的C代码来尝试模拟CentOS 6.0机器上的击键:


# include <stdio.h>

# include <string.h>

# include <fcntl.h>

# include <unistd.h>

# inlcude <linux/input.h>

# include <linux/uinput.h>

# include <sys/time.h>

static int fd = -1;
struct uinput_user_dev uidev;
struct input_event event;

int main()
{
    int i;
    fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);

    memset(&uidev, 0, sizeof(uidev));

    snrpintf(uidev.name, UINPUT_MAX_NAME_SIZE, "uinput-kbd");
    uidev.id.version = 1;
    uidev.id.vendor = 0x1;
    uidev.id.product = 0x1;
    uidev.id.bustype = BUS_USB;

    ioctl(fd, UI_SET_EVBIT, EV_KEY);

    for(i = 0; i < 256; i++)
    {
        ioctl(fd, UI_SET_KEYBIT, i);
    }

    ioctl(fd, UI_SET_EVBIT, EV_SYN);

    write(fd, &uidev, sizeof(uidev));

    ioctl(fd, UI_DEV_CREATE));

    memset(&event, 0, sizeof(event));
    gettimeofday(&event.time, NULL);
    event.type = EV_KEY;
    event.code = KEY_1;
    event.value = 1;
    write(fd, &event, sizeof(event));

    event.type = EV_SYN;
    event.code = SYN_REPORT;
    event.value = 0;
    write(fd, &event, sizeof(event));

    memset(&event, 0, sizeof(event));
    gettimeofday(&event.time, NULL);
    event.type = EV_KEY;
    event.code = KEY_1;
    event.value = 0;
    write(fd, &event, sizeof(event));

    event.type = EV_SYN;
    event.code = SYN_REPORT;
    event.value = 0;
    write(fd, &event, sizeof(event));

    ioctl(fd, UI_DEV_DESTROY);
    close(fd);

    return 0;
}

如果我是正确的,这段代码应该在机器上创建一个虚拟输入设备,然后在该设备上按“1”键。(在我的示例代码中,我没有包括用于检查以确保设备正在创建以及击键正在写入等的代码,因为它会变得太长),但我看不出任何实际的击键痕迹。
我的印象是,如果我直接登录到机器,从终端窗口运行这个程序,我应该看到一个“1”字符出现在我正在运行它的终端窗口上。如果我通过ssh登录到机器,并以这种方式运行它,击键应该在机器上注册,而不是ssh会话。但我在这两种情况下都没有得到任何结果。
我是否误解了这段代码的用途?我是否做错了?或者我需要添加更多才能正确模拟击键?

wh6knrhe

wh6knrhe1#

哇,几分钟前我遇到了和你一样的问题,但是现在我不再有这个问题了,而且根据evtest,它似乎可以工作。我不知道我做了什么,不幸的是解决了这个问题。
下面是我用来排除故障的步骤,希望至少能让你有所收获:

  • 验证dmesg在连接时是否报告输入设备。

示例:

[Fri Jul 22 22:38:55 2022] input: Custom Tourbox TBG_H Driver as /devices/virtual/input/input25
  • 验证程序是否可以写入/dev/uinput文件。可以通过检查write()调用的返回值来完成(您列出的示例代码没有)。

如果您对上述内容有任何问题,请仔细检查权限。(我以root身份运行我的程序,然后通过以下方法将/dev/uinput文件的权限更改为全局可写:

$ chmod +0666 /dev/uinput

但这可能不是推荐的做法,最好创建一个组,然后将用户添加到该组中)

  • 验证evtest是否识别新驱动程序。

运行时间:

$ sudo evtest

您应该会看到您的设备(可能在底部):

/dev/input/event24: Custom Tourbox TBG_H Driver
  • 验证evtest是否识别出您的设备已经为您要使用的键注册了一个事件处理程序。在我的例子中,我需要模拟'a'的按键,所以我确保验证该键被列为可能的事件类型之一:

示例输出如下所示:

Input driver version is 1.0.1
Input device ID: bus 0x3 vendor 0x483 product 0xbeef version 0x0
Input device name: "Custom Tourbox TBG_H Driver"
Supported events:
  Event type 0 (EV_SYN)
  Event type 1 (EV_KEY)
    Event code 30 (KEY_A)

从那里,我所做的就是按下键,它就工作了。

uajslkp6

uajslkp62#

现在我发现了为什么这个不能工作,我花了两天时间来寻找这个问题。幸运的是,最后,我在第7.4章的linux内核5.60源代码示例中找到了它。这是图片。Solution
文件说我们最好等一段时间,这样用户空间就有空间来检测事件,因为在内核态创建一个设备节点,和发送一个事件给fd相比,要花很多时间,希望答案不要太晚。
这里是链接7.Uinput-module

相关问题