版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、驅(qū)動(dòng)程序設(shè)計(jì) 課程大作業(yè)驅(qū)動(dòng)程序設(shè)計(jì)課程大作業(yè)鍵盤過濾驅(qū)動(dòng)程序設(shè)計(jì)班級(jí):姓名: 學(xué)號(hào):2009年2月11日一、主要設(shè)計(jì)思路目標(biāo):鍵盤過濾驅(qū)動(dòng)。利用驅(qū)動(dòng)分層機(jī)制,使用過濾驅(qū)動(dòng)捕獲鍵盤的掃描碼并保存下來;應(yīng)用程序定時(shí)訪問驅(qū)動(dòng)程序取回掃描碼,轉(zhuǎn)換成相應(yīng)的按鍵名稱并顯示;通過應(yīng)用程序設(shè)定按鍵映射,應(yīng)用程序?qū)⒅噶顐魉徒o驅(qū)動(dòng)程序,以實(shí)現(xiàn)將指定的按鍵消息轉(zhuǎn)換成其他按鍵。應(yīng)用程序驅(qū)動(dòng)程序顯示按鍵設(shè)置映射讀掃描碼設(shè)置映射捕獲掃描碼 鍵盤過濾驅(qū)動(dòng)是工作在異步模式下的。系統(tǒng)為了得到一個(gè)按鍵操作,首先要發(fā)送一個(gè)irp_mj_read消息到驅(qū)動(dòng)的設(shè)備棧,驅(qū)動(dòng)收到這個(gè)irp后,會(huì)一直保持這個(gè)irp為未確定(pending
2、)態(tài),因?yàn)楫?dāng)時(shí)并沒有按鍵操作。直到一個(gè)鍵被真正的按下,驅(qū)動(dòng)此時(shí)就會(huì)立刻完成這個(gè)irp,并將剛按下的鍵的相關(guān)數(shù)據(jù)做為該irp的返回值。在該irp帶著對(duì)應(yīng)的數(shù)據(jù)返回后,操作系統(tǒng)將這些值傳遞給對(duì)應(yīng)的事件系統(tǒng)來處理,然后系統(tǒng)緊接著又會(huì)立刻發(fā)送一個(gè)irp_mj_read請(qǐng)求,等待下次的按鍵操作,重復(fù)以上的步驟。為了實(shí)現(xiàn)截獲鍵盤消息,需要在過濾驅(qū)動(dòng)程序中創(chuàng)建一個(gè)掛接到物理鍵盤設(shè)備上層的過濾驅(qū)動(dòng)設(shè)備。系統(tǒng)發(fā)送的irp_mj_read消息會(huì)首先到達(dá)過濾驅(qū)動(dòng)設(shè)備,這樣就可以有機(jī)會(huì)給irp_mj_read設(shè)置指定的完成例程,然后將消息下傳給物理鍵盤設(shè)備。當(dāng)有按鍵動(dòng)作發(fā)生時(shí),irp_mj_read消息在完成后就會(huì)調(diào)
3、用指定的完成例程,這時(shí)就可以在完成例程中讀出鍵盤動(dòng)作的內(nèi)容,或者修改這些信息,以實(shí)現(xiàn)按鍵的映射。鍵盤設(shè)備過濾設(shè)備irp_mj_read設(shè)置完成例程完成讀掃描碼標(biāo)準(zhǔn)的按鍵掃描碼和ascii碼沒有直接的對(duì)應(yīng)關(guān)系,大部分按鍵的掃描碼為一個(gè)字節(jié);部分功能鍵為兩個(gè)字節(jié),且都以0xe0為高字節(jié)。但實(shí)驗(yàn)中發(fā)現(xiàn),irp中返回的按鍵信息和標(biāo)準(zhǔn)的掃描碼并不全等。在keyboard_input_data結(jié)構(gòu)中,makecode字段僅包含了一個(gè)字節(jié)的編碼,還要同時(shí)參照flags字段的內(nèi)容才能判斷出按鍵的掃描碼。下表是keyboard_input_data結(jié)構(gòu)中兩個(gè)字段的內(nèi)容與其所代表的按鍵動(dòng)作的對(duì)應(yīng)關(guān)系。當(dāng)flags
4、=0或1時(shí),說明按下的按鍵是掃描碼為一個(gè)字節(jié)的按鍵;若flags=2或3,則說明按下的是掃描碼為兩個(gè)字節(jié)的按鍵,而makecode中只保留掃描碼的低字節(jié)。flagsmakecode動(dòng)作0等于掃描碼按下1等于掃描碼松開2掃描碼的低字節(jié)按下3掃描碼的低字節(jié)松開若使用指定的內(nèi)容改寫返回值中的keyboard_input_data結(jié)構(gòu),就可以改變按鍵的作用,實(shí)現(xiàn)按鍵映射的功能。除了irp_mj_read以外,對(duì)于其他發(fā)送給鍵盤設(shè)備的消息,到達(dá)過濾驅(qū)動(dòng)設(shè)備時(shí)就可以不做處理,直接下傳給鍵盤設(shè)備,以保證系統(tǒng)的正常工作。在完成例程中將每次捕獲得到的掃描碼保存起來,應(yīng)用程序每隔一定的時(shí)間(100ms)讀取一次并
5、將其清空,再根據(jù)掃描碼查表得到相應(yīng)按鍵的名稱,這樣就可以做到在應(yīng)用程序中實(shí)時(shí)的顯示鍵盤動(dòng)作。用戶在應(yīng)用程序中設(shè)定好按鍵映射的對(duì)應(yīng)關(guān)系后,可以通過irp_mj_device_control消息將映射關(guān)系發(fā)送給過濾驅(qū)動(dòng)程序,還是在完成例程中實(shí)現(xiàn)按鍵的映射替代。2、 模塊的劃分、實(shí)現(xiàn)及說明具體實(shí)現(xiàn)分為驅(qū)動(dòng)程序和應(yīng)用程序兩大部分。驅(qū)動(dòng)程序用c和windowsxp ddk實(shí)現(xiàn),應(yīng)用程序通過vc+ 6.0基于mfc實(shí)現(xiàn)。在調(diào)試和測(cè)試中使用了drivermonitor和dbgview等工具。下面分別介紹其中主要部分的實(shí)現(xiàn):(一)驅(qū)動(dòng)程序部分1. device_extension的定義/定義設(shè)備擴(kuò)展對(duì)象typ
6、edef struct _device_extension pdriver_object pdriver;/對(duì)應(yīng)的驅(qū)動(dòng)pdevice_object pdevice;/驅(qū)動(dòng)對(duì)應(yīng)的設(shè)備對(duì)象pdevice_object pkbdevice;/掛接到的鍵盤設(shè)備unicode_string ustrdevicename;/設(shè)備名稱unicode_string ustrsymlinkname;/符號(hào)鏈接名ulong irppendingcount;/運(yùn)行中的irp數(shù)量ulong lastscancode;/最近獲得的鍵盤掃描碼ulong setcode2;/按鍵映射規(guī)則:setcode0->setc
7、ode1 device_extension, *pdevice_extension;2. driverentry主要任務(wù)是填寫majorfunction數(shù)組、設(shè)置卸載例程,并調(diào)用createdevice函數(shù)。對(duì)所關(guān)心的一些消息分別設(shè)置回調(diào)函數(shù),為其他消息設(shè)置通用處理函數(shù)。/通用事件處理例程for (i=0; i<=irp_mj_maximum_function;i+)pdriverobject->majorfunctioni = keyfilter_dispatchgeneral;/指定卸載驅(qū)動(dòng)例程pdriverobject->driverunload = keyfilter
8、_unload;/捕獲irp_mj_read消息pdriverobject->majorfunctionirp_mj_read = keyfilter_dispatchread;/與應(yīng)用程序通訊pdriverobject->majorfunctionirp_mj_device_control = keyfilter_deviceiocontrol;pdriverobject->majorfunctionirp_mj_create = keyfilter_onfilecreate;pdriverobject->majorfunctionirp_mj_close = key
9、filter_onclose;3. dispatchgeneral對(duì)于不關(guān)心的那些消息,返回成功值并傳遞給下一層的鍵盤設(shè)備,本層不作處理。/將消息傳遞到下一個(gè)單元iocopycurrentirpstacklocationtonext(pirp);/將irp下發(fā)給鍵盤設(shè)備status = iocalldriver(pdevext->pkbdevice, pirp);return status;4. createdevice建立設(shè)備對(duì)象,初始化device_extension結(jié)構(gòu),建立符號(hào)鏈接,將過濾驅(qū)動(dòng)設(shè)備掛接到物理鍵盤設(shè)備之上。/設(shè)備名稱rtlinitunicodestring(&
10、;devname, l"devicekeyfilterdriver");/要掛接的設(shè)備rtlinitunicodestring(&hookdevname, l"devicekeyboardclass0");/符號(hào)鏈接rtlinitunicodestring(&symlinkname,l"?keyfilterdriver");/建立鍵盤類設(shè)備status = iocreatedevice(pdriverobject,/驅(qū)動(dòng)程序?qū)ο髎izeof(device_extension),/要求的設(shè)備擴(kuò)展的大小&devna
11、me,/設(shè)備名稱file_device_keyboard,/設(shè)備的類型0,/指示可刪除介質(zhì)、只讀等。false,/非獨(dú)占訪問方式&hookpdeviceobject);/返回的設(shè)備對(duì)象if(!nt_success(status)/創(chuàng)建設(shè)備失敗,輸出調(diào)試信息dbgprint("keyfilter: keyboard hook failed to create device!n");return status;/對(duì)設(shè)備進(jìn)行必要的初始化hookpdeviceobject->flags |= do_buffered_io;pdevext = (pdevice_exte
12、nsion)hookpdeviceobject->deviceextension;pdevext->pdevice = hookpdeviceobject;pdevext->pdriver = pdriverobject;pdevext->ustrdevicename = devname;pdevext->ustrsymlinkname = symlinkname;pdevext->irppendingcount = 0;pdevext->setcode0 = pdevext->setcode1 = 0;/掛接過濾設(shè)備到devicekeyboar
13、dclass0設(shè)備的上層status = ioattachdevice(hookpdeviceobject, &hookdevname, &kbddevice);if(!nt_success(status)/連接失敗,輸出調(diào)試信息dbgprint("keyfilter: connect with keyboard failed!n");/刪除設(shè)備iodeletedevice(hookpdeviceobject);return status;pdevext->pkbdevice = kbddevice;/創(chuàng)建符號(hào)鏈接status = iocreatesy
14、mboliclink(&symlinkname,&devname);if(!nt_success(status)dbgprint("keyfilter: create symboliclink failed!n");iodeletedevice(hookpdeviceobject);return status;5. dispatchread在收到irp_mj_read的irp后,為其設(shè)置指定的完成例程readcomplete,然后再將irp發(fā)送給物理鍵盤設(shè)備。/獲取當(dāng)前irp包堆棧指針currentirpstack = iogetcurrentirpstac
15、klocation(pirp);/傳遞到下一個(gè)單元iocopycurrentirpstacklocationtonext(pirp);/設(shè)置完成例程iosetcompletionroutine(pirp, keyfilter_readcomplete, pdeviceobject, true, true, true);/將irp下發(fā)給鍵盤設(shè)備status = iocalldriver(pdevext->pkbdevice, pirp);6. readcomplete在irp完成時(shí)會(huì)調(diào)用readcomplete例程,此時(shí)用keyboard_input_data結(jié)構(gòu)讀取irp中的返回值,得到
16、按鍵事件的掃描碼并保存。同時(shí)若符合按鍵映射規(guī)則,則改寫irp中的返回值,實(shí)現(xiàn)按鍵的替換。/獲取當(dāng)前irp包堆棧指針pirpsp = iogetcurrentirpstacklocation(pirp);if(nt_success(pirp->iostatus.status)/獲得按鍵數(shù)據(jù)keydata = pirp->associatedirp.systembuffer;dbgprint("flag: %d code:0x%04xn", keydata->flags,keydata->makecode);/根據(jù)flags和makecode字段生成掃描
17、碼switch(keydata->flags)case 0:case 1:keycode = keydata->makecode;break;case 2:case 3:keycode = 0xe000 + keydata->makecode;break;case 4:case 5:keycode = 0xe100 + keydata->makecode;break;default:keycode = 0;break;/實(shí)現(xiàn)按鍵映射if(keycode = pdevext->setcode0)keycode = pdevext->setcode1;/寫回ir
18、pkeydata->makecode = (ushort)keycode;/只記錄鍵盤按下事件if(keydata->flags=0 | keydata->flags=2 | keydata->flags=4)pdevext->lastscancode = keycode;7. deviceiocontrol實(shí)現(xiàn)與應(yīng)用程序之間的通信。當(dāng)應(yīng)用程序通過deviceiocontrol讀掃描碼時(shí),利用irp中的iostatus.information字段返回一個(gè)ulong類型的掃描碼。當(dāng)應(yīng)用程序設(shè)定按鍵映射規(guī)則時(shí),同樣使用deviceiocontrol通過系統(tǒng)內(nèi)存緩沖區(qū)傳
19、遞兩個(gè)ulong型的掃描碼到pdevext->setcode數(shù)組中。/得到當(dāng)前堆棧currentirpstack = iogetcurrentirpstacklocation(pirp);/得到控制碼iocontrolcode = currentirpstack->parameters.deviceiocontrol.iocontrolcode;switch (iocontrolcode)case read_scancode:/讀掃描碼if(pdevext->lastscancode)dbgprint("read_scancode 0x%04xn",pde
20、vext->lastscancode);info = pdevext->lastscancode;pdevext->lastscancode = 0;break;case set_code:/設(shè)定按鍵映射pbuffer = (ulong *)pirp->associatedirp.systembuffer;pdevext->setcode0 = *pbuffer;pbuffer+;pdevext->setcode1 = *pbuffer;info = 1;break;/完成irpstatus = status_success;pirp->iostatu
21、s.status = status;pirp->iostatus.information = info;iocompleterequest(pirp, io_no_increment);return status;(2) 應(yīng)用程序部分使用mfc實(shí)現(xiàn)應(yīng)用界面,在程序啟動(dòng)時(shí)打開過濾驅(qū)動(dòng)設(shè)備。/打開設(shè)備m_hdevice = createfile(".keyfilterdriver",generic_read | generic_write,0,null,open_existing,file_attribute_normal,null);if (m_hdevice = in
22、valid_handle_value)cstring str;str.format("獲得設(shè)備驅(qū)動(dòng)句柄失敗,錯(cuò)誤代碼:%d", getlasterror();messagebox(str, "錯(cuò)誤");exit(0);開辟新的工作線程,實(shí)現(xiàn)定時(shí)(100ms)讀取捕獲到的鍵盤掃描碼,將掃描碼翻譯成按鍵名稱,并按時(shí)間順序?qū)存I動(dòng)作顯示在listbox中。while(1)deviceiocontrol(m_hdevice, read_scancode, null, 0, null, 0, &info, null);if(info)time=ctime:
23、getcurrenttime(); sprintf(mess,"%s code:0x%04x %sn",time.format("%h:%m:%s"),info,codename(info);plistbox1->addstring(mess);plistbox1->setcursel(plistbox1->getcount()-1);sleep(100);設(shè)定按鍵映射規(guī)則時(shí),通過deviceiocontrol將兩個(gè)dword類型的掃描碼通過系統(tǒng)緩沖io的方式傳遞給驅(qū)動(dòng)程序。getdlgitemtext(idc_edit1,mess,8
24、);sscanf(mess,"0x%x",&code0);getdlgitemtext(idc_edit2,mess,8);sscanf(mess,"0x%x",&code1);if(code0>0xe000 | code1>0xe000)messagebox("請(qǐng)輸入小于0xe000的編碼!");return;deviceiocontrol(m_hdevice, set_code, code, sizeof(code), null, 0, &info, null);3、 所遇到的問題及解決方法鍵盤
25、過濾驅(qū)動(dòng)的卸載問題。在使用常規(guī)的驅(qū)動(dòng)卸載步驟時(shí),會(huì)發(fā)生系統(tǒng)藍(lán)屏重啟的故障。通過分析和查閱相關(guān)資料,終于得出了解決的辦法。由于irm_mj_read是異步的,在給irp_mj_read設(shè)置了完成例程的情況下,該irp完成后會(huì)調(diào)用過濾驅(qū)動(dòng)所指定的完成例程,使得有了處理返回?cái)?shù)據(jù)的機(jī)會(huì)。但也正是因?yàn)檫@樣,當(dāng)動(dòng)態(tài)御載了鍵盤過濾驅(qū)動(dòng),也就卸載掉了完成例程,而之后的再次按鍵動(dòng)作在完成了這個(gè)irp后還是會(huì)調(diào)用那個(gè)已經(jīng)不存在了的完成例程,因而引發(fā)錯(cuò)誤。同理可知,在安裝過濾驅(qū)動(dòng)時(shí),就已經(jīng)有一個(gè)irp在鍵盤設(shè)備驅(qū)動(dòng)中等待按鍵了,而該irp并沒有被設(shè)置完成例程。因此可知,在驅(qū)動(dòng)運(yùn)行之后的第一個(gè)按鍵動(dòng)作是不會(huì)被截獲的。在實(shí)驗(yàn)中的確證實(shí)了這個(gè)推想。動(dòng)態(tài)卸載的實(shí)現(xiàn),是在設(shè)備擴(kuò)展對(duì)象中加入一個(gè)irppendingcount計(jì)數(shù)器,用來記錄正在運(yùn)行中的
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 二零二五年度線上線下融合門店托管承包經(jīng)營(yíng)協(xié)議4篇
- 2025年度城市綜合體樓批量裝修與智能化升級(jí)施工合同4篇
- 2025版美容院與專業(yè)美容攝影工作室合作協(xié)議4篇
- 2025年度環(huán)保型車間生產(chǎn)責(zé)任承包合同示范文本4篇
- 2025年度老舊小區(qū)車位改造與代理銷售服務(wù)合同4篇
- 二零二五年度安防設(shè)備研發(fā)與市場(chǎng)推廣采購(gòu)協(xié)議3篇
- 2025年度定制型鋁合金門窗設(shè)計(jì)與施工一體化合同4篇
- 二零二五年銷售合同服務(wù)內(nèi)容擴(kuò)展2篇
- 二零二五版服裝店長(zhǎng)聘用合同范本:精細(xì)化管理3篇
- 2025年度特色民宿租賃及運(yùn)營(yíng)服務(wù)合同4篇
- 《沙盤技術(shù)》教學(xué)大綱
- 職業(yè)培訓(xùn)師培訓(xùn)課件
- (新版)多旋翼無人機(jī)超視距駕駛員執(zhí)照參考試題庫(kù)(含答案)
- 哈利波特中英文全集
- DLT5210.1-電力建設(shè)施工質(zhì)量驗(yàn)收及評(píng)價(jià)規(guī)程全套驗(yàn)評(píng)表格之歐陽(yáng)法創(chuàng)編
- 500句漢語(yǔ)日常對(duì)話
- 《抽搐的鑒別與處理》課件
- 2024-2030年中國(guó)凈菜加工行業(yè)產(chǎn)能預(yù)測(cè)及投資規(guī)模分析報(bào)告版
- 自來水廠建設(shè)項(xiàng)目可行性研究報(bào)告
- 承諾保證協(xié)議
- 2025年公司副總經(jīng)理述職報(bào)告范文
評(píng)論
0/150
提交評(píng)論