键值从键盘到Linux内核传输过程分析

键值从键盘到Linux内核传输过程分析


        这是一个以前没有了解过的一个盲区。
        源于在制作一个带有特殊键的键盘,键盘厂商让挑选择殊键的实现方法。并举例说明了普通按键z在他们的MCU中其实是00 00 1d 00 00 00 00 00(以下简称:MCU键值)即0x1d十进制29,我立即通过hexdump /dev/input/eventX方法查看键盘上z键的在Linux内核上传过来的值(以下简称:Linux键值),一看是0x2c(十进制:44)。那么这两个值是什么关系呢?
        于是乎我赶紧Google一番,更离奇的是Windows系统中将z键定义为90(以下简称:Windows键值)。这下出现了三套键值,事情变得复杂又觉得有些清晰了。
        既然同一个键盘可以在Linux和Windows下正常使用,那么他们之间必须有一个共用的标准。先抛开Windows不说,看看在Linux内核中是如何将29转换为44的。

        定位到Linux内核中usb键盘的驱动程序是drivers/hid/usbhid/usbkbd.c,然后上来就搜索[44],结果真就出来了一张"表",且经过分析后29恰恰是44所在位置的坐标。

键值从键盘到Linux内核传输过程分析_第1张图片

        问题进一步清晰了,那么接下来想要明白的是 29 在哪个表中,那个表应该也是一个标准的协议规范,代码中也没有关于这个的注释,我应该怎么办?在我准备给代码的作者发邮件时,键盘厂商发来了一个对这个问题的说明。并附上了一个《USB HID to PS/2 Scan Code Translation Table》的表,而29(0x1d)正是在上表中。
        Google搜索《 USB HID to PS/2 Scan Code Translation Table》()[注1]就能找到微软整理的一个表。第三列为HID协议中规定的原始键值码。Linux系统中的HID驱动也是将HID设备发来的原始键值码转换为自己系统所制定的码值。详情见:drivers/hid/usbhid/usbkbd.c源码。
        MCU键值 学名为:HID Usage Page,Linux或者Windows系统以其为基准对应出自己的系统所使用的系统键值码。

        了解过这个情况后,以后在定制键盘时,告知给键盘设计厂商的应该是HID原始键值码。

Linux下对键盘输入事件的调试

日期:20150402

    第一行中的getevent是截取键盘输入的命令,该命令运行后先首先将所以的输入设备列出来,比如图上就有键鼠,物理按键,耳机hook,红外遥控按键等几种类型的输入设备,这里只讨论标准键盘输入。

    列出输入设备以下的内容就是按键后截取的信息,它们分别是TYPE CODEVALUE,其中TYPE常见的类型有:更多解释见《Linux inputevent-codes》

* EV_SYN:

  -Used as markers to separate events. Events may be separated in time or in

   space, such as with the multitouch protocol.

* EV_KEY:

  -Used to describe state changes of keyboards, buttons, or other key-like

Devices.

* EV_MSC:

  -Used to describe miscellaneous input data that do not fit into other types.。

对于EV_SYN其中CODE是不同的键值。

图中是输入了一个Z键,一秒后抬起的总输出信息,它们的意思分别是:


 

TYPE

CODE

VALUE

备注

EV_SYN

SYN_REPORT

0

上报

1

Auto-repeat

EV_KEY

   KEY_NAME

DOWN

按下

UP

抬起

REPEAT

Kernel soft-repeat

EV_MSC

MSC_SCAN

0007001D

键盘HID码《》

对于Auto-repeat的实现,内核中有自行实现,但是在上层系统中真正使用的不多,比如x11,Android。像Android是这样说的:来源《keyboard-devices》

Android performsits own keyboard repeating. Auto-repeat functionality should be disabled in thedriver.

如果需要禁用kernel中的auto-repeat以减小上层系统的无用处理,可以使用以下方法:

#include

#include

#include

#include

#include

 

#ifndef EVIOCSREP

#define EVIOCSREP _IOW('E', 0x03, int[2])

#endif

 

int main(int argc, char** argv) {

       int fd = 0;

       int rep[2] = {0};

       if ((fd = open("/dev/input/event4",

                     O_RDWR))< 0) {

              perror("unableto access /dev/input/event2, exiting");

              exit(1);

       }

       // get current auto-repeat args.

       if (ioctl(fd,EVIOCGREP, rep)) {

              perror("unableto set delay and repeat rate for input devices");

              exit(1);

       }

       rep[1] =0;  // set auto-repeat rate as 0.

       if (ioctl(fd,EVIOCSREP, rep)) {

              perror("unableto set delay and repeat rate for input devices");

              exit(1);

       }

       printf("rep[0]:%d;rep[1]:%d\n", rep[0], rep[1]);

       close(fd);

}

《完》


注1:当然也可以在 CSDN上下载

你可能感兴趣的:(Hardware,Linux设备驱动,Linux-kernel)