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