MacBook Pro 2017 13寸版 触摸板windows驱动开发(开发HID鼠标键盘驱动之一)
生活随笔
收集整理的這篇文章主要介紹了
MacBook Pro 2017 13寸版 触摸板windows驱动开发(开发HID鼠标键盘驱动之一)
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
by fanxiushu 2017-10-27 轉(zhuǎn)載或引用請(qǐng)注明原始作者。
如下連接,
http://blog.csdn.net/fanxiushu/article/details/78186745
因?yàn)樾陆鼡Q的電腦是macbook pro 2017 13寸帶bar的機(jī)器,其他還能將就,
就是觸摸板難用,動(dòng)不動(dòng)就彈出右鍵菜單,經(jīng)常誤觸,
而且尤其不爽的是拖動(dòng)時(shí)候,必須按住邊緣,另一只手指才能拖動(dòng),
觸摸板這么大,基本無(wú)法單手進(jìn)行拖動(dòng)操作,需要另一個(gè)手的手指按住觸摸板邊緣,然后拖動(dòng)。
雖然可以點(diǎn)擊兩次,第2次不離開(kāi)觸摸板來(lái)拖動(dòng),但是非常不習(xí)慣這種手勢(shì)。
還是習(xí)慣傳統(tǒng)的食指按住觸摸板,中指來(lái)拖動(dòng)(因?yàn)檫@種手勢(shì)更加接近按住鼠標(biāo)左鍵移動(dòng)鼠標(biāo)的效果)。
像我這種經(jīng)常把電腦放到大腿上或者床上的人(反正就是不會(huì)老老實(shí)實(shí)的放到電腦桌上),
如果帶個(gè)鼠標(biāo)是很不方便的,只能依賴觸摸板來(lái)控制電腦。
而且我的要求也不高,不需要什么多手勢(shì),只要觸摸板能盡量模擬鼠標(biāo)的效果就行了。
其實(shí)個(gè)人覺(jué)得windows本身的易操作性,使用鼠標(biāo)的效果就能控制操作系統(tǒng)的所有的東西了,
手勢(shì)多了我也記不住,每次切換不同手勢(shì)還得思考一下也挺累(也許是還沒(méi)習(xí)慣,也懶得去習(xí)慣了)。
基于以上各種原因,于是決定重新開(kāi)發(fā)這款電腦的觸摸板驅(qū)動(dòng)。
首先解釋一下“點(diǎn)按”和”輕點(diǎn)“:
按住或重壓,就是按下去,能聽(tīng)到“噠”的一聲響;
”點(diǎn)按“就是“噠”的一聲按下去然后立馬彈上來(lái),
還有一個(gè)就是”輕點(diǎn)“,就是手指接觸到觸摸板然后迅速離開(kāi)。
我需要達(dá)到的效果也非常簡(jiǎn)單明了,用兩根手指模擬鼠標(biāo)效果,操作整個(gè)系統(tǒng)。
1,首先一根手指按住觸摸板的任意位置(是任意位置而不是觸摸板邊緣),另一根手指在觸摸板上移動(dòng)來(lái)達(dá)到拖動(dòng)效果,
這就相當(dāng)于按住鼠標(biāo)左鍵,移動(dòng)鼠標(biāo)的效果一樣。
2,一根手指輕點(diǎn),相當(dāng)于鼠標(biāo)左鍵按下去然后立馬彈上來(lái)。
???? 一根手指按住觸摸板,相當(dāng)于按下鼠標(biāo)左鍵,從觸摸板彈上來(lái)相當(dāng)于彈出左鍵。
3,兩根手指同時(shí)輕點(diǎn),相當(dāng)于鼠標(biāo)右鍵按下去然后立馬彈上來(lái)。
???? 一根手指按住觸摸板右邊四分之三到四分之四部分(是整個(gè)右邊3/4,而不是右下邊緣),相當(dāng)于按住鼠標(biāo)右鍵。
4,兩根手指同時(shí)在觸摸板移動(dòng),相當(dāng)于滾輪滾動(dòng)。
5,另外再附加實(shí)現(xiàn)一個(gè)功能:三指拖移。等于是第1個(gè)功能的效果:一個(gè)手指按住,另一個(gè)手指移動(dòng)。
????? 這樣不重壓觸摸板的也能操作整個(gè)系統(tǒng)。
不模擬鼠標(biāo)的中間鍵按下效果,好像中間鍵沒(méi)啥用處。
以上就是我的簡(jiǎn)單明了的要求,當(dāng)然習(xí)慣各種手勢(shì)的你可能并不贊同,甚至有點(diǎn)嗤之以鼻,然而這依然是我的簡(jiǎn)單明了的要求。
重新開(kāi)發(fā)的觸摸板驅(qū)動(dòng)也只實(shí)現(xiàn)上邊的功能而已。
要重新開(kāi)發(fā)macbook pro 2017年 13寸帶bar(以下簡(jiǎn)稱mbp2017)的觸摸板的windows驅(qū)動(dòng),
首先需要解決兩件事:
一,采集mbp2017的觸摸板數(shù)據(jù),
二,模擬開(kāi)發(fā)鼠標(biāo)驅(qū)動(dòng)。
第二個(gè)問(wèn)題100%的確保能解決,使用HID模式的鼠標(biāo)驅(qū)動(dòng)就可以了。
關(guān)鍵是第一個(gè)問(wèn)題,如果不能采集和解析觸摸板的數(shù)據(jù),基本就沒(méi)戲了,只能老老實(shí)實(shí)的使用那個(gè)難用的原裝驅(qū)動(dòng)程序。
mbp2017的觸摸板數(shù)據(jù)結(jié)構(gòu)格式是沒(méi)有公開(kāi)的,而且未來(lái)也很可能被蘋果公司改變,因此沒(méi)有通用性,
我測(cè)試的對(duì)應(yīng)bootcamp版本是 6.1.6813,對(duì)應(yīng)的觸摸板總線驅(qū)動(dòng)的驅(qū)動(dòng)日期是 2016/05/26, 版本 6.1.6500.0,
其他版本的沒(méi)測(cè)試過(guò),所以不知道的數(shù)據(jù)格式是不是不同。
既然這個(gè)數(shù)據(jù)沒(méi)有公開(kāi),我們就必須要自己來(lái)采集和分析觸摸板的數(shù)據(jù),
好在觸摸板這類設(shè)備本身的數(shù)據(jù)量不大,數(shù)據(jù)結(jié)構(gòu)也應(yīng)該不會(huì)多復(fù)雜,只要Apple公司沒(méi)變態(tài)到做加密,估計(jì)是能解析出來(lái)的。
自己動(dòng)手解析之前,先要搞清楚它的驅(qū)動(dòng)運(yùn)行流程。
蘋果使用的SPI總線來(lái)傳輸觸摸板和鍵盤的數(shù)據(jù),SPI總線接口,也是我在接觸mbp2017時(shí)候才發(fā)現(xiàn)還有這么一個(gè)玩意,真是孤陋寡聞了。
SPI 全稱Serial Peripheral Interface--串行外設(shè)接口, 最初是Motorola提出和開(kāi)發(fā)的,它使用主從模式通訊,這點(diǎn)跟USB有點(diǎn)像,
同時(shí)通訊也很簡(jiǎn)單,比RS232(串口)還簡(jiǎn)單,所以不論軟件或硬件成本都比較低。
但是應(yīng)付鍵盤和觸摸板這類不需要大量通訊數(shù)據(jù)的器件完全足夠了。更詳細(xì)的關(guān)于SPI介紹,請(qǐng)查詢其他資料。
mbp2017的電腦windows驅(qū)動(dòng)中關(guān)于SPI的,首先有個(gè)SPI總線驅(qū)動(dòng),在SPI總線驅(qū)動(dòng)下掛載兩個(gè)位置,
位置1是鍵盤驅(qū)動(dòng),位置2才是觸摸板驅(qū)動(dòng)。詳細(xì)可看下邊的圖示:
畫(huà)紅線的部分,在”系統(tǒng)設(shè)備“里邊的 “Apple SPI Device ” 就是總線驅(qū)動(dòng),它負(fù)責(zé)給鍵盤和觸摸板的功能驅(qū)動(dòng)提供數(shù)據(jù),
在“人體學(xué)輸入設(shè)備”里邊的“ Apple SPI Keyboard” 和 “ Apple SPI Trackpad” 對(duì)應(yīng)的就是 鍵盤的功能驅(qū)動(dòng)和觸摸板的功能驅(qū)動(dòng),
再看“Apple SPI Trackpad” 的屬性, 它在總線驅(qū)動(dòng)的位置是 2, 我們要做的事情,就是替換這個(gè)功能驅(qū)動(dòng),使用我們自己開(kāi)發(fā)的驅(qū)動(dòng)來(lái)代替。
另外我們順便看看這款電腦內(nèi)置的USB接口的設(shè)備,
上邊的藍(lán)線部分,在 “通用串行總線控制器” 里邊存在一個(gè)“Apple USB Composite Device”的復(fù)合設(shè)備,
這個(gè)復(fù)合設(shè)備管理著三個(gè)設(shè)備,“Apple Touch Bar”就是其中一個(gè),這個(gè)就是multi-touch bar, 在windows平臺(tái)下沒(méi)啥用的雞肋。
另外兩個(gè)看下圖所示:
Apple USB Composite Device一共包含三個(gè)設(shè)備:
FaceTime HD Camera,
Apple Touch Bar,
USB接口的光感氛圍器,就是檢測(cè)環(huán)境光線強(qiáng)弱,從而自動(dòng)調(diào)節(jié)屏幕的亮度。
看圖示的最下邊, bNumConfigurations 是 3, 也就是三個(gè)配置描述符,分別對(duì)應(yīng)這三種設(shè)備。
正如上篇文章所說(shuō)的,在單純只安裝windows系統(tǒng)的時(shí)候,這個(gè)“Apple USB Composite Device” 設(shè)備不能被發(fā)現(xiàn),
從而造成 攝像頭,multi-touch bar,和光感器件找不到,也不知道蘋果在設(shè)計(jì)硬件的時(shí)候搞了什么。
估計(jì)得保留安裝蘋果系統(tǒng)時(shí)候的那個(gè)EFI Parttion 分區(qū),才能被識(shí)別,只是后來(lái)沒(méi)再折騰了,保留了MacOS系統(tǒng)。
再回到觸摸板驅(qū)動(dòng),我們打開(kāi)注冊(cè)表,在 如下的位置:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\SPI\VID_05ac&PID_0277&MI_02
能找到這個(gè)驅(qū)動(dòng)的安裝信息,
注意:mbp2017 對(duì)應(yīng)的觸摸板的PID是0277, VID是05ac, 不同型號(hào)的,可能PID會(huì)不同,這個(gè)得看具體機(jī)器。
如上圖所示,在里邊的LowerFilters字段里是 蘋果的 AppleSPITrackpad驅(qū)動(dòng),
Service字段是 mshidkmdf ,從這信息,
我們立馬就知道 AppleSPITrackpad 是一個(gè)KMDF模型的驅(qū)動(dòng)程序,并且屬于標(biāo)準(zhǔn)的HID的KMDF程序。
AppleSPITrackpad負(fù)責(zé)獲取上邊提到的 “Apple SPI Device" 總線驅(qū)動(dòng)發(fā)上來(lái)的觸摸板數(shù)據(jù),
并且解析模擬成標(biāo)準(zhǔn)的兼容windows的 HID鼠標(biāo)驅(qū)動(dòng)數(shù)據(jù)。
AppleSPITrackpad在解析觸摸板數(shù)據(jù)時(shí)候,提供了讓人難以適應(yīng)(至少我比較難適應(yīng))的鼠標(biāo)動(dòng)作模擬,
因此重新開(kāi)發(fā)這個(gè)驅(qū)動(dòng)來(lái)解決這個(gè)問(wèn)題。
至此,我們大致知道他們的驅(qū)動(dòng)的工作流程了。
現(xiàn)在的任務(wù)首先就是獲取SPI總線驅(qū)動(dòng)發(fā)上來(lái)的數(shù)據(jù)結(jié)構(gòu)格式。
可以開(kāi)發(fā)一個(gè)簡(jiǎn)單的WDM 過(guò)濾驅(qū)動(dòng),掛載到 LowerFilters字段里邊的 AppleSPITrackpad 前邊。
這樣AppleSPITrackpad跟SPI總線驅(qū)動(dòng)通訊的所有IRP請(qǐng)求都能被截獲到,從而就能獲取到觸摸板數(shù)據(jù)。
WDM Filter的開(kāi)發(fā)可以查看我很早前的一篇文章:
http://blog.csdn.net/fanxiushu/article/details/8834385
當(dāng)然如果你能找到其他現(xiàn)成的工具來(lái)分析AppleSPITrackpad的通訊數(shù)據(jù),會(huì)更快捷。
通過(guò)分析,AppleSPITrackpad發(fā)給SPI總線驅(qū)動(dòng)四個(gè)請(qǐng)求:
IOCTL_HID_GET_DEVICE_DESCRIPTOR
IOCTL_HID_GET_DEVICE_ATTRIBUTES
IOCTL_HID_SET_FEATURE
IOCTL_HID_READ_REPORT
都是標(biāo)準(zhǔn)的HID請(qǐng)求命令,其中IOCTL_HID_SET_FEATURE 應(yīng)該是用于告訴SPI總線驅(qū)動(dòng)開(kāi)啟或者關(guān)閉觸摸板功能的。
最主要的就是 IOCTL_HID_READ_REPORT命令,這個(gè)就是獲取觸摸板數(shù)據(jù)。
分析在 bootcamp版本是 6.1.6813,對(duì)應(yīng)的觸摸板SPI總線驅(qū)動(dòng)的驅(qū)動(dòng)日期是 2016/05/26, 版本 6.1.6500.0,
(這里再次提到版本和日期,因?yàn)椴煌姹竞芸赡苁遣煌臄?shù)據(jù)格式,由于本人就一臺(tái)mac機(jī)器,無(wú)法測(cè)試其他情況)
數(shù)據(jù)格式結(jié)構(gòu)大致如下:
前46個(gè)字節(jié)是格式頭,接著每個(gè)手指占據(jù)30個(gè)字節(jié)。
比如 一個(gè)手指在觸摸板上,IOCTL_HID_READ_REPORT獲取到的數(shù)據(jù)長(zhǎng)度是46 + 30 = 76個(gè)字節(jié),
如果是兩個(gè)手指在觸摸板,IOCTL_HID_READ_REPORT獲取的長(zhǎng)度是 46 + 30*2 = 106字節(jié),以此類推。
前46個(gè)字節(jié)描述成c語(yǔ)言數(shù)據(jù)結(jié)構(gòu)大致如下:
typedef unsigned char????????????? u8;
46 length
struct tp_protocol
{
??? u8????????????????? type;????? // unknown type? =2
??? u8????????????????? clicked;?? // 按住了觸摸板, 不管幾個(gè)按住,都是 1
??? u8????????????????? unknown1[5]; //
??? u8????????????????? is_finger;?? // 觸摸板有手指 1,當(dāng)離開(kāi)瞬間,出現(xiàn) 0
??? u8????????????????? unknown2[8]; //
??? u8????????????????? unknown3[8]; // 未知,固定 00-01-07-97-02-00-06-00
??? u8????????????????? finger_data_length; // 手指數(shù)據(jù)總長(zhǎng)度, 手指?jìng)€(gè)數(shù)*30
??? u8????????????????? unknown4[5]; //
??? u8????????????????? finger_number; //手指?jìng)€(gè)數(shù)
??? u8????????????????? Clicked; // 同上邊的clicked
??? u8????????????????? state;?? // 手指在上邊好像是 0x10, 手指離開(kāi)瞬間最高設(shè)置 1,變成 0x80(0x90),最后離開(kāi)后,還會(huì)出現(xiàn) 0x00
??? u8????????????????? state2;? // 手指在上邊 0x20,離開(kāi)瞬間 變 0
??? u8????????????????? state3;? // 平時(shí)0, Clicked為 0x10
??? u8????????????????? zero;??? // 始終 0
??? u8????????????????? unknown5[10]; /
};
如上所示,其中unknown字段是 沒(méi)能解析出來(lái)的,不過(guò)后來(lái)發(fā)現(xiàn)就已知的字段已經(jīng)足夠模擬鼠標(biāo)動(dòng)作了。
手指的30個(gè)字節(jié)的c語(yǔ)言結(jié)構(gòu)如下:
/ 30 length
struct tp_finger
{
??? short???????????? org_x; //按下后,這個(gè)數(shù)字不變,
??? short???????????? org_y; //
??? short???????????? x;???? //隨著手指移動(dòng)改變,
??? short???????????? y;???? //
??? short ?????????? unknown[11];
};
其中unknown未知,org_x,org_y好像沒(méi)啥用,最有用的是 x,y。表示的是手指在觸摸板的坐標(biāo)位置。
整個(gè)觸摸板(13寸機(jī)器)測(cè)試下來(lái),觸摸板范圍,最左邊大致是 -6300多, 左右邊坐標(biāo) 6800多,
最上邊坐標(biāo)7700左右,最下邊-200左右。這些都是用手指移動(dòng)到邊界得出來(lái)的大致數(shù)據(jù)。
有了這些原始的觸摸板的數(shù)據(jù),我們基本就能確定能實(shí)現(xiàn)自己的mbp2017的觸摸板驅(qū)動(dòng)來(lái)模擬鼠標(biāo)操作了。
/
再來(lái)看看windows平臺(tái)下的HID驅(qū)動(dòng)開(kāi)發(fā)過(guò)程,
HID(Human Interface Device,人機(jī)接口設(shè)備)是一類設(shè)備總稱,用于提供人和電腦進(jìn)行交互的接口設(shè)備,
像最常用的鼠標(biāo),鍵盤等,觸摸板,還有游戲使用的游戲桿等等。
像鼠標(biāo)鍵盤都是windows提供的標(biāo)準(zhǔn)驅(qū)動(dòng),我們?cè)陂_(kāi)發(fā)HID驅(qū)動(dòng)時(shí)候,填寫適當(dāng)?shù)腍ID描述符,
告訴windows我們開(kāi)發(fā)的是一個(gè)HID的鼠標(biāo)或者HID鍵盤,windows自動(dòng)就會(huì)給我們加載兼容的鼠標(biāo)鍵盤驅(qū)動(dòng)。
同時(shí)我們?cè)谧约旱腍ID驅(qū)動(dòng)開(kāi)發(fā)中正確響應(yīng) IOCTL_HID_XXX事件(主要是IOCTL_HID_READ_REPORT)
這個(gè)鼠標(biāo)鍵盤就能正常工作起來(lái)。看起來(lái)是非常簡(jiǎn)單明了的。確實(shí)也是如此。
比如我們要虛擬鼠標(biāo)鍵盤,也使用HID來(lái)開(kāi)發(fā),比起掛鉤什么PS/2或者HOOK之類的做法,也顯得簡(jiǎn)單和穩(wěn)定得多,
這個(gè)在以后開(kāi)發(fā)的博客中會(huì)繼續(xù)闡述。
我們先看看WDM模型的HID開(kāi)發(fā)過(guò)程,
首先在 DriverEntry中注冊(cè)
IRP_MJ_INTERNAL_DEVICE_CONTROL, IRP_MJ_POWER, IRP_MJ_PNP 三個(gè)派遣函數(shù),
然后填寫 HID_MINIDRIVER_REGISTRATION 結(jié)構(gòu)的參數(shù),調(diào)用HidRegisterMinidriver注冊(cè)HID的小端口驅(qū)動(dòng),
這樣總體框架就建立起來(lái)了。
然后在 IRP_MJ_POWER和IRP_MJ_PNP派遣函數(shù)中,按部就班的實(shí)現(xiàn)電源管理和即插即用事件,
如果是真實(shí)HID設(shè)備,則要認(rèn)真實(shí)現(xiàn)這兩個(gè)功能,如果是虛擬設(shè)備,則不用太在意,找個(gè)現(xiàn)成框架套上去就行,
接著就是核心處理事件 IRP_MJ_INTERNAL_DEVICE_CONTROL,
在這個(gè)派遣函數(shù)中,一般處理
IOCTL_HID_GET_DEVICE_DESCRIPTOR
IOCTL_HID_GET_DEVICE_ATTRIBUTES
IOCTL_HID_READ_REPORT
三個(gè)事件就能讓鼠標(biāo)鍵盤跑起來(lái),當(dāng)然處理的越多,功能越完善,但是HID的IOCTL命令也多不多到哪去。
是的,就是這么簡(jiǎn)單的框架,
但是在這里,我們不打算使用WDM的框架,而使用的是 KMDF(WDF的內(nèi)核部分,就是對(duì)WDM的封裝 )來(lái)開(kāi)發(fā)。
KMDF就更加省事了,連 PNP和POWER也省略了,就只要關(guān)心 IRP_MJ_INTERNAL_DEVICE_CONTROL 就可以了。
但是正如微軟自己所說(shuō),他們的WDF框架跟HID的minidriver小端口驅(qū)動(dòng)在某些IO請(qǐng)求中存在沖突(IRP_MJ_POWER和IRP_MJ_PNP)
因此WDF框架不能直接橋接 HID的class driver和mini driver,他們使用了一個(gè)折中方案,
開(kāi)發(fā)一個(gè) mshidkmdf的驅(qū)動(dòng)來(lái)橋接WDF框架和classdriver,在此驅(qū)動(dòng)中調(diào)用HidRegisterMinidriver 來(lái)注冊(cè)HID小端口驅(qū)動(dòng),
并且mshidkmdf作為服務(wù)安裝,而 我們開(kāi)發(fā)的HID驅(qū)動(dòng)則作為L(zhǎng)owerFilters來(lái)安裝。詳細(xì)可查看如下鏈接:
?https://msdn.microsoft.com/en-us/library/windows/hardware/ff540774
?這就是我們?yōu)楹卧谏厦娴膱D中看到蘋果的 AppleSPItrackpad觸摸板驅(qū)動(dòng)變成了 Lowerfilters 的底層過(guò)濾驅(qū)動(dòng)了。
最后看看我們開(kāi)發(fā)KMDF模型的這款觸摸板驅(qū)動(dòng)的流程:
首先在DriverEntry中,配置好參數(shù),這里主要關(guān)心的是 EvtDeviceAdd 函數(shù),
調(diào)用WdfDriverCreate 來(lái)初始化框架。
在EvtDeviceAdd 函數(shù)中,首先調(diào)用WdfFdoInitSetFilter 表明我們開(kāi)發(fā)的是一個(gè)過(guò)濾驅(qū)動(dòng)。
然后調(diào)用WdfDeviceInitAssignWdmIrpPreprocessCallback 注冊(cè)IRP_MN_QUERY_ID這個(gè)特殊查詢事件,
因?yàn)槲覀儽仨氝@么做,才能讓windows識(shí)別到我們的驅(qū)動(dòng)ID,
對(duì)應(yīng)這塊觸摸板,我們還得注冊(cè)兩個(gè)電源事件,就是D0狀態(tài)(加電和掉電)轉(zhuǎn)換,
因?yàn)榧与娗闆r下,我們得通知SPI總線驅(qū)動(dòng),開(kāi)啟蘋果的觸摸板驅(qū)動(dòng),掉電情況做些停止操作處理,
大致如下注冊(cè)電源事件:
//設(shè)置電源回調(diào)函數(shù)
??? WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks);
??? //設(shè)備處于工作(供電D0狀態(tài))或者非工作狀態(tài)
??? pnpPowerCallbacks.EvtDeviceD0Entry = EvtDeviceD0Entry ;// 設(shè)備加電時(shí)候被調(diào)用
??? pnpPowerCallbacks.EvtDeviceD0Exit = EvtDeviceD0Exit;????? // 設(shè)備掉電時(shí)候被調(diào)用
??? WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); ///
然后就是創(chuàng)建過(guò)濾設(shè)備,創(chuàng)建IO隊(duì)列,一共兩個(gè)隊(duì)列,一個(gè)是默認(rèn)的IO隊(duì)列,用于處理 InternalDeviceControl請(qǐng)求,
一個(gè)是手動(dòng)隊(duì)列,我們?cè)谔幚?IOCTL_HID_READ_REPORT時(shí)候,需要入隊(duì)等待處理,
然后就是初始化一些相關(guān)變量等數(shù)據(jù)。
這里我們讀取SPI總線驅(qū)動(dòng)的原始觸摸板數(shù)據(jù),使用的是串行讀取,因此整個(gè)驅(qū)動(dòng)創(chuàng)建一個(gè)全局的Request來(lái)重復(fù)使用,
在InternalDeviceControl 的 IOCTL_HID_GET_DEVICE_DESCRIPTOR,IOCTL_HID_GET_DEVICE_ATTRIBUTES
中我們把事先準(zhǔn)備好的HID的鼠標(biāo)描述符,屬性等信息報(bào)告給classdriver,?
然后接收到 IOCTL_HID_READ_REPORT命令時(shí)候調(diào)用WdfRequestForwardToIoQueue 加到手動(dòng)的IO隊(duì)列。
當(dāng)EvtDeviceD0Entry函數(shù)被調(diào)用(就是設(shè)備加電了),發(fā)起全局的Request對(duì)SPI總線驅(qū)動(dòng)的讀取操作,
同時(shí)設(shè)置這個(gè)Request的完成回調(diào)函數(shù),在完成函數(shù)中分析處理讀取到的觸摸板數(shù)據(jù),處理完成后接著繼續(xù)發(fā)起對(duì)觸摸板數(shù)據(jù)的讀取。
?
更詳細(xì)的請(qǐng)查看稍后發(fā)布到GITHUB和CSDN上的源代碼和驅(qū)動(dòng)程序。
驅(qū)動(dòng)實(shí)現(xiàn)的功能一個(gè)5個(gè)(如上邊所說(shuō))
1,一個(gè)手指按住觸摸板任意位置,另一個(gè)手指移動(dòng)來(lái)達(dá)到拖動(dòng)效果
2,一個(gè)手指輕點(diǎn)或者一個(gè)手指按下觸摸板,模擬鼠標(biāo)左擊
3,兩個(gè)手指輕點(diǎn),或者一個(gè)手指按住觸摸板右邊3/4-4/4位置,模擬鼠標(biāo)右擊
4,雙指同時(shí)移動(dòng)來(lái)模擬滾輪滾動(dòng)
5,三指拖移。
做這個(gè)驅(qū)動(dòng),寫這篇文章的目的就是因?yàn)閙acBook pro 2017版的觸摸板在windows平臺(tái)下難用,
于是決定重新開(kāi)發(fā)macbook pro 2017觸摸板的windows驅(qū)動(dòng)。已經(jīng)開(kāi)發(fā)好的驅(qū)動(dòng)和源代碼下載地址:
GITHUB:?? https://github.com/fanxiushu/kmouse_filter-AppleSPITrack-driver
CSDN:?? http://download.csdn.net/download/fanxiushu/10047600
如下連接,
http://blog.csdn.net/fanxiushu/article/details/78186745
因?yàn)樾陆鼡Q的電腦是macbook pro 2017 13寸帶bar的機(jī)器,其他還能將就,
就是觸摸板難用,動(dòng)不動(dòng)就彈出右鍵菜單,經(jīng)常誤觸,
而且尤其不爽的是拖動(dòng)時(shí)候,必須按住邊緣,另一只手指才能拖動(dòng),
觸摸板這么大,基本無(wú)法單手進(jìn)行拖動(dòng)操作,需要另一個(gè)手的手指按住觸摸板邊緣,然后拖動(dòng)。
雖然可以點(diǎn)擊兩次,第2次不離開(kāi)觸摸板來(lái)拖動(dòng),但是非常不習(xí)慣這種手勢(shì)。
還是習(xí)慣傳統(tǒng)的食指按住觸摸板,中指來(lái)拖動(dòng)(因?yàn)檫@種手勢(shì)更加接近按住鼠標(biāo)左鍵移動(dòng)鼠標(biāo)的效果)。
像我這種經(jīng)常把電腦放到大腿上或者床上的人(反正就是不會(huì)老老實(shí)實(shí)的放到電腦桌上),
如果帶個(gè)鼠標(biāo)是很不方便的,只能依賴觸摸板來(lái)控制電腦。
而且我的要求也不高,不需要什么多手勢(shì),只要觸摸板能盡量模擬鼠標(biāo)的效果就行了。
其實(shí)個(gè)人覺(jué)得windows本身的易操作性,使用鼠標(biāo)的效果就能控制操作系統(tǒng)的所有的東西了,
手勢(shì)多了我也記不住,每次切換不同手勢(shì)還得思考一下也挺累(也許是還沒(méi)習(xí)慣,也懶得去習(xí)慣了)。
基于以上各種原因,于是決定重新開(kāi)發(fā)這款電腦的觸摸板驅(qū)動(dòng)。
首先解釋一下“點(diǎn)按”和”輕點(diǎn)“:
按住或重壓,就是按下去,能聽(tīng)到“噠”的一聲響;
”點(diǎn)按“就是“噠”的一聲按下去然后立馬彈上來(lái),
還有一個(gè)就是”輕點(diǎn)“,就是手指接觸到觸摸板然后迅速離開(kāi)。
我需要達(dá)到的效果也非常簡(jiǎn)單明了,用兩根手指模擬鼠標(biāo)效果,操作整個(gè)系統(tǒng)。
1,首先一根手指按住觸摸板的任意位置(是任意位置而不是觸摸板邊緣),另一根手指在觸摸板上移動(dòng)來(lái)達(dá)到拖動(dòng)效果,
這就相當(dāng)于按住鼠標(biāo)左鍵,移動(dòng)鼠標(biāo)的效果一樣。
2,一根手指輕點(diǎn),相當(dāng)于鼠標(biāo)左鍵按下去然后立馬彈上來(lái)。
???? 一根手指按住觸摸板,相當(dāng)于按下鼠標(biāo)左鍵,從觸摸板彈上來(lái)相當(dāng)于彈出左鍵。
3,兩根手指同時(shí)輕點(diǎn),相當(dāng)于鼠標(biāo)右鍵按下去然后立馬彈上來(lái)。
???? 一根手指按住觸摸板右邊四分之三到四分之四部分(是整個(gè)右邊3/4,而不是右下邊緣),相當(dāng)于按住鼠標(biāo)右鍵。
4,兩根手指同時(shí)在觸摸板移動(dòng),相當(dāng)于滾輪滾動(dòng)。
5,另外再附加實(shí)現(xiàn)一個(gè)功能:三指拖移。等于是第1個(gè)功能的效果:一個(gè)手指按住,另一個(gè)手指移動(dòng)。
????? 這樣不重壓觸摸板的也能操作整個(gè)系統(tǒng)。
不模擬鼠標(biāo)的中間鍵按下效果,好像中間鍵沒(méi)啥用處。
以上就是我的簡(jiǎn)單明了的要求,當(dāng)然習(xí)慣各種手勢(shì)的你可能并不贊同,甚至有點(diǎn)嗤之以鼻,然而這依然是我的簡(jiǎn)單明了的要求。
重新開(kāi)發(fā)的觸摸板驅(qū)動(dòng)也只實(shí)現(xiàn)上邊的功能而已。
要重新開(kāi)發(fā)macbook pro 2017年 13寸帶bar(以下簡(jiǎn)稱mbp2017)的觸摸板的windows驅(qū)動(dòng),
首先需要解決兩件事:
一,采集mbp2017的觸摸板數(shù)據(jù),
二,模擬開(kāi)發(fā)鼠標(biāo)驅(qū)動(dòng)。
第二個(gè)問(wèn)題100%的確保能解決,使用HID模式的鼠標(biāo)驅(qū)動(dòng)就可以了。
關(guān)鍵是第一個(gè)問(wèn)題,如果不能采集和解析觸摸板的數(shù)據(jù),基本就沒(méi)戲了,只能老老實(shí)實(shí)的使用那個(gè)難用的原裝驅(qū)動(dòng)程序。
mbp2017的觸摸板數(shù)據(jù)結(jié)構(gòu)格式是沒(méi)有公開(kāi)的,而且未來(lái)也很可能被蘋果公司改變,因此沒(méi)有通用性,
我測(cè)試的對(duì)應(yīng)bootcamp版本是 6.1.6813,對(duì)應(yīng)的觸摸板總線驅(qū)動(dòng)的驅(qū)動(dòng)日期是 2016/05/26, 版本 6.1.6500.0,
其他版本的沒(méi)測(cè)試過(guò),所以不知道的數(shù)據(jù)格式是不是不同。
既然這個(gè)數(shù)據(jù)沒(méi)有公開(kāi),我們就必須要自己來(lái)采集和分析觸摸板的數(shù)據(jù),
好在觸摸板這類設(shè)備本身的數(shù)據(jù)量不大,數(shù)據(jù)結(jié)構(gòu)也應(yīng)該不會(huì)多復(fù)雜,只要Apple公司沒(méi)變態(tài)到做加密,估計(jì)是能解析出來(lái)的。
自己動(dòng)手解析之前,先要搞清楚它的驅(qū)動(dòng)運(yùn)行流程。
蘋果使用的SPI總線來(lái)傳輸觸摸板和鍵盤的數(shù)據(jù),SPI總線接口,也是我在接觸mbp2017時(shí)候才發(fā)現(xiàn)還有這么一個(gè)玩意,真是孤陋寡聞了。
SPI 全稱Serial Peripheral Interface--串行外設(shè)接口, 最初是Motorola提出和開(kāi)發(fā)的,它使用主從模式通訊,這點(diǎn)跟USB有點(diǎn)像,
同時(shí)通訊也很簡(jiǎn)單,比RS232(串口)還簡(jiǎn)單,所以不論軟件或硬件成本都比較低。
但是應(yīng)付鍵盤和觸摸板這類不需要大量通訊數(shù)據(jù)的器件完全足夠了。更詳細(xì)的關(guān)于SPI介紹,請(qǐng)查詢其他資料。
mbp2017的電腦windows驅(qū)動(dòng)中關(guān)于SPI的,首先有個(gè)SPI總線驅(qū)動(dòng),在SPI總線驅(qū)動(dòng)下掛載兩個(gè)位置,
位置1是鍵盤驅(qū)動(dòng),位置2才是觸摸板驅(qū)動(dòng)。詳細(xì)可看下邊的圖示:
畫(huà)紅線的部分,在”系統(tǒng)設(shè)備“里邊的 “Apple SPI Device ” 就是總線驅(qū)動(dòng),它負(fù)責(zé)給鍵盤和觸摸板的功能驅(qū)動(dòng)提供數(shù)據(jù),
在“人體學(xué)輸入設(shè)備”里邊的“ Apple SPI Keyboard” 和 “ Apple SPI Trackpad” 對(duì)應(yīng)的就是 鍵盤的功能驅(qū)動(dòng)和觸摸板的功能驅(qū)動(dòng),
再看“Apple SPI Trackpad” 的屬性, 它在總線驅(qū)動(dòng)的位置是 2, 我們要做的事情,就是替換這個(gè)功能驅(qū)動(dòng),使用我們自己開(kāi)發(fā)的驅(qū)動(dòng)來(lái)代替。
另外我們順便看看這款電腦內(nèi)置的USB接口的設(shè)備,
上邊的藍(lán)線部分,在 “通用串行總線控制器” 里邊存在一個(gè)“Apple USB Composite Device”的復(fù)合設(shè)備,
這個(gè)復(fù)合設(shè)備管理著三個(gè)設(shè)備,“Apple Touch Bar”就是其中一個(gè),這個(gè)就是multi-touch bar, 在windows平臺(tái)下沒(méi)啥用的雞肋。
另外兩個(gè)看下圖所示:
Apple USB Composite Device一共包含三個(gè)設(shè)備:
FaceTime HD Camera,
Apple Touch Bar,
USB接口的光感氛圍器,就是檢測(cè)環(huán)境光線強(qiáng)弱,從而自動(dòng)調(diào)節(jié)屏幕的亮度。
看圖示的最下邊, bNumConfigurations 是 3, 也就是三個(gè)配置描述符,分別對(duì)應(yīng)這三種設(shè)備。
正如上篇文章所說(shuō)的,在單純只安裝windows系統(tǒng)的時(shí)候,這個(gè)“Apple USB Composite Device” 設(shè)備不能被發(fā)現(xiàn),
從而造成 攝像頭,multi-touch bar,和光感器件找不到,也不知道蘋果在設(shè)計(jì)硬件的時(shí)候搞了什么。
估計(jì)得保留安裝蘋果系統(tǒng)時(shí)候的那個(gè)EFI Parttion 分區(qū),才能被識(shí)別,只是后來(lái)沒(méi)再折騰了,保留了MacOS系統(tǒng)。
再回到觸摸板驅(qū)動(dòng),我們打開(kāi)注冊(cè)表,在 如下的位置:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\SPI\VID_05ac&PID_0277&MI_02
能找到這個(gè)驅(qū)動(dòng)的安裝信息,
注意:mbp2017 對(duì)應(yīng)的觸摸板的PID是0277, VID是05ac, 不同型號(hào)的,可能PID會(huì)不同,這個(gè)得看具體機(jī)器。
如上圖所示,在里邊的LowerFilters字段里是 蘋果的 AppleSPITrackpad驅(qū)動(dòng),
Service字段是 mshidkmdf ,從這信息,
我們立馬就知道 AppleSPITrackpad 是一個(gè)KMDF模型的驅(qū)動(dòng)程序,并且屬于標(biāo)準(zhǔn)的HID的KMDF程序。
AppleSPITrackpad負(fù)責(zé)獲取上邊提到的 “Apple SPI Device" 總線驅(qū)動(dòng)發(fā)上來(lái)的觸摸板數(shù)據(jù),
并且解析模擬成標(biāo)準(zhǔn)的兼容windows的 HID鼠標(biāo)驅(qū)動(dòng)數(shù)據(jù)。
AppleSPITrackpad在解析觸摸板數(shù)據(jù)時(shí)候,提供了讓人難以適應(yīng)(至少我比較難適應(yīng))的鼠標(biāo)動(dòng)作模擬,
因此重新開(kāi)發(fā)這個(gè)驅(qū)動(dòng)來(lái)解決這個(gè)問(wèn)題。
至此,我們大致知道他們的驅(qū)動(dòng)的工作流程了。
現(xiàn)在的任務(wù)首先就是獲取SPI總線驅(qū)動(dòng)發(fā)上來(lái)的數(shù)據(jù)結(jié)構(gòu)格式。
可以開(kāi)發(fā)一個(gè)簡(jiǎn)單的WDM 過(guò)濾驅(qū)動(dòng),掛載到 LowerFilters字段里邊的 AppleSPITrackpad 前邊。
這樣AppleSPITrackpad跟SPI總線驅(qū)動(dòng)通訊的所有IRP請(qǐng)求都能被截獲到,從而就能獲取到觸摸板數(shù)據(jù)。
WDM Filter的開(kāi)發(fā)可以查看我很早前的一篇文章:
http://blog.csdn.net/fanxiushu/article/details/8834385
當(dāng)然如果你能找到其他現(xiàn)成的工具來(lái)分析AppleSPITrackpad的通訊數(shù)據(jù),會(huì)更快捷。
通過(guò)分析,AppleSPITrackpad發(fā)給SPI總線驅(qū)動(dòng)四個(gè)請(qǐng)求:
IOCTL_HID_GET_DEVICE_DESCRIPTOR
IOCTL_HID_GET_DEVICE_ATTRIBUTES
IOCTL_HID_SET_FEATURE
IOCTL_HID_READ_REPORT
都是標(biāo)準(zhǔn)的HID請(qǐng)求命令,其中IOCTL_HID_SET_FEATURE 應(yīng)該是用于告訴SPI總線驅(qū)動(dòng)開(kāi)啟或者關(guān)閉觸摸板功能的。
最主要的就是 IOCTL_HID_READ_REPORT命令,這個(gè)就是獲取觸摸板數(shù)據(jù)。
分析在 bootcamp版本是 6.1.6813,對(duì)應(yīng)的觸摸板SPI總線驅(qū)動(dòng)的驅(qū)動(dòng)日期是 2016/05/26, 版本 6.1.6500.0,
(這里再次提到版本和日期,因?yàn)椴煌姹竞芸赡苁遣煌臄?shù)據(jù)格式,由于本人就一臺(tái)mac機(jī)器,無(wú)法測(cè)試其他情況)
數(shù)據(jù)格式結(jié)構(gòu)大致如下:
前46個(gè)字節(jié)是格式頭,接著每個(gè)手指占據(jù)30個(gè)字節(jié)。
比如 一個(gè)手指在觸摸板上,IOCTL_HID_READ_REPORT獲取到的數(shù)據(jù)長(zhǎng)度是46 + 30 = 76個(gè)字節(jié),
如果是兩個(gè)手指在觸摸板,IOCTL_HID_READ_REPORT獲取的長(zhǎng)度是 46 + 30*2 = 106字節(jié),以此類推。
前46個(gè)字節(jié)描述成c語(yǔ)言數(shù)據(jù)結(jié)構(gòu)大致如下:
typedef unsigned char????????????? u8;
46 length
struct tp_protocol
{
??? u8????????????????? type;????? // unknown type? =2
??? u8????????????????? clicked;?? // 按住了觸摸板, 不管幾個(gè)按住,都是 1
??? u8????????????????? unknown1[5]; //
??? u8????????????????? is_finger;?? // 觸摸板有手指 1,當(dāng)離開(kāi)瞬間,出現(xiàn) 0
??? u8????????????????? unknown2[8]; //
??? u8????????????????? unknown3[8]; // 未知,固定 00-01-07-97-02-00-06-00
??? u8????????????????? finger_data_length; // 手指數(shù)據(jù)總長(zhǎng)度, 手指?jìng)€(gè)數(shù)*30
??? u8????????????????? unknown4[5]; //
??? u8????????????????? finger_number; //手指?jìng)€(gè)數(shù)
??? u8????????????????? Clicked; // 同上邊的clicked
??? u8????????????????? state;?? // 手指在上邊好像是 0x10, 手指離開(kāi)瞬間最高設(shè)置 1,變成 0x80(0x90),最后離開(kāi)后,還會(huì)出現(xiàn) 0x00
??? u8????????????????? state2;? // 手指在上邊 0x20,離開(kāi)瞬間 變 0
??? u8????????????????? state3;? // 平時(shí)0, Clicked為 0x10
??? u8????????????????? zero;??? // 始終 0
??? u8????????????????? unknown5[10]; /
};
如上所示,其中unknown字段是 沒(méi)能解析出來(lái)的,不過(guò)后來(lái)發(fā)現(xiàn)就已知的字段已經(jīng)足夠模擬鼠標(biāo)動(dòng)作了。
手指的30個(gè)字節(jié)的c語(yǔ)言結(jié)構(gòu)如下:
/ 30 length
struct tp_finger
{
??? short???????????? org_x; //按下后,這個(gè)數(shù)字不變,
??? short???????????? org_y; //
??? short???????????? x;???? //隨著手指移動(dòng)改變,
??? short???????????? y;???? //
??? short ?????????? unknown[11];
};
其中unknown未知,org_x,org_y好像沒(méi)啥用,最有用的是 x,y。表示的是手指在觸摸板的坐標(biāo)位置。
整個(gè)觸摸板(13寸機(jī)器)測(cè)試下來(lái),觸摸板范圍,最左邊大致是 -6300多, 左右邊坐標(biāo) 6800多,
最上邊坐標(biāo)7700左右,最下邊-200左右。這些都是用手指移動(dòng)到邊界得出來(lái)的大致數(shù)據(jù)。
有了這些原始的觸摸板的數(shù)據(jù),我們基本就能確定能實(shí)現(xiàn)自己的mbp2017的觸摸板驅(qū)動(dòng)來(lái)模擬鼠標(biāo)操作了。
/
再來(lái)看看windows平臺(tái)下的HID驅(qū)動(dòng)開(kāi)發(fā)過(guò)程,
HID(Human Interface Device,人機(jī)接口設(shè)備)是一類設(shè)備總稱,用于提供人和電腦進(jìn)行交互的接口設(shè)備,
像最常用的鼠標(biāo),鍵盤等,觸摸板,還有游戲使用的游戲桿等等。
像鼠標(biāo)鍵盤都是windows提供的標(biāo)準(zhǔn)驅(qū)動(dòng),我們?cè)陂_(kāi)發(fā)HID驅(qū)動(dòng)時(shí)候,填寫適當(dāng)?shù)腍ID描述符,
告訴windows我們開(kāi)發(fā)的是一個(gè)HID的鼠標(biāo)或者HID鍵盤,windows自動(dòng)就會(huì)給我們加載兼容的鼠標(biāo)鍵盤驅(qū)動(dòng)。
同時(shí)我們?cè)谧约旱腍ID驅(qū)動(dòng)開(kāi)發(fā)中正確響應(yīng) IOCTL_HID_XXX事件(主要是IOCTL_HID_READ_REPORT)
這個(gè)鼠標(biāo)鍵盤就能正常工作起來(lái)。看起來(lái)是非常簡(jiǎn)單明了的。確實(shí)也是如此。
比如我們要虛擬鼠標(biāo)鍵盤,也使用HID來(lái)開(kāi)發(fā),比起掛鉤什么PS/2或者HOOK之類的做法,也顯得簡(jiǎn)單和穩(wěn)定得多,
這個(gè)在以后開(kāi)發(fā)的博客中會(huì)繼續(xù)闡述。
我們先看看WDM模型的HID開(kāi)發(fā)過(guò)程,
首先在 DriverEntry中注冊(cè)
IRP_MJ_INTERNAL_DEVICE_CONTROL, IRP_MJ_POWER, IRP_MJ_PNP 三個(gè)派遣函數(shù),
然后填寫 HID_MINIDRIVER_REGISTRATION 結(jié)構(gòu)的參數(shù),調(diào)用HidRegisterMinidriver注冊(cè)HID的小端口驅(qū)動(dòng),
這樣總體框架就建立起來(lái)了。
然后在 IRP_MJ_POWER和IRP_MJ_PNP派遣函數(shù)中,按部就班的實(shí)現(xiàn)電源管理和即插即用事件,
如果是真實(shí)HID設(shè)備,則要認(rèn)真實(shí)現(xiàn)這兩個(gè)功能,如果是虛擬設(shè)備,則不用太在意,找個(gè)現(xiàn)成框架套上去就行,
接著就是核心處理事件 IRP_MJ_INTERNAL_DEVICE_CONTROL,
在這個(gè)派遣函數(shù)中,一般處理
IOCTL_HID_GET_DEVICE_DESCRIPTOR
IOCTL_HID_GET_DEVICE_ATTRIBUTES
IOCTL_HID_READ_REPORT
三個(gè)事件就能讓鼠標(biāo)鍵盤跑起來(lái),當(dāng)然處理的越多,功能越完善,但是HID的IOCTL命令也多不多到哪去。
是的,就是這么簡(jiǎn)單的框架,
但是在這里,我們不打算使用WDM的框架,而使用的是 KMDF(WDF的內(nèi)核部分,就是對(duì)WDM的封裝 )來(lái)開(kāi)發(fā)。
KMDF就更加省事了,連 PNP和POWER也省略了,就只要關(guān)心 IRP_MJ_INTERNAL_DEVICE_CONTROL 就可以了。
但是正如微軟自己所說(shuō),他們的WDF框架跟HID的minidriver小端口驅(qū)動(dòng)在某些IO請(qǐng)求中存在沖突(IRP_MJ_POWER和IRP_MJ_PNP)
因此WDF框架不能直接橋接 HID的class driver和mini driver,他們使用了一個(gè)折中方案,
開(kāi)發(fā)一個(gè) mshidkmdf的驅(qū)動(dòng)來(lái)橋接WDF框架和classdriver,在此驅(qū)動(dòng)中調(diào)用HidRegisterMinidriver 來(lái)注冊(cè)HID小端口驅(qū)動(dòng),
并且mshidkmdf作為服務(wù)安裝,而 我們開(kāi)發(fā)的HID驅(qū)動(dòng)則作為L(zhǎng)owerFilters來(lái)安裝。詳細(xì)可查看如下鏈接:
?https://msdn.microsoft.com/en-us/library/windows/hardware/ff540774
?這就是我們?yōu)楹卧谏厦娴膱D中看到蘋果的 AppleSPItrackpad觸摸板驅(qū)動(dòng)變成了 Lowerfilters 的底層過(guò)濾驅(qū)動(dòng)了。
最后看看我們開(kāi)發(fā)KMDF模型的這款觸摸板驅(qū)動(dòng)的流程:
首先在DriverEntry中,配置好參數(shù),這里主要關(guān)心的是 EvtDeviceAdd 函數(shù),
調(diào)用WdfDriverCreate 來(lái)初始化框架。
在EvtDeviceAdd 函數(shù)中,首先調(diào)用WdfFdoInitSetFilter 表明我們開(kāi)發(fā)的是一個(gè)過(guò)濾驅(qū)動(dòng)。
然后調(diào)用WdfDeviceInitAssignWdmIrpPreprocessCallback 注冊(cè)IRP_MN_QUERY_ID這個(gè)特殊查詢事件,
因?yàn)槲覀儽仨氝@么做,才能讓windows識(shí)別到我們的驅(qū)動(dòng)ID,
對(duì)應(yīng)這塊觸摸板,我們還得注冊(cè)兩個(gè)電源事件,就是D0狀態(tài)(加電和掉電)轉(zhuǎn)換,
因?yàn)榧与娗闆r下,我們得通知SPI總線驅(qū)動(dòng),開(kāi)啟蘋果的觸摸板驅(qū)動(dòng),掉電情況做些停止操作處理,
大致如下注冊(cè)電源事件:
//設(shè)置電源回調(diào)函數(shù)
??? WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks);
??? //設(shè)備處于工作(供電D0狀態(tài))或者非工作狀態(tài)
??? pnpPowerCallbacks.EvtDeviceD0Entry = EvtDeviceD0Entry ;// 設(shè)備加電時(shí)候被調(diào)用
??? pnpPowerCallbacks.EvtDeviceD0Exit = EvtDeviceD0Exit;????? // 設(shè)備掉電時(shí)候被調(diào)用
??? WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); ///
然后就是創(chuàng)建過(guò)濾設(shè)備,創(chuàng)建IO隊(duì)列,一共兩個(gè)隊(duì)列,一個(gè)是默認(rèn)的IO隊(duì)列,用于處理 InternalDeviceControl請(qǐng)求,
一個(gè)是手動(dòng)隊(duì)列,我們?cè)谔幚?IOCTL_HID_READ_REPORT時(shí)候,需要入隊(duì)等待處理,
然后就是初始化一些相關(guān)變量等數(shù)據(jù)。
這里我們讀取SPI總線驅(qū)動(dòng)的原始觸摸板數(shù)據(jù),使用的是串行讀取,因此整個(gè)驅(qū)動(dòng)創(chuàng)建一個(gè)全局的Request來(lái)重復(fù)使用,
在InternalDeviceControl 的 IOCTL_HID_GET_DEVICE_DESCRIPTOR,IOCTL_HID_GET_DEVICE_ATTRIBUTES
中我們把事先準(zhǔn)備好的HID的鼠標(biāo)描述符,屬性等信息報(bào)告給classdriver,?
然后接收到 IOCTL_HID_READ_REPORT命令時(shí)候調(diào)用WdfRequestForwardToIoQueue 加到手動(dòng)的IO隊(duì)列。
當(dāng)EvtDeviceD0Entry函數(shù)被調(diào)用(就是設(shè)備加電了),發(fā)起全局的Request對(duì)SPI總線驅(qū)動(dòng)的讀取操作,
同時(shí)設(shè)置這個(gè)Request的完成回調(diào)函數(shù),在完成函數(shù)中分析處理讀取到的觸摸板數(shù)據(jù),處理完成后接著繼續(xù)發(fā)起對(duì)觸摸板數(shù)據(jù)的讀取。
?
更詳細(xì)的請(qǐng)查看稍后發(fā)布到GITHUB和CSDN上的源代碼和驅(qū)動(dòng)程序。
驅(qū)動(dòng)實(shí)現(xiàn)的功能一個(gè)5個(gè)(如上邊所說(shuō))
1,一個(gè)手指按住觸摸板任意位置,另一個(gè)手指移動(dòng)來(lái)達(dá)到拖動(dòng)效果
2,一個(gè)手指輕點(diǎn)或者一個(gè)手指按下觸摸板,模擬鼠標(biāo)左擊
3,兩個(gè)手指輕點(diǎn),或者一個(gè)手指按住觸摸板右邊3/4-4/4位置,模擬鼠標(biāo)右擊
4,雙指同時(shí)移動(dòng)來(lái)模擬滾輪滾動(dòng)
5,三指拖移。
如果你已經(jīng)適應(yīng)了蘋果的觸摸板windows的手勢(shì)行為,則無(wú)需留意本文的內(nèi)容。
總結(jié)
以上是生活随笔為你收集整理的MacBook Pro 2017 13寸版 触摸板windows驱动开发(开发HID鼠标键盘驱动之一)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: showdialog 尝试读取或写入受保
- 下一篇: 王者荣耀虚拟服务器设置方法,《王者荣耀》