哈嘍,大家好,我是LittleG。
如果將 Linux 比作一個人,那么Linux input子系統(tǒng)就好比我們的眼睛,手,腳,以及到大腦的神經(jīng)網(wǎng)絡(luò),可以通過它們獲取和傳遞信息,感知外圍世界?;氐?Linux/Android 世界,像手機設(shè)備中,按鍵、觸摸屏、各種sensor,數(shù)據(jù)流一般也是走的input子系統(tǒng)上報給上層的,所以學(xué)習(xí)和理解input子系統(tǒng)很重要。
正文
#include <linux/input.h>
在這個文件中,我們可以找到這個結(jié)構(gòu)體:
描述一個輸入事件 /* * The event structure itself */ struct input_event { struct timeval time; __u16 type; __u16 code; __s32 value; };
先來解讀下這個結(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ù),tv_usec為微秒數(shù),即秒后面的零頭。
【type】
域顯示了被報告事件的類型,例如,一個 key press或者 button press, relative motion(比如移動鼠標(biāo) ) 或者 absolute motion(比如移動游戲桿 ); 常用的事件類型 type
有 EV_KEY , EV_REL , EV_ABS , EV_SYN ;分別對應(yīng)keyboard事件,相對事件,絕對事件,同步事件;EV_SYN 則表示一組完整事件已經(jīng)完成,需要處理;
【code】
域根據(jù)type
的不同而含義不同,上報是哪一個key或者哪一個坐標(biāo)軸在被操作; 例如,type
為 EV_KEY 時,code表示鍵盤code或者鼠標(biāo)Button值;type
為 EV_REL 時,code表示操作的是哪個坐標(biāo)軸,如:REL_X,REL_Y (因為鼠標(biāo)有x,y兩個軸向,所以一次鼠標(biāo)移動,會產(chǎn)生兩個input_event);type
為 EV_ABS 時,code表示絕對坐標(biāo)軸向。
【value】
域也是根據(jù)type
的不同而含義不同,上報現(xiàn)在的狀態(tài)或者運動情況是什么。例如:type
為EV_KEY時,value:0表示按鍵抬起,1表示按鍵按下;(4表示持續(xù)按下等?)type
為EV_REL時,value: 表明移動的值和方向(正負(fù)值);type
為EV_ABS時,value: 表示絕對位置;
那么,最主要的事件有以下三種:相對事件(鼠標(biāo)),絕對事件(觸摸屏),鍵盤事件。
例如:
我們說鼠標(biāo),我們在移動鼠標(biāo)的時候鼠標(biāo)就是一個相對事件,所以type的類型也就是底層上報給用戶的事件為相對事件類型,那么code表示的就是相對于鼠標(biāo)當(dāng)前的位置的X或者Y的坐標(biāo),value也就是相對于當(dāng)前的位置偏移多少。
事件類型(type)在 input.h 主要有以下:
/* * Event types */ #define EV_SYN 0x00 ? ? //同步事件,就是將結(jié)果上報給系統(tǒng)的過程 #define EV_KEY 0x01 ? ? //按鍵事件,如 KEY_VOLUMEDOWN 事件 #define EV_REL 0x02 ? ? //相對事件, 如鼠標(biāo)上報的坐標(biāo) #define EV_ABS 0x03 ? ? //絕對事件,如觸摸屏上報的坐標(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 */ //在這里,我們暫時只會用來REL_X和REL_Y這兩個參數(shù) #define REL_X 0x00 ? //相對X坐標(biāo) #define REL_Y 0x01 ? //相對Y坐標(biāo) #define REL_Z 0x02 ? //相對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)出來的值,鼠標(biāo)就是相對于當(dāng)前X或者相對于當(dāng)前Y的值。
接下來,我們來看一下如何來讀取鼠標(biāo)事件,寫一段代碼測試一下:
#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、定義一個結(jié)構(gòu)體變量用來描述input事件 struct input_event event_mouse ; //2、打開input設(shè)備的事件節(jié)點 我的電腦鼠標(biāo)事件的節(jié)點是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相對位移 //code表示相對位移X或者Y,當(dāng)判斷是X時,打印X的相對位移value //當(dāng)判斷是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); } 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)下通過如下命令可以看到所有的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
下期見~