2021年07月30日 更新

evdevでキーやマウスのイベント取得

どうも、クラゲです。
Pythonで実行画面が表示されていなくても、キーボードやマウスなどから入力を受ける方法をご紹介します。応用すれば、無線テンキーボードなどがラズパイのリモコンのように使えて便利です。

inputの課題

Python標準モジュールで使えるinputは以下の課題があります。

  1. エンターキーを押されるまで入力待ちの状態になる
  2. 非アクティブ(実行画面が後ろに隠れている)やバックグラウンド(実行画面なし)では読み込みできない

上記の1を解決する案として、OpenCVのwaitKey関数やreadcharモジュールなどがありますが、2についてはやはり解決できません。

evdevで解決

先程の1と2の両方を解決してくれるのがevdevモジュールです。
https://python-evdev.readthedocs.io

インストール

Python3の場合はpip3でインストールします。

pip3 install evdev

デバイスのevent番号を調べる

event番号とは具体的には event2 という文字列のことです。
調べる方法はいくつかありますので、お好みでどうぞ。
ラズパイにデバイスを接続した状態で確認してください。デバイスは、マウスやキーボード、テンキーなどを意味しています。

方法1:コマンドで詳細確認

以下のコマンドを打つと詳細情報が出てくるので、何番なのか確認できます。

cat /proc/bus/input/devices

方法2:コマンドで簡易確認

もし、たくさんのデバイスが接続されている場合は、以下のコマンドが便利です。
デバイスを接続する前と後それぞれで、コマンドを打って、差分を見てください。

ls /dev/input

方法3:プログラムで確認

以下のPythonコードでも確認可能です。
この後のサンプルではevent番号で指定していますが、これを活用すればデバイス名で指定することも可能と思います。

import evdev

devices = [evdev.InputDevice(path) for path in evdev.list_devices()]

for device in devices:
    print(device.path, device.name, device.phys)

サンプルプログラム

マウスの場合の例です。
左クリック、中央クリック、右クリックを行ったときに表示が出ます。
実行しているプログラムの表示が非アクティブ(他のウィンドウが最前面)であっても読み込まれていると思います。

import evdev

#検知したいデバイスのevent番号を書いてください
device = evdev.InputDevice('/dev/input/event0')

for event in device.read_loop():
    if event.type == evdev.ecodes.EV_KEY:
        if event.value == 1: #0:UP, 1:DOWN
            if event.code == evdev.ecodes.BTN_LEFT:
                print('Left Click')
            if event.code == evdev.ecodes.BTN_MIDDLE:
                print('Middle Click')
            if event.code == evdev.ecodes.BTN_RIGHT:
                print('Right Click')

サンプルプログラム2

テンキーの場合の例です。
1, 2, 3 のキーを押すと表示が出ます。

import evdev

#検知したいデバイスのevent番号を書いてください
device = evdev.InputDevice('/dev/input/event1')

for event in device.read_loop():
    if event.type == evdev.ecodes.EV_KEY:
        if event.value == 1: #0:UP, 1:DOWN
            if event.code == evdev.ecodes.KEY_KP1:
                print('KEY1')
            if event.code == evdev.ecodes.KEY_KP2:
                print('KEY2')
            if event.code == evdev.ecodes.KEY_KP3:
                print('KEY3')

サンプルプログラム3

複数のデバイス(今回はマウスとテンキーの例)対応コードです。
様々な方法がありますが、今回はselectを採用しました。
https://python-evdev.readthedocs.io/en/latest/tutorial.html

#複数のデバイス読み込み対応(select使用)
import evdev
from select import select

#検知したいデバイスのevent番号を書いてください
devices = map(evdev.InputDevice, ('/dev/input/event0', '/dev/input/event1'))
devices = {dev.fd: dev for dev in devices}

while True:
    r, w, x = select(devices, [], [])
    for fd in r:
        for event in devices[fd].read():
            if event.type == evdev.ecodes.EV_KEY:
                if event.value == 1: #0:UP, 1:DOWN
                    if event.code == evdev.ecodes.BTN_LEFT:
                        print('Left Click')
                    if event.code == evdev.ecodes.KEY_KP1:
                        print('KEY1')

その他

ちょっと役立つクラゲの豆知識を記しておきます。

  • evdev.ecodes.KEY_KP1evdev.ecodes.ecodes['KEY_KP1'] でも同じ意味
  • print(event.code) で押したキーのコード番号を知ることができる
  • print(evdev.ecodes.KEY[コード番号])KEY_KP1 などのコード名がわかる

event番号が取れれば、USBでなくても無線テンキーや無線マウスなどもOKですし、Bluetoothデバイスもいけます。以下のように、100均で売っていたBluetoothボタンでも制御可能です。

https://monomonotech.jp/kurage/raspberrypi/daiso_btshutter.html

以上、evdevでキーボードやマウスのイベント取得でした!