Linux 输入设备事件,如何检索初始状态



我正在使用 gpio 键设备驱动程序来处理运行 Linux 的嵌入式设备中的一些按钮。用户空间中的应用程序只需打开/dev/input/eventX并在循环中读取输入事件。

我的问题是如何获取按钮的初始状态。有一个 ioctl 调用 ( EVIOCGKEY ) 可用于此目的,但是如果我先检查这一点,然后开始从/dev/input/eventX读取,则无法保证状态在两者之间没有变化。

有什么建议吗?

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 queuen");
    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 storedn", evt.code, evt.value,
                        (key_states[evt.code / 8] >> (evt.code % 8)) & 1);
            }
        }
    }
}

启动后,程序故意等待 5 秒。在这段时间内按一些键来填充缓冲区。在我的系统上,我需要输入大约 70 个字符才能触发SYN_DROPPEDEV_KEY处理代码检查事件是否与 EVIOCGKEY iotl 报告的状态一致。

相关内容

  • 没有找到相关文章

最新更新