私がやろうとしていること
そのため、Linuxでキーボード入力にアクセスしようとしています。具体的には、他のキーを押さずに修飾キーの押下にアクセスできるようにする必要があります。さらに、 X システムを実行せずにこれを実行できるようにしたいと考えています。
つまり、要するに、私の要件は次のとおりです。
- Linuxで動作
- X11は必要ありません
- 他のキーを押さ
ずに修飾キーの押下を取得できます
- これには、次のキーが含まれます。
- シフト
- コントロール
- 代替
- 必要なのは、キーボードがチェックされているときにキーが押されているかどうかを知らせる単純な だけ
0 = not pressed
です1 = currently pressed
- これには、次のキーが含まれます。
マイ コンピューターのセットアップ
私の通常の Linux マシンは、新しいアパートに向かうトラックに乗っています。そのため、現在使用できる Macbook Air しかありません。したがって、これをテストするために VM で Linux を実行しています。
VirtualBox の仮想マシン
- OS:リナックスミント16
- デスクトップ環境: XFCE
以下は全てこの環境で行いました。X を実行している状態と、他の tty の 1 つで試しました。
私の考え
誰かが私を修正できる場合、私はこれを変更します。
高レベルのライブラリがこの種の機能を提供していないことを理解するために、私はかなりの量の読書をしました。修飾キーは、代替キー コードを提供するために他のキーと共に使用されます。Linux の高レベル ライブラリを介して修飾キー自体にアクセスすることは、それほど簡単ではありません。というか、Linux でこのための高レベル API を見つけられませんでした。
libtermkeyが答えになると思いましたが、通常のキーストローク検索よりも Shift 修飾キーをサポートしていないようです。Xなしで動作するかどうかもわかりません。
libtermkey を使用しているときに (Shift-Return のような場合にシフトしないことに気付く前に)、キーボード イベントを収集するために実行されるデーモンを作成することを計画していました。デーモン プログラムのコピーを実行すると、単純にキーボード データの要求をパイプし、応答としてキーボード データを受け取ります。このセットアップを使用して、特定の時間にキー コードのステータスを確認できない場合 (発生時にキー コードを受信する必要がある場合) に備えて、何かを常にバックグラウンドで実行することができます。
以下は、Linux キーボード デバイスから読み取ることができるプログラムを作成するための 2 つの試みです。また、適切なデバイスを持っていることを確認するために、小切手も含めました。
試み #1
キーボード デバイスに直接アクセスしようとしましたが、問題が発生しています。ここで、別のスタック オーバーフロー スレッドにある提案を試しました。セグメンテーション違反が発生しました。そのため、fopen から open に変更しました。
// ...
int fd;
fd = open("/dev/input/by-path/platform-i8042-serio-0-event-kbd", O_RDONLY);
char key_map[KEY_MAX/8 + 1];
memset(key_map, 0, sizeof(key_map));
ioctl(fd, EVIOCGKEY(sizeof key_map), key_map);
// ...
セグメンテーション違反はありませんでしたが、キーが押されたことを示すインジケーターはありませんでした (修飾キーだけではありません)。私はこれを使用してテストしました:
./foo && echo "TRUE" || echo "FALSE"
これを使用して、コマンドからの成功したリターン コードをかなり多くテストしました。だから、私はそれが大丈夫だと知っています。また、キー (常に 0) とマスク (0100) を出力して確認しました。何も検出していないようです。
試み #2
ここからは、少し違ったアプローチを試してみようと思いました。私は自分が何を間違っていたのかを理解したかったのです。キーコードの印刷を示すスニペットを提供するこのページに続いて、それをプログラムにバンドルしました。
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <fcntl.h>
#include <linux/input.h>
int main(int argc, char** argv) {
uint8_t keys[128];
int fd;
fd = open("/dev/input/by-path/platform-i8042-serio-event-kbd", O_RDONLY);
for (;;) {
memset(keys, 0, 128);
ioctl (fd, EVIOCGKEY(sizeof keys), keys);
int i, j;
for (i = 0; i < sizeof keys; i++)
for (j = 0; j < 8; j++)
if (keys[i] & (1 << j))
printf ("key code %d\n", (i*8) + j);
}
return 0;
}
以前は、サイズが 128 バイトではなく 16 バイトでした。正直なところ、ioctl と EVIOCGKEY の理解にもう少し時間を費やす必要があります。ビットを特定のキーにマップして、プレスなどを示すと思われることを知っているだけです(間違っている場合は修正してください!)。
また、最初はループがなく、キーコードが表示されるかどうかを確認するためにさまざまなキーを押したままにしていました。私は何も受け取りませんでした。そのため、ループを使用すると、何かを見逃した場合にチェックをテストしやすくなると思いました。
入力デバイスが正しいことを知る方法
cat
入力デバイスで実行してテストしました。具体的には:
$ sudo cat /dev/input/by-path/platform-i8042-serio-0-event-kbd
cat を使用して出力を開始したときに、return (enter) キーで始まるキーを押して解放するイベントで、ガベージ ASCII が端末に送信されました。また、Linux VM を実行している Macbook では、Shift、Control、Function、さらには Apple のコマンド キーなどの修飾キーでも問題なく機能するようです。キーが押されたときに出力が現れ、キーを押し続けることによって送信される後続の信号から急速に現れ始め、キーが離されるとさらに多くのデータが出力されました。
したがって、私のアプローチは正しいものではないかもしれませんが (代替案を喜んで聞きます)、デバイスは私が必要とするものを提供しているようです.
さらに、このデバイスは実行中の /dev/input/event2 を指す単なるリンクであることもわかっています。
$ ls -l /dev/input/by-path/platform-i8042-serio-0-event-kbd
上記の両方のプログラムを /dev/input/event2 で試しましたが、データを受け取りませんでした。/dev/input/event2 で cat を実行すると、リンクと同じ出力が得られました。