mieki256's diary



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
#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.cpp
getkbdpath と 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つ以上出現する場合は、ちょっと困ったことになるなと…。

例えば、手持ちの機器の中には、以下のような製品があるのだけど。
  • 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はキーボードやマウスとの相性があるよ、 ということで…。プログラム側での解決策は、自分の知識状態では思いつかんです…。手詰まりです。

それにしても、他のプログラム類は、このへんどうやって解決してるのだろう…。

以上です。

過去ログ表示

Prev - 2021/03 - Next
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31

カテゴリで表示

検索機能は Namazu for hns で提供されています。(詳細指定/ヘルプ


注意: 現在使用の日記自動生成システムは Version 2.19.6 です。
公開されている日記自動生成システムは Version 2.19.5 です。

Powered by hns-2.19.6, HyperNikkiSystem Project