哈嘍,大家好,我是LittleG。
如果將 Linux 比作一個(gè)人,那么Linux input子系統(tǒng)就好比我們的眼睛,手,腳,以及到大腦的神經(jīng)網(wǎng)絡(luò),可以通過(guò)它們獲取和傳遞信息,感知外圍世界?;氐?Linux/Android 世界,像手機(jī)設(shè)備中,按鍵、觸摸屏、各種sensor,數(shù)據(jù)流一般也是走的input子系統(tǒng)上報(bào)給上層的,所以學(xué)習(xí)和理解input子系統(tǒng)很重要。
正文
#include <linux/input.h>
在這個(gè)文件中,我們可以找到這個(gè)結(jié)構(gòu)體:
描述一個(gè)輸入事件 /* * The event structure itself */ struct input_event { struct timeval time; __u16 type; __u16 code; __s32 value; };
先來(lái)解讀下這個(gè)結(jié)構(gòu)體的含義:
struct timeval結(jié)構(gòu)體在time.h中的定義為:
struct timeval { __time_t tv_sec; /* Seconds. */ __suseconds_t tv_usec; /*Microseconds. */ };
【time】
域的 tv_sec 為Epoch到創(chuàng)建struct timeval時(shí)的秒數(shù),tv_usec為微秒數(shù),即秒后面的零頭。
【type】
域顯示了被報(bào)告事件的類型,例如,一個(gè) key press或者 button press, relative motion(比如移動(dòng)鼠標(biāo) ) 或者 absolute motion(比如移動(dòng)游戲桿 ); 常用的事件類型 type
有 EV_KEY , EV_REL , EV_ABS , EV_SYN ;分別對(duì)應(yīng)keyboard事件,相對(duì)事件,絕對(duì)事件,同步事件;EV_SYN 則表示一組完整事件已經(jīng)完成,需要處理;
【code】
域根據(jù)type
的不同而含義不同,上報(bào)是哪一個(gè)key或者哪一個(gè)坐標(biāo)軸在被操作; 例如,type
為 EV_KEY 時(shí),code表示鍵盤(pán)code或者鼠標(biāo)Button值;type
為 EV_REL 時(shí),code表示操作的是哪個(gè)坐標(biāo)軸,如:REL_X,REL_Y (因?yàn)槭髽?biāo)有x,y兩個(gè)軸向,所以一次鼠標(biāo)移動(dòng),會(huì)產(chǎn)生兩個(gè)input_event);type
為 EV_ABS 時(shí),code表示絕對(duì)坐標(biāo)軸向。
【value】
域也是根據(jù)type
的不同而含義不同,上報(bào)現(xiàn)在的狀態(tài)或者運(yùn)動(dòng)情況是什么。例如:type
為EV_KEY時(shí),value:0表示按鍵抬起,1表示按鍵按下;(4表示持續(xù)按下等?)type
為EV_REL時(shí),value: 表明移動(dòng)的值和方向(正負(fù)值);type
為EV_ABS時(shí),value: 表示絕對(duì)位置;
那么,最主要的事件有以下三種:相對(duì)事件(鼠標(biāo)),絕對(duì)事件(觸摸屏),鍵盤(pán)事件。
例如:
我們說(shuō)鼠標(biāo),我們?cè)谝苿?dòng)鼠標(biāo)的時(shí)候鼠標(biāo)就是一個(gè)相對(duì)事件,所以type的類型也就是底層上報(bào)給用戶的事件為相對(duì)事件類型,那么code表示的就是相對(duì)于鼠標(biāo)當(dāng)前的位置的X或者Y的坐標(biāo),value也就是相對(duì)于當(dāng)前的位置偏移多少。
事件類型(type)在 input.h 主要有以下:
/* * Event types */ #define EV_SYN 0x00 ? ? //同步事件,就是將結(jié)果上報(bào)給系統(tǒng)的過(guò)程 #define EV_KEY 0x01 ? ? //按鍵事件,如 KEY_VOLUMEDOWN 事件 #define EV_REL 0x02 ? ? //相對(duì)事件, 如鼠標(biāo)上報(bào)的坐標(biāo) #define EV_ABS 0x03 ? ? //絕對(duì)事件,如觸摸屏上報(bào)的坐標(biāo) #define EV_MSC 0x04 ? ? //其它 #define EV_SW 0x05 ? ? // #define EV_LED 0x11 ? ? //LED #define EV_SND 0x12 ? ? //聲音 #define EV_REP 0x14 ? ? //Repeat #define EV_FF 0x15 ? ? //力反饋 #define EV_PWR 0x16 ? ? //電源 #define EV_FF_STATUS 0x17 ? ? //狀態(tài) #define EV_MAX 0x1f #define EV_CNT (EV_MAX+1)
以鼠標(biāo)為例,涉及鼠標(biāo)的事件讀取/控制相關(guān)的code有:
/* * Relative axes */ //在這里,我們暫時(shí)只會(huì)用來(lái)REL_X和REL_Y這兩個(gè)參數(shù) #define REL_X 0x00 ? //相對(duì)X坐標(biāo) #define REL_Y 0x01 ? //相對(duì)Y坐標(biāo) #define REL_Z 0x02 ? //相對(duì)Z坐標(biāo) #define REL_RX 0x03 #define REL_RY 0x04 #define REL_RZ 0x05 #define REL_HWHEEL 0x06 #define REL_DIAL 0x07 #define REL_WHEEL 0x08 #define REL_MISC 0x09 #define REL_MAX 0x0f #define REL_CNT (REL_MAX+1)
最后value,就是選擇具體的type、具體的code以后所反應(yīng)出來(lái)的值,鼠標(biāo)就是相對(duì)于當(dāng)前X或者相對(duì)于當(dāng)前Y的值。
接下來(lái),我們來(lái)看一下如何來(lái)讀取鼠標(biāo)事件,寫(xiě)一段代碼測(cè)試一下:
#include <stdio.h> #include <linux/input.h> #include <unistd.h> #include <stdlib.h> #include <fcntl.h> /* struct input_event { ? ? ? ?struct timeval time; ? ? ? ?__u16 type; ? ? ? ?__u16 code; ? ? ? ?__s32 value; }; */ /* Event types #define EV_SYN ? ? ? ? ? ? ? ? 0x00 #define EV_KEY ? ? ? ? ? ? ? ? 0x01 #define EV_REL ? ? ? ? ? ? ? ? 0x02 #define EV_ABS ? ? ? ? ? ? ? ? 0x03 */ /* Relative axes #define REL_X ? ? ? ? ? ? ? ? ? 0x00 #define REL_Y ? ? ? ? ? ? ? ? ? 0x01 #define REL_Z ? ? ? ? ? ? ? ? ? 0x02 #define REL_RX ? ? ? ? ? ? ? ? 0x03 #define REL_RY ? ? ? ? ? ? ? ? 0x04 #define REL_RZ ? ? ? ? ? ? ? ? 0x05 #define REL_HWHEEL ? ? ? ? ? ? 0x06 #define REL_DIAL ? ? ? ? ? ? ? 0x07 #define REL_WHEEL ? ? ? ? ? ? ? 0x08 #define REL_MISC ? ? ? ? ? ? ? 0x09 #define REL_MAX ? ? ? ? ? ? ? ? 0x0f #define REL_CNT ? ? ? ? ? ? ? ? (REL_MAX+1) */ //event8 mouse //event9 keyboard int main(void) { //1、定義一個(gè)結(jié)構(gòu)體變量用來(lái)描述input事件 struct input_event event_mouse ; //2、打開(kāi)input設(shè)備的事件節(jié)點(diǎn) 我的電腦鼠標(biāo)事件的節(jié)點(diǎn)是event3 int fd = open("/dev/input/event3",O_RDWR); int value ; int type ; int buffer[10]={0}; if(-1 == fd){ printf("open mouse event fair!n"); return -1 ; } while(1){ //3、讀事件 read(fd ,&event_mouse ,sizeof(event_mouse)); //4、判斷事件類型,并打印鍵碼 switch(event_mouse.type){ case EV_SYN: ? ? printf("sync!n"); ? ? break ; case EV_REL: //鼠標(biāo)事件,XY相對(duì)位移 //code表示相對(duì)位移X或者Y,當(dāng)判斷是X時(shí),打印X的相對(duì)位移value //當(dāng)判斷是Y時(shí),打印Y的相對(duì)位移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); } if(event_mouse.code == REL_Y){ ? ? printf("event_mouse.code_Y:%dn",event_mouse.code); ? ? printf("event_mouse.value_Y:%dn",event_mouse.value); } defalut: break ; } } return 0 ; }
附:在Linux系統(tǒng)下通過(guò)如下命令可以看到所有的input設(shè)備
cat /proc/bus/input/devices
I: Bus=0000 Vendor=0000 Product=0000 Version=0000 N: Name="qpnp_pon" P: Phys=qpnp_pon/input0 S: Sysfs=/devices/platform/soc/c440000.qcom,spmi/spmi-0/spmi0-00/c440000.qcom,spmi:qcom,pm8150@0:qcom,power-on@800/input/input0 U: Uniq= H: Handlers=event0 cpufreq B: PROP=0 B: EV=3
B: KEY=600000000000000 0 14000000000000 0
............
I: Bus=0018 Vendor=0000 Product=0000 Version=0000
N: Name="light"
P: Phys=
S: Sysfs=/devices/virtual/input/input3
U: Uniq=
H: Handlers=event3
B: PROP=0
B: EV=5
B: REL=3
......
I: Bus=0019 Vendor=0001 Product=0001 Version=0100
N: Name="gpio-keys"
P: Phys=gpio-keys/input0
S: Sysfs=/devices/platform/soc/soc:gpio_keys/input/input6
U: Uniq=
H: Handlers=event6 cpufreq
B: PROP=0
B: EV=3
B: KEY=8000000000000 0
下期見(jiàn)~