2021/03/02(火) [n年前の日記]
#1 [hsp][raspberrypi][linux] キーボードとマウスに割り当てられたevent番号を得る
HSP3.6beta を Raspberry Pi Zero W + Raspberry Pi OS buster 上で動かした際に、キーボードやマウスが無反応になる件について。
/proc/bus/input/devices の情報から、キーボードやマウスに割り当てられた event* を取得する方法について調べているところ。
/proc/bus/input/devices の情報から、キーボードやマウスに割り当てられた event* を取得する方法について調べているところ。
◎ キーボードの判別について。 :
キーボードについては、/proc/bus/input/devices の中から、EV=1200.. を探すことで、おそらくメインで使われているのであろうキーボードの event* を取得できそうだなと分かってきた。
以下のやりとりが参考になった。
_c - Determine Linux keyboard events device - Stack Overflow
上記のやり取りの中では、EV=120013 という値を決め打ちで探しているけれど、手持ちのタッチパッド付キーボード Logicool K400r は EV=12001f を返してきたりするので、まあ、EV=1200.. を探せば、キーボードを見つけることができるのではないかと…。
ちなみに、EV=1200.. の 12 の部分は、EV_REP と EV_LED のフラグが立ってることを示している。
手持ちのキーボード、Logicool K400r や Lenovo KU-1255 にはLEDがついてないのだけど、どちらも EV_LED を返してくる。おそらくだけど、キーボードの類は、実際にはLEDを持っていなくてもLEDを持っているものとして情報を返すことになってたりするのではないか、と…。いや、分からんけど。でも、少なくとも、手持ちの各機器を調べた範囲では、そう見えてる。もしかすると例外な機器ががある可能性も否定できないけど。
あるいは、EV=1200.. ではなく、Handlers= に kbd と leds が存在するものをキーボードとして扱う、という手もありそうだなと。
以下のやりとりが参考になった。
_c - Determine Linux keyboard events device - Stack Overflow
上記のやり取りの中では、EV=120013 という値を決め打ちで探しているけれど、手持ちのタッチパッド付キーボード Logicool K400r は EV=12001f を返してきたりするので、まあ、EV=1200.. を探せば、キーボードを見つけることができるのではないかと…。
ちなみに、EV=1200.. の 12 の部分は、EV_REP と EV_LED のフラグが立ってることを示している。
- EV_REP は、キーリピートが発生する入力機器であることを示す。
- EV_LED は、LEDの制御ができる機器であることを示す。
手持ちのキーボード、Logicool K400r や Lenovo KU-1255 にはLEDがついてないのだけど、どちらも EV_LED を返してくる。おそらくだけど、キーボードの類は、実際にはLEDを持っていなくてもLEDを持っているものとして情報を返すことになってたりするのではないか、と…。いや、分からんけど。でも、少なくとも、手持ちの各機器を調べた範囲では、そう見えてる。もしかすると例外な機器ががある可能性も否定できないけど。
あるいは、EV=1200.. ではなく、Handlers= に kbd と leds が存在するものをキーボードとして扱う、という手もありそうだなと。
- EV=120013 を返してくる機器は、「H: Handlers=sysrq kbd leds event0」を返す。
- EV=12001f を返してくる機器は、「H: Handlers=sysrq kbd leds mouse0 event0」を返す。
◎ event*を取り出す方法。 :
さておき。/proc/bus/input/devices の内容から、キーボードの event* を得る方法だけど。
前述のやり取りの中で、grep を何度も呼び出して求めてしまう方法が紹介されてた。
結果がどう変わっていくか、一応以下に示しておく。
自分、プログラム内でこの手の処理をみっちり書かねばならないものと思い込んでいたので、既存のコマンドを数回呼んで目的を達成してしまうやり方に、なんだかちょっと目から鱗が落ちたというか…。単機能のコマンドを繋げて目的を果たすのが、*NIXの文化なのね、みたいな。
前述のやり取りの中で紹介されてるのは、おそらくC++?を使った記述だろうけど、C言語で同じことをしている事例も見かけた。
_c - Reading events from the keyboard device and storing it in a file skips some input - Stack Overflow
FILE* fpp = popen() と fgets() を使えば、C言語のソース内で grep を呼んで使うことができるらしいなと…。まだ実際に試してないので、本当にそんなことができるのか分かってないけど。
前述のやり取りの中で、grep を何度も呼び出して求めてしまう方法が紹介されてた。
grep -E 'Handlers|EV=' /proc/bus/input/devices | grep -B1 'EV=1200..' | grep -Eo 'event[0-9]+' | grep -Eo '[0-9]+' | tr -d '\n'
- grep -E 'Handlers|EV=' /proc/bus/input/devices で、/proc/bus/input/devices の中から、Handlers または EV= が含まれた行を取り出す。
- grep -B1 'EV=1200..' で、EV=1200.. と書かれた行と、その1行前の行(Handlers が書かれた行)を取り出す。
- grep -Eo 'event[0-9]+' で、「event*」と書かれた部分だけを取り出す。
- grep -Eo '[0-9]+' で、「event*」の数字部分だけを取り出す。
- この状態では改行が含まれてることがあるので、tr -d '\n' で、改行を消去する。
結果がどう変わっていくか、一応以下に示しておく。
$ grep -E 'Handlers=|EV=' buffalo_bskbw03wh_and_logicool_vx_nano.txt H: Handlers=sysrq kbd leds event0 B: EV=120013 H: Handlers=mouse0 event1 B: EV=17 H: Handlers=kbd event2 B: EV=1f H: Handlers=kbd event3 B: EV=13 H: Handlers=mouse1 event4 B: EV=17 H: Handlers=kbd event5 B: EV=1f $ grep -E 'Handlers=|EV=' buffalo_bskbw03wh_and_logicool_vx_nano.txt | grep -B1 'EV=1200..' H: Handlers=sysrq kbd leds event0 B: EV=120013 $ grep -E 'Handlers=|EV=' buffalo_bskbw03wh_and_logicool_vx_nano.txt | grep -B1 'EV=1200..' | grep -Eo 'event[0-9]+' event0 $ grep -E 'Handlers=|EV=' buffalo_bskbw03wh_and_logicool_vx_nano.txt | grep -B1 'EV=1200..' | grep -Eo 'event[0-9]+' | grep -Eo '[0-9]+' 0最終的に、event* の数字の部分だけを取得できている。
自分、プログラム内でこの手の処理をみっちり書かねばならないものと思い込んでいたので、既存のコマンドを数回呼んで目的を達成してしまうやり方に、なんだかちょっと目から鱗が落ちたというか…。単機能のコマンドを繋げて目的を果たすのが、*NIXの文化なのね、みたいな。
前述のやり取りの中で紹介されてるのは、おそらくC++?を使った記述だろうけど、C言語で同じことをしている事例も見かけた。
_c - Reading events from the keyboard device and storing it in a file skips some input - Stack Overflow
FILE* fpp = popen() と fgets() を使えば、C言語のソース内で grep を呼んで使うことができるらしいなと…。まだ実際に試してないので、本当にそんなことができるのか分かってないけど。
◎ マウスの判別について。 :
キーボードの判別・event*の取得は、上記のやり方でなんとかなりそうだなと思えてきたけど。マウスの判別が、ちょっと難しい…。
一応、Handlers= の中に、mouse* という記述があるものが対象としてリストアップできそう、とは分かったけれど。
対象が1行しか出てこない場合は、ソイツがルパンだ!
ソイツがマウスだ、と考えていいのだろうけど。問題は、2行以上出てきた場合。Handlers= の情報だけでは、どっちが真のマウスなのか、分からない…。
もしかすると、Phys= の情報が頼りになるのだろうか?
ただ、この input* は、必ずしも input0 や input1 になるとは限らなくて。例えば、Logicool K400r は、以下のような値になってしまう。
まあ、K400r の場合、それだけを接続している状態なら、mouse が含まれる行が1行しか出てこないので、それがマウスだと決めつけてしまっていいのかもしれないけれど。ただ、複数の入力機器を接続している場合は、ちょっと困ったことになるよなと…。
何にせよ…。/proc/bus/input/devices の中に、
ただ、その判別方法を、C言語でどう書けばいいのか。そこがちょっと悩むところで…。
一応、Handlers= の中に、mouse* という記述があるものが対象としてリストアップできそう、とは分かったけれど。
$ grep -E 'Handlers=.*mouse*' buffalo_bskbw03wh_and_logicool_vx_nano.txt H: Handlers=mouse0 event1 H: Handlers=mouse1 event4 $ grep -E 'Handlers=.*mouse*' logicool_k400r.txt H: Handlers=sysrq kbd leds mouse0 event0 $ grep -E 'Handlers=.*mouse*' lenovo_ku-1255.txt H: Handlers=mouse0 event1
対象が1行しか出てこない場合は、
もしかすると、Phys= の情報が頼りになるのだろうか?
$ grep -E 'Handlers=|Phys=' buffalo_bskbw03wh_and_logicool_vx_nano.txt P: Phys=usb-20980000.usb-1.1/input0 H: Handlers=sysrq kbd leds event0 P: Phys=usb-20980000.usb-1.1/input1 H: Handlers=mouse0 event1 P: Phys=usb-20980000.usb-1.1/input2 H: Handlers=kbd event2 P: Phys=usb-20980000.usb-1.1/input2 H: Handlers=kbd event3 P: Phys=usb-20980000.usb-1.2/input0 H: Handlers=mouse1 event4 P: Phys=usb-20980000.usb-1.2/input1 H: Handlers=kbd event5 $ grep -E 'Handlers=|Phys=' buffalo_bskbw03wh_and_logicool_vx_nano.txt | grep -B1 'mouse' P: Phys=usb-20980000.usb-1.1/input1 H: Handlers=mouse0 event1 -- P: Phys=usb-20980000.usb-1.2/input0 H: Handlers=mouse1 event4何故か「--」という行が含まれているのが気になるけど、それはさておき。Phys= に input* が含まれていたとして、数字が小さいほうが真のマウスだ、みたいな。
ただ、この input* は、必ずしも input0 や input1 になるとは限らなくて。例えば、Logicool K400r は、以下のような値になってしまう。
$ grep -E 'Handlers=|Phys=' logicool_k400r.txt | grep -B1 'mouse' P: Phys=usb-20980000.usb-1.1/input2:1 H: Handlers=sysrq kbd leds mouse0 event0「input2:1」ってなんやねん。
まあ、K400r の場合、それだけを接続している状態なら、mouse が含まれる行が1行しか出てこないので、それがマウスだと決めつけてしまっていいのかもしれないけれど。ただ、複数の入力機器を接続している場合は、ちょっと困ったことになるよなと…。
何にせよ…。/proc/bus/input/devices の中に、
- Handlers=.*mouse.* が1行しか出てこないなら、それがマウス。
- Handlers=.*mouse.* が2行以上出てくるなら、Phys=.*input.* の数値が小さいほうが、実際に使っているマウス。
ただ、その判別方法を、C言語でどう書けばいいのか。そこがちょっと悩むところで…。
◎ コマンドを活用してどうにかできないか。 :
行数を数えるなら、wc というコマンドが使えるらしい。
_テキストファイルの行数や単語数を調べるには
_【 wc 】コマンド――テキストファイルの文字数や行数を数える:Linux基本コマンドTips(62) - @IT
wcコマンドは、文字数や行数を数えられるけど、-l を付ければ行数だけを数えるそうで。
一つだけなら、キーボードの event* を調べた時と同様に、grep を数回呼ぶことでなんとかなるかなと…。
つまり、以下のようになるのかな…。
だけど問題は、マウスらしきものが2つ以上ある場合。さて、どういう手法で、どれが真のマウスなのかを判別すればいいのか…。
再度書くけど、以下の状態まではコマンドを駆使して絞り込める。
いっそ、キーボードやマウスに割り当てられたevent*を調べて返すPythonスクリプトでも書いて、それを呼んじゃうという手は…。
_テキストファイルの行数や単語数を調べるには
_【 wc 】コマンド――テキストファイルの文字数や行数を数える:Linux基本コマンドTips(62) - @IT
wcコマンドは、文字数や行数を数えられるけど、-l を付ければ行数だけを数えるそうで。
$ grep -E 'Handlers=.*mouse.*' logicool_k400r.txt | wc -l 1 $ grep -E 'Handlers=.*mouse.*' buffalo_bskbw03wh_and_logicool_vx_nano.txt | wc -l 2これで、マウスらしきものが1つだけ接続されているのか、2つ以上接続されているのか、その程度の判別ならできそうな予感。
一つだけなら、キーボードの event* を調べた時と同様に、grep を数回呼ぶことでなんとかなるかなと…。
$ grep -E 'Handlers=.*mouse.*' logicool_k400r.txt | grep -Eo 'event[0-9]+' event0 $ grep -E 'Handlers=.*mouse.*' logicool_k400r.txt | grep -Eo 'event[0-9]+' | grep -Eo '[0-9]+' 0
つまり、以下のようになるのかな…。
grep -E 'Handlers=.*mouse.*' /proc/bus/input/devices | grep -Eo 'event[0-9]+' | grep -Eo '[0-9]+' | tr -d '\n'これで、マウスに割り当てられた event* の数字部分は得られそう。
だけど問題は、マウスらしきものが2つ以上ある場合。さて、どういう手法で、どれが真のマウスなのかを判別すればいいのか…。
再度書くけど、以下の状態まではコマンドを駆使して絞り込める。
$ grep -E 'Handlers=|Phys=' buffalo_bskbw03wh_and_logicool_vx_nano.txt | grep -B1 'mouse' P: Phys=usb-20980000.usb-1.1/input1 H: Handlers=mouse0 event1 -- P: Phys=usb-20980000.usb-1.2/input0 H: Handlers=mouse1 event4ここからどうする…。コマンドでどうにかなるのか…? 頓智が求められるなあ…。
いっそ、キーボードやマウスに割り当てられたevent*を調べて返すPythonスクリプトでも書いて、それを呼んじゃうという手は…。
◎ input*で判別するのは怪しいかもしれない。 :
ふと、他のLinux環境ではどうなるのかと気になって、VMware Workstation 16 Player 16.1.0 build-17198959 + Ubuntu Linux 20.04 LTS で確認してみたのだけど。
mouse* が3つほど出てきて、Phys=.*:input0 ではなく Phys=.*:input1 のほうが反応することに気づいた。
ということは、必ずしも input* の数字の小さいほうが真のマウスとは言えない感じだなと…。
その後も試してたら、event2 はマウスを動かすと反応して、event3 はマウスホイールを回すと反応することに気づいた。event4 は謎。sudo evtest /dev/input/event4 と打ってみると、マウスの拡張ボタンを返すようにも見えるけど、実際押してみても反応してるようには見えず。
マウス座標を返してくる event と、ホイール回転を返してくる event が別になってるということは、もしかして mouse* を返してくるそれぞれに対して全部情報を取得しないといかんのだろうか…?
mouse* が3つほど出てきて、Phys=.*:input0 ではなく Phys=.*:input1 のほうが反応することに気づいた。
$ cat /proc/bus/input/devices I: Bus=0019 Vendor=0000 Product=0001 Version=0000 N: Name="Power Button" P: Phys=LNXPWRBN/button/input0 S: Sysfs=/devices/LNXSYSTM:00/LNXPWRBN:00/input/input0 U: Uniq= H: Handlers=kbd event0 B: PROP=0 B: EV=3 B: KEY=10000000000000 0 I: Bus=0011 Vendor=0001 Product=0001 Version=ab41 N: Name="AT Translated Set 2 keyboard" P: Phys=isa0060/serio0/input0 S: Sysfs=/devices/platform/i8042/serio0/input/input1 U: Uniq= H: Handlers=sysrq kbd event1 leds B: PROP=0 B: EV=120013 B: KEY=402000000 3803078f800d001 feffffdfffefffff fffffffffffffffe B: MSC=10 B: LED=7 I: Bus=0011 Vendor=0002 Product=0013 Version=0006 N: Name="VirtualPS/2 VMware VMMouse" P: Phys=isa0060/serio1/input1 S: Sysfs=/devices/platform/i8042/serio1/input/input4 U: Uniq= H: Handlers=mouse0 event2 B: PROP=0 B: EV=b B: KEY=70000 0 0 0 0 B: ABS=3 I: Bus=0011 Vendor=0002 Product=0013 Version=0006 N: Name="VirtualPS/2 VMware VMMouse" P: Phys=isa0060/serio1/input0 S: Sysfs=/devices/platform/i8042/serio1/input/input3 U: Uniq= H: Handlers=mouse1 event3 B: PROP=1 B: EV=7 B: KEY=30000 0 0 0 0 B: REL=103 I: Bus=0003 Vendor=0e0f Product=0003 Version=0110 N: Name="VMware VMware Virtual USB Mouse" P: Phys=usb-0000:02:00.0-1/input0 S: Sysfs=/devices/pci0000:00/0000:00:11.0/0000:02:00.0/usb2/2-1/2-1:1.0/0003:0E0F:0003.0001/input/input5 U: Uniq= H: Handlers=mouse2 event4 B: PROP=0 B: EV=17 B: KEY=ff0000 0 0 0 0 B: REL=903 B: MSC=10
ということは、必ずしも input* の数字の小さいほうが真のマウスとは言えない感じだなと…。
その後も試してたら、event2 はマウスを動かすと反応して、event3 はマウスホイールを回すと反応することに気づいた。event4 は謎。sudo evtest /dev/input/event4 と打ってみると、マウスの拡張ボタンを返すようにも見えるけど、実際押してみても反応してるようには見えず。
$ sudo evtest /dev/input/event4 Input driver version is 1.0.1 Input device ID: bus 0x3 vendor 0xe0f product 0x3 version 0x110 Input device name: "VMware VMware Virtual USB Mouse" Supported events: Event type 0 (EV_SYN) Event type 1 (EV_KEY) Event code 272 (BTN_LEFT) Event code 273 (BTN_RIGHT) Event code 274 (BTN_MIDDLE) Event code 275 (BTN_SIDE) Event code 276 (BTN_EXTRA) Event code 277 (BTN_FORWARD) Event code 278 (BTN_BACK) Event code 279 (BTN_TASK) Event type 2 (EV_REL) Event code 0 (REL_X) Event code 1 (REL_Y) Event code 8 (REL_WHEEL) Event code 11 (REL_WHEEL_HI_RES) Event type 4 (EV_MSC) Event code 4 (MSC_SCAN) Properties: Testing ... (interrupt to exit)
マウス座標を返してくる event と、ホイール回転を返してくる event が別になってるということは、もしかして mouse* を返してくるそれぞれに対して全部情報を取得しないといかんのだろうか…?
[ ツッコむ ]
以上です。