我正在尝试使用 php 在 GNU/Linux 上获取键盘事件,代码如下:
<?php
$fd = fopen("/dev/input/event0", "rb");
while (true) {
$ev = fread($fd, 24);
$event = unpack("Lsec/Lusec/Stype/Scode/Ivalue", $ev);
var_dump($event);
}
fclose($fd);
?>
但结果与我在以下 C 程序中得到的事件不同:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/input.h>
int main()
{
struct input_event ev;
int fd = open("/dev/input/event0", O_RDONLY);
while(1)
{
read(fd, &ev, sizeof(ev));
printf ("Event sec: %lu\n", ev.time.tv_sec);
printf ("Event usec: %lu\n", ev.time.tv_usec);
printf("Event type: %d\n", ev.type);
printf("Event code: %d\n", ev.code);
printf("Event value: %d\n", ev.value);
printf("Event value: %s\n", "***************");
}
close(fd);
}
部分结果对比:
C:
Event sec: 1700377522
Event usec: 896483
Event type: 4
Event code: 4
Event value: 31
Event value: ***************
Event sec: 1700377522
Event usec: 896483
Event type: 1
Event code: 31
Event value: 1
Event value: ***************
Event sec: 1700377522
Event usec: 896483
Event type: 0
Event code: 0
Event value: 0
Event value: ***************
PHP:
array(5) {
["sec"]=>
int(1700377522)
["usec"]=>
int(0)
["type"]=>
int(44515)
["code"]=>
int(13)
["value"]=>
int(0)
}
array(5) {
["sec"]=>
int(1700377522)
["usec"]=>
int(0)
["type"]=>
int(44515)
["code"]=>
int(13)
["value"]=>
int(0)
}
array(5) {
["sec"]=>
int(1700377522)
["usec"]=>
int(0)
["type"]=>
int(44515)
["code"]=>
int(13)
["value"]=>
int(0)
}
sec
参数似乎解码正常,另一方面,其他参数,我猜测问题是由解包格式引起的:unpack("Lsec/Lusec/Stype/Scode/Ivalue", $ev);
,但我根据/usr/include/linux/input.h
:设置了所有内容
struct input_event {
struct timeval time; = {long seconds, long microseconds}
unsigned short type;
unsigned short code;
unsigned int value;
};
这有什么问题吗?
注: 我在“input.h”中看到一些填充字节:
#if defined(__sparc__) && defined(__arch64__)
unsigned int __usec;
unsigned int __pad;
#else
这可能是问题所在吗?我该如何解决它?
在 64 位 Linux 上,C 整数类型具有以下宽度:
short
:16 位int
:32 位long
:64 位input_event
结构体大小为 8 + 8 + 2 + 2 + 4 = 24 字节。
pack()
函数的文档说:
L unsigned long(始终为 32 位,机器字节顺序)
这里存在不匹配:对于
long
字段,您读取的是 32 位而不是 64 位。你应该使用这个:
q 有符号 long long(始终为 64 位,机器字节顺序)
所以正确的拆包是:
$event = unpack("qsec/qusec/Stype/Scode/Lvalue", $ev);