當(dāng)前位置:首頁 > 公眾號精選 > 嵌入式云IOT技術(shù)圈
[導(dǎo)讀]什么是input子系統(tǒng)?不管是什么操作系統(tǒng),都有一個程序是用于管理各種輸入設(shè)備的,打個比方,生活中使用的電腦鍵盤、鼠標(biāo)就是輸入設(shè)備,小到日常生活中無可避免的智能手機,智能手機上的觸摸屏,按鍵也是輸入設(shè)備。那么操作系統(tǒng)是怎么管理這些輸入設(shè)備的呢?這里還是以最常用的操作系統(tǒng)Linux來進行講解。



微信公眾號:morixinguan
關(guān)注可了解更多的教程。問題或建議,請公眾號留言;
如果你覺得本文對你有幫助,歡迎贊賞


▲長按圖片保存可分享至朋友圈


么是input子系統(tǒng)?不管是什么操作系統(tǒng),都有一個程序是用于管理各種輸入設(shè)備的,打個比方,生活中使用的電腦鍵盤、鼠標(biāo)就是輸入設(shè)備,小到日常生活中無可避免的智能手機,智能手機上的觸摸屏,按鍵也是輸入設(shè)備。那么操作系統(tǒng)是怎么管理這些輸入設(shè)備的呢?這里還是以最常用的操作系統(tǒng)Linux來進行講解。

Linux內(nèi)核中,有非常多的子系統(tǒng),用于管理很多設(shè)備,比如顯示系統(tǒng),輸入子系統(tǒng),音頻子系統(tǒng),電源管理子系統(tǒng),時鐘管理子系統(tǒng)等等,本節(jié)我們重點關(guān)注Linux下的輸入子系統(tǒng)。輸入子系統(tǒng)是 Linux內(nèi)核用于管理各種輸入設(shè)備 (鍵盤,鼠標(biāo),遙控桿,書寫板等等 )的部分,用戶通過輸入子系統(tǒng)進行內(nèi)核,命令行,圖形接口之間的交換。

輸入子系統(tǒng)在內(nèi)核里實現(xiàn),因為設(shè)備經(jīng)常要通過特定的硬件接口被訪問 (例如串口, ps/2usb等等 ),這些硬件接口由內(nèi)核保護和管理。內(nèi)核給用戶導(dǎo)出一套固定的硬件無關(guān)的 input API,供用戶空間程序使用。

在Linux的輸入子系統(tǒng)中,分三塊進行管理,分別是: input core(輸入系統(tǒng)核心層), drivers(輸入系統(tǒng)驅(qū)動層) event handlers(輸入系統(tǒng)事件層),如此說來感覺太抽象,我們來看圖4-5-9就清楚了。

先從應(yīng)用程序的角度來認識下input子系統(tǒng),在此可以從以下這個文件可以看到對應(yīng)的設(shè)備。打開Linux終端,然后輸入cat ?/proc/bus/input/devices可以看到類似以下的內(nèi)容。

1I:?Bus=0003?Vendor=046d?Product=c018?Version=0111 2N:?Name="?USB?Optical?Mouse" 3P:?Phys=usb-0000:00:1d.1-2/input0 4S:?Sysfs=/class/input/input24 5U:?Uniq= 6H:?Handlers=mouse1?event2 7B:?EV=7 8B:?KEY=70000?0?0?0?0?0?0?0?0 9B:?REL=103 

這些devices主要是用來描述注冊在input子系統(tǒng)的一些設(shè)備文件,可能有鼠標(biāo),鍵盤,觸摸屏,重力傳感器,溫度傳感器等等的設(shè)備,寫驅(qū)動的時候,通過內(nèi)核提供的input設(shè)備注冊設(shè)備相關(guān)的接口后,這些信息都會保存到對應(yīng)的文件里去。

那我們?nèi)绾蝸砻枋鲞@樣的一個設(shè)備呢?Linux系統(tǒng)為我們提供了這個輸入系統(tǒng)操作相關(guān)的頭文件:#include

在這個文件中,我們可以找到這個結(jié)構(gòu)體:

1//用于描述一個輸入事件 2struct input_event { 3 struct timeval time; 4 __u16?type; 5 __u16?code; 6 __s32?value; 7};

在這其中,我們看到input_event這個結(jié)構(gòu)體中還有一個結(jié)構(gòu)體描述:struct timeval time;

先來解讀下這個結(jié)構(gòu)體的含義:

struct timeval結(jié)構(gòu)體在time.h中的定義如下

1struct timeval 2{ 3__time_t tv_sec; /*?Seconds.?*/ 4__suseconds_t tv_usec; /*Microseconds.?*/ 5};

其中,tv_secEpoch到創(chuàng)建struct timeval時的秒數(shù),tv_usec為微秒數(shù),即秒后面的零頭。type域顯示了被報告事件的類型,例如,一個 key press或者 button press, relative motion(比如移動鼠標(biāo) )或者 absolute motion(比如移動游戲桿 ); code域告訴你是哪一個key或者坐標(biāo)軸在被操作; value域告訴你現(xiàn)在的狀態(tài)或者運動情況是什么。

那么,最主要的事件有以下三種:相對事件(例如鼠標(biāo)),絕對事件(例如觸摸屏),鍵盤事件。

例如:我們說說鼠標(biāo),我們在移動鼠標(biāo)的時候鼠標(biāo)就是一個相對事件,所以type的類型也就是底層上報給用戶的事件為相對事件類型,那么code表示的就是相對于鼠標(biāo)當(dāng)前的位置的X或者Y的坐標(biāo),value也就是相對于當(dāng)前的位置偏移多少。

事件類型(type)input.h主要有以下:

 1/*  2 *?Event?types  3 */  4#define EV_SYN????????????0x00 //同步事件,就是將結(jié)果上報給系統(tǒng)的過程  5#define EV_KEY????????????0x01 //按鍵事件  6#define EV_REL????????????0x02 //相對事件  7#define EV_ABS????????????0x03 //絕對事件  8本節(jié),我們來實現(xiàn)一個input控制鼠標(biāo)的應(yīng)用程序。所以還會用到以下事件:  9/* 10 *?Relative?axes 11 */ 12//在這里,我們暫時只會用REL_X和REL_Y這兩個參數(shù) 13#define REL_X????????????0x00 //相對X坐標(biāo) 14#define REL_Y????????????0x01 //相對Y坐標(biāo) 

那么value,就是選擇具體的type,具體的code以后所反應(yīng)出來的值,鼠標(biāo)就是相對于當(dāng)前X或者相對于當(dāng)前Y的值。

我們可以使用cat命令來測試當(dāng)前的鼠標(biāo)事件到底屬于哪一個事件節(jié)點,如圖4-5-10所示:

只需切換到/dev/input下,找到對應(yīng)的事件節(jié)點,然后使用cat eventx(事件節(jié)點),然后移動鼠標(biāo)就可以看到數(shù)據(jù)打印啦,但是這些數(shù)據(jù)我們顯然是看不懂的,但我們可以使用一個測試程序?qū)⑹髽?biāo)的值讀出來。

接下來,我們來看一下如何來讀取鼠標(biāo)事件,寫一段代碼測試一下: mouse.c

 1#include   2#include   3#include   4#include   5#include   6/*  7struct?input_event?{  8 struct?timeval?time;  9 __u16?type; 10 __u16?code; 11 __s32?value; 12}; 13*/ 14/* 15Event?types 16#define?EV_SYN??????????????????0x00 17#define?EV_KEY??????????????????0x01 18#define?EV_REL??????????????????0x02 19#define?EV_ABS??????????????????0x03 20*/ 21/* 22 Relative?axes 23#define?REL_X???????????????????0x00 24#define?REL_Y???????????????????0x01 25#define?REL_Z???????????????????0x02 26#define?REL_MAX?????????????????0x0f 27#define?REL_CNT?????????????????(REL_MAX+1) 28*/ 29//event8??mouse 30//event9??keyboard 31int main(void) 32{ 33 //1、定義一個結(jié)構(gòu)體變量用來描述input事件 34 struct input_event event_mouse ; 35 //2、打開input設(shè)備的事件節(jié)點我的電腦對應(yīng)的鼠標(biāo)事件的節(jié)點是event3 36//讀者的電腦的設(shè)備節(jié)點可能和我的不一樣,可以使用cat命令去獲取,然后 37//不斷嘗試 38 int fd?=?open("/dev/input/event4",O_RDWR); 39 int value?; 40 int type?; 41 int buffer[10]={0}; 42 if(-1 ==?fd){ 43 printf("open?mouse?event?fair!\n"); 44 return -1 ; 45 } 46 while(1){ 47 //3、讀事件 48 read(fd?,&event_mouse?,sizeof(event_mouse)); 49 //4、判斷事件類型,并打印鍵碼 50 switch(event_mouse.type){ 51 //同步事件 52 case EV_SYN: 53 printf("sync!\n"); 54 break ; 55 case EV_REL: 56 //鼠標(biāo)事件,XY相對位移 57 //code表示相對位移X或者Y,當(dāng)判斷是X時,打印X的相對位移value 58 //當(dāng)判斷是Y時,打印Y的相對位移value 59 if(event_mouse.code?==?REL_X){ 60 printf("event_mouse.code_X:%d\n",event_mouse.code); 61 printf("event_mouse.value_X:%d\n",event_mouse.value); 62 } 63 if(event_mouse.code?==?REL_Y){ 64 printf("event_mouse.code_Y:%d\n",event_mouse.code); 65 printf("event_mouse.value_Y:%d\n",event_mouse.value); 66 } 67 defalut: 68 break ; 69 } 70 } 71 return 0 ; 72}

運行結(jié)果,如圖4-5-11所示。

當(dāng)我們不斷移動鼠標(biāo)的時候,這些值將會被打印出來。

請思考一個問題,既然我們移動鼠標(biāo)能夠打印數(shù)值,我們能不能夠?qū)懸粋€程序控制鼠標(biāo)自動移動呢?那肯定是可以的,下面我們就讓鼠標(biāo)自己來畫一個正方形,上代碼:

 1#include   2#include   3#include   4#include   5#include   6  7//event8??mouse  8//event9??keyboard  9int main(void) 10{ 11 //1、定義一個結(jié)構(gòu)體變量用來描述input事件 12 struct input_event event_mouse ; 13 //2、打開input設(shè)備的事件節(jié)點??我的電腦鼠標(biāo)事件的節(jié)點是event3 14 int fd?=?open("/dev/input/event3",O_RDWR); 15 int value?; 16 int type?; 17 int i?; 18 int buffer[10]={0}; 19 if(-1 ==?fd){ 20 printf("open?mouse?event?fair!\n"); 21 return -1 ; 22 } 23 while(1){ 24 //3、寫事件 25 for(i?= 0 ;?i?< 20 ;?i++){ 26 event_mouse.type?=?EV_REL?; 27 event_mouse.code?=?REL_X?; 28 event_mouse.value?=?i?; 29 write(fd,&event_mouse,sizeof(event_mouse)); 30 event_mouse.code?= 0 ; 31 event_mouse.value?= 0; 32 event_mouse.type?=?EV_SYN?; 33 write(fd,&event_mouse,sizeof(event_mouse)); 34 usleep(50000); 35 } 36 for(i?= 0 ;?i?< 20 ;?i++){ 37 event_mouse.type?=?EV_REL?; 38 event_mouse.code?=?REL_Y?; 39 event_mouse.value?=?i?; 40 write(fd,&event_mouse,sizeof(event_mouse)); 41 event_mouse.code?= 0 ; 42 event_mouse.value?= 0 ; 43 event_mouse.type?=?EV_SYN?; 44 write(fd,&event_mouse,sizeof(event_mouse)); 45 usleep(50000); 46 } 47 for(i?= 0 ;?i?> -20 ;?i--){ 48 event_mouse.type?=?EV_REL?; 49 event_mouse.code?=?REL_X?; 50 event_mouse.value?=?i?; 51 write(fd,&event_mouse,sizeof(event_mouse)); 52 event_mouse.code?= 0 ; 53 event_mouse.value?= 0; 54 event_mouse.type?=?EV_SYN?; 55 write(fd,&event_mouse,sizeof(event_mouse)); 56 usleep(50000); 57 } 58 for(i?= 0 ;?i?> -20 ;?i--){ 59 event_mouse.type?=?EV_REL?; 60 event_mouse.code?=?REL_Y?; 61 event_mouse.value?=?i?; 62 write(fd,&event_mouse,sizeof(event_mouse)); 63 event_mouse.code?= 0 ; 64 event_mouse.value?= 0 ; 65 event_mouse.type?=?EV_SYN?; 66 write(fd,&event_mouse,sizeof(event_mouse)); 67 usleep(50000); 68 } 69 70 } 71 return 0 ; 72}

執(zhí)行效果讀者自行驗證!

接下來我們再寫一個案例,在Tiny4412平臺上獲取電容屏的坐標(biāo)值。

觸摸屏上報坐標(biāo)值的事件屬于絕對事件,也就是,觸摸的坐標(biāo)點X和Y會在屏幕的分辨率范圍內(nèi)上報一個絕對的坐標(biāo)(X,Y)。

那么上報對于的類型(type)如下:EV_ABS

對于的code如下:

絕對于X:

ABS_MT_POSITION_X

絕對于Y:

ABS_MT_POSITION_Y

我用了一個程序獲取了屏幕的分辨率,得知分辨率寬為480,高為800。

首先,寫這個程序時,我通過adb進到Android根目錄,然后用getevent -p查到觸摸屏的事件節(jié)點為event0,同時也知道觸摸屏是一個絕對事件,如下:

接下來,我在Android5.0的源代碼external目錄下創(chuàng)建了如下目錄:Getft5x0x_Test

該目錄下有如下兩個文件文件:

Android.mk???? Get_ft5x0x_tp.c

(1)先看Android.mk

 1LOCAL_PATH?:= $(call my-dir)  2include $(CLEAR_VARS)  3LOCAL_MODULE_TAGS?:=?eng  4LOCAL_SHARED_LIBRARIES?+=?libcutils?libutils  5#LOCAL_STATIC_LIBRARIES?+=?libz?libstdc++?libpng?libvtpng  6LOCAL_STATIC_LIBRARIES?+=?libz?libstdc++?libpng  7  8LOCAL_SRC_FILES?:=?Get_ft5x0x_tp.c  9LOCAL_MODULE?:=?ft5x0x_tp 10include $(BUILD_EXECUTABLE) 

(2)Get_ft5x0x_tp.c

 1#include   2#include   3#include   4#include   5#include   6#include   7#include   8#include   9#include  10#include  11#include  12#include  13#include  14#include  15#include  16#include  17//ft5x0x_ts觸摸屏事件初始化 18int touch_fd?= -1 ; 19int ft5x0x_ts__init(void) 20{ 21 touch_fd?=?open("/dev/input/event0",?O_RDONLY); 22 if (touch_fd?< 0) 23 { 24 printf("open?/dev/input/event0?failed\n"); 25 return -1; 26 } 27 return 0; 28} 29 30//獲取ft5x0x_ts觸摸屏上的坐標(biāo)點 31int Get_ft5x0x_ts_postion(int *x, int *y) 32{ 33 int touch_ret?= -1 ; 34 //1、定義一個結(jié)構(gòu)體變量用來描述ft5x0x觸摸屏事件  35 struct input_event ft5x0x_ts ; 36 37 //2、讀事件  38 touch_ret?=?read(touch_fd?,&ft5x0x_ts?,sizeof(ft5x0x_ts)); 39 if(touch_ret?< 0){ 40 printf("read?touch?fair!\n"); 41 } 42 //3、判斷事件類型 43 switch(ft5x0x_ts.type) 44 { 45 case EV_SYN: 46 break ; 47 case EV_ABS: 48 if(ft5x0x_ts.code?==?ABS_MT_POSITION_X){ 49 *x?=?ft5x0x_ts.value?; 50 } 51 if(ft5x0x_ts.code?==?ABS_MT_POSITION_Y){ 52 *y?=?ft5x0x_ts.value?; 53 } 54 defalut: 55 break ; 56 } 57 return 0; 58} 59 60 61int main(int argc, char **argv) 62{ 63 int tp_ret?; 64 int ft5x0x_x?= 0; 65 int ft5x0x_y?= 0; 66 tp_ret?=?ft5x0x_ts__init(); 67 if(-1 ==?tp_ret){ 68 printf("tp?init?fair!\n"); 69 return -1 ; 70 } 71 printf("tp?init?success!\n"); 72 while(1) 73 { //獲取屏幕上的絕對坐標(biāo)點 74 Get_ft5x0x_ts_postion(&ft5x0x_x,&ft5x0x_y); 75 printf("ft5x0x_x:%d?????ft5x0x_y:%d\n",ft5x0x_x,ft5x0x_y); 76 usleep(100); 77 } 78 return 0; 79}

編寫萬makefile還有.c程序后:

我們切換到Android的根目錄下:

用以下命令編譯這個程序:

使用m,mm,mmm命令之前一定要先:

執(zhí)行:source和lunch這兩個步驟,如下:

 1root@morixinguan:/work/android-5.0.2#?source?build/envsetup.sh   2including?device/samsung/manta/vendorsetup.sh  3including?device/moto/shamu/vendorsetup.sh  4including?device/friendly-arm/tiny4412/vendorsetup.sh  5including?device/generic/mini-emulator-x86_64/vendorsetup.sh  6including?device/generic/mini-emulator-armv7-a-neon/vendorsetup.sh  7including?device/generic/mini-emulator-mips/vendorsetup.sh  8including?device/generic/mini-emulator-arm64/vendorsetup.sh  9including?device/generic/mini-emulator-x86/vendorsetup.sh 10including?device/asus/deb/vendorsetup.sh 11including?device/asus/fugu/vendorsetup.sh 12including?device/asus/grouper/vendorsetup.sh 13including?device/asus/tilapia/vendorsetup.sh 14including?device/asus/flo/vendorsetup.sh 15including?device/lge/hammerhead/vendorsetup.sh 16including?device/lge/mako/vendorsetup.sh 17including?sdk/bash_completion/adb.bash 18root@morixinguan:/work/android-5.0.2#?lunch  19 20You're?building?on?Linux 21 22Lunch?menu...?pick?a?combo: 23 1.?aosp_arm-eng 24 2.?aosp_arm64-eng 25 3.?aosp_mips-eng 26 4.?aosp_mips64-eng 27 5.?aosp_x86-eng 28 6.?aosp_x86_64-eng 29 7.?aosp_manta-userdebug 30 8.?aosp_shamu-userdebug 31 9.?full_tiny4412-userdebug 32 10.?full_tiny4412-eng 33 11.?mini_emulator_x86_64-userdebug 34 12.?m_e_arm-userdebug 35 13.?mini_emulator_mips-userdebug 36 14.?mini_emulator_arm64-userdebug 37 15.?mini_emulator_x86-userdebug 38 16.?aosp_deb-userdebug 39 17.?full_fugu-userdebug 40 18.?aosp_fugu-userdebug 41 19.?aosp_grouper-userdebug 42 20.?aosp_tilapia-userdebug 43 21.?aosp_flo-userdebug 44 22.?aosp_hammerhead-userdebug 45 23.?aosp_mako-userdebug 46 47Which?would?you?like??[aosp_arm-eng]?20 48 49============================================ 50PLATFORM_VERSION_CODENAME=REL 51PLATFORM_VERSION=5.0.2 52TARGET_PRODUCT=aosp_tilapia 53TARGET_BUILD_VARIANT=userdebug 54TARGET_BUILD_TYPE=release 55TARGET_BUILD_APPS= 56TARGET_ARCH=arm 57TARGET_ARCH_VARIANT=armv7-a-neon 58TARGET_CPU_VARIANT=cortex-a9 59TARGET_2ND_ARCH= 60TARGET_2ND_ARCH_VARIANT= 61TARGET_2ND_CPU_VARIANT= 62HOST_ARCH=x86_64 63HOST_OS=linux 64HOST_OS_EXTRA=Linux-4.8.0-46-generic-x86_64-with-Ubuntu-16.04-xenial 65HOST_BUILD_TYPE=release 66BUILD_ID=LRX22G 67OUT_DIR=out 68============================================ 69 70root@morixinguan:/work/android-5.0.2#  

接下來,編譯程序:

mmm external/Getft5x0x_Test/

然后我們看到以下顯示:

這個二進制生成的絕對路徑是在out目錄下,我們需要ft5x0x_tp這個文件,這個名字就是上面Android.mk里面對應(yīng)的:

LOCAL_MODULE := ft5x0x_tp

Install: out/target/product/tiny4412/system/bin/ft5x0x_tp

將這個文件拷貝到當(dāng)前目錄下:

cp out/target/product/tiny4412/system/bin/ft5x0x_tp .

然后,用USB線連接你的開發(fā)板,然后用adb命令將ft5x0x_tp ?push到system/bin/目錄下,這個目錄是Android的根文件系統(tǒng)下的一個命令,很多命令都在這個目錄下。

如果沒有安裝adb,可以apt-get install adb 安裝adb


adb push完畢以后:

我們在終端: adb shell切換到根目錄下:

執(zhí)行ft5x0x_tp這個bin文件,然后我們觸摸觸摸屏,如下,坐標(biāo)值打印出來了。


長期商務(wù)合作服務(wù):




免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺僅提供信息存儲服務(wù)。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!

本站聲明: 本文章由作者或相關(guān)機構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
關(guān)閉
關(guān)閉