I'm trying to get keyboard events on GNU/Linux using php, with this code:
<?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);
?>
but the result is different from event I get in the following C program:
#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);
}
Comparing a part of results:
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)
}
The sec
parameter seems to be decoded alright, other parameters on the other hand, I'm guessing the problem is caused by unpack formats: unpack("Lsec/Lusec/Stype/Scode/Ivalue", $ev);
, but I set everything according to /usr/include/linux/input.h
:
struct input_event {
struct timeval time; = {long seconds, long microseconds}
unsigned short type;
unsigned short code;
unsigned int value;
};
What's wrong with that?
Note: I see some padding bytes in "input.h":
#if defined(__sparc__) && defined(__arch64__)
unsigned int __usec;
unsigned int __pad;
#else
Could it be the problem? How can I fix it?
On a 64-bit Linux, the C integer types have the following widths:
short
: 16 bitsint
: 32 bitslong
: 64 bitsThe input_event
struct size is 8 + 8 + 2 + 2 + 4 = 24 bytes.
The documentation for the PHP pack()
function says:
L unsigned long (always 32 bit, machine byte order)
There is a mismatch here: you're reading 32 bits instead of 64 for the long
fields. You should use this instead:
q signed long long (always 64 bit, machine byte order)
So the correct unpacking is:
$event = unpack("qsec/qusec/Stype/Scode/Lvalue", $ev);