Linux 需要拦截HID键盘事件(然后阻止它们)

Linux 需要拦截HID键盘事件(然后阻止它们),linux,keyboard-events,hid,Linux,Keyboard Events,Hid,我有一个RFID USB设备,可以注册为HID设备(或多或少是一个USB键盘) 我正在寻找一种方法来捕获这个输入,并在它到达普通键盘事件处理程序(并将10位RFID代码输出到控制台)之前对其进行阻止/过滤 当然,我必须只捕获这个设备,而不使用真正的键盘输入(或者传递) 我最初的想法是在UDEV中阻止设备(因此usbhid/event/kbd内核模块没有绑定到它),并为这个设备编写我自己的基本驱动程序——但我不知道从哪里开始,或者这是否可行 如果我编写一个事件过滤器模块,它可以与事件驱动程序保持一

我有一个RFID USB设备,可以注册为HID设备(或多或少是一个USB键盘)

我正在寻找一种方法来捕获这个输入,并在它到达普通键盘事件处理程序(并将10位RFID代码输出到控制台)之前对其进行阻止/过滤

当然,我必须只捕获这个设备,而不使用真正的键盘输入(或者传递)

我最初的想法是在UDEV中阻止设备(因此usbhid/event/kbd内核模块没有绑定到它),并为这个设备编写我自己的基本驱动程序——但我不知道从哪里开始,或者这是否可行

如果我编写一个事件过滤器模块,它可以与事件驱动程序保持一致,并从RFID单元捕获(然后过滤)适当的输入,但让其他一切都通过,那将是一件好事(我不确定是否可以做到这一点)。我想这样一个模块不需要太多代码,而且是最实用的

帮忙

[编辑:我应该补充一点,Xorg未安装-仅控制台]

cat /proc/bus/input:
  I: Bus=0003 Vendor=0419 Product=0912 Version=0100
  N: Name="NewRoad Sem. NewRoad System PS2 Interface"
  P: Phys=usb-0000:00:1d.3-2/input0
  S: Sysfs=/devices/pci0000:00/0000:00:1d.3/usb5/5-2/5-2:1.0/input/input20
  U: Uniq=
  H: Handlers=sysrq kbd mouse0 event3
  B: PROP=0
  B: EV=120017
  B: KEY=70000 0 0 e080ffdf01cfffff fffffffffffffffe
  B: REL=103
  B: MSC=10
  B: LED=1f
更多信息:

lsusb -d 0419:0912 -v
Bus 005 Device 019: ID 0419:0912 Samsung Info. Systems America, Inc.
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               1.00
  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0
  bDeviceProtocol         0
  bMaxPacketSize0         8
  idVendor           0x0419 Samsung Info. Systems America, Inc.
  idProduct          0x0912
  bcdDevice            0.01
  iManufacturer           1 NewRoad Sem.
  iProduct                2 NewRoad System PS2 Interface
  iSerial                 0
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           34
    bNumInterfaces          1
    bConfigurationValue     1
    iConfiguration          4
    bmAttributes         0xa0
      (Bus Powered)
      Remote Wakeup
    MaxPower              100mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           1
      bInterfaceClass         3 Human Interface Device
      bInterfaceSubClass      1 Boot Interface Subclass
      bInterfaceProtocol      1 Keyboard
      iInterface              5
        HID Device Descriptor:
          bLength                 9
          bDescriptorType        33
          bcdHID               1.00
          bCountryCode            0 Not supported
          bNumDescriptors         1
          bDescriptorType        34 Report
          wDescriptorLength     119
         Report Descriptors:
           ** UNAVAILABLE **
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0008  1x 8 bytes
        bInterval              10
Device Status:     0x0000
  (Bus Powered)

您可以在事件设备上使用EVIOCGRAB ioctl以独占方式捕获它

所以我根据我找到的那篇帖子,快速开发了一款概念验证应用程序

它正是我所需要的——尽管我无论如何都会分享我的解决方案

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <dirent.h>
#include <linux/input.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/select.h>
#include <sys/time.h>
#include <termios.h>
#include <signal.h>

int main(int argc, char* argv[])
{
    struct input_event ev[64];
    int fevdev = -1;
    int result = 0;
    int size = sizeof(struct input_event);
    int rd;
    int value;
    char name[256] = "Unknown";
    char *device = "/dev/input/event3";


    fevdev = open(device, O_RDONLY);
    if (fevdev == -1) {
        printf("Failed to open event device.\n");
        exit(1);
    }

    result = ioctl(fevdev, EVIOCGNAME(sizeof(name)), name);
    printf ("Reading From : %s (%s)\n", device, name);

    printf("Getting exclusive access: ");
    result = ioctl(fevdev, EVIOCGRAB, 1);
    printf("%s\n", (result == 0) ? "SUCCESS" : "FAILURE");

    while (1)
    {
        if ((rd = read(fevdev, ev, size * 64)) < size) {
            break;
        }

        value = ev[0].value;

        if (value != ' ' && ev[1].value == 1 && ev[1].type == 1) {
            printf ("Code[%d]\n", (ev[1].code));
        }
    }

    printf("Exiting.\n");
    result = ioctl(fevdev, EVIOCGRAB, 1);
    close(fevdev);
    return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
int main(int argc,char*argv[])
{
结构输入事件ev[64];
int-fevdev=-1;
int结果=0;
int size=sizeof(结构输入事件);
国际公路;
int值;
字符名[256]=“未知”;
char*device=“/dev/input/event3”;
fevdev=打开(仅限设备);
如果(fevdev==-1){
printf(“无法打开事件设备。\n”);
出口(1);
}
结果=ioctl(fevdev,eviogname(sizeof(name)),name);
printf(“读取:%s(%s)\n”、设备、名称);
printf(“获得独占访问:”);
结果=ioctl(fevdev,EVIOCGRAB,1);
printf(“%s\n”,结果==0)?“成功”:“失败”);
而(1)
{
如果((rd=读取(fevdev,ev,大小*64))
取消抓取需要一个“false”值参数,如下所示:

result = ioctl(fevdev, EVIOCGRAB, 0);

我想可能有我想要的答案…在获取输入之前应该调用sleep(),否则它可能会在执行编译的二进制文件时阻止ENTER发布。@Litch我不明白如何过滤事件。你刚刚阻止了他们,但是你打算如何传播这些事件?@WscriChy我不认为Litch试图传播这些事件。他的代码库一开始就是消费者。我正在寻找类似的解决方案。但是,在我的案例中,我需要截取输入提要中的部分事件,但传播其他事件…因此我的任务更像您正在思考的任务。是否可以只过滤一些事件并将其他事件转发给其他侦听器?您的确切意思是什么?