? ? 大家好,我是ST。
? ? 今天主要和大家聊一聊,如何使用標準輸入設備,進行控制信息的識別。
第一:按鍵應用編程方法
? ? ?編寫一個應用程序,獲取按鍵狀態,判斷按鍵當前是按下,松開或長按狀態。
?
#以字母A鍵為例 KEY_A????//上報KEY_A事件 SYN_REPORT //同步
?
? ? ??如果是按下,則上報KEY_A事件時,value=1;如果是松開,則value=0;如果長按,則value=2。接下來編寫按鈕應用程序,讀取按鍵狀態并將結果打印出來,代碼如下所示。
?
#include#include #include #include #include #include #include int main(int argc, char *argv[]) { struct input_event in_ev = {0}; int fd = -1; int value = -1; /* 校驗傳參 */ if (2 != argc) { fprintf(stderr, "usage: %s ", argv[0]); exit(-1); } /* 打開文件 */ if (0 > (fd = open(argv[1], O_RDONLY))) { perror("open error"); exit(-1); } for ( ; ; ) { /* 循環讀取數據 */ if (sizeof(struct input_event) != read(fd, &in_ev, sizeof(struct input_event))) { perror("read error"); exit(-1); } if (EV_KEY == in_ev.type) { //按鍵事件 switch (in_ev.value) { case 0: printf("code<%d>: 松開 ", in_ev.code); break; case 1: printf("code<%d>: 按下 ", in_ev.code); break; case 2: printf("code<%d>: 長按 ", in_ev.code); break; } } } }
?
?? ?在for循環中,調用read()讀取輸入設備上報的數據,當按鍵按下或松開(以及長按)動作發生時,read()會讀取到輸入設備上報的數據,首先判斷此次上報的事件是否是按鍵類事件(EV_KEY),如果是按鍵類事件,接著根據value值來判斷按鍵當前的狀態是松開、按下還是長按。
? ??將編譯得到的可執行文件復制到開發板Linux系統的家目錄下:
注意:除了能夠測試KEY0按鍵之外,還可以測試鍵盤上的按鍵,可以找到一個USB鍵盤連接到開發板的USB HOST接口上,當鍵盤插入之后,終端將會打印出相應的驅動加載信息。
? ? ?驅動加載成功之后,可以查看下該鍵盤設備對應的設備節點,使用命令"cat /proc/bus/input/devices",在打印信息中找到鍵盤設備的信息:
? ? ? 操作的時候,可以對應相應的設備節點/dev/input/event3,運行測試程序并按下、松開鍵盤上的按鍵;
? ? ?大家可以根據code值查詢對應的按鍵,譬如code=30對應的鍵盤上的字母A鍵,code=48對應的字母B鍵。
第二:單點觸摸應用程序實現
? ? ?通過上面的詳細介紹,大家應該知道如何編寫一個觸摸屏的應用程序了,接下來我們編寫一個單點觸摸屏應用程序,獲取一個觸摸點的坐標信息,并將其打印出來。具體代碼實現如下:
?
#include#include #include #include #include #include #include int main(int argc, char *argv[]) { struct input_event in_ev; int x, y; //觸摸點 x 和 y 坐標 int down; //用于記錄 BTN_TOUCH 事件的 value,1 表示按下,0 表示松開,-1 表示移動 int valid; //用于記錄數據是否有效(我們關注的信息發生更新表示有效,1 表示有效,0 表示無效) int fd = -1; /* 校驗傳參 */ if (2 != argc) { fprintf(stderr, "usage: %s ", argv[0]); exit(EXIT_FAILURE); } /* 打開文件 */ if (0 > (fd = open(argv[1], O_RDONLY))) { perror("open error"); exit(EXIT_FAILURE); } x = y = 0; //初始化 x 和 y 坐標值 down = -1; //初始化<移動> valid = 0;//初始化<無效> for ( ; ; ) { /* 循環讀取數據 */ if (sizeof(struct input_event) != read(fd, &in_ev, sizeof(struct input_event))) { perror("read error"); exit(EXIT_FAILURE); } ?switch(in_ev.type) { case EV_KEY: //按鍵事件 if (BTN_TOUCH == in_ev.code) { down = in_ev.value; valid = 1; } break; case EV_ABS: //絕對位移事件 switch (in_ev.code) { case ABS_X: //X 坐標 x = in_ev.value; valid = 1; break; case ABS_Y: //Y 坐標 y = in_ev.value; valid = 1; break; } break; case EV_SYN: //同步事件 if (SYN_REPORT == in_ev.code) { if (valid) {//判斷是否有效 switch (down) {//判斷狀態 case 1: printf("按下(%d, %d) ", x, y); break; case 0: printf("松開 "); break; case -1: printf("移動(%d, %d) ", x, y); break; } valid = 0; //重置 valid down = -1; //重置 down } } break; } } }
?
? ? ?分析:程序中先傳入參數,main()函數中定義了4個變量;
⑴、變量 x 表示觸摸點的 X 坐標;
⑵、變量 y 表示觸摸點的 Y 坐標;
⑶、變量 down 表示手指狀態時候按下、松開還是滑動,down=1 表示手指按下、down=0 表示手指松開、down=-1 表示手指滑動;
⑷、變量 valid 表示數據是否有效,valid=1 表示有效、valid=0 表示無效;有效指的是我們檢測的信息發生了更改,譬如程序中只檢測了手指的按下、松開動作以及坐標值的變化。接著調用 open()打開觸摸屏設備文件得到文件描述符 fd;在 for 循環之前,首先對 x、y、down、valid這 4 個變量進行初始化操作。在 for 循環讀取觸摸屏上報的數據,將讀取到的數據存放在 struct input_event數據結構中。在 switch…case 語句中對讀取到的數據進行解析,獲取 BTN_TOUCH 事件的 value 數據,判斷觸摸屏是按下還是松開狀態,獲取 ABS_X 和 ABS_Y 事件的 value 變量,得到觸摸點的 X 軸坐標和 Y 軸坐標。
? ? 當上報同步事件時,表示數據已上傳完整,接著對得到的數據進行分析,打印坐標信息。
第三:多點觸摸應用程序實現
? ? 實現了單點觸摸應用程序之后,可以再來實現多點觸摸屏應用程序該如何實現。
?
#include#include #include #include #include #include #include #include #include /* 用于描述 MT 多點觸摸每一個觸摸點的信息 */ struct ts_mt { int x; //X 坐標 int y; //Y 坐標 int id; //對應 ABS_MT_TRACKING_ID int valid; //數據有效標志位(=1 表示觸摸點信息發生更新) }; /* 一個觸摸點的 x 坐標和 y 坐標 */ struct tp_xy { int x; int y; }; static int ts_read(const int fd, const int max_slots, struct ts_mt *mt) { struct input_event in_ev; static int slot = 0;//用于保存上一個 slot static struct tp_xy xy[12] = {0};//用于保存上一次的 x 和 y 坐標值,假設觸摸屏支持的最大觸摸點數不會超 過 12 int i; /* 對緩沖區初始化操作 */ memset(mt, 0x0, max_slots * sizeof(struct ts_mt)); //清零 for (i = 0; i < max_slots; i++) mt[i].id = -2;//將 id 初始化為-2, id=-1 表示觸摸點刪除, id>=0 表示創建 for ( ; ; ) { if (sizeof(struct input_event) != read(fd, &in_ev, sizeof(struct input_event))) { perror("read error"); return -1; } switch (in_ev.type) { case EV_ABS: switch (in_ev.code) { case ABS_MT_SLOT: slot = in_ev.value; break; case ABS_MT_POSITION_X: xy[slot].x = in_ev.value; mt[slot].valid = 1; break; case ABS_MT_POSITION_Y: xy[slot].y = in_ev.value; mt[slot].valid = 1; break; case ABS_MT_TRACKING_ID: mt[slot].id = in_ev.value; mt[slot].valid = 1; break; } break; //case EV_KEY://按鍵事件對單點觸摸應用比較有用 // break; case EV_SYN: if (SYN_REPORT == in_ev.code) { for (i = 0; i < max_slots; i++) { mt[i].x = xy[i].x; mt[i].y = xy[i].y; } } return 0; } } } int main(int argc, char *argv[]) { struct input_absinfo slot; struct ts_mt *mt = NULL; int max_slots; int fd; int i; /* 參數校驗 */ if (2 != argc) { fprintf(stderr,"usage: %s ", argv[0]); exit(EXIT_FAILURE); } /* 打開文件 */ fd = open(argv[1], O_RDONLY); if (0 > fd) { perror("open error"); exit(EXIT_FAILURE); } /* 獲取觸摸屏支持的最大觸摸點數 */ if (0 > ioctl(fd, EVIOCGABS(ABS_MT_SLOT), &slot)) { perror("ioctl error"); close(fd); exit(EXIT_FAILURE); } max_slots = slot.maximum + 1 - slot.minimum; printf("max_slots: %d ", max_slots); /* 申請內存空間并清零 */ mt = calloc(max_slots, sizeof(struct ts_mt)); /* 讀數據 */ for ( ; ; ) { if (0 > ts_read(fd, max_slots, mt)) break; for (i = 0; i < max_slots; i++) { if (mt[i].valid) {//判斷每一個觸摸點信息是否發生更新(關注的信息發生更新) if (0 <= mt[i].id) printf("slot<%d>, 按下(%d, %d) ", i, mt[i].x, mt[i].y); else if (-1 == mt[i].id) printf("slot<%d>, 松開 ", i); else printf("slot<%d>, 移動(%d, %d) ", i, mt[i].x, mt[i].y); } } } /* 關閉設備、退出 */ close(fd); free(mt); exit(EXIT_FAILURE); }
?
? ? ? 示例代碼中申明了 struct ts_mt 數據結構,用于描述多點觸摸情況下每一個觸摸點的信息。
? ? ? 首先來看下 main()函數,定義了 max_slots 變量,用于指定觸摸屏設備的支持的最大觸摸點數,通過:
ioctl(fd, EVIOCGABS(ABS_MT_SLOT), &slot)
獲取到觸摸屏該信息。
接著根據 max_slots 變量的值,為 mt 指針申請內存:
? ? ? ? ? ? mt = calloc(max_slots, sizeof(struct ts_mt));
? ? ?for( ; ; )循環中調用 ts_read()函數,該函數是自定義函數,用于獲取觸摸屏上報的數據,第一個參數表示文件描述符 fd、第二個參數表示觸摸屏支持的最大觸摸點數、第三個參數則是 struct ts_mt 數組,ts_read()函數會將獲取到的數據存放在數組中,mt[0]表示 slot<0>數據、mt[1]表示 slot<1>的數據依次類推!
? ? 在內部的 for 循環中,則對獲取到的數據進行分析,判斷數據是否有效,并根據 id 判斷手指的動作,在單點觸摸應用程序中,我們是通過 BTN_TOUCH 事件來判斷手指的動作;而在多點觸摸應用中,我們需要通過 id 來判斷多個手指的動作。
? ? ?關于自定義函數 ts_read()就不再介紹了,代碼的注釋已經描述很清楚了!
? ? ?接著編譯應用程序,將編譯得到的可執行文件拷貝到開發板 Linux 系統的用戶家目錄下,執行應用程序,接著可以用多個手指觸摸觸摸屏、松開、滑動等操作。
總結:每一個不同的slot表示不同的觸摸點,譬如 slot<0>表示觸摸點 0、slot<1>表示觸摸點 1 以此類推!
評論
查看更多