evdev デバイスはイベントを待ち行列に入れるread()
ので、ほとんどの場合、デバイスを開いて を実行しioctl()
、すぐにそこからイベントを読み取り始めます。ドライバーがキューからいくつかのイベントを削除した場合、イベントが送信SYN_DROPPED
されるため、それが発生した状況を検出できます。libevdev のドキュメントには、その状況をどのように処理すべきかについていくつかのアイデアがあります。私が読んだ方法では、単に再試行する必要があります。つまり、保留中のイベントをすべて削除し、イベントioctl()
がなくなるまでやり直しSYN_DROPPED
ます。
このコードを使用して、このアプローチが機能することを確認しました。
#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/input.h>
#include <string.h>
#define EVDEV "/dev/input/event9"
int main(int argc, char **argv) {
unsigned char key_states[KEY_MAX/8 + 1];
struct input_event evt;
int fd;
memset(key_states, 0, sizeof(key_states));
fd = open(EVDEV, O_RDWR);
ioctl(fd, EVIOCGKEY(sizeof(key_states)), key_states);
// Create some inconsistency
printf("Type (lots) now to make evdev drop events from the queue\n");
sleep(5);
printf("\n");
while(read(fd, &evt, sizeof(struct input_event)) > 0) {
if(evt.type == EV_SYN && evt.code == SYN_DROPPED) {
printf("Received SYN_DROPPED. Restart.\n");
fsync(fd);
ioctl(fd, EVIOCGKEY(sizeof(key_states)), key_states);
}
else if(evt.type == EV_KEY) {
// Ignore repetitions
if(evt.value > 1) continue;
key_states[evt.code / 8] ^= 1 << (evt.code % 8);
if((key_states[evt.code / 8] >> (evt.code % 8)) & 1 != evt.value) {
printf("Inconsistency detected: Keycode %d is reported as %d, but %d is stored\n", evt.code, evt.value,
(key_states[evt.code / 8] >> (evt.code % 8)) & 1);
}
}
}
}
起動後、プログラムは意図的に 5 秒間待機します。その間にいくつかのキーを押して、バッファーを埋めます。私のシステムでは、約 70 文字を入力してSYN_DROPPED
. 処理コードは、イベントがioctlEV_KEY
によって報告された状態と一致しているかどうかをチェックします。EVIOCGKEY