S3C6410 KeyPad驱动(上)
********************************LoongEmbedded********************************
作者:LoongEmbedded(kandi)
時(shí)間:2011.12.19
類(lèi)別:WINCE驅(qū)動(dòng)開(kāi)發(fā)
********************************LoongEmbedded********************************
?
1.? keyboard驅(qū)動(dòng)概述
1.1? 鍵盤(pán)驅(qū)動(dòng)功能概述
Keyboard驅(qū)動(dòng)的主要的功能是從keyboard硬件輸入轉(zhuǎn)換為keyboard事件并且發(fā)送給GWES,根據(jù)這些的keyboard事件產(chǎn)生合適的Unicode字符,keyboard驅(qū)動(dòng)的架構(gòu)圖1所示
圖1 keyboard驅(qū)動(dòng)的架構(gòu)
如圖1所示,Keyboard驅(qū)動(dòng)分為layout manager(布局管理器)、current input language和device layouts(設(shè)備布局),其中WINCE默認(rèn)支持的鍵盤(pán)(設(shè)備)布局有PS/2(Personal System 2)和Matrix(矩陣式)鍵盤(pán)布局,PS/2鍵盤(pán)布局是針對(duì)PS/2 8042-compatible keyboard controller設(shè)計(jì)的,Matrix鍵盤(pán)布局是針對(duì)矩陣式鍵盤(pán)來(lái)設(shè)計(jì)的,比如S3C6410內(nèi)置了keypad接口用于外接矩陣式鍵盤(pán)。這樣的設(shè)計(jì)思想便于開(kāi)發(fā)任何的鍵盤(pán)布局,如果有不同于上面這兩種布局,就需要自己添加了。鍵盤(pán)布局是指特定鍵盤(pán)的按鍵安排(key arrangement),例如包括按鍵數(shù)量和按鍵的配置(比如不同的鍵盤(pán)布局,同一個(gè)按鍵會(huì)對(duì)應(yīng)不同的功能)。一些私有的鍵盤(pán)使用自己的布局,并且很多鍵盤(pán)允許用戶(hù)根據(jù)個(gè)人的偏愛(ài)來(lái)建立按鍵到字符的映射。
?
一些鍵盤(pán)驅(qū)動(dòng)必須處理一些按鍵產(chǎn)生的多個(gè)按鍵(virtual keys,可以理解為虛擬碼),可以不需要像桌面工作機(jī)一樣把所有的物理按鍵都布置在鍵盤(pán)上,這對(duì)于小型硬件平臺(tái)很有用。所以一些按鍵就有多種或、和可以修改的功能。鍵盤(pán)驅(qū)動(dòng)根據(jù)特定物理按鍵和修飾按鍵(modifier key,比如SHIFT和ALT)的狀態(tài)來(lái)產(chǎn)生虛擬按鍵。
?
通常,我們需要把鍵盤(pán)驅(qū)動(dòng)作為一個(gè)分層驅(qū)動(dòng)來(lái)實(shí)現(xiàn),分為上層或是MDD層,這層映射掃描碼成虛擬鍵碼和產(chǎn)生于虛擬鍵碼關(guān)聯(lián)的字符數(shù)據(jù),接著打包鍵盤(pán)消息并放入到系統(tǒng)范圍(system-wide)的消息隊(duì)列中,這樣GWES就可以從消息隊(duì)列中取出并且分發(fā)給相應(yīng)的應(yīng)用程序來(lái)處理和顯示。另一層是低層或是PDD層,負(fù)責(zé)從鍵盤(pán)獲取掃描碼。
?
因?yàn)殒I盤(pán)驅(qū)動(dòng)依賴(lài)于語(yǔ)言,掃描碼映到虛擬鍵碼和虛擬鍵碼到unicode字符的映射都只依賴(lài)于語(yǔ)言的鍵盤(pán)布局,故不同于其他設(shè)備驅(qū)動(dòng)。PFN_KEYBD_DRIVER_VKEY_TO_UNICODE指針類(lèi)型函KeybdDriverVKeyToUnicode數(shù)根據(jù)虛擬鍵的狀態(tài)來(lái)產(chǎn)生正確的unicode字符,此函數(shù)只依賴(lài)于指定語(yǔ)言的鍵盤(pán)布局(the keyboard layout for the language),這兩種轉(zhuǎn)換基于轉(zhuǎn)換表。并且如果有必要,我們可以創(chuàng)建自己的鍵盤(pán)映射或者基于已經(jīng)存在的鍵盤(pán)映射來(lái)定制。
?
1.2? 鍵盤(pán)驅(qū)動(dòng)的加載及初始化
在系統(tǒng)啟動(dòng)的過(guò)程中GWES加載鍵盤(pán)驅(qū)動(dòng),當(dāng)GWES開(kāi)始后,它從注冊(cè)表鍵HKEY_LOCAL_MACHINE\Hardware\DeviceMap\KEYBD\Drivername下的子鍵“Drivername”中取得鍵盤(pán)驅(qū)動(dòng)的dll名字,我這里是smdk6410_keypad.dll,但如果在此入口下沒(méi)有找到dll,GWES就采用默認(rèn)的Keybddr.dll。接著就加載此dll并 核實(shí)所有需要的入口函數(shù)是否存在,比如對(duì)于smdk6410_keypad.dll,會(huì)核實(shí)此dll對(duì)應(yīng)的def文件中導(dǎo)出的接口函數(shù)是否存在,這些導(dǎo)出函數(shù)如圖2所示
圖2 smdk6410_keypad.dll的導(dǎo)出接口函數(shù)
GWES然后調(diào)用PFN_KEYBD_DRIVER_INITIALIZE函數(shù)指針類(lèi)型的KeybdDriverInitializeEx函數(shù)初始化layout管理器和鍵盤(pán)驅(qū)動(dòng)支持的PDD,并且傳遞鍵盤(pán)事件回調(diào)函數(shù)進(jìn)來(lái)。在此函數(shù)中,鍵盤(pán)驅(qū)動(dòng)在本地保存一份GWES的鍵盤(pán)事件回調(diào)函數(shù)的副本以及初始化硬件和IST來(lái)處理中斷。當(dāng)按鍵中斷產(chǎn)生的時(shí)候,鍵盤(pán)驅(qū)動(dòng)負(fù)責(zé)轉(zhuǎn)換硬件掃描碼為虛擬鍵碼,并且通過(guò)鍵盤(pán)事件回調(diào)函數(shù)KeybdEventCallback或者keybd_event函數(shù)來(lái)傳遞掃描碼和虛擬鍵碼給GWES。后來(lái),GWES從隊(duì)列中取出鍵盤(pán)事件并回調(diào)PFN_KEYBD_DRIVER_VKEY_TO_UNICODE指針函數(shù)類(lèi)型的KeybdDriverVKeyToUnicode函數(shù)來(lái)分析指定的按鍵事件和把虛擬鍵碼映射為相應(yīng)的unicode字符,然后GWES發(fā)送虛擬鍵碼和字符給相應(yīng)的應(yīng)用。另外,為了支持可聽(tīng)見(jiàn)的稽聲(audible key click,我的理解是可聽(tīng)見(jiàn)的按鍵延時(shí)聲),鍵盤(pán)驅(qū)動(dòng)必須為虛擬鍵碼增加KEYBD_DEVICE_SILENT or KEYBD_DEVICE_SILENT_REPEAT或者傳遞KEYEVENTF_SILENT給keybd_event函數(shù)。
?
1.3? 獲取和設(shè)置鍵盤(pán)的信息
GWES通過(guò)鍵盤(pán)驅(qū)動(dòng)PFN_KEYBD_DRIVER_GET_INFO函數(shù)指針類(lèi)型的KeybdDriverGetInfo函數(shù)和PFN_KEYBD_DRIVER_SET_MODE函數(shù)指針類(lèi)型的KeybdDriverSetMode函數(shù)來(lái)獲取和設(shè)置有關(guān)鍵盤(pán)的信息。當(dāng)主輸入線程(main input thread)處理KeybdEventCallback函數(shù)傳遞回來(lái)的關(guān)聯(lián)鍵盤(pán)的事件的時(shí)候,此線程調(diào)用KeybdDriverGetInfo函數(shù)來(lái)獲取鍵盤(pán)驅(qū)動(dòng)支持的虛擬鍵碼到unicode數(shù)據(jù)的轉(zhuǎn)換,也為鍵盤(pán)驅(qū)動(dòng)所用的虛擬碼狀態(tài)數(shù)據(jù)和任何附加的數(shù)據(jù)分配所需要的內(nèi)存。
?
1.4? 鍵盤(pán)驅(qū)動(dòng)必需和可選的功能
當(dāng)鍵盤(pán)的任何按鍵有效按下時(shí),鍵盤(pán)驅(qū)動(dòng)必須調(diào)用鍵盤(pán)事件回調(diào)函數(shù)KeybdEventCallback或者keybd_event函數(shù)來(lái)通知GWES,下面列舉的鍵盤(pán)驅(qū)動(dòng)可選的功能:
1)? 更新鍵盤(pán)驅(qū)動(dòng)來(lái)配合layout管理器一起工作。
2)? 實(shí)現(xiàn)MapVirtualKey(uCode,0)支持把虛擬鍵碼映射為XT掃描碼來(lái)使能遠(yuǎn)程桌面協(xié)議RDP(Remote Desktop Protocol)。
3)? 實(shí)現(xiàn)MapVirtualKey(uCode,3)支持把AT掃描碼映射為虛擬鍵碼來(lái)使能USB鍵盤(pán)。
4)? 使能USB鍵盤(pán)LED。
?
1.5? ?
2.? layout管理器
2.1? layout管理器的功能
layout管理器管理設(shè)備布局和輸入語(yǔ)言這兩部分,下面是layout管理器處理掃描碼的步驟:
1)? PDD接收到一個(gè)掃描碼。
2)? PDD發(fā)送掃描碼給layout管理器。
3)? Layout管理器根據(jù)鍵盤(pán)來(lái)調(diào)用ScanCodeToVKey函數(shù)轉(zhuǎn)換掃描碼為虛擬鍵碼,并發(fā)送對(duì)應(yīng)的事件和當(dāng)前的設(shè)備布局。
4)? Layout管理器根據(jù)鍵盤(pán)重新映射掃描碼,并發(fā)送對(duì)應(yīng)的事件和當(dāng)前的設(shè)備布局。
5)? Layout管理器處理自動(dòng)重復(fù)性的功能(the auto-repeat functionality),所有的鍵盤(pán)共享相同的自動(dòng)重復(fù)功能。
6)? Layout管理器調(diào)用keybd_event函數(shù)發(fā)送單個(gè)或者多個(gè)事件。
?
在PDD獲取到指定事件并且layout管理器在處理此事件的時(shí)候,如果輸入?yún)^(qū)域(input locale)發(fā)生改變,鍵盤(pán)事件被映射為新設(shè)備布局。當(dāng)layout管理器收到一個(gè)轉(zhuǎn)換虛擬鍵碼為unicode數(shù)據(jù)的請(qǐng)求,它使用僅限于當(dāng)前輸入語(yǔ)言的輔助狀態(tài)和輔助表 (modifier state and tables),在這之前,layout管理器執(zhí)行ALT+數(shù)字小鍵盤(pán)邏輯(numeric keypad logic),可通過(guò)同時(shí)按下ALT鍵和鍵入數(shù)字鍵區(qū)上的符號(hào)數(shù)字值來(lái)產(chǎn)生隨意的unicode字符。
?
Layout管理器保存每個(gè)PDD的信息在一個(gè)通過(guò)鍵盤(pán)標(biāo)識(shí)符來(lái)索引的數(shù)組中,此數(shù)組在SMDK6410\SRC\DRIVERS\KEYBD\Pddlist下面定義,如下所示
PFN_KEYBD_PDD_ENTRY g_rgpfnPddEntries[] = {
??? PS2_NOP_Entry,
??? Matrix_Entry,
??? NULL
};
而鍵盤(pán)標(biāo)識(shí)符是在layout管理器在初始化PDD的時(shí)候?yàn)槊總€(gè)PDD指定的,layout管理器保存一系列的入口點(diǎn)、有效的設(shè)備布局和每個(gè)PDD當(dāng)前的設(shè)備布局。上面的數(shù)組表示此鍵盤(pán)驅(qū)動(dòng)支持兩種設(shè)備布局,分別為PS2和矩陣式鍵盤(pán)。
?
當(dāng)輸入?yún)^(qū)域(input locale)改變的時(shí)候,layout管理器改變每個(gè)PDD的設(shè)備布局為匹配新輸入?yún)^(qū)域的設(shè)備布局。它也轉(zhuǎn)變之前的輸入語(yǔ)言為當(dāng)前輸入?yún)^(qū)域的低位字描述的輸入語(yǔ)言,這里的低位字是指language identifier。
?
Layout管理器支持多個(gè)鍵盤(pán)布局,可在運(yùn)行時(shí)切換鍵盤(pán)布局、打包多個(gè)設(shè)備布局和輸入語(yǔ)言到運(yùn)行時(shí)鏡像中(run-time image),也可在運(yùn)行時(shí)增加新的鍵盤(pán)布局。比如,在運(yùn)行時(shí),我們可以從德語(yǔ)鍵盤(pán)布局切換到荷蘭語(yǔ)鍵盤(pán)布局。
?
2.2? Layout管理器定義的專(zhuān)門(mén)術(shù)語(yǔ)
1)? Device layout
設(shè)備布局,描述硬件具體信息,包含掃描碼到虛擬鍵碼的轉(zhuǎn)換和虛擬鍵碼的重新映射功能。
2)? Input language
輸入語(yǔ)言,主要實(shí)現(xiàn)虛擬鍵碼到unicode字符的通用性(generic mapping)映射,這其中考慮了SHIFT按鍵的虛擬鍵碼到unicode字符的映射,同一個(gè)鍵盤(pán),對(duì)于中文版的windows xp操作系統(tǒng),按下組合鍵SHIFT+4在聯(lián)想的主機(jī)上輸出符號(hào)是¥,而英文版的windows xp操作系統(tǒng)輸出$,這是因?yàn)橹形陌娴膇nput lanugae部分修改通過(guò)修改虛擬鍵碼到unicode字符的映射表來(lái)完成這個(gè)不同的顯示的。這部分也包含虛擬鍵碼到掃描碼的映射(見(jiàn)1.4節(jié)的描述),因?yàn)榇斯δ苁菫橹С諶DP而用于映射為XT掃描碼服務(wù)的。
?
輸入語(yǔ)言部分和設(shè)備布局要相互對(duì)應(yīng)起來(lái)(The input language and the device layout correspond to one another),每個(gè)鍵盤(pán)類(lèi)型,例如一個(gè)PS/2鍵盤(pán)或矩陣鍵盤(pán),有一個(gè)當(dāng)前設(shè)備布局匹配全局共享的當(dāng)前輸入語(yǔ)言。
3)? Input locale
輸入?yún)^(qū)域,解析帶有輸入法的輸入語(yǔ)言(Pairing of an input language with an input method),比如對(duì)于標(biāo)準(zhǔn)美國(guó)101個(gè)按鍵的鍵盤(pán)的輸入?yún)^(qū)域識(shí)別碼(input locale identifier)是00000409,其中低位字0409是語(yǔ)言識(shí)別碼(language identifier),表示美式英語(yǔ),高位字0000是類(lèi)型識(shí)別符(type identifier),這里是指鍵盤(pán)類(lèi)型,比如有QWERTY、DVORAK、MALT鍵盤(pán)。另外Dvorak鍵盤(pán)的輸入?yún)^(qū)域識(shí)別碼是00010409。
?
一個(gè)輸入?yún)^(qū)域和輸入?yún)^(qū)域句柄不同(An input locale and an input locale handle differ),一旦輸入?yún)^(qū)域被裝載,layout管理器產(chǎn)生一個(gè)可被用作鍵盤(pán)API的句柄給輸入?yún)^(qū)域(HKL)。
?
3.? input language
Input Language的入口函數(shù)名字是:IL_{layout序號(hào)},見(jiàn)圖2。不像設(shè)備布局,輸入語(yǔ)言
和具體的硬件無(wú)關(guān),InputLang.h描述輔助鍵和虛擬鍵碼轉(zhuǎn)換為unicode字符的復(fù)雜關(guān)系(complex relationship),layout管理器映射當(dāng)前輔助鍵(例如SHIFT、CTRL按鍵等等)為虛擬鍵碼的一個(gè)索引,并把此索引傳遞到unicode表中,接著,layout管理器搜索適用于虛擬鍵碼的unicode表,并使用輔助鍵的索引來(lái)確定它的unicode值。
typedef struct _INPUT_LANGUAGE {
??? DWORD?? dwSize;
??? DWORD?? dwType;
??? DWORD?? dwSubType;
?
??? // Modifier keys
??? const MODIFIERS *pCharModifiers;
?
??? // Optional shift key table
??? const VK_TO_SHIFT *pVkToShiftState;
?
??? // Optional toggle key table
??? const VK_TO_SHIFT *pVkToToggledState;
?
??? // Virtual key to Unicode
??? const VK_TO_WCHAR_TABLE *pVkToWcharTable;//ptr to tbl of ptrs to tbl
?
??? // Dead keys
??? const DEADKEY *pDeadKey;
?
??? // Virtual key to XT scan code
??? const VKEY_TO_SCANCODE *pVkToScanCodeTable;
?
??? // Locale-specific special processing???
??? DWORD fLocaleFlags;
?
??? // Ligatures
??? BYTE???????????? nLgMax;??? // Maximum ligature table characters
??? BYTE???????????? cbLgEntry; // Count of bytes in each ligature table row
??? const LIGATURE1 *pLigature; // Pointer to ligature table
?
??? BYTE? ??bcFnKeys;
} INPUT_LANGUAGE, *PINPUT_LANGUAGE;
?
4.? device layout
?
設(shè)備布局是和具體硬件相關(guān)的鍵盤(pán)信息,它包含掃描碼到虛擬鍵碼的轉(zhuǎn)換和虛擬鍵碼的重新映射,例如,korean(韓語(yǔ),朝鮮語(yǔ))PS/2鍵盤(pán)比korean矩陣鍵盤(pán)有更多的設(shè)備布局。
因?yàn)閁SB人機(jī)界面設(shè)備(HID)鍵盤(pán)驅(qū)動(dòng)轉(zhuǎn)換USB鍵盤(pán)掃描碼為AT掃描碼,所以沒(méi)有HID設(shè)備布局。HID驅(qū)動(dòng)通過(guò)關(guān)聯(lián)了PDD層的設(shè)備布局,并結(jié)合掃描碼調(diào)用MapVirtualKey函數(shù)來(lái)獲取相應(yīng)的虛擬鍵碼,這一連串動(dòng)作只需要在設(shè)備布局中執(zhí)行,以便掃描碼到虛擬鍵碼轉(zhuǎn)換的定位。接著HID鍵盤(pán)驅(qū)動(dòng)用虛擬鍵碼和掃描碼來(lái)調(diào)用keybd_event函數(shù)。
?
多種設(shè)備布局可以和一種輸入語(yǔ)言一致,比如,標(biāo)準(zhǔn)美國(guó)101鍵鍵盤(pán)的設(shè)備布局和一個(gè)美國(guó)Dvorak鍵盤(pán)的設(shè)備布局都使用美式英語(yǔ)作為輸入語(yǔ)言。
?
布局管理器執(zhí)行掃描碼到虛擬鍵碼的映射,DeviceLayout.h文件描述了相關(guān)的數(shù)據(jù)結(jié)果,布局管理器在掃描碼轉(zhuǎn)換為虛擬鍵碼后重新映射。微軟提供了一個(gè)數(shù)字鍵盤(pán)映射庫(kù)來(lái)靜態(tài)鏈接到設(shè)備布局的重新映射電路,這樣我們可以不需要開(kāi)發(fā)數(shù)字鍵盤(pán)共有的代碼。數(shù)字鍵盤(pán)庫(kù)在NUMLOCK關(guān)閉的時(shí)候,執(zhí)行比如是VK_NUMPADD0到VK_INSERT的映射。
?
WINCE默認(rèn)支持美國(guó)英語(yǔ)、日本、韓語(yǔ)和朝鮮語(yǔ)的鍵盤(pán)布局,如果要支持其他語(yǔ)言的鍵盤(pán)布局,我們必須從windows xp布局的DLL中獲取語(yǔ)言,并且創(chuàng)建一個(gè)對(duì)應(yīng)的新鍵盤(pán)布局,比如我們要獲取russian(俄語(yǔ))的鍵盤(pán)布局和輸入語(yǔ)言的源代碼文件及注冊(cè)表信息,首先通過(guò)PC機(jī)上的windows xp操作系統(tǒng)下面的注冊(cè)表信息
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Keyboard Layouts]來(lái)獲取russian
的dll名稱(chēng)及輸入?yún)^(qū)域識(shí)別碼(input locale identifier),見(jiàn)下圖:
圖3 當(dāng)前windows xp系統(tǒng)的鍵盤(pán)布局
然后可以使用鍵盤(pán)布局產(chǎn)生工具kbdgen.exe,在PB中輸入下面的內(nèi)容,輸出如下:
圖4 kbdgen工具產(chǎn)生俄語(yǔ)的相關(guān)轉(zhuǎn)換表
另外在PB工程的release目錄下生成輸入語(yǔ)言源文件russianIL.cpp、設(shè)備布局源文件russianDL.cpp和這個(gè)布局有可能用到的注冊(cè)表樣例入口文件russian.reg。對(duì)于接下來(lái)的啟動(dòng)動(dòng)作參考help文檔。
?
設(shè)備布局的數(shù)據(jù)結(jié)構(gòu)體如下
// Remapping function typedefs
typedef UINT (*PFN_KEYBD_REMAP)(
? const KEYBD_EVENT *pKbdEvents,
? UINT cKbdEvents,
? KEYBD_EVENT *pRmpKbdEvents,?
? UINT cMaxRmpKbdEvents
);
?
typedef struct tagDEVICE_LAYOUT {
? DWORD dwSize;
? WORD wPddMask; // Matches the device layout with its PDD
?
? // Scan code to virtual key
? ScanCodeToVKeyData **rgpscvk;
? UINT cpscvk;
?
? // Remapping functions
? PFN_KEYBD_REMAP pfnRemapKey;
} DEVICE_LAYOUT, *PDEVICE_LAYOUT;
?
typedef BOOL (*PFN_DEVICE_LAYOUT_ENTRY)(PDEVICE_LAYOUT pDeviceLayout);
這里需要注意的是,布局管理器通過(guò)支持的設(shè)備布局中根據(jù)PDD數(shù)據(jù)結(jié)構(gòu)體成員wPddMask來(lái)找到匹配的設(shè)備布局。wPddMask成員是可以correlate一個(gè)設(shè)備布局到多個(gè)PDD類(lèi)型,比如一個(gè)AT掃描碼設(shè)備布局可以correlate為PS/2 PDD和一個(gè)stub PDD。
5.? 鍵盤(pán)驅(qū)動(dòng)的工作流程
5.1? 初始化流程
根據(jù)1.2節(jié)的描述可知,GWES加載鍵盤(pán)驅(qū)動(dòng)的時(shí)候,調(diào)用laymgr.cpp下的KeybdDriverInitializeEx函數(shù)初始化layout管理器和鍵盤(pán)驅(qū)動(dòng)支持的PDD,下面就來(lái)學(xué)習(xí)這個(gè)函數(shù)。
5.1.1?? 創(chuàng)建化臨界區(qū)、事件和線程
初始化訪問(wèn)input locale信息和發(fā)送事件回調(diào)函數(shù)的臨界區(qū)對(duì)象、創(chuàng)建按鍵事件發(fā)送開(kāi)始和處理結(jié)束的事件、創(chuàng)建按鍵事件處理線程及按鍵通知線程。
圖5 創(chuàng)建化臨界區(qū)、事件和線程
?
5.1.2?? 初始化PDD數(shù)據(jù)結(jié)構(gòu)、為PDD鏈表分配空間和初始化每個(gè)PDD
圖6 為PDD分配內(nèi)存空間和調(diào)用PDD入口函數(shù)
?
1)? 獲取支持的PDD個(gè)數(shù),也即layout manager支持的device layout個(gè)數(shù)。
PDD的入口是全局?jǐn)?shù)組g_rgpfnPddEntries,在PDD中定義,MDD中使用,其定義及初始化如下:
PFN_KEYBD_PDD_ENTRY g_rgpfnPddEntries[] = {
??? PS2_NOP_Entry,//在COMMON\OAK\DRIVERS\KEYBD\NOP\PDD\nopkb.cpp下定義
??? Matrix_Entry,//在PDD中定義
??? NULL
};
由此可知此鍵盤(pán)驅(qū)動(dòng)支持的PDD為兩個(gè),我們接下來(lái)是針對(duì)矩陣鍵盤(pán)來(lái)學(xué)習(xí)的,所以后面重點(diǎn)學(xué)習(xí)Matrix_Entry這個(gè)PDD,先來(lái)看PFN_KEYBD_PDD_ENTRY的定義,如下:
typedef BOOL (*PFN_KEYBD_PDD_ENTRY)(UINT uiPddId,
PFN_KEYBD_EVENT pfnKeybdEvent, PKEYBD_PDD *ppKeybdPdd);
可知PFN_KEYBD_PDD_ENTRY為一個(gè)函數(shù)指針,下面來(lái)看其參數(shù)及相應(yīng)數(shù)據(jù)結(jié)構(gòu)。
⑴uiPddId
uiPddId表示PDD的索引值,可以知道Matrix_Entry對(duì)應(yīng)的索引值為1。
?
⑵ pfnKeybdEvent
pfnKeybdEvent是指向PFN_KEYBD_EVENT函數(shù)指針的指針,根據(jù)后面的代碼可知此參數(shù)正是傳遞KeybdEventCallback給PDD層的全局函數(shù)指針v_pfnKeybdEvent的,此指針類(lèi)型定義如下:
typedef void (*PFN_KEYBD_EVENT)(UINT uiPddId, UINT32 uiScanCode,
BOOL fKeyDown);
此函數(shù)指針指向的函數(shù)的第一個(gè)參數(shù)表示PDP的索引值,第二個(gè)參數(shù)表示鍵盤(pán)的掃描碼,第三個(gè)參數(shù)表示按鍵的狀態(tài),按下或松開(kāi)。
?
⑶ ppKeybdPdd
ppKeybdPdd是一個(gè)指向KEYBD_PDD結(jié)構(gòu)體類(lèi)型的指針,此結(jié)構(gòu)體定義如下:
typedef struct tagKEYBD_PDD {
??? WORD wPddMask; // Matches the keyboard layout with its PDD
??? LPCTSTR pszName; // Used to identify PDD to user
??? PFN_KEYBD_PDD_POWER_HANDLER pfnPowerHandler;
??? PFN_KEYBD_PDD_TOGGLE_LIGHTS pfnToggleLights;
} KEYBD_PDD, *PKEYBD_PDD;
?
wPddMask
layout管理器通過(guò)此成員來(lái)從自身支持的多個(gè)鍵盤(pán)布局中匹配出對(duì)應(yīng)的鍵盤(pán)布局。
?
pszName
為用戶(hù)標(biāo)示PDD的顯示名稱(chēng),需要驗(yàn)證,比如下圖所示:
圖7 PDD顯示給用戶(hù)的標(biāo)識(shí)符
pfnPowerHandler
指向PFN_KEYBD_PDD_POWER_HANDLER函數(shù)指針類(lèi)型的指針,最終會(huì)傳遞PDD層的Matrix_PowerHandler函數(shù)來(lái)實(shí)現(xiàn)。
?
pfnToggleLights
指向PFN_KEYBD_PDD_TOGGLE_LIGHTS函數(shù)指針類(lèi)型的指針,最終會(huì)傳遞PDD層的Matrix_ToggleLights函數(shù)來(lái)實(shí)現(xiàn)。
?
結(jié)合g_rgpfnPddEntries的初始化,可知
2)? layout管理器從堆中為其支持的每個(gè)PDD分配和結(jié)構(gòu)體KEYBD_PDD_INFO大小一樣的空間。
3)? 初始化每個(gè)PDD相關(guān)的函數(shù)指針或者結(jié)構(gòu)體指針
圖8 矩陣鍵盤(pán)MDD調(diào)用PDD的入口函數(shù)
結(jié)合圖6和圖8,可知在第二個(gè)for循環(huán)的時(shí)候,會(huì)調(diào)用到矩陣鍵盤(pán)PDD的入口函數(shù)Matrix_Entry,并且把此PDD的ID和按鍵事件回調(diào)函數(shù)KeybdEventCallback傳遞到PDD中,而由PDD的Matrix_Entry來(lái)初始化第三個(gè)輸出參數(shù)為MatrixPdd,這樣可使MDD中的全局變量g_pPdds的成員指針pKeybdPdd指向MatrixPdd,下面我們來(lái)看Matrix_Entry函數(shù)。
圖9 Matrix_Entry函數(shù)
4)? 指示當(dāng)前的PDD是否有效,也即layout manager是否支持此PDD。
?
5.1.3? 獲取默認(rèn)的input method并調(diào)用input language的入口函數(shù)
圖10獲取默認(rèn)的input method并調(diào)用input language的入口函數(shù)
1)? 獲取默認(rèn)的input method
KeybdDriverInitializeEx函數(shù)接著調(diào)用GetDefaultInputMethodName的函數(shù)體,下面來(lái)看此函數(shù)的函數(shù)體。
圖11 獲取默認(rèn)的input method
?
2)? 獲取上面中輸入法對(duì)應(yīng)的input language,并且調(diào)用其入口函數(shù),比如IL_00000409。
下面來(lái)看SetInputLanguage函數(shù)如何根據(jù)GetDefaultInputMethodName函數(shù)獲取的默認(rèn)輸入法的名字,比如“e0010804”來(lái)獲取對(duì)應(yīng)的input language的,下面是SetInputLanguage的函數(shù)體,依次介紹
1)? 獲取輸入法對(duì)應(yīng)的input language的入口函數(shù)。
圖12 SetInputLanguage函數(shù)體第一部分
2)? 調(diào)用input lanuage的入口函數(shù)來(lái)獲取此input language的全局變量InputLanguage的值,并驗(yàn)證是否有效。
?
圖13 SetInputLanguage函數(shù)體第二部分
在此我們來(lái)看一下描述input language的全局變量InputLanguage及其類(lèi)型如下:
圖14 全局變量InputLanguage及其類(lèi)型
3)? 初始化描述input language信息的iliNew,并賦值給g_ili,這樣layout manager就能獲取到inputlanguage的信息了。
?
圖15 SetInputLanguage函數(shù)體第三部分
?
⑴GenerateModifierToShiftTable函數(shù)
圖16 GenerateModifierToShiftTable函數(shù)體
結(jié)合圖17可更好理解此函數(shù)的作用
圖17 g_rgVkToShiftState等全局?jǐn)?shù)組的內(nèi)容
?
5.1.4? 初始化每個(gè)PDD的device layout
圖18 初始化device layout
下面學(xué)習(xí)SetDeviceLayout函數(shù)體,此函數(shù)根據(jù)傳遞進(jìn)來(lái)的hkl來(lái)設(shè)置特定PDD的device layout。
1)? SetDeviceLayout函數(shù)體第一部分
圖19 SetDeviceLayout函數(shù)體第一部分
下面介紹此部分調(diào)用的一些函數(shù)
⑴SelectDeviceLayout函數(shù)
圖20 SelectDeviceLayout函數(shù)體
圖21 SelectDeviceLayout函數(shù)通過(guò)此注冊(cè)表信息獲取device layout的入口
這樣比如可以知道szValueName指向"PS2_AT",szValueData指向"smdk6410_keypad.dll",下面看DeviceLayoutMatchesPDD函數(shù)的實(shí)現(xiàn)部分:
圖22 DeviceLayoutMatchesPDD函數(shù)體
上面會(huì)調(diào)用到PDD的Matrix(),此函數(shù)會(huì)把描述device layout信息的靜態(tài)全局變量dlMatrixEngUs傳遞給MDD,內(nèi)容如下:
static DEVICE_LAYOUT dlMatrixEngUs =
{
??? sizeof(DEVICE_LAYOUT),
??? MATRIX_PDD,
??? rgscvkMatrixEngUSTables,
??? dim(rgscvkMatrixEngUSTables),
??? MatrixUsRemapVKey,
};
其中rgscvkMatrixEngUSTables就包含了掃描碼到虛擬鍵碼的轉(zhuǎn)換表,這個(gè)表示需要PDD層來(lái)根據(jù)開(kāi)發(fā)的鍵盤(pán)布局來(lái)調(diào)整。
2)? SetDeviceLayout函數(shù)體第二部分
圖23 SetDeviceLayout函數(shù)體第二部分
?
到此KeybdDriverInitializeEx函數(shù)介紹完成了。
總結(jié)
以上是生活随笔為你收集整理的S3C6410 KeyPad驱动(上)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: S3C6410的SPI控制器
- 下一篇: S3C6410 KeyPad驱动(下)