【问题标题】:Linux input device events, how to retrieve initial stateLinux输入设备事件,如何检索初始状态
【发布时间】:2015-01-19 17:52:36
【问题描述】:

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

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

有什么建议吗?

【问题讨论】:

    标签: linux linux-kernel embedded evdev


    【解决方案1】:

    evdev 设备queue events 直到你read() 他们,所以在大多数情况下打开设备,执行ioctl() 并立即开始从中读取事件应该可以工作。如果驱动程序从队列中删除了一些事件,它是sends you a SYN_DROPPED event,因此您可以检测到发生这种情况的情况。 The libevdev documentation 对如何处理这种情况有一些想法;按照我的阅读方式,您应该简单地重试,即删除所有待处理的事件,然后重做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_DROPPEDEV_KEY 处理代码检查事件是否与EVIOCGKEY ioctl 报告的状态一致。

    【讨论】:

    • 这很有帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-03-10
    • 2021-04-22
    • 2016-08-02
    • 2014-10-07
    • 1970-01-01
    • 2019-03-06
    • 2016-10-15
    相关资源
    最近更新 更多