Linuxで入力デバイスの抜き差しを検出する

キオスク端末に特定の入力デバイスが差されたことを契機に、メンテナンスモードが立ち上がるみたいなことをする方法について書きます。セキュリティは考えてないです。

まず可能だけど不採用だった方法として、Linuxが認識している入力デバイスはこの proc ファイルを見るとわかりますので、定期的に監視すれば簡単に入力デバイスの抜き差しを検出できます。

$ cat /proc/bus/input/devices
I: Bus=0011 Vendor=0001 Product=0001 Version=ab00
N: Name="AT Translated Set 2 keyboard"
P: Phys=d34b2567-b9b6-42b9-8778-0a4ec0b
S: Sysfs=/devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0004:00/VMBUS:00/d34b2567-b9b6-42b9-8778-0a4ec0b955bf/serio0/input/input0
U: Uniq=
H: Handlers=sysrq kbd event0 
B: PROP=0
B: EV=100013
B: KEY=402000000 3803078f800d001 feffffdfffefffff fffffffffffffffe
B: MSC=10

I: Bus=0006 Vendor=045e Product=0621 Version=0001
N: Name="Microsoft Vmbus HID-compliant Mouse"
P: Phys=
S: Sysfs=/devices/0006:045E:0621.0001/input/input1
U: Uniq=
H: Handlers=mouse0 event1 js0 
B: PROP=0
B: EV=1f
B: KEY=1f0000 0 0 0 0
B: REL=100
B: ABS=3
B: MSC=10</code>

できますが、 proc ファイルは read されるとき中身が作られるので、更新イベントとしては取れません。ポーリングが嫌いなのでこの方法は不採用です。

そこで採用した方法ですが、Linuxがキーボードとかマウスとかペンタブとかを認識すると、 /dev/input/* に入力デバイスイベントファイルが作られます。このファイルの削除/作成を監視すれば、入力デバイスが抜き差しを検出できます。

Python で書くとこんな感じです。ファイルの監視には watchdog モジュールを使いました。

import sys
import time

from watchdog.events import PatternMatchingEventHandler
from watchdog.observers import Observer


class InputDeviceDetector(PatternMatchingEventHandler):
    def __init__(self, patterns):
        super().__init__(patterns=patterns)

    def on_created(self, event):
        print('detected to connect an input device. [%s]' % event.src_path)
        # 入力デバイスが差されたときの処理を書く

    def on_deleted(self, event):
        print('detected to disconnect an input device. [%s]' % event.src_path)
        # 入力デバイスが抜かれたときの処理を書く


def main():
    input_dev_handler = InputDeviceDetector(['/dev/input/by-id/*'])
    observer = Observer()
    observer.schedule(input_dev_handler, '/dev/input/', recursive=True)
    observer.start()
    
    try:
        while True:
            time.sleep(10)
    except KeyboardInterrupt:
        pass
    
    observer.stop()
    observer.join()


if __name__ == '__main__':
    main()

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

*