2014-11-21 70 views
4

我正在使用gpio-keys設備驅動程序來處理運行Linux的嵌入式設備中的某些按鈕。用戶空間中的應用程序可以打開/dev/input/eventX並在循環中讀取輸入事件。Linux輸入設備事件,如何檢索初始狀態

我的問題是如何獲得按鈕的初始狀態。有一個ioctl電話(EVIOCGKEY)可以用於此,但是如果我首先檢查這個,然後開始從/dev/input/eventX讀取,則無法保證狀態在兩者之間沒有變化。

有什麼建議嗎?

回答

6

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報告的狀態一致。

+0

這是非常有幫助的。 – Grodriguez 2014-11-26 16:25:59