文章目錄
3 輸入系統應用開發
3.1 什么是輸入系統?
3.2 輸入系統應用框架描述
3.3 輸入系統事件的讀取與分析
3.5 輸入系統應用編程實戰二:通用鍵盤事件讀取
3.6 輸入系統應用編程實戰三:百問網imx6ul開發板觸摸屏事件讀取
3 輸入系統應用開發
3.1 什么是輸入系統?
? 在了解輸入系統之前,先來了解什么是輸入設備?常見的輸入設備有鍵盤、鼠標、遙控桿、書寫板、觸摸屏等等,用戶通過這些輸入設備與Linux系統進行數據交換,Linux系統為了統一管控和處理這些設備,于是就實現了一套固定的與硬件無關的輸入系統框架,供用戶空間程序使用,這就是輸入系統。
3.2 輸入系統應用框架描述
? 在Linux輸入系統中,主要分三層進行管理,分別是input core(輸入系統核心層)、drivers(輸入系統驅動層)以及event handlers(輸入系統事件層),如下圖所示,這就是Linux輸入系統的基本框架:
? 舉個非常簡單的例子,比如用戶按下鍵盤里的其中一個按鍵,它遵循流程是這樣的:
? 按鍵按下–>輸入系統驅動層–>輸入系統核心層–>輸入系統事件層—>用戶空間
? 對于應用程序軟件編程的角度,我們只需要關注用戶空間是怎么得到按鍵按下以后獲取的是什么事件就可以了,例如我想知道我當前按下的按是短按還是長按?或者我想知道當前我按下鍵盤的是空格鍵還是回車鍵等等。
3.3 輸入系統事件的讀取與分析
? 用戶空間的設備節點那么多,怎么知道當前是哪個設備上報的呢?例如想知道鍵盤是由哪個設備節點上報的,就可以通過以下這條指令來獲?。?/p>
cat /proc/bus/input/devices
? 這條指令的含義就是獲取與event對應的相關設備信息,在ubuntu系統上,我們輸入這個指令可以看到以下結果:
? 那么這里的I、N、P、S、U、H、B對應的每一行是什么含義呢?
I:id of the device(設備ID)
該參數由結構體struct input_id來進行描述
41 struct input_id { 42 //總線類型 43 __u16 bustype; 44 //與廠商相關ID 45 __u16 vendor; 46 //與產品相關ID 47 __u16 product; 48 //版本ID 49 __u16 version; 50 };
N:name of the device
設備名稱
P:physical path to the device in the system hierarchy
系統層次結構中設備的物理路徑。
S:sysfs path
位于sys文件系統的路徑
U:unique identification code for the device(if device has it)
設備的唯一標識碼
H:list of input handles associated with the device.
與設備關聯的輸入句柄列表。
B:bitmaps(位圖)
PROP:device properties and quirks.
EV:types of events supported by the device.
KEY:keys/buttons this device has.
MSC:miscellaneous events supported by the device.
LED:leds present on the device.
PROP:設備屬性和怪癖。
EV:設備支持的事件類型。
KEY:此設備具有的鍵/按鈕。
MSC:設備支持的其他事件。
LED:設備上的指示燈。
通過了解以上參數的含義,結合以下指令
cat /proc/bus/input/devices
顯示出來的信息很容易可以知道event1即是鍵盤上報的事件設備節點,通過讀取這個event1即可獲得當前用戶按下的按鍵具體是哪個事件。
使用cat命令來測試鍵盤事件
當我們在終端輸入
cat /dev/input/event1
? 這條指令并按回車鍵后可以看到一堆亂碼數據,這些數據我們看不懂,但是我們可以知道如果按下了按鍵,終端有反饋消息,這時候就知道這個事件就是我們當前操作的這個設備上報的事件,那么如何能讓這些數據看得懂呢?這時候可以使用hexdump命令來讀取鍵盤事件。
使用hexdump命令來測試鍵盤事件
這些數值是通過input_event結構體來上報的,它位于/usr/include/linux/input.h這個頭文件,input_event結構體描述如下:
24 struct input_event { 25 //事件發生的事件 26 struct timeval time; 27 //事件類型 28 __u16 type; 29 //事件值 30 __u16 code; 31 //該事件上報的數值 32 __s32 value; 33 };
而input_event結構體中的time即是:
1 struct timeval 2 { 3 __time_t tv_sec; /* Seconds. */ 4 __suseconds_t tv_usec; /*Microseconds. */ 5 };
? 其中tv_sec為Epoch到創建struct timeval時的秒數,tv_usec為微秒數,即秒后面的零頭,Epoch的意思是指定為1970年一月一日凌晨零點零分零秒,格林威治時間。
? 回到input_event結構體,事件類型type主要有以下三種,分別是:相對事件、絕對事件、鍵盤事件
? 例如:鼠標就是一個相對事件,有些情況下也有可能是絕對事件,當移動鼠標的時候,type類型也就是底層上報給用戶的事件類型,那么code表示的就是相對于鼠標當前的位置的X或者Y的坐標,value則表示相對于當前的位置偏移了多少。
事件類型(type)
文件頭文件路徑:
/usr/include/linux/input-event-codes.h
當然Linux內核版本較低的有可能在以下路徑的這個頭文件:
/usr/include/linux/input.h
34 /* 35 * Event types 36 */ 37 38 #define EV_SYN 0x00 //同步事件 39 #define EV_KEY 0x01 //按鍵事件 40 #define EV_REL 0x02 //相對事件 41 #define EV_ABS 0x03 //絕對事件 42 #define EV_MSC 0x04 43 #define EV_SW 0x05 44 #define EV_LED 0x11 45 #define EV_SND 0x12 46 #define EV_REP 0x14 47 #define EV_FF 0x15 48 #define EV_PWR 0x16 49 #define EV_FF_STATUS 0x17 50 #define EV_MAX 0x1f 51 #define EV_CNT (EV_MAX+1)
事件值(code)
由于事件值種類繁多,這里就不一一列舉出來,這里舉例鍵盤的部分事件值:
文件頭文件路徑:
/usr/include/linux/input-event-codes.h
當然Linux內核版本較低的有可能在以下路徑的這個頭文件:
/usr/include/linux/input.h 64 /* 65 * Keys and buttons 66 * 67 * Most of the keys/buttons are modeled after USB HUT 1.12 68 * (see http://www.usb.org/developers/hidpage). 69 * Abbreviations in the comments: 70 * AC - Application Control 71 * AL - Application Launch Button 72 * SC - System Control 73 */ 74 75 #define KEY_RESERVED 0 76 #define KEY_ESC 1 77 #define KEY_1 2 78 #define KEY_2 3 79 #define KEY_3 4 80 #define KEY_4 5 81 #define KEY_5 6 82 #define KEY_6 7 83 #define KEY_7 8 84 #define KEY_8 9 85 #define KEY_9 10 86 #define KEY_0 11 87 #define KEY_MINUS 12 88 #define KEY_EQUAL 13 89 #define KEY_BACKSPACE 14 90 #define KEY_TAB 15 91 #define KEY_Q 16 92 #define KEY_W 17 ...
當然還有鼠標事件值、搖桿事件值、觸摸屏事件值等等。
該事件上報的數值(value)
? 這部分上面已經舉了鼠標的案例進行了介紹,接下來我們就通過應用程序來獲取事件,后面章節將會通過鼠標、鍵盤以及觸摸屏三個案例,進一步的了解輸入系統的應用編程。
3.4 輸入系統應用編程實戰一:通用USB鼠標事件讀取
? 根據前面章節的講解,如果我們需要獲取USB鼠標的事件,首先我們要先通過cat /proc/bus/input/devices這個指令查詢與USB鼠標事件對應的相關設備信息,通過實際測試得知,event2為USB鼠標上報的事件節點。
接下來,通過hexdump命令測試一下鼠標事件的輸出:
? 具體上報的數值是什么含義可以結合3.3章節進行分析,這里就不再進行闡述,本節的目的是編寫一個獲取通用USB鼠標的事件的應用程序,要獲取一個事件,我們需要了解以下幾個部分。
1 設備上報事件類型(type)
通過3.3章節,我們知道找到對應的事件類型的定義:
文件頭文件路徑:
/usr/include/linux/input-event-codes.h
當然Linux內核版本較低的有可能在以下路徑的這個頭文件:
/usr/include/linux/input.h
34 /* 35 * Event types 36 */ 37 38 #define EV_SYN 0x00 //同步事件 39 #define EV_KEY 0x01 //按鍵事件 40 #define EV_REL 0x02 //相對事件 41 #define EV_ABS 0x03 //絕對事件 42 #define EV_MSC 0x04 43 #define EV_SW 0x05 44 #define EV_LED 0x11 45 #define EV_SND 0x12 46 #define EV_REP 0x14 47 #define EV_FF 0x15 48 #define EV_PWR 0x16 49 #define EV_FF_STATUS 0x17 50 #define EV_MAX 0x1f 51 #define EV_CNT (EV_MAX+1)
2 設備上報的事件值(code)
由于本節我們寫的是通用USB鼠標的應用程序,所以我們找到鼠標相關的code,如下:
文件頭文件路徑:
/usr/include/linux/input-event-codes.h
當然Linux內核版本較低的有可能在以下路徑的這個頭文件:
/usr/include/linux/input.h
696 /* 697 * Relative axes 698 */ 699 700 #define REL_X 0x00 //相對X坐標 701 #define REL_Y 0x01 //相對Y坐標 702 #define REL_Z 0x02 703 #define REL_RX 0x03 704 #define REL_RY 0x04 705 #define REL_RZ 0x05 706 #define REL_HWHEEL 0x06 707 #define REL_DIAL 0x07 708 #define REL_WHEEL 0x08 709 #define REL_MISC 0x09 710 #define REL_MAX 0x0f 711 #define REL_CNT (REL_MAX+1)
在這里,我們暫時只會用來REL_X和REL_Y這兩個參數。
? 那么所謂的value,就是選擇具體的事件類型(type)和具體的事件值(code)以后所反應出來的值,鼠標就是相對于當前X或者相對于當前Y的值,接下來,我們來看一下如何來讀取鼠標事件。
在編寫input應用程序之前,在程序中需要包含以下頭文件:
#include
程序編寫步驟:
1 定義一個結構體變量input_event用于描述input事件
struct input_event event_mouse ;
2 打開input設備的事件節點,這里我們獲取的通用USB鼠標是event2
open("/dev/input/event2",O_RDONLY);
3 讀取事件
read(fd ,&event_mouse ,sizeof(event_mouse));
4 根據上報的事件進行處理
//判斷鼠標上報的類型,可能為絕對事件,也有可能是相對事件 if(EV_ABS == event_mouse.type || EV_REL == event_mouse.type) { //code表示相對位移X或者Y,當判斷是X時,打印X的相對位移value //當判斷是Y時,打印Y的相對位移value if(event_mouse.code == REL_X) { printf("event_mouse.code_X:%dn", event_mouse.code); printf("event_mouse.value_X:%dn", event_mouse.value); } else if(event_mouse.code == REL_Y) { printf("event_mouse.code_Y:%dn", event_mouse.code); printf("event_mouse.value_Y:%dn", event_mouse.value); } }
5 關閉文件描述符
close(fd);
不難發現,獲取一個輸入系統事件,也是標準的文件操作,這體現了Linux一切皆文件的思想。
完整的程序案例如下:
01 #include 02 #include 03 #include 04 #include 05 #include 06 07 int main(void) 08 { 09 //1、定義一個結構體變量用來描述input事件 10 struct input_event event_mouse ; 11 //2、打開input設備的事件節點 我的通用USB鼠標事件的節點是event2 12 int fd = -1 ; 13 fd = open("/dev/input/event2", O_RDONLY); 14 if(-1 == fd) 15 { 16 printf("open mouse event fair!n"); 17 return -1 ; 18 } 19 while(1) 20 { 21 //3、讀事件 22 read(fd, &event_mouse, sizeof(event_mouse)); 23 if(EV_ABS == event_mouse.type || EV_REL == event_mouse.type) 24 { 25 //code表示相對位移X或者Y,當判斷是X時,打印X的相對位移value 26 //當判斷是Y時,打印Y的相對位移value 27 if(event_mouse.code == REL_X) 28 { 29 printf("event_mouse.code_X:%dn", event_mouse.code); 30 printf("event_mouse.value_X:%dn", event_mouse.value); 31 } 32 else if(event_mouse.code == REL_Y) 33 { 34 printf("event_mouse.code_Y:%dn", event_mouse.code); 35 printf("event_mouse.value_Y:%dn", event_mouse.value); 36 } 37 } 38 } 39 close(fd); 40 return 0 ; 41 }
代碼編寫完畢后,然后執行
gcc test_mouse.c -o test_mouse
編譯程序:
編譯成功后會生成test_mouse,接下來執行test_mouse這個程序。
當鼠標左右移動的時候上報的事件:
這時候可以看到,只有相對于X的事件值在發生,這時候打印的value是X方向相對于原點坐標的偏移值。
當鼠標上下移動的時候上報的事件:
這時候可以看到,只有相對于Y的事件值在發生,這時候打印的value是Y方向相對于原點坐標的偏移值。
3.5 輸入系統應用編程實戰二:通用鍵盤事件讀取
? 如何獲取鍵盤事件在3.3章節已經有了相應的介紹,這里就不再寫出來,本節實現的是通用鍵盤事件的獲取,結合3.4章節獲取鼠標事件的方式,這里通用鍵盤事件的節點為event1,通過結合3.3章節與3.4章節,編寫步驟如下:
在編寫input應用程序之前,在程序中需要包含以下頭文件:
#include
程序編寫步驟:
1 定義一個結構體變量input_event用于描述input事件
struct input_event event_keyboard ;
2 打開input設備的事件節點,我的通用鍵盤事件的節點是event1
open("/dev/input/event1",O_RDONLY);
3 讀取事件
read(fd ,&event_keyboard ,sizeof(event_keyboard));
4 根據上報的事件進行處理
//判斷鍵盤事件上報的類型 if(EV_KEY == event_keyboard.type) { if(1 == event_keyboard.value) printf("事件類型:%d 事件值:%d 按下n", event_keyboard.type, event_keyboard.code); else if(0 == event_keyboard.value) printf("事件類型:%d 事件值:%d 釋放n", event_keyboard.type, event_keyboard.code); }
5 關閉文件描述符
close(fd);
完整程序案例實現如下:
01 #include 02 #include 03 #include 04 #include 05 #include 06 07 int main(void) 08 { 09 //1、定義一個結構體變量用來描述input事件 10 struct input_event event_keyboard ; 11 //2、打開input設備的事件節點 我的通用鍵盤事件的節點是event1 12 int fd = -1 ; 13 fd = open("/dev/input/event1", O_RDONLY); 14 if(-1 == fd) 15 { 16 printf("open mouse event fair!n"); 17 return -1 ; 18 } 19 while(1) 20 { 21 //3、讀事件 22 read(fd, &event_keyboard, sizeof(event_keyboard)); 23 if(EV_KEY == event_keyboard.type) 24 { 25 if(1 == event_keyboard.value) 26 printf("事件類型:%d 事件值:%d 按下n",event_keyboard.type,event_keyboard.code); 27 else if(0 == event_keyboard.value) 28 printf("事件類型:%d 事件值:%d 釋放n",event_keyboard.type,event_keyboard.code); 29 } 30 } 31 close(fd); 32 return 0 ; 33 }
? 不難發現,通用USB鍵盤程序編寫步驟與通用USB鼠標程序編寫步驟幾乎一樣,區別只是讀取的事件類型以及后面處理的數據value不同。
代碼編寫完畢后,然后執行
gcc test_keyboard.c -o test_keyboard
編譯程序:
編譯成功后會生成test_keyboard,接下來執行test_keyboard這個程序。
當按下按鍵時候,可以觀察到按鍵的按下和釋放的過程,這其實就是同一個事件下的兩個不同的狀態。
3.6 輸入系統應用編程實戰三:百問網imx6ul開發板觸摸屏事件讀取
? 在前面,我們已經熟悉了鼠標、鍵盤的基本操作,但發現一個規律,那就是編程方法類似,唯一不同的地方就是獲取的事件類型以及事件值不同,那么觸摸屏在input系統中是一類什么事件呢?
? 一般情況下,觸摸屏在input系統中屬于絕對事件,也就是觸摸的坐標點X和Y會在屏幕的分辨率范圍內上報一個絕對的坐標。
絕對事件對應的值為:EV_ABS
相應X和Y分量的值分別為:
ABS_MT_POSITION_X、ABS_MT_POSITION_Y
通過結合前面的章節內容,很容易編寫如下程序:
01 #include 02 #include 03 #include 04 #include 05 #include 06 07 int main(int argc, char **argv) 08 { 09 int tp_fd = -1 ; 10 int tp_ret = -1 ; 11 int touch_x,touch_y ; 12 struct input_event imx6ull_ts ; 13 //1、打開觸摸屏事件節點 14 tp_fd = open("/dev/input/event1",O_RDONLY); 15 if(tp_fd < 0) 16 { 17 printf("open /dev/input/event1 fail!n"); 18 return -1 ; 19 } 20 while(1) 21 { 22 //2、獲取觸摸屏相應的事件,并打印出當前觸摸的坐標 23 read(tp_fd ,&imx6ull_ts ,sizeof(imx6ull_ts)); 24 switch(imx6ull_ts.type) 25 { 26 case EV_ABS: 27 if(imx6ull_ts.code == ABS_MT_POSITION_X) 28 touch_x = imx6ull_ts.value ; 29 if(imx6ull_ts.code == ABS_MT_POSITION_Y) 30 touch_y = imx6ull_ts.value ; 31 break ; 32 defalut: 33 break ; 34 } 35 printf("touch_x:%d touch_y:%dn",touch_x,touch_y); 36 usleep(100); 37 } 38 close(tp_fd); 39 return 0; 40 }
代碼編寫完畢后,然后執行
gcc test_touchscreen.c -o test_touchscreen
交叉編譯程序:(注意這里是要在開發板運行,不是在PC端)
接下來啟動開發板,然后串口終端輸出rz命令,等待接收PC端的文件,這里我們將test_touchscreen這個文件傳輸到開發板。
具體操作步驟可參考第11章:PC和開發板之間傳輸文件
接下來給test_touchscreen添加可執行權限:
執行test_touchscreen,然后用手觸摸屏,可以看到有相應的坐標值打?。?/p>
審核編輯黃昊宇
-
Linux
+關注
關注
87文章
11499瀏覽量
213348 -
開發
+關注
關注
0文章
373瀏覽量
41456
發布評論請先 登錄
現代控制理論-第三章-線性系統的能控性與能觀性
慕課嵌入式開發及應用(第三章.脈寬調制.輸入捕捉.輸出比較))

慕課嵌入式開發及應用(第三章.單元測試)

慕課嵌入式開發及應用(第三章.GPIO應用-鍵盤)

評論