You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linux下除/dev/input/eventx外,字符级访问类键盘HID设备的方法?

解决条码扫描器的ASCII流读取问题(无需处理底层按键事件)

看起来你已经摸透了底层input_event的痛点——确实,手动解析按键按下/抬起、处理Shift组合这些工作繁琐又容易出错。既然你的设备已经被内核识别为键盘(Handlers里的kbd就是信号),我们完全可以利用系统现成的键盘处理层来直接拿到ASCII字符流,同时解决输入流向终端导致的登录失败问题。

下面是几个实用的方案,按推荐优先级排序:

方案一:用agetty绑定专属终端(最省心)

这个方法直接让系统帮你把扫描器的输入转换成ASCII流,你只需要从一个虚拟终端文件读取即可,完全不用碰底层事件:

  1. 创建udev规则:
    编辑/etc/udev/rules.d/99-barcode-scanner.rules(文件名任意,只要以99-开头保证优先级),替换成你的扫描器的硬件属性(可以从udevadm info -a /dev/input/event9获取):

    SUBSYSTEM=="input", ATTRS{idVendor}=="04b8", ATTRS{idProduct}=="0202", ATTRS{name}=="EPSON TM-T88V Receipt Printer", SYMLINK+="barcode-scanner", RUN+="/usr/bin/agetty -L /dev/barcode-scanner 9600 vt100"
    
    • SYMLINK+="barcode-scanner"会给设备创建一个友好的软链接/dev/barcode-scanner
    • agetty会启动一个轻量终端会话,自动处理键盘输入到ASCII的转换
  2. 生效规则:
    执行命令重新加载udev规则并触发设备识别:

    udevadm control --reload-rules && udevadm trigger
    
  3. 在守护进程中读取:
    你的代码可以直接打开/dev/barcode-scanner,用普通的文件读取方式(比如read())就能拿到扫描器输出的ASCII条码,连换行符(扫描器通常会附加)都帮你处理好了。而且因为agetty独占了设备,输入不会再流向tty1,也就不会出现登录失败的日志。

方案二:用libevdev简化事件处理(灵活可控)

如果你需要对扫描过程有更多控制(比如实时判断扫描状态),libevdev比直接解析struct input_event轻松太多,它帮你封装了事件处理和键码转换:

  1. 安装依赖:
    先安装libevdev开发包:

    sudo apt install libevdev-dev # Debian/Ubuntu
    # 或者
    sudo dnf install libevdev-devel # RHEL/CentOS
    
  2. 核心代码示例:
    大致逻辑如下(简化版):

    #include <libevdev/libevdev.h>
    #include <fcntl.h>
    #include <unistd.h>
    
    int main() {
        struct libevdev *dev = NULL;
        int fd = open("/dev/input/event9", O_RDONLY|O_NONBLOCK);
        int rc = libevdev_new_from_fd(fd, &dev);
    
        // 独占设备,阻止输入流向终端
        libevdev_grab(dev, LIBEVDEV_GRAB);
    
        struct input_event ev;
        while (1) {
            rc = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_NORMAL, &ev);
            if (rc == LIBEVDEV_READ_STATUS_SUCCESS) {
                // 只处理按键释放事件(扫描器通常是按下即发送,释放完成)
                if (ev.type == EV_KEY && ev.value == 0) {
                    const char *key_name = libevdev_event_get_key_name(ev.code);
                    // 这里可以用系统keymap转换键码到ASCII,避免手动处理Shift组合
                    printf("扫描到字符: %s\n", key_name);
                }
            }
            usleep(1000);
        }
    
        libevdev_free(dev);
        close(fd);
        return 0;
    }
    

    这里的关键是libevdev_grab会帮你独占设备,而且你可以利用系统的keymap来转换键码到ASCII(比如结合libkbd的相关函数),不用自己处理Shift这些组合键。

方案三:解绑设备与默认终端(手动读取)

如果你不想用额外工具或库,可以通过udev规则阻止设备输入流向tty1,然后自己利用kbd子系统的转换:

  1. 创建udev规则:
    在/etc/udev/rules.d/99-barcode-scanner.rules中添加:

    SUBSYSTEM=="input", ATTRS{name}=="你的扫描器名称", ENV{CONSOLE}=""
    

    这条规则会告诉系统不要把这个设备的输入发送到默认console(tty1),避免登录失败日志。

  2. 读取转换后的字符:
    你可以使用kbd工具的kbd_mode设置设备为字符模式,然后通过读取/dev/input/event9的事件,再用kbd_translate函数(来自libkbd)转换为ASCII字符。不过这个方法需要链接libkbd,代码量比方案二多一些,优先级不如前两个。

注意事项

  • 所有操作都需要root权限,或者给你的守护进程添加CAP_SYS_ADMIN能力(用setcap cap_sys_admin+ep your_daemon)
  • 一定要替换规则中的设备属性(idVendor、idProduct、name),可以用udevadm info -a /dev/input/event9获取准确值

内容的提问来源于stack exchange,提问作者code9016

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:35:53