android6.0按键处理浅析
?
?
處理流程及示意圖:
1,硬件配置:
kernel-3.18\arch\arm\boot\dts\projectxxx.dts
&keypad {
???????? mediatek,kpd-key-debounce= <1024>;
???????? mediatek,kpd-sw-pwrkey= <116>;
???????? mediatek,kpd-hw-pwrkey= <8>;
???????? mediatek,kpd-use-extend-type= <0>;
???????? /*HWKeycode [0~71] -> Linux Keycode*/
???????? mediatek,kpd-hw-map-num= <72>;
// kpd-hw-init-map為硬件掃描的矩陣列表。跟具體硬件接法相關。即為linux_code
???????? mediatek,kpd-hw-init-map= <115 114 0 0 0 0 0 0 0 158 0 0 0 0 0 0 0 0 0 0 0 0 0 0
???????????????????????????????????? 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
???????????????????????????????????? 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 >;
???????? mediatek,kpd-pwrkey-eint-gpio= <0>;
???????? mediatek,kpd-pwkey-gpio-din? = <0>;
???????? mediatek,kpd-hw-dl-key0= <0>;
???????? mediatek,kpd-hw-dl-key1= <1>;
???????? mediatek,kpd-hw-dl-key2= <8>;
???????? mediatek,kpd-hw-recovery-key= <0>;
???????? mediatek,kpd-hw-factory-key? = <1>;
???????? status= "okay";
};
?
硬件接法,軟件注意各個IO的功能配置,以確保按鍵掃描時獲取到正確的值。
2,kernel驅動:
按下按鍵后,會出發中斷,然后進去中斷處理程序中進行按鍵的掃描:
?
static void kpd_keymap_handler(unsignedlong data)
{
???????? inti, j;
???????? boolpressed;
???????? u16new_state[KPD_NUM_MEMS], change, mask;
???????? u16hw_keycode, linux_keycode;
?
???????? kpd_get_keymap_state(new_state);
?
???????? wake_lock_timeout(&kpd_suspend_lock,HZ / 2);
?
???????? for(i = 0; i < KPD_NUM_MEMS; i++) {
?????????????????? change= new_state[i] ^ kpd_keymap_state[i];
?????????????????? if(!change)
??????????????????????????? continue;
?
?????????????????? for(j = 0; j < 16; j++) {
??????????????????????????? mask= 1U << j;
??????????????????????????? if(!(change & mask))
???????????????????????????????????? continue;
?
??????????????????????????? hw_keycode = (i << 4) + j;//獲取到硬件掃描的HW_code值,這個與硬件接法相關。
??????????????????????????? /*bit is 1: not pressed, 0: pressed */
??????????????????????????? pressed= !(new_state[i] & mask);
??????????????????????????? if(kpd_show_hw_keycode)
???????????????????????????????????? kpd_print("(%s)HW keycode = %u\n", pressed ? "pressed" : "released",hw_keycode);
??????????????????????????? BUG_ON(hw_keycode>= KPD_NUM_KEYS);
??????????????????????????? linux_keycode = kpd_keymap[hw_keycode];//根據對應的hw_coed,按照dts中的對應,映射獲取到linux_code.
??????????????????????????? if(unlikely(linux_keycode == 0)) {
???????????????????????????????????? kpd_print("Linuxkeycode = 0\n");
???????????????????????????????????? continue;
??????????????????????????? }
??????????????????????????? kpd_aee_handler(linux_keycode,pressed);
?
??????????????????????????? input_report_key(kpd_input_dev, linux_keycode, pressed);//通過INPUT發送linux_code的input subsystem。
??????????????????????????? input_sync(kpd_input_dev);
??????????????????????????? kpd_print("reportLinux keycode = %u\n", linux_keycode);
?????????????????? }
???????? }
?
???????? memcpy(kpd_keymap_state,new_state, sizeof(new_state));
???????? kpd_print("savenew keymap state\n");
???????? enable_irq(kp_irqnr);
}
3,input 子系統對按鍵的處理:
具體請參照:input子系統按鍵處理
?adb可以參看proc/bus/input下面的devices和handler。
?
Devices的key:
I: Bus=0019 Vendor=2454 Product=6500Version=0010
N: Name="mtk-kpd"
P: Phys=
S:Sysfs=/devices/soc/10011000.keypad/input/input1
U: Uniq=
H: Handlers=event1
B: PROP=0
B: EV=3
B: KEY=40000000 1c0000 0 0 0
?
Hander:
N: Number=0 Name=sysrq (filter)
N: Number=1 Name=evdev Minor=64//這個是我們所用到的
?
?主要是對下面三個結構體進行配置:
Device: input的核心層,主要文件input.c,建立設備節點,對驅動層提供統一的接口。如主要的input_report_key() 就是他提供的。作用我覺得主要是對下形成對硬件,驅動進行接口的統一,對上次配合事件層提供相應的匹配接口。
Handler:event事件層,主要文件evdev.c。主要作用是用戶核心層的device相匹配,匹配成功后,然后新建handle。產生事件的節點。并且對上提供讀寫相關的接口。供上層獲取或者寫入相應的鍵值。evdev_read,evdev_write;到這里應該是kernel層的任務就完成了。
Handle:通過handler->connect(),將device與handler匹配連接起來。主要是匹配id。個人覺得只是形成一個簡單的綜合體,方便對匹配成功的device和handler的訪問。
?
static ssize_t evdev_read(struct file*file, char __user *buffer,
??????????????????????????? ? size_t count, loff_t *ppos)
{
???????? structevdev_client *client = file->private_data;
???????? structevdev *evdev = client->evdev;
???????? structinput_event event;
???????? size_tread = 0;
???????? interror;
?
???????? if(count != 0 && count < input_event_size())
?????????????????? return-EINVAL;
?
???????? for(;;) {
?????????????????? if(!evdev->exist || client->revoked)
??????????????????????????? return-ENODEV;
?
?????????????????? if(client->packet_head == client->tail &&
?????????????????? ??? (file->f_flags & O_NONBLOCK))
??????????????????????????? return-EAGAIN;
?
?????????????????? /*
?????????????????? ?* count == 0 is special - no IO is done but wecheck
?????????????????? ?* for error conditions (see above).
?????????????????? ?*/
?????????????????? if(count == 0)
??????????????????????????? break;
?
?????????????????? while(read + input_event_size() <= count &&
?????????????????? ?????? evdev_fetch_next_event(client,&event)) {
?
??????????????????????????? if(input_event_to_user(buffer + read, &event))//將獲取到的event信息反饋到用戶層
???????????????????????????????????? return-EFAULT;
?
??????????????????????????? read+= input_event_size();
?????????????????? }
?
?????????????????? if(read)
??????????????????????????? break;
?
?????????????????? if(!(file->f_flags & O_NONBLOCK)) {
??????????????????????????? error= wait_event_interruptible(evdev->wait,
?????????????????????????????????????????????? client->packet_head!= client->tail ||
?????????????????????????????????????????????? !evdev->exist|| client->revoked);
??????????????????????????? if(error)
???????????????????????????????????? returnerror;
?????????????????? }
???????? }
?
???????? returnread;
}
4,inputmanager對按鍵事件的獲取和向上派發:
參照文檔:inputmanager對按鍵事件的獲取和向上派發
說明:
調試的時候,可以用adb來進行調試。Input keyevent? 26//power key
先大致介紹一下整個流程,再做重點分析。輸入事件流程一共涉及到下面這幾個文件:
/frameworks/base/services/Java/com/Android/server/WindowManagerService.java
/frameworks/base/services/java/com/android/server/InputManager.java
/frameworks/base/services/jni/com_android_server_InputManager.cpp
/frameworks/base/libs/ui/InputReader.cpp
/frameworks/base/libs/ui/InputDispatcher.cpp
/frameworks/base/libs/ui/EventHub.cpp
其中,WindowManagerService.java和InputManager.java主要向Android為窗口系統提供服務,EventHub.cpp主要用來讀取設備文件中的RawEvent,而InputReader.cpp和InputDispatcher.cpp算是它們之間的對接層。
?
它們的關系是:WindowManagerService通過InputManager提供的接口開啟一個線程驅動InputReader不斷地從/dev/input/目錄下面的設備文件讀取事件,然后通過InputDispatcher分發給連接到WindowManagerService服務的客戶端。
InputReader從設備文件中讀取的是RawEvent,在交給InputDispatcher進行分發之前,它需要先把RawEvent進行轉化分類,拆分成KeyEvent、MotionEvent、TrackEvent各種類型等。這篇文章主要關注的就是這個RawEvent的拆分過程,所以我們的重點在EventHub.cpp中。并且,為了簡單化分析過程,在這里我的分析只關注觸摸屏事件。看它是如何從RawEvent被拆分成應用層用戶事件MotionEvent的。
?
?
5,InputDispatcher分發與客戶端的接收:
待分析。
總結
以上是生活随笔為你收集整理的android6.0按键处理浅析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python计算图形面积的方法_Pyth
- 下一篇: 关于GR/IR—业务流程篇