Today I would like to show how you can work with stream of bytes from /dev/input/eventX
.
First of all I found which files in /dev/input/
bind to my keyboard and mouse. To do it I used command:
$ cat /proc/bus/input/devices
And I have got that my mouse bindind is /dev/input/event10
and my keyboard binding is /dev/input/event3
.
...
H: Handlers=sysrq kbd event3 leds # keyboard
...
...
H: Handlers=mouse1 event10 # mouse
...
I found in documentation Linux Input drivers that steam of bytes in device eventX
is structured this way:
You can use blocking and nonblocking reads, also select() on the
/dev/input/eventX devices, and you'll always get a whole number of input
events on a read. Their layout is:
struct input_event {
struct timeval time;
unsigned short type;
unsigned short code;
unsigned int value;
};
I used simple program in C to figure out size of input_event
and timeval
:
printf("%ld\n", sizeof(struct input_event));
printf("%ld\n", sizeof(struct timeval));
It shows that input_event
has 24 bytes and timeval
has 16.
+ 16 + 2 + 2 + 4 +
| sec + µsec | | | |
+-----------------------------------------------------------------------+
| 0| 1| 2| 3| 4| 5| 6| 7| 8| 9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|
+-----------------------------------------------------------------------+
| | | | |
+ timeval +type + code+ value +
This means that each of 24 bytes has information about time, type of event, code of event and value of this event.
After that I wrote a simple program on Go for reading 24 bytes in loop from /dev/input/event10
(reading from /dev/input/*
needs root permisions):
package main
import (
"fmt"
"os"
)
func main() {
f, err := os.Open("/dev/input/event10")
if err != nil {
panic(err)
}
defer f.Close()
b := make([]byte, 24)
for {
f.Read(b)
fmt.Printf("%b\n", b)
}
}
After compiling and running this program I have got some data:
[1001000 11001110 10110011 1011001 0 0 0 0 11100110 110000 1100 0 0 0 0 0 0 0 0 0 0 0 0 0]
[1001000 11001110 10110011 1011001 0 0 0 0 1101100 1010000 1100 0 0 0 0 0 10 0 1 0 11111111 11111111 11111111 11111111]
[1001000 11001110 10110011 1011001 0 0 0 0 1101100 1010000 1100 0 0 0 0 0 0 0 0 0 0 0 0 0]
[1001000 11001110 10110011 1011001 0 0 0 0 1111111 1101111 1100 0 0 0 0 0 10 0 1 0 11111111 11111111 11111111 11111111]
[1001000 11001110 10110011 1011001 0 0 0 0 1111111 1101111 1100 0 0 0 0 0 0 0 0 0 0 0 0 0]
First 16 bytes shows time. First 8 bytes stand for seconds and next 8 bytes stand for microseconds. We can use packages time
and encoding/binary
in Go to encode it.
sec := binary.LittleEndian.Uint64(b[0:8])
usec := binary.LittleEndian.Uint64(b[8:16])
t := time.Unix(int64(sec), int64(usec)*1000)
fmt.Println(t)
You can see how it works:
[1000000 11010010 10110011 1011001 0 0 0 0 110010 100001 101 0 0 0 0 0 0 0 0 0 0 0 0 0]
2017-09-09 13:36:32.000336178 +0200 CEST
[1000000 11010010 10110011 1011001 0 0 0 0 11000111 1011111 101 0 0 0 0 0 10 0 1 0 11111111 11111111 11111111 11111111]
2017-09-09 13:36:32.000352199 +0200 CEST
[1000000 11010010 10110011 1011001 0 0 0 0 11000111 1011111 101 0 0 0 0 0 0 0 0 0 0 0 0 0]
2017-09-09 13:36:32.000352199 +0200 CEST
I decoded type, code and value the same way:
var value int32
typ := binary.LittleEndian.Uint16(b[16:18])
code := binary.LittleEndian.Uint16(b[18:20])
binary.Read(bytes.NewReader(b[20:]), binary.LittleEndian, &value)
fmt.Printf("type: %x\ncode: %d\nvalue: %d\n", typ, code, value)
After running it I can see decoded data of events:
....
2017-09-09 13:42:01.000336178 +0200 CEST
type: 2
code: 0
value: 2
....
....
....
2017-09-09 13:42:02.000312149 +0200 CEST
type: 2
code: 1
value: -1
....
....
....
2017-09-09 13:42:10.000351198 +0200 CEST
type: 1
code: 272
value: 0
....
In this file we can see that type 0x02 equals EV_REL
, code 0x00 means REL_X
and value means change of mouse position +2 OX.
Type 0x01 equals EV_KEY
, code 0x110(272) means BTN_LEFT
.
You can see that reading and parsing data from /dev/input/*
is quite simple.
All necessary code is bellow here:
package main
import (
"bytes"
"encoding/binary"
"fmt"
"os"
"time"
)
func main() {
f, err := os.Open("/dev/input/event10")
if err != nil {
panic(err)
}
defer f.Close()
b := make([]byte, 24)
for {
f.Read(b)
sec := binary.LittleEndian.Uint64(b[0:8])
usec := binary.LittleEndian.Uint64(b[8:16])
t := time.Unix(int64(sec), int64(usec))
fmt.Println(t)
var value int32
typ := binary.LittleEndian.Uint16(b[16:18])
code := binary.LittleEndian.Uint16(b[18:20])
binary.Read(bytes.NewReader(b[20:]), binary.LittleEndian, &value)
fmt.Printf("type: %x\ncode: %d\nvalue: %d\n", typ, code, value)
}
}