[Linux] /dev/input からマウスイベントを取得する

Linuxでデバイスファイルからマウスのイベントを取得するメモ

# デバイスの確認
`/proc/bus/input/devices` で認識されている各デバイスを確認できる。

```console:マウスデバイスの確認
$ cat /proc/bus/input/devices
~前略~
I: Bus=0001 Vendor=80ee Product=cafe Version=0500
N: Name="VirtualBox mouse integration"
P: Phys=
S: Sysfs=/devices/pci0000:00/0000:00:04.0/input/input7
U: Uniq=
H: Handlers=event6 js1 
B: PROP=0
B: EV=b
B: KEY=10000 0 0 0 0
B: ABS=3
```

上記の例だと、`Handler` に記載されている `event6`, `js1` が、`/dev/input` 以下にデバイスファイルとして作成される。

# 入力の確認

ターミナルで出力できる文字列としては出力されないため、`od`, `hexdump` 等を使用して内容を確認する。
マウスを動かしてみると入力が入ってくることが確認できる。

```console:odで確認
$ sudo cat /dev/input/event6 | od -t x1
0000000 66 db 86 58 00 00 00 00 68 fd 07 00 00 00 00 00
0000020 03 00 01 00 c9 69 00 00 66 db 86 58 00 00 00 00
0000040 68 fd 07 00 00 00 00 00 00 00 00 00 00 00 00 00
0000060 66 db 86 58 00 00 00 00 ca 1b 08 00 00 00 00 00
...
```

```console:hexdumpで確認
$ sudo hexdump /dev/input/event6 
0000000 db45 5886 0000 0000 de4d 0002 0000 0000
0000010 0003 0000 6d7f 0000 db45 5886 0000 0000
0000020 de4d 0002 0000 0000 0000 0000 0000 0000
0000030 db45 5886 0000 0000 fd4d 0002 0000 0000
...
```

# 入力の確認（詳細）

上の例では何かが入力されていることはわかるが、内容はさすがに読めないのでパースしてみる。

```c:入力の仕様
struct input_event {
    struct timeval time;
    unsigned short type;
    unsigned short code;
    unsigned int value;
};

// 厳密にはlongでそのまま定義はされてないが、
// 最終的にはlongと考えて良い
struct timeval {
    long tv_sec;  /* seconds */
    long tv_usec; /* microseconds */
}
```

[Linux/Documentation/input/input.txt - Linux Cross Reference - Free Electrons](http://lxr.free-electrons.com/source/Documentation/input/input.txt)

pythonでパースしてみる。

```py:パースしてを表示するコード例(test.py)
#!/usr/bin/env python

import struct

infile_path = "/dev/input/event6"

# struct input_event {
#     struct timeval time;
#     unsigned short type;
#     unsigned short code;
#     unsigned int value;
# };

EVENT_FORMAT = "llHHI"; # long, long, unsigned short, unsigned short, unsigned int
EVENT_SIZE = struct.calcsize(EVENT_FORMAT)

with open(infile_path, "rb") as file:
    event = file.read(EVENT_SIZE)
    while event:
        #(tv_sec, tv_usec, type, code, value) = struct.unpack(EVENT_FORMAT, event)
        print struct.unpack(EVENT_FORMAT, event)
        event = file.read(EVENT_SIZE)
```

```console:実行例
$ sudo python test.py
(1485235334, 542364, 3, 0, 18883)
(1485235334, 542364, 3, 1, 42469)
(1485235334, 542364, 0, 0, 0)
(1485235334, 550414, 3, 0, 18849)
(1485235334, 550414, 0, 0, 0)
(1485235334, 558122, 3, 0, 18815)
(1485235334, 558122, 3, 1, 42402)
(1485235334, 558122, 0, 0, 0)
(1485235334, 574054, 3, 0, 18781)
(1485235334, 574054, 0, 0, 0)
(1485235334, 590100, 3, 0, 18747)
(1485235334, 590100, 0, 0, 0)
(1485235334, 605869, 3, 0, 18713)
(1485235334, 605869, 3, 1, 42334)
(1485235334, 605869, 0, 0, 0)
...
```

タイムスタンプとデータが取得できることを確認できた。

# TODO

移動は取得できたが、クリックイベントや移動データに関しての読み方を追記する

# `python-evdev` を利用する

上では `/dev/input` 以下のインプットデバイスをそのままパースしたが、
Pythonではevdev interfaceを取り扱う用に `python-evdev` というパッケージがある。

[Introduction — Python-evdev](https://python-evdev.readthedocs.io/en/latest/)

# 参考
[epics/powermate-event – Epics Users JP](http://cerldev.kek.jp/trac/EpicsUsersJP/wiki/epics/powermate-event)
[Linux Input Subsystemの使い方](http://www.tatapa.org/~takuo/input_subsystem/input_subsystem.html)
[インプットデバイスの情報を表示する - はわわーっ](http://yomi322.hateblo.jp/entry/2013/10/05/141654)
[device - Getting live info from /dev/input - Stack Overflow](http://stackoverflow.com/questions/16032982/getting-live-info-from-dev-input)
[7.3. struct — 文字列データをパックされたバイナリデータとして解釈する — Python 2.7.x ドキュメント](http://docs.python.jp/2/library/struct.html)