Webカメラの入力イベントをキーボードのキーに再マッピングする

Webカメラの入力イベントをキーボードのキーに再マッピングする

私は、アプリケーションに特定のタスクを実行させるようにWebカメラのトリガーから入力を読み取る必要があるアプリケーションを開発しています。

このプロジェクトにはQTサポートで構築されたOpenCVが含まれており、このトリガーを適用するとランダムな競合が発生します(ASSERT:qasciikey.cppファイルの「false」、495行)。

だからもっと簡単で信頼性の高い方法は、外部トリガーをキー(特にスペースバー)にマッピングすることだと思います。したくない書くスペースバーを押すと、トリガーがスペースバーを押したように見えます。

これまでevtestを使用してデバイスを選択しました。

/dev/input/event13: See3CAM_CU51

カメラを起動すると、次のものが表示されます。

Event: time 1507757166.472300, type 1 (EV_KEY), code 212 (KEY_CAMERA), value 1
Event: time 1507757166.472300, -------------- SYN_REPORT ------------
Event: time 1507757167.147649, type 1 (EV_KEY), code 212 (KEY_CAMERA), value 0
Event: time 1507757167.147649, -------------- SYN_REPORT ------------

「値1」はピンが高く引っ張られている場合(トリガされている場合)、「値0」はピンが切り離された場合です。そのため、KEY_CAMERAをスペースバーに再マップすることができますが、Ubuntu 16.04でこれを行う最もきちんとした方法はわかりません。

キーボードデバイスを選択するとき:

/dev/input/event4: AT Translated Set 2 keyboard

スペースバーを押すと、次のような結果が出力されます。

Event: time 1507757327.011812, -------------- SYN_REPORT ------------
Event: time 1507757328.818177, type 4 (EV_MSC), code 4 (MSC_SCAN), value 39
Event: time 1507757328.818177, type 1 (EV_KEY), code 57 (KEY_SPACE), value 1
Event: time 1507757328.818177, -------------- SYN_REPORT ------------
Event: time 1507757328.896970, type 4 (EV_MSC), code 4 (MSC_SCAN), value 39
Event: time 1507757328.896970, type 1 (EV_KEY), code 57 (KEY_SPACE), value 0

私はhwdb udevファイルの作成について読みましたが、あるデバイスから別のデバイスに入力をマップする方法が見つかりませんでした。可能ですか?これを達成する最も簡単な方法は何ですか?

よろしくお願いします。

答え1

正解は、おそらく[hwdb]ファイルを書くことによって KEY_CAMERAKEY_SPACEこれ例のように見えますが、ディテールが少し不足していますね。

ファイル形式は、主にファイルの頭部/usr/lib/udev/hwdb.d/60-keyboard.hwdb(私のシステムの場合)のコメントに記載されています。アーキテクチャLinuxこれに関する議論。この形式はsystemdのバージョンによって異なりますので、自分のファイルを確認してください。入力デバイスを次の3つのモードのいずれかに合わせることができます。

  • ユニバーサル入力デバイスの一致:

      evdev:入力:bZZZZvYYYYpXXXXeWWWW-VVVV

    これは入力デバイスのカーネルモーダルエイリアスと一致します。デフォルトでは、ZZZZはバスID(/usr/include/linux/input.h BUS_ *を参照)、YYYY、XXXX、およびWWWは4桁の16進大文字プロバイダ、製品およびバージョンID、およびVVVVはデバイス機能を記述する任意の長さです。入力フォームです。

  • ATキーボードDMIデータマッチング:

      evdev:atkbd:dmi:bvn*:bvr*:bd*:svn行商人:pn製品:個人映像*

    VendorとProductは、カーネルDMIモーダルからエクスポートされたファームウェアによって提供される文字列です。

  • 一致するドライバデバイス名とDMIデータを入力してください。

      evdev:名前:デバイス名を入力してください:dmi:bvn*:bvr*:bd*:svn行商人:pn*

    入力デバイス名はドライバによって指定されたデバイス名であり、ベンダはカーネルDMIモダリアからエクスポートされたファームウェアによって提供される文字列です。

もう1つの可能性は、evtestのようにWebカメライベントストリームを読み取り、キーが表示されたらKEY_SPACE別のイベントストリームに挿入する小さなプログラムを作成することです。これに関するより多くのドキュメントとそのようなPythonの例がたくさんあるようです。地図時間イベント注入のための作品。

答え2

hwdbの使用に関する@meuhの答えに加えて、hwdbのしくみについて学んだいくつかの点は次のとおりです。これは主にhwdbへのキーボードスキャンコードマッピングに関するものですが、多くの部分が他のhwdb情報にも役立ちます。

源泉:

ここで収集された情報を処理する方法の実際的な例については、次を参照してください。この投稿「エコボタン」の用途変更に関連して、押されたときに一連のキー入力を送信するシングルボタン「キーボード」です。

hwdbにはどの識別子が使用されますか?

実際にどのhwdb識別子が使用されているかを確認するには、次のようにしますudevadm

$ sudo udevadm test /sys/class/input/event256 |& grep builtin.command..hwdb
event256: /usr/lib/udev/rules.d/60-evdev.rules:8 Importing properties from results of builtin command 'hwdb --subsystem=input --lookup-prefix=evdev:'
event256: /usr/lib/udev/rules.d/60-evdev.rules:18 Importing properties from results of builtin command 'hwdb 'evdev:name:HID 3412:7856:phys:usb-0000:00:14.0-1.1.2.4/input0:ev:120013:dmi:bvnINSYDECorp.:bvr03.17:bd10/27/2022:br3.17:svnFramework:pnLaptop:pvrAB:rvnFramework:rnFRANBMCP0B:rvrAB:cvnFramework:ct10:cvrAB:skuFRANBMCP0B:''
event256: /usr/lib/udev/rules.d/60-evdev.rules:23 Importing properties from results of builtin command 'hwdb 'evdev:name:HID 3412:7856:dmi:bvnINSYDECorp.:bvr03.17:bd10/27/2022:br3.17:svnFramework:pnLaptop:pvrAB:rvnFramework:rnFRANBMCP0B:rvrAB:cvnFramework:ct10:cvrAB:skuFRANBMCP0B:''
event256: /usr/lib/udev/rules.d/60-input-id.rules:6 Importing properties from results of builtin command 'hwdb --subsystem=input --lookup-prefix=id-input:modalias:'
event256: /usr/lib/udev/rules.d/65-libwacom.rules:19 Importing properties from results of builtin command 'hwdb --subsystem=input '--lookup-prefix=libwacom:name:HID 3412:7856:''

これは、上記のudevルールに示されている4つのhwdbコマンドのうち3つを試していることに注意してください。 evdev:atkbdコマンドはこのUSBキーボードにのみ適用され、DRIVERS=="atkbd"このUSBキーボードには適用されません。

たとえば、上記の出力には次のものが含まれます。

event256: /usr/lib/udev/rules.d/60-evdev.rules:18 Importing properties from results of builtin command 'hwdb 'evdev:name:HID 3412:7856:phys:usb-0000:00:14.0-1.1.2.4/input0:ev:120013:dmi:bvnINSYDECorp.:bvr03.17:bd10/27/2022:br3.17:svnFramework:pnLaptop:pvrAB:rvnFramework:rnFRANBMCP0B:rvrAB:cvnFramework:ct10:cvrAB:skuFRANBMCP0B:''

これには、私が接続したUSBキーボードではなく、私のラップトップに関連する識別子がたくさん含まれているようです。ただし、USB vidpid(3412:7856)は最初に含まれており、次のように一致できます。

evdev:name:HID 3412:7856:*
  KEYBOARD_KEY_70028=backspace

あるいは、evdev出力には次の内容も含まれます(2行目はgrepのため上には表示されませんが、出力全体には表示されます)。

event256: /usr/lib/udev/rules.d/60-evdev.rules:8 Importing properties from results of builtin command 'hwdb --subsystem=input --lookup-prefix=evdev:'
event256: hwdb modalias key: "input:b0003v3412p7856e0100-e0,1,4,11,14,k74,75,77,7D,7E,7F,B7,ram4,l0,1,2,3,4,sfw"

このhwdb呼び出しは、後続の呼び出しのように指定された完全一致キーを取得できないようですが、hwdbによって自動的に生成されるプレフィックスとモダリアスキーで構成されています。したがって、上記の結果は完全なコアです。

evdev:input:b0003v3412p7856e0100-e0,1,4,11,14,k74,75,77,7D,7E,7F,B7,ram4,l0,1,2,3,4,sfw

これはUSB vid / pidと一致し、次のように使用できます。

evdev:input:b????v3412p7856e*
  KEYBOARD_KEY_70028=backspace

?これは、他のUSBバス/ポートを接続するときに一致するようにバス番号を一致させるためにワイルドカードを使用します。また、*バージョン番号とそれ以降のその他のモーダルコンテンツにはワイルドカードを使用しますが、これは関連性がない可能性があります。

どのスキャンコードを使用する必要がありますか?

正しいスキャンコードを取得する最も安定した方法はevtestを使用するようです。実行してボタンを押すと、次の結果が表示されます。

sudo evtest --grab /dev/input/event256 
[ snip debug output]
Event: time 1675505630.859393, -------------- SYN_REPORT ------------
Event: time 1675505630.867333, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70028
Event: time 1675505630.867333, type 1 (EV_KEY), code 28 (KEY_ENTER), value 0

これには70028スキャンコードがあります(実際には16進数ですが、予想されるものですKEYBOARD_KEY_xx(例KEYBOARD_KEY_70028=backspace:))。USBキーボードは700xxスキャンコードを使用しているように見えますが、古いATキーボードはより低いスキャンコードを使用しているようです。オンラインでコードを探すのではなく、キーボードでテストしてみてください。

さらに、これらのスキャンコードは16進数(0xプレフィックスはどこでも省略)で書かれているように見えますが、キーコードは10進数で作成および分析されますが、100%はわかりません。

また、見ることができますこのページ

どのキーコードを使用する必要がありますか?

これらのキーコードの正式なソースは次のとおりです。イベントコードを入力してくださいカーネルでは、すべてのKEY_xxx定数です。

数値、KEY_xxx、xxxの値はすべて許可されているようです。たとえば、次はEnterキーをマップしてバックスペースキーを生成するのと同じです。

 KEYBOARD_KEY_70028=14
 KEYBOARD_KEY_70028=key_backspace
 KEYBOARD_KEY_70028=backspace

evtest起動時に出力(サポートされているEV_KEYイベントコード)、evtestキーが押されたとき(EV_KEYイベントコード)同じキーコードが表示されるように見えます

また、見ることができますこのページ

入力デバイスの現在のスキャンコードマッピングをどのように表示できますか?

入力デバイスと一部のioctlを使用してクエリを実行する必要があると仮定していますが、これを実行できる既存のコマンドラインツールがあるかどうかはわかりません。見つかったらコメントを残してください。

起動時に印刷されるサポートされているEV_KEYのリストはヒントを提供しているようですevtest。リストには、一部のスキャンコードがマップされたキーコードのみが含まれているようです。

hwdbファイルに変更を適用するには?

次のコマンドを使用して、hwdbファイルを/etc/udev/hwdb.binに再コンパイルする必要があります。

$ sudo systemd-hwdb update

USBデバイスを再接続するか、次のようにudevにルールを再実行するように強制します。

$ sudo udevadm trigger /sys/class/input/event256

hwdbはどこで呼び出されますか?

hwdbのキーと値はudevにハードコードされず、ルールファイルによって決まります。たとえば、/usr/lib/udev/rules.d/60-evdev.rulesは入力/キーボードルールを処理します。

IMPORT{builtin}="hwdb --subsystem=input --lookup-prefix=evdev:", \
  IMPORT{builtin}="keyboard", GOTO="evdev_end"

# AT keyboard matching by the machine's DMI data
DRIVERS=="atkbd", \
  IMPORT{builtin}="hwdb 'evdev:atkbd:$attr{[dmi/id]modalias}'", \
  IMPORT{builtin}="keyboard", GOTO="evdev_end"

# device matching the input device name + properties + the machine's DMI data
KERNELS=="input*", \
  IMPORT{builtin}="hwdb 'evdev:name:$attr{name}:phys:$attr{phys}:ev:$attr{capabilities/ev}:$attr{[dmi/id]modalias}'", \
  IMPORT{builtin}="keyboard", GOTO="evdev_end"

# device matching the input device name and the machine's DMI data
KERNELS=="input*", \
  IMPORT{builtin}="hwdb 'evdev:name:$attr{name}:$attr{[dmi/id]modalias}'", \
  IMPORT{builtin}="keyboard", GOTO="evdev_end"

したがって、上記のルールは、hwdb識別子がどのように構成されているかを正確に示しています。さらに、60-evdev.rulesと60-keyboard.hwdbは互いに関連していますが、これは慣例にすぎません。すべてのhwdbエントリは単一のデータベースに格納され、正しい識別子を提供する任意のudevルールと一致することができます。

hwdb属性はどのように処理されますか?

この行が行うことは、IMPORT{builtin}="hwdb ..."hwdbを照会し、そこにリストされているすべての属性を通常のudevデバイス属性として表示することです(つまり、を使用して照会できますudevadm info)。

また、上記のルールには、IMPORT{builtin}="keyboard"udev組み込みユーティリティを呼び出してKEYBOARD_*属性を処理し、それを使用してカーネルでキーコードマッピングのスキャンコードを設定するために使用されるものも含まれています(EVIOCSKEYCODE入力デバイスでioctlを使用するを参照)。源泉)。

繰り返しますが、udevadmin info上記のように使用すると、組み込みの決定が適用されるキーマップが何でも表示されるため、ここでも役立ちます。

$ sudo udevadm test /sys/class/input/event256 |& grep mapping
event256: keyboard: mapping scan code 18 (0x12) to key code 0 (0x0)
event256: keyboard: mapping scan code 458770 (0x70012) to key code 0 (0x0)
event256: keyboard: mapping scan code 36 (0x24) to key code 0 (0x0)

udevadm test実際にはこのように実行されます。する文書は一度だけ実行する必要があることを示していますが、これらのキーマップを直接適用してください。 「組み込み」メカニズムは元の変更を適用せずに情報のみを収集するように設計されていると思われるため、これはバグの可能性があります。)

udevルールでhwdb / KEYBOARD属性を設定する

Hwdbエントリは、本質的にudevルールが直接行うことができるのと同じようにデバイス属性を設定するだけです(しかし、hwdbは非常に詳細なudevルールを必要とせずに複数のプロパティを簡潔に設定することをより簡単にするために発明されたようです) 。ただし、これはより複雑なhwdbの代わりにudevルールのみを使用してこのキーの再マッピングを実行することが可能であることを意味します。たとえば、次のようになります。

SUBSYSTEM=="input", KERNEL=="event3", ENV{KEYBOARD_KEY_01}="capslock", ENV{KEYBOARD_KEY_3a}="esc"
SUBSYSTEM=="input", KERNEL=="event3", IMPORT{builtin}="keyboard"

「キーボード」プラグインを実行するudevルールは、60-evdev.rules組み込みのhwdbルールと同じです。私はこれがhwdb組み込み関数が情報を見つけた場合にのみ「キーボード」ルールが実行されることを意味すると信じています。

hwdbルールがこの特定のデバイスと一致しない場合、組み込みの「キーボード」が実行されない可能性があるため、これを実行するために上記の明示的なルールを追加しました(同じルールにある場合、これは別のルールである必要がありますENV。実行後にのみ適用され、以前は適用されません。

hwdbルールがある場合する60-evdev.rulesこの特定のデバイスと一致させるには、上記の2番目のルールを省略して内蔵キーボードを実行します(ただし、上記のudevルールは実行中のルールファイルに存在する必要があります)。今後 60-evdev.rules、それ以降ではありません。 udev / eudevの以前のバージョンは、組み込みのRUNキーボードを呼び出す代わりに使用IMPORTし、これらの順序に制約がないようです。

この情報の一部のソースは次のとおりです。この問題

udevの組み込み関数はどこに文書化されていますか?

行くところがないようです。バラよりこの回答これらの組み込み関数のソースコードへのいくつかのポインタです。

関連情報