2021/03/04(木) [n年前の日記]
#1 [hsp][raspberrypi][linux] キーボードに割り当てられたeventを取得できるか実験
Raspberry Pi用HSPが、キーボードやマウスを検出できない件について。とりあえず、/proc/bus/input/devices の内容から、キーボードに割り当てられた event* を取得できそうかどうか試してみたり。
以下のやり取りの中で、/proc/bus/input/devices を参照することでキーボードの event番号?を取得する方法が紹介されていて、2つほど、サンプルソースが提示されてる。
_c - Determine Linux keyboard events device - Stack Overflow
それぞれ、手元の環境でも動くように書き直してみたり。いやまあ、前述のサンプルをほとんどコピペしたようなものだけど…。
動作確認した環境は以下。
_getkbdpath.cpp
_getkbdpath2.cpp
g++ を使ってコンパイル。
Raspberry Pi Zero W 上で実行。キーボードは Logicool K400r を接続。
以下のやり取りの中で、/proc/bus/input/devices を参照することでキーボードの event番号?を取得する方法が紹介されていて、2つほど、サンプルソースが提示されてる。
_c - Determine Linux keyboard events device - Stack Overflow
- 一つは、grep を何度も呼んで、最終的に event* の数字を求める方法。
- 一つは、C/C++の関数?を使って頑張って求める方法。
それぞれ、手元の環境でも動くように書き直してみたり。いやまあ、前述のサンプルをほとんどコピペしたようなものだけど…。
動作確認した環境は以下。
- Raspberry Pi Zero W + Raspberry Pi OS buster
- VMware Workstation 16 Player 16.1.0 build-17198959 + Ubuntu Linux 20.04 LTS
_getkbdpath.cpp
#include <string>
#include <cstdio>
static const std::string CMD_GET_KBD_DEV_NUM = "grep -E 'Handlers|EV=' /proc/bus/input/devices | grep -B1 'EV=1200..' | grep -Eo 'event[0-9]+' | grep -Eo '[0-9]+' | tr -d '\n'";
static const std::string CMD_COUNT_KBD_DEV = "grep -E 'Handlers|EV=' /proc/bus/input/devices | grep -B1 'EV=1200..' | grep -Eo 'event[0-9]+' | wc -l";
std::string execCmd(const char *cmd)
{
FILE *pipe = popen(cmd, "r");
char buf[2048];
std::string r = "";
while (!feof(pipe))
if (fgets(buf, 2048, pipe) != NULL)
r += buf;
pclose(pipe);
return r;
}
std::string getKbdDevPath()
{
std::string kbdCnt = "";
std::string devNum = "";
kbdCnt += execCmd(CMD_COUNT_KBD_DEV.c_str());
if (kbdCnt[0] == '0')
{
// Not found keyboard
return "";
}
else if (kbdCnt[0] == '1')
{
devNum += execCmd(CMD_GET_KBD_DEV_NUM.c_str());
if (devNum[0] == '\0')
{
// Not found keyboard
return "";
}
// found keyboard
return "/dev/input/event" + devNum;
}
printf("Multiple keyboards exist\n");
return "";
}
int main()
{
std::string devPath = getKbdDevPath();
if (devPath[0] == '\0')
{
printf("Not found keyboard\n");
}
else
{
printf("keyboard: %s\n", devPath.c_str());
}
}
_getkbdpath2.cpp
#include <stdio.h>
#include <string.h>
#include <string>
std::string getInputDevPath()
{
const char *pdevsName = "/proc/bus/input/devices";
std::string devPath = "";
char buf[8196];
FILE *fp;
if ((fp = fopen(pdevsName, "r")) == NULL)
{
printf("[ERR] Cannot open '%s'\n", pdevsName);
return "";
}
int rd = fread(buf, sizeof(*buf), sizeof(buf) / sizeof(*buf), fp);
fclose(fp);
if (rd < 6)
{
printf("[ERR] Wrong size was read from devs file\n");
return "";
}
buf[rd] = 0;
char *pHandlers, *pEV = buf;
do
{
pHandlers = strstr(pEV, "Handlers=");
pEV = strstr(pHandlers, "EV=");
} while (pHandlers && pEV && 0 != strncmp(pEV + 3, "1200", 4));
if (pHandlers && pEV)
{
char *pevent = strstr(pHandlers, "event");
if (pevent)
{
devPath += "/dev/input/event";
devPath.push_back(pevent[5]);
}
else
{
printf("[ERR] Abnormal keyboard event device\n");
}
}
else
{
printf("[ERR] Keyboard event device not found\n");
}
return devPath;
}
int main()
{
std::string r = "keyboard: " + getInputDevPath();
printf("%s\n", r.c_str());
}
g++ を使ってコンパイル。
g++ -o getkbdpath getkbdpath.cpp g++ -o getkbdpath2 getkbdpath2.cppgetkbdpath と getkbdpath2 という実行ファイルができる。
Raspberry Pi Zero W 上で実行。キーボードは Logicool K400r を接続。
$ ./getkbdpath keyboard: /dev/input/event0 $ ./getkbdpath2 keyboard: /dev/input/event0タッチパッド付キーボードでありながら、/dev/input/by-id 以下で event-kbd を返してくれない Logicool K400r でも、割り当てられた event番号を取得することができた。こういう方法でも判別できるのだな…。
◎ 問題点。 :
/proc/bus/input/devices の中に、EV=1200.. が1つだけ出現する場合は、これでなんとかなるけれど。2つ以上出現する場合は、ちょっと困ったことになるなと…。
例えば、手持ちの機器の中には、以下のような製品があるのだけど。
この2つを組み合わせると最悪の状態が発生する。キーボードを1つ、マウスを1つしか接続してないのに、/proc/bus/input/devices 内ではキーボードが2つ存在することになってしまう。
一応、この組み合わせの場合の情報もアップしておくけど…。
_buffalo_bskbw03wh_and_a4tech_xl755bk.md
この場合…。
つまり…。
後者の解決策が思いつかない…。手詰まりかなあ…。
例えば、手持ちの機器の中には、以下のような製品があるのだけど。
- USB接続ワイヤレスキーボード BUFFALO BSKBW03WH。/dev/input/by-id 以下で、event-kbd の他に event-mouse も返してくる。
- USB有線接続マウス A4Tech XL-755BK。/dev/input/by-id 以下で、event-mouse の他に event-kbd も返してくる。しかも、/proc/bus/input/devices の中で、EV=1200.. まで返してくる。
この2つを組み合わせると最悪の状態が発生する。キーボードを1つ、マウスを1つしか接続してないのに、/proc/bus/input/devices 内ではキーボードが2つ存在することになってしまう。
一応、この組み合わせの場合の情報もアップしておくけど…。
_buffalo_bskbw03wh_and_a4tech_xl755bk.md
この場合…。
- grep を駆使して探す方法では、正しいevent番号が得られない。
- C/C++の関数を駆使する方法では、最初に見つかったevent番号しか得られない。
つまり…。
- /proc/bus/input/devices の内容を解析して、キーボードに割り当てられたevent*を取得するやり方は、/dev/input/by-id 以下に event-kbd が出現しないキーボード製品についても対応できるメリットがある。
- しかし、キーボード(event-kbd)なのにマウス(event-mouse)でもあると言い出したり、マウス(event-mouse)なのにキーボード(event-kbd)でもあると言い出す製品群には結局対応できない。どれが本当に使えるキーボードなのか、判別する方法がない。
後者の解決策が思いつかない…。手詰まりかなあ…。
◎ 他の案。 :
このあたりの問題を緩和する他の方法は無いのかなと考えてみたり。
例えば、HSP対応(?)のキーボードとマウスなのか確認できるスクリプトを別途用意しておいて…。そのスクリプトを動かしてみて、「Keyboard, Mouse : Good」と言ってくるならHSPは使えますよ、でも「Keyboard, Moues : Bad」と言ってくるなら使えないので別のキーボードやマウスを探して繋いでみてね、てなことにしておく。とか。
あるいは、keyboard.ini だの mouse.ini というファイルがもし存在していて、/dev/input/event0 だの /dev/input/event4 だのが書いてあるなら、それをキーボードやマウスとして使うことにする、てな仕様にしておくとか。どうしても自動検出できない場面に遭遇したら、それらファイルを新規作成して環境に合わせたファイルパスを記述すれば一応動くよ、と。
まあ、何にせよ、 _現状のRaspberry Pi用HSPはキーボードやマウスとの相性があるよ、 ということで…。プログラム側での解決策は、自分の知識状態では思いつかんです…。手詰まりです。
それにしても、他のプログラム類は、このへんどうやって解決してるのだろう…。
例えば、HSP対応(?)のキーボードとマウスなのか確認できるスクリプトを別途用意しておいて…。そのスクリプトを動かしてみて、「Keyboard, Mouse : Good」と言ってくるならHSPは使えますよ、でも「Keyboard, Moues : Bad」と言ってくるなら使えないので別のキーボードやマウスを探して繋いでみてね、てなことにしておく。とか。
あるいは、keyboard.ini だの mouse.ini というファイルがもし存在していて、/dev/input/event0 だの /dev/input/event4 だのが書いてあるなら、それをキーボードやマウスとして使うことにする、てな仕様にしておくとか。どうしても自動検出できない場面に遭遇したら、それらファイルを新規作成して環境に合わせたファイルパスを記述すれば一応動くよ、と。
まあ、何にせよ、 _現状のRaspberry Pi用HSPはキーボードやマウスとの相性があるよ、 ということで…。プログラム側での解決策は、自分の知識状態では思いつかんです…。手詰まりです。
それにしても、他のプログラム類は、このへんどうやって解決してるのだろう…。
[ ツッコむ ]
以上です。