需求
读取二维码 DataMatrix
格式的扫码头是 usb
接口,通过键盘输入的形式输出数据。程序需要读取这些数据。
解决
设备信息
获取设备信息
键盘输入在 linux 当中属于 input
子系统,对应的设备号是
/dev/input/eventX
, 如果希望知道自己的设备具体对应那个,可以使用下面这条命令来获取所有的输入设备信息。如果希望了解输入的更多内容,可以查看
https://www.kernel.org/doc/Documentation/input/input.txt
cat /proc/bus/input/devices
I: Bus=0019 Vendor=2454 Product=6575 Version=0010
N: Name="mtk-kpd"
P: Phys=
S: Sysfs=/devices/platform/mtk-kpd/input/input0
U: Uniq=
H: Handlers=event0
B: PROP=0
B: EV=3
B: KEY=1c0000 0 0 0
I: Bus=0019 Vendor=0000 Product=0000 Version=0000
N: Name="ACCDET"
P: Phys=
S: Sysfs=/devices/virtual/input/input1
U: Uniq=
H: Handlers=event1
B: PROP=0
B: EV=3
B: KEY=80 0 78 0 40c0000 0 0 0
I: Bus=0000 Vendor=0000 Product=0000 Version=0000
N: Name="hwmdata"
P: Phys=
S: Sysfs=/devices/virtual/input/input2
U: Uniq=
H: Handlers=event2
B: PROP=0
B: EV=5
B: REL=2
分析设备信息
根据上面的输出信息,可以根据 Name
这一行大概找到自己的设备,如果希望知道设备支持的详细内容可以查看 EV
值,根据
/usr/include/linux/input-event-codes.h
文件内容, 可以按照哪一位置位来知道设备支持的输入形式。
#define EV_SYN 0x00
#define EV_KEY 0x01
#define EV_REL 0x02
#define EV_ABS 0x03
#define EV_MSC 0x04
#define EV_SW 0x05
#define EV_LED 0x11
#define EV_SND 0x12
#define EV_REP 0x14
#define EV_FF 0x15
#define EV_PWR 0x16
#define EV_FF_STATUS 0x17
#define EV_MAX 0x1f
#define EV_CNT (EV_MAX+1)
常用的对应关系:
键盘 | 鼠标 | 触摸 |
---|---|---|
EV_KEY | EV_REL | EV_ABS |
按键类型 | 相对位置 | 绝对位置 |
比如说带按键的触摸屏,那么 EV
值就是 (1 << 1) | (1 << 3)
. 如果需要在 C/C++
, 当中来获取这些数据,可以使用如下代码:
char name[64]; /* RATS: Use ok, but could be better */
char buf[256] = { 0, }; /* RATS: Use ok */
unsigned char mask[EV_MAX/8 + 1]; /* RATS: Use ok */
#define test_bit(bit) (mask[(bit)/8] & (1 << ((bit)%8)))
for (i = 0; i < 32; i++) {
sprintf(name, "/dev/input/event%d", i);
if ((fd = open(name, O_RDONLY, 0)) >= 0) {
ioctl(fd, EVIOCGVERSION, &version);
ioctl(fd, EVIOCGNAME(sizeof(buf)), buf);
ioctl(fd, EVIOCGBIT(0, sizeof(mask)), mask);
printf("%s\n", name);
printf(" evdev version: %d.%d.%d\n",
version >> 16, (version >> 8) & 0xff, version & 0xff);
printf(" name: %s\n", buf);
printf(" features:");
for (j = 0; j < EV_MAX; j++) {
if (test_bit(j)) {
const char *type = "unknown";
switch(j) {
case EV_KEY: type = "keys/buttons"; break;
case EV_REL: type = "relative"; break;
case EV_ABS: type = "absolute"; break;
case EV_MSC: type = "reserved"; break;
case EV_LED: type = "leds"; break;
case EV_SND: type = "sound"; break;
case EV_REP: type = "repeat"; break;
case EV_FF: type = "feedback"; break;
}
printf(" %s", type);
}
}
printf("\n");
close(fd);
}
}
读取数据
从 event
中读取数据,数据是按照 input_event
的格式给出的,定义在
/usr/include/linux/input.h
中。
struct input_event {
#if (__BITS_PER_LONG != 32 || !defined(__USE_TIME_BITS64)) && !defined(__KERNEL__)
struct timeval time;
#define input_event_sec time.tv_sec
#define input_event_usec time.tv_usec
#else
__kernel_ulong_t __sec;
#if defined(__sparc__) && defined(__arch64__)
unsigned int __usec;
unsigned int __pad;
#else
__kernel_ulong_t __usec;
#endif
#define input_event_sec __sec
#define input_event_usec __usec
#endif
__u16 type;
__u16 code;
__s32 value;
};
-
time: 按键时间
-
type: 类型,就是
EV_KEY
,EV_REL
之类的。 -
code: 按键的键值,鼠标的键值,鼠标的轨迹类型
#define KEY_RESERVED 0 #define KEY_ESC 1 #define KEY_1 2 #define KEY_2 3 #define KEY_3 4 #define KEY_4 5 #define KEY_5 6 #define KEY_6 7 #define KEY_7 8 #define KEY_8 9 #define KEY_9 10 #define KEY_0 11 #define KEY_MINUS 12 #define KEY_EQUAL 13 #define KEY_BACKSPACE 14 #define KEY_TAB 15 #define KEY_Q 16 #define KEY_W 17 #define KEY_E 18 ...
#define BTN_MOUSE 0x110 #define BTN_LEFT 0x110 #define BTN_RIGHT 0x111 #define BTN_MIDDLE 0x112 #define BTN_SIDE 0x113 #define BTN_EXTRA 0x114 #define BTN_FORWARD 0x115 #define BTN_BACK 0x116 #define BTN_TASK 0x117 #define BTN_JOYSTICK 0x120 #define BTN_TRIGGER 0x120 #define BTN_THUMB 0x121 #define BTN_THUMB2 0x122 #define BTN_TOP 0x123 #define BTN_TOP2 0x124 ...
#define REL_X 0x00 #define REL_Y 0x01 #define REL_Z 0x02 #define REL_RX 0x03 #define REL_RY 0x04 #define REL_RZ 0x05 #define REL_HWHEEL 0x06 #define REL_DIAL 0x07 #define REL_WHEEL 0x08 #define REL_MISC 0x09
#define ABS_X 0x00 #define ABS_Y 0x01 #define ABS_Z 0x02 #define ABS_RX 0x03 #define ABS_RY 0x04 #define ABS_RZ 0x05 #define ABS_THROTTLE 0x06 #define ABS_RUDDER 0x07 #define ABS_WHEEL 0x08 #define ABS_GAS 0x09 #define ABS_BRAKE 0x0a #define ABS_HAT0X 0x10 #define ABS_HAT0Y 0x11 #define ABS_HAT1X 0x12 #define ABS_HAT1Y 0x13 #define ABS_HAT2X 0x14 #define ABS_HAT2Y 0x15 #define ABS_HAT3X 0x16 #define ABS_HAT3Y 0x17 #define ABS_PRESSURE 0x18 #define ABS_DISTANCE 0x19 #define ABS_TILT_X 0x1a
-
value: 事件的值,如果是键盘,那么按下为 1, 松开为 0,如果是鼠标,那么正负表示两个不同方向的值。
打开设备并读取可以使用 while
来读取,深入一点可以使用 select
来读取。
const string kInputDevice = "/dev/input/event11";
int main()
{
int fd = 0;
if ((fd = open(kInputDevice.c_str(), O_RDONLY)) < 0) {
fprintf(stderr, "open error\n");
return -1;
}
struct input_event key;
while (1) {
if (read(fd, &key, sizeof(struct input_event)) == sizeof(struct input_event)) {
printf("type: %d, code: %d, value: %d\n", key.type, key.code, key.value);
}
}
close(fd);
return 0;
}
获取的数据类似如下, 我按照按下和抬起,做了初步的分隔。实际的值为: C301001001,
// shift + c, 1
type: 4, code: 4, value: 458981
type: 1, code: 54, value: 1
type: 4, code: 4, value: 458758
type: 1, code: 46, value: 1
type: 0, code: 0, value: 0
// shift + c, 0
type: 4, code: 4, value: 458981
type: 1, code: 54, value: 0
type: 4, code: 4, value: 458758
type: 1, code: 46, value: 0
type: 0, code: 0, value: 0
// 3, 1
type: 4, code: 4, value: 458784
type: 1, code: 4, value: 1
type: 0, code: 0, value: 0
// 3, 0
type: 4, code: 4, value: 458784
type: 1, code: 4, value: 0
type: 0, code: 0, value: 0
// 0, 1
type: 4, code: 4, value: 458791
type: 1, code: 11, value: 1
type: 0, code: 0, value: 0
// 0, 0
type: 4, code: 4, value: 458791
type: 1, code: 11, value: 0
type: 0, code: 0, value: 0
// 1, 1
type: 4, code: 4, value: 458782
type: 1, code: 2, value: 1
type: 0, code: 0, value: 0
// 1, 0
type: 4, code: 4, value: 458782
type: 1, code: 2, value: 0
type: 0, code: 0, value: 0
// 0, 1
type: 4, code: 4, value: 458791
type: 1, code: 11, value: 1
type: 0, code: 0, value: 0
// 0, 0
type: 4, code: 4, value: 458791
type: 1, code: 11, value: 0
type: 0, code: 0, value: 0
// 0, 1
type: 4, code: 4, value: 458791
type: 1, code: 11, value: 1
type: 0, code: 0, value: 0
// 0, 0
type: 4, code: 4, value: 458791
type: 1, code: 11, value: 0
type: 0, code: 0, value: 0
// 1, 1
type: 4, code: 4, value: 458782
type: 1, code: 2, value: 1
type: 0, code: 0, value: 0
// 1, 0
type: 4, code: 4, value: 458782
type: 1, code: 2, value: 0
type: 0, code: 0, value: 0
// 0, 1
type: 4, code: 4, value: 458791
type: 1, code: 11, value: 1
type: 0, code: 0, value: 0
// 0, 0
type: 4, code: 4, value: 458791
type: 1, code: 11, value: 0
type: 0, code: 0, value: 0
// 0, 1
type: 4, code: 4, value: 458791
type: 1, code: 11, value: 1
type: 0, code: 0, value: 0
// 0, 0
type: 4, code: 4, value: 458791
type: 1, code: 11, value: 0
type: 0, code: 0, value: 0
// 1, 1
type: 4, code: 4, value: 458782
type: 1, code: 2, value: 1
type: 0, code: 0, value: 0
// 1, 0
type: 4, code: 4, value: 458782
type: 1, code: 2, value: 0
type: 0, code: 0, value: 0
// , , 1
type: 4, code: 4, value: 458806
type: 1, code: 51, value: 1
type: 0, code: 0, value: 0
// , , 0
type: 4, code: 4, value: 458806
type: 1, code: 51, value: 0
type: 0, code: 0, value: 0
如果读取程序更加完善,可以参考如下的示例代码:
if (argc > 1) {
sprintf(name, "/dev/input/event%d", atoi(argv[1]));
if ((fd = open(name, O_RDWR, 0)) >= 0) {
printf("%s: open, fd = %d\n", name, fd);
for (i = 0; i < LED_MAX; i++) {
event.time.tv_sec = time(0);
event.time.tv_usec = 0;
event.type = EV_LED;
event.code = i;
event.value = 0;
write(fd, &event, sizeof(event));
}
while ((rc = read(fd, &event, sizeof(event))) > 0) {
printf("%-24.24s.%06lu type 0x%04x; code 0x%04x;"
" value 0x%08x; ",
ctime(&event.time.tv_sec),
event.time.tv_usec,
event.type, event.code, event.value);
switch (event.type) {
case EV_KEY:
if (event.code > BTN_MISC) {
printf("Button %d %s",
event.code & 0xff,
event.value ? "press" : "release");
} else {
printf("Key %d (0x%x) %s",
event.code & 0xff,
event.code & 0xff,
event.value ? "press" : "release");
}
break;
case EV_REL:
switch (event.code) {
case REL_X: tmp = "X"; break;
case REL_Y: tmp = "Y"; break;
case REL_HWHEEL: tmp = "HWHEEL"; break;
case REL_DIAL: tmp = "DIAL"; break;
case REL_WHEEL: tmp = "WHEEL"; break;
case REL_MISC: tmp = "MISC"; break;
default: tmp = "UNKNOWN"; break;
}
printf("Relative %s %d", tmp, event.value);
break;
case EV_ABS:
switch (event.code) {
case ABS_X: tmp = "X"; break;
case ABS_Y: tmp = "Y"; break;
case ABS_Z: tmp = "Z"; break;
case ABS_RX: tmp = "RX"; break;
case ABS_RY: tmp = "RY"; break;
case ABS_RZ: tmp = "RZ"; break;
case ABS_THROTTLE: tmp = "THROTTLE"; break;
case ABS_RUDDER: tmp = "RUDDER"; break;
case ABS_WHEEL: tmp = "WHEEL"; break;
case ABS_GAS: tmp = "GAS"; break;
case ABS_BRAKE: tmp = "BRAKE"; break;
case ABS_HAT0X: tmp = "HAT0X"; break;
case ABS_HAT0Y: tmp = "HAT0Y"; break;
case ABS_HAT1X: tmp = "HAT1X"; break;
case ABS_HAT1Y: tmp = "HAT1Y"; break;
case ABS_HAT2X: tmp = "HAT2X"; break;
case ABS_HAT2Y: tmp = "HAT2Y"; break;
case ABS_HAT3X: tmp = "HAT3X"; break;
case ABS_HAT3Y: tmp = "HAT3Y"; break;
case ABS_PRESSURE: tmp = "PRESSURE"; break;
case ABS_DISTANCE: tmp = "DISTANCE"; break;
case ABS_TILT_X: tmp = "TILT_X"; break;
case ABS_TILT_Y: tmp = "TILT_Y"; break;
case ABS_MISC: tmp = "MISC"; break;
default: tmp = "UNKNOWN"; break;
}
printf("Absolute %s %d", tmp, event.value);
break;
case EV_MSC: printf("Misc"); break;
case EV_LED: printf("Led"); break;
case EV_SND: printf("Snd"); break;
case EV_REP: printf("Rep"); break;
case EV_FF: printf("FF"); break;
break;
}
printf("\n");
}
printf("rc = %d, (%s)\n", rc, strerror(errno));
close(fd);
}
}
参考
请问怎么知道/dev/input/eventX对应的是什么设备?
How can I translate Linux keycodes from /dev/input/event* to ASCII in Perl?
如何读取Linux键值,输入子系统,key,dev/input/event,dev/event,C语言键盘
Linux下键盘键值对应input event下的code值表
{笔记分享} {遥控器}Android红外及蓝牙遥控器适配流程
input_event(input_dev, EV_MSC, MSC_SCAN, code)具体意义