linux下用ioctl重新映射键盘

Posted

技术标签:

【中文标题】linux下用ioctl重新映射键盘【英文标题】:Remap a keyboard with ioctl under linux 【发布时间】:2015-03-17 16:16:36 【问题描述】:

我实际上是在尝试编写一个小程序来捕获来自 linux 下特定 USB 键盘的全局键盘输入。

我正在用这段代码进行测试:

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

static const char *const evval[3] = 
    "RELEASED",
    "PRESSED ",
    "REPEATED"
;

int main(void)

    const char *dev = "/dev/input/event2";
    struct input_event ev;
    ssize_t n;
    int fd;
    char name[256]= "Unknown";

//    int codes[2];

//    codes[0] = 58; /* M keycap */
//    codes[1] = 49; /* assign to N */

    fd = open(dev, O_RDONLY);
    if (fd == -1) 
        fprintf(stderr, "Cannot open %s: %s.\n", dev, strerror(errno));
        return EXIT_FAILURE;
    

    if(ioctl(fd, EVIOCGNAME(sizeof(name)), name) > 0) 
    
        printf("The device on %s says its name is '%s'\n", dev, name);
    

    /*
    int err = ioctl(fd, EVIOCSKEYCODE, codes);
    if (err) 
        perror("evdev ioctl");
    */

    while (1) 
        n = read(fd, &ev, sizeof ev);
        if (n == (ssize_t)-1) 
            if (errno == EINTR)
                continue;
            else
                break;
         else
        if (n != sizeof ev) 
            errno = EIO;
            break;
        

        if (ev.type == EV_KEY && ev.value >= 0 && ev.value <= 2)
            printf("%s 0x%04x (%d)\n", evval[ev.value], (int)ev.code, (int)ev.code);

    

    fflush(stdout);
    fprintf(stderr, "%s.\n", strerror(errno));

    return EXIT_FAILURE;

这点是我不知道如何改变其他输入键。我尝试通过更改事件代码在当前红色事件上调用 write(),发送的密钥仍然是前一个,我尝试将 ioctl 与 EVIOCSKEYCODE 一起使用,但调用失败并出现“无效参数”错误(我不是一定要正确调用它)。

如何正确更改输出的密钥?

【问题讨论】:

【参考方案1】:

使用 EVIOCGRAB ioctl 获取输入设备,以便通过读取事件来使用它们。通常(未抓取)事件在您阅读它们时不会被消耗。 ioctl 需要一个额外的参数,(int)1 用于抓取,(int)0 用于释放。

要重新注入任何事件,只需将它们写入uinput 设备即可。参见例如。 mouse example here。 (事件结构是同类型的,你只需要先写一个struct uinput_user_dev结构到uinput设备,来描述你的新输入设备(提供映射事件)。)

换句话说,你不会重新映射:你消费和转发。

【讨论】:

所以如果我理解的话,我会从我的真实事件设备中抓取,但我会写入一个虚拟的“uinput”设备?对吗? @sigzegv:是的。请注意,您只需使用 ioctl 一次;那么您只需正常阅读事件即可。 ioctl 只是告诉内核您通过读取事件来使用它们。通常,在非抓取模式下,即使您阅读了事件,内核和其他应用程序也会处理这些事件。

以上是关于linux下用ioctl重新映射键盘的主要内容,如果未能解决你的问题,请参考以下文章

gpio IOCTL控制

自定义 linux 内核的 ioctl 突然停止响应并在几分钟后重新启动

linux 下修改键盘映射

linux下用rinetd做端口转发

(10)Linux 网络编程之ioctl函数

Linux下利用ioctl函数获取网卡信息