標籤:
http://www.cnblogs.com/rogee/archive/2010/09/14/1827248.html
本文最早在編程論壇上發表,文章地址:http://programbbs.com/bbs/view12-17207-1.htm,相關檔案可以在上述地址的頁面中下載。轉載時請註明出處。
前言
一日發現SendInput對某程式居然無效,無奈只好開始研究WinIo。上網查了很多資料,發現關於WinIo類比滑鼠鍵盤的資料很少,有的也只是支言片語講的不是很詳細,而且大部分都是關於類比鍵盤的。自己寫了一些程式研究一方,經曆了無數次的鍵盤死結、滑鼠滿屏亂飛、複位重啟,總算小有結果。現在將研究結果寫出來與大家分享。另外,本人的水平有限文中有出錯的地方歡迎根貼討論。(PS:關於SendInput的使用可以參考我寫的另一篇貼子《Delphi下利用SendInput類比滑鼠鍵盤》http://programbbs.com/bbs/view12-17219-1.htm)
我已經將主要的類比功能寫在了一個單元檔案中:MouseKeyboard.pas,調用該單元檔案中的相關函數就可以實現滑鼠鍵盤的類比。該單元檔案的下載和使用方法請參考2樓的內容。在本樓的末尾有一個中英文對譯PS/2滑鼠鍵盤協議的下載,這個協議對編寫類比滑鼠鍵盤的程式很有協助。另外我還提供了一個滑鼠移動速度測試程式、一個使用MouseKeyboard.pas的簡單示範程式的下載。
一、WinIo簡介
WinIo通過載入一個核心模式的裝置驅動程式,利用幾種底層編程技巧,使得Windows應用程式可以直接對I/O連接埠和實體記憶體進行存取,從而繞過了Windows系統的保護機制。WinIo包含了3個檔案:WinIo.dll、WinIo.sys和WINIO.VXD,其中WINIO.VXD驅動程式用在Win95/98系統上,WinIo.sys驅動程式用在WinNT/2000/XP系統上,WinIo.dll提供了功能函數的調用。在WinIo.dll中有兩個函數最重要:InitializeWinIo用來初始化WinIo的驅動程式,必須在調用所有其它功能函數之前調用該函數;ShutdownWinIo用來卸載WinIo的驅動程式,在中止應用函數之前或者不再需要使用WinIo時調用。在初始化完成之後就可以直接讀寫I/O連接埠而不會出現非法操作,本程式就是利用向滑鼠鍵盤硬體連接埠寫入資料來類比滑鼠鍵盤的操作。
由於是底層的硬體連接埠讀寫,所以必需對硬體的相關協議有所瞭解,對於滑鼠鍵盤最重要的協議就是PS/2滑鼠鍵盤協議(以下簡稱PS/2協議)。我這裡提供了一個pdf版的中英文對譯PS/2滑鼠鍵盤協議,在該協議的前半部主要講硬體的電氣介面協議,但是後半部分的內容對於類比滑鼠鍵盤非常有用。這個協議可是我在網上翻騰了好久才找到的。協議的下載見本樓末尾。
二、Intel 8042
Intel 8042或相容微控制器(以下簡稱i8042)被用作PC鍵盤的控制器,雖然名為鍵盤控制器,但是實際上滑鼠也是由其控制的。i8042一般整合在晶片集中。向i8042發送指定的命令和資料就可以類比滑鼠鍵盤的操作。i8042包含了如下四個寄存器:
一個位元組的輸入緩衝區:包含從滑鼠或鍵盤讀入的位元組;唯讀。
一個位元組的輸出緩衝區:包含要寫到滑鼠或鍵盤的位元組;唯寫。
一個位元組的狀態寄存器:8個狀態標誌;唯讀。
一個位元組的控制寄存器:7個控制標誌;讀寫。
其中前三個寄存器(輸入、輸出、狀態)可以通過$60和$64連接埠直接存取,讀寫$60和$64連接埠所實現的功能如下:
連接埠 讀寫 功能
$60 讀 讀輸入緩衝區
$60 寫 寫輸出緩衝區
$64 讀 讀狀態寄存器
$64 寫 發送命令
寫$64連接埠不會寫入到任何特定的寄存器中,但是解釋為發送命令給i8042。如果命令接收一個參數,則參數被發往$60連接埠。同樣,命令的任何返回結構可以從$60連接埠讀出。i8042的狀態標誌是從$64連接埠讀出的。它們包含了錯誤資訊、狀態資訊和輸入輸出緩衝區裡有無資料的指示。這些標誌的定義如下:
Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
┌──┬──┬──┬──┬──┬──┬──┬──┐
│PERR│TO │MOBF│INH │A2 │SYS │IBF │OBF │
└──┴──┴──┴──┴──┴──┴──┴──┘
其中標誌位OBF最重要(其它標誌位的意思請參考PS/2協議),它表示輸出緩衝區是否已滿,是否可以寫入輸出緩衝區。0表示輸出緩衝區空,1表示輸出緩衝區已滿。所以在向$60連接埠寫入資料之前要檢查該標誌位是否已被置0。另外在向$64連接埠發送命令之前也要檢查該標誌位,已確保上次的操作已經完成。向指定連接埠寫入資料的程式如下,其中使用了內嵌彙編對連接埠進行操作。注意:滑鼠鍵盤是慢速裝置,每次操作時要有一定的延時:
procedure SetByte(Por,Cod : Byte);
begin
Sleep(1);
asm
PUSH EAX
PUSH EDX
//等待狀態寄存器標誌位OBF置0
@Loop:
IN AL,$64
AND AL,01b
JNZ @Loop
//寫入資料
MOV AL,Cod
MOV DL,Por
MOV DH,0
OUT DX,AL
POP EDX
POP EAX
end;
end;
發送命令給i8042就是寫$64連接埠。在命令發送後,命令參數寫到$60連接埠。命令中用來類比滑鼠鍵盤操作的有兩條(其它命令請參考PS/2協議):
$D2:寫鍵盤緩衝區,把參數寫到輸入緩衝區就像從鍵盤接收到的一樣。
$D3:寫滑鼠緩衝區,把參數寫到輸入緩衝區就像從滑鼠接收到的一樣。
例如:按下“A”鍵,利用上面的程式可以寫成“SetByte($64,$D2); SetByte($60,$1E);”。注意:如果向$60連接埠發送的資料不只1個位元組,那麼發送的每個位元組前都要發送一條命令,例如:按下“Insert”鍵的程式為“SetByte($64,$D2); SetByte($60,$E0); SetByte($64,$D2); SetByte($60,$52);”,要調用SetByte四次。知道了如何向i8042發送命令,下面就可以具體的類比滑鼠鍵盤。
三、鍵盤類比
鍵盤的處理器會掃描或監視按鍵矩陣。如果它發現有鍵被按下、釋放或按住,鍵盤將發送“掃描碼”的資料包到i8042。掃描碼有兩種不同的類型:“通碼”和“斷碼”,當一個鍵被按下或按住就發送通碼;當一個鍵被釋放就發送斷碼。每個按鍵被分配了唯一的通碼和斷碼,這樣i8042通過尋找唯一的掃描碼就可以測定是哪個按鍵。每個鍵一整套的通斷碼組成了“掃描碼集”。有三套標準的掃描碼集分別是第一套、第二套和第三套。i8042預設支援第一套掃描碼。
一部份鍵的斷碼是將通碼的最高位置1,但並不是所有的鍵都這樣,而且很多鍵的掃描碼不只有1個位元組。所以沒有一個簡單的公式可以計算掃描碼。如果你要知道某特定按鍵的通碼和斷碼,你將不得不查表獲得。例如:“A”鍵的通碼為$1E,斷碼為$9E,“Insert”鍵的通碼為$E0,$52,斷碼為$E0,$D2,類比按鍵的程式如下:
//按下並放開“A”鍵
SetByte($64,$D2); SetByte($60,$1E);
SetByte($64,$D2); SetByte($60,$9E);
//按下並放開“Insert”鍵
SetByte($64,$D2); SetByte($60,$E0);
SetByte($64,$D2); SetByte($60,$52);
SetByte($64,$D2); SetByte($60,$E0);
SetByte($64,$D2); SetByte($60,$D2);
特別的在PS/2協議中說在第一第二套掃描碼裡沒有“Pause/Break”鍵的斷碼。當這個鍵按下時發送它的通碼,當它釋放時,什麼都沒有被發送。在第一套掃描碼裡Pause鍵的通碼長達6個位元組:$E1,$1D,$45,$E1,$9D,$C5。但是我在實際測試中發現Pause鍵的通碼其實是前3個位元組:$E1,$1D,$45,後3個位元組$E1,$9D,$C5是Pause鍵的斷碼。至少在我的鍵盤上是這樣。
在PS/2協議中已經把所有三套掃描碼集中所有的通碼和斷碼做成了表格,具體的內容可以查閱相關的部份。在單元檔案MouseKeyboard.pas中我已經將第一套鍵盤掃描碼定義成常量數組,其中還包括了鍵對應的字元。單元中有兩個函數MKFindKeyCode和MKFindKeyChar,可以用來對常量數組進行尋找。
四、滑鼠類比
標準的PS/2滑鼠支援下面的輸入:X(左右)位移、Y(上下)位移、左鍵、中鍵和右鍵。滑鼠以一個固定的頻率讀取這些輸入並更新不同的計數器然後標記出反映的移動和按鍵狀態。有很多PS/2滑鼠具有額外的輸入比如微軟的Intellimouse,它既支援標準輸入也支援滾輪和兩個附加的按鍵。
標準的滑鼠有兩個計數器保持位移的跟蹤:X位移計數器和Y位移計數器。可存放9位的2進位補碼並且每個計數器都有相關的溢出標誌。它們的內容連同三個滑鼠按鍵的狀態一起以三位元組移動資料包的形式發送給i8042。位移計數器表示從最後一次位移資料包被送往i8042後有位移量發生。標準的PS/2滑鼠發送位移和按鍵資訊給i8042採用如下的3位元組資料包格式:
Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
┌────┬────┬────┬────┬──┬───┬───┬───┐
Byte 1 │Y 溢出位│X 溢出位│Y 符號位│X 符號位│置 1│中鍵位│右鍵位│左鍵位│
├────┴────┴────┴────┴──┴───┴───┴───┤
Byte 2 │ X 左右移位值,補碼 │
├──────────────────────────────────┤
Byte 3 │ Y 上下移位值,補碼 │
└──────────────────────────────────┘
位移計數器是一個9位二進位補碼整數。它的最高位作為符號位出現在位移資料包的第一個位元組裡,這些計數器在滑鼠讀取輸入發現有位移時被更新,這些值是自從最後一次發送位移資料包給i8042後位移的累計量(即最後一次包發給i8042後位移計數器被複位),位移計數器可表示的值的範圍是-255到+255。如果超過了範圍,相應的溢出位就被設定,並且在複位前計數器不會增減。
對標準的PS/2滑鼠的一個流行的擴充是微軟的Intellimouse。它包括支援五個滑鼠按鍵和三個位移軸(左右、上下和滾輪)。這些附加特徵要求使用4位元組的位移資料包而不是標準3位元組資料包。微軟的Intellimouse使用4位元組的位移資料包格式有兩種情況分別如下:
1、三鍵帶滾輪滑鼠:
Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
┌────┬────┬────┬────┬──┬───┬───┬───┐
Byte 1 │Y 溢出位│X 溢出位│Y 符號位│X 符號位│置 1│中鍵位│右鍵位│左鍵位│
├────┴────┴────┴────┴──┴───┴───┴───┤
Byte 2 │ X 左右移位值,補碼 │
├──────────────────────────────────┤
Byte 3 │ Y 上下移位值,補碼 │
├──────────────────────────────────┤
Byte 4 │ Z 滾動移位值,補碼 │
└──────────────────────────────────┘
Z位移是二進位補碼錶示滾輪的自上次資料報告以來的位移。有效值的範圍在-8到+7,這意味著數值實際只有低四位有用,高四位僅用作符號擴充位。當Z小於0時表示向上滾動,當Z大於0時表示向下滾動。
2、五鍵帶滾輪滑鼠:
Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
┌────┬────┬────┬────┬──┬───┬───┬───┐
Byte 1 │Y 溢出位│X 溢出位│Y 符號位│X 符號位│置 1│中鍵位│右鍵位│左鍵位│
├────┴────┴────┴────┴──┴───┴───┴───┤
Byte 2 │ X 左右移位值,補碼 │
├──────────────────────────────────┤
Byte 3 │ Y 上下移位值,補碼 │
├────┬────┬────┬────┬──┬───┬───┬───┤
Byte 4 │ 置 0 │ 置 0 │第5鍵位 │第4鍵位 │ Z3 │ Z2 │ Z1 │ Z0 │
└────┴────┴────┴────┴──┴───┴───┴───┘
Z0~Z3是二進位補碼用於表示從上次資料報告以來滾輪的位移量,有效範圍從-8到+7;第4鍵位:置1表示第4鍵按下了,置0表示第4鍵沒有按下;第5鍵位:置1表示第5鍵按下了,置0表示第5鍵沒有按下。可以看出三鍵帶滾輪滑鼠和五鍵帶滾輪滑鼠這兩種資料包格式是相互相容的。一般現在使用的滑鼠都是帶滾輪的,所以使用的都是4位元組的資料包格式。調用API函數GetSystemMetrics(SM_CMOUSEBUTTONS)可以返回當前滑鼠的按鍵數,調用GetSystemMetrics(SM_MOUSEWHEELPRESENT)可以返回當前滑鼠是否有帶滾輪。通過調用這兩個API函數可以判斷當前使用的是3位元組資料包還是4位元組資料包。知道了資料包的格式就可以向i8042發送$D3命令類比滑鼠操作,類比單擊滑鼠左鍵的程式如下:
//按下滑鼠左鍵
SetByte($64,$D3); SetByte($60,$09);
SetByte($64,$D3); SetByte($60,$00);
SetByte($64,$D3); SetByte($60,$00);
SetByte($64,$D3); SetByte($60,$00); //三鍵帶滾輪滑鼠
//放開滑鼠左鍵
SetByte($64,$D3); SetByte($60,$08);
SetByte($64,$D3); SetByte($60,$00);
SetByte($64,$D3); SetByte($60,$00);
SetByte($64,$D3); SetByte($60,$00); //三鍵帶滾輪滑鼠
現在再來談談滑鼠移動的類比,滑鼠移動的類比其實是一個很頭痛的問題。如果只是讓滑鼠隨便動動那是很簡單,但是要將滑鼠在螢幕上的指標移動到指定座標就不是那麼容易的事件了。首先,滑鼠位移計數器使用的是平面直角座標系。也就說當滑鼠向左移動時X小於0,當滑鼠向右移動時X大於0,當滑鼠向下移動時Y小於0當滑鼠向上移動時Y大於0。螢幕上的指標座標使用的是電腦螢幕座標系,對應於平面直角座標系在X軸上是一致的,在Y軸上相差一個加號或減號。
其次,決定位移計數器增減數量的參數叫解析度,預設的解析度為:4計數單位每毫米。這就意味著滑鼠位移計數器的位移量(以下簡稱滑鼠位移量)同滑鼠指標在螢幕上的象素位移量(以下簡稱指標位移量)並不一樣。滑鼠位移量同指標位移量的比值與滑鼠移動速度的設定有關,通過“控制台”中“滑鼠”選項卡的“調整指標移動速度”可以對該值進行設定,這個值儲存在註冊表HKEY_CURRENT_USER\Control Panel\Mouse\MouseSensitivity中,通過修改註冊表可以將這個值設定成帶有小數點的,通過調用API函數SystemParametersinfo使用參數SPI_GETMOUSESPEED就可以擷取該值。另外,使用第三方滑鼠驅動程式也可以設定滑鼠的移動速度,一般這類驅動程度都有帶滑鼠加速功能,這使得滑鼠位移量同指標位移量的比值根本無法確定。
當使用Windows內建的滑鼠驅動程式,在滑鼠選項卡中將指標移動速度設定在中間位置,註冊表中MouseSensitivity的值為10,此時滑鼠位移量同指標位移量的比值還是可以計算的,當滑鼠位移量小於7時:指標位移量等於滑鼠位移量;當滑鼠位移量大於等於7時:指標位移量等於滑鼠位移量的2倍。在這種情況下的前20個比值如下,其中n為滑鼠位移量,cX、cY為指標位移量:
n, cX, cY
1, 1, 1
2, 2, 2
3, 3, 3
4, 4, 4
5, 5, 5
6, 6, 6
7, 14, 14
8, 16, 16
9, 18, 18
10, 20, 20
11, 22, 22
12, 24, 24
13, 26, 26
14, 28, 28
15, 30, 30
16, 32, 32
17, 34, 34
18, 36, 36
19, 38, 38
20, 40, 40
例如:讓滑鼠指標在螢幕上移動的程式如下:
//滑鼠上移50象索
SetByte($64,$D3); SetByte($60,$08);
SetByte($64,$D3); SetByte($60,$00);
SetByte($64,$D3); SetByte($60,$19);
SetByte($64,$D3); SetByte($60,$00); //三鍵帶滾輪
//滑鼠左移50象索
SetByte($64,$D3); SetByte($60,$18);
SetByte($64,$D3); SetByte($60,$E7);
SetByte($64,$D3); SetByte($60,$00);
SetByte($64,$D3); SetByte($60,$00); //三鍵帶滾輪
另外我發現一些滑鼠對於大的滑鼠移動量(大於128或大於170)沒有反應。可能是因為沒有人可以用手把滑鼠移動的這麼快,所以不需要。這在類比滑鼠移動過程中是要注意的。由於沒有很好的演算法,在MouseKeyboard.pas中我使用了一個滑鼠移動換算表來計算滑鼠的移動量,這個表其實就是一個255長度的Integer數組,裡面記錄了每當滑鼠移動多少個單位,指標就會移動多少個象素。我還寫了幾個函數,提供對該表匯入匯出到ini格式檔案中的功能,這樣應該可以適應大多數的滑鼠配置。我寫了一個測試滑鼠移動速度的程式,它可以測試當前滑鼠位移量同指標位移量的比值,可以根據對角移動、水平移動、垂直移動的比值計算出滑鼠移動換算表並儲存到ini檔案中。這個程式的下載見本樓末尾。
五、使用WinIo的優缺點
使用WinIo的優點是不言而喻的,直接的硬體連接埠讀寫使得很多程式無法對其進行屏蔽。它的缺點也很頭痛,首先就是相容性的問題,直接讀寫硬體連接埠會使程式在一些配置的電腦上正常運行,而在另一些配置的電腦上無法運行。特別是USB滑鼠,我的程式是在PS/2滑鼠上測試的,可能對一部份USB滑鼠不相容。其次就是資料衝突的問題,在類比操作的時候滑鼠鍵盤仍然在工作,如果這時操作滑鼠鍵盤可能會出現失控的現象。特別是滑鼠。原因在於:當程式進行類比操作的時候操作滑鼠鍵盤,程式發送給i8042的資料包可能會與滑鼠鍵盤發送給i8042的資料包相互交錯在一起(因為每次只能發送1個位元組),從而造成資料包混亂引起滑鼠鍵盤的失控。我在一次測試時就碰了一下滑鼠,滑鼠指標就在螢幕上亂飛。最後一點缺點就是這種類比是全域性,在類比操作的過程中你什麼都不能做,其實SendInput也是一樣。
六、MouseKeyboard.pas的使用
在上面的壓縮包中包含了4個檔案:MouseKeyboard.pas、WinIo.dll、WinIo.sys和WINIO.VXD,後面3個檔案是WinIo的相關檔案。把這4個檔案放到項目同一個檔案夾下,將MouseKeyboard添加到單元的uses段中就可以調用MouseKeyboard.pas中的函數。值得注意的是當你的程式發布時WinIo.dll、WinIo.sys和WINIO.VXD這3個檔案要和可執行檔放在同一個檔案夾下,程式啟動並執行時候會調用它們。當程式在一個“陌生”的電腦上運行時,最好調用一下MKTestConversion函數測試並儲存當前電腦的滑鼠移動換算表。使用上樓提供的滑鼠Mobile Testing程式產生ini檔案也可以。
在MouseKeyboard.pas中我定義了一個枚舉類型的TMKKeyCode,裡面有104個項對應不同的按鍵。我還定義了一個常量記錄數組MKKeyData,裡面定義了104鍵的掃描碼、通碼長度、斷碼長度以及鍵對應的字元。在MouseKeyboard.pas中共有21個函數,使用說明如下:
1、function MKInitMouseKey: Boolean;
這個函數會初始化WinIo,並對一些內部變數進行初始化,同時這個函數會嘗試從當前檔案夾中開啟一個名為“Mouse.ini”的ini檔案,並從檔案的“Conversion”節中載入滑鼠移動換算表,如果失敗這個函數會調用MKInitConversion初始化一個預設的滑鼠移動換算表。一般情況下不要調用這個函數,在單元被載入的時候會自動調用這個函數來完成初始化。
2、procedure MKFreeMouseKey;
釋放驅動程式卸載WinIo,一般情況下不要調用這個函數,在單元被卸載的時候會自動調用這個函數來完成卸載釋放。
3、function MKSendData(const Data : TMKPacketData; Len : Byte; Typ : TMKDataType): Boolean;
向指定的鍵盤滑鼠連接埠發送資料包,返回是否成功。資料包最長只能是4個位元組,Len為資料包的位元組長度。這個函數內嵌了一個上文提到的SetByte函數用以對連接埠的位元組發送。
4、function MKFindKeyCode(Code : TMKKeyCode): Integer;
尋找指定鍵碼在MKKeyData中的id,找到返回id,沒找到返回-1。
5、function MKFindKeyChar(Char : AnsiChar): Integer;
尋找指定字元在MKKeyData中的id,找到返回id,沒找到返回-1。
6、function MKKeyDown(Code : TMKKeyCode): Boolean;
按下指定的鍵,返回是否成功。
7、function MKKeyUp(Code : TMKKeyCode): Boolean;
放開指定的鍵,返回是否成功。
8、function MKKeyPress(Code : TMKKeyCode; Interval : Cardinal): Boolean;
按下並放開指定的鍵,返回是否成功。Interval為按下和放開之間的時間間隔,單位毫秒。注意:本函數不支援重複機打,即無論Interval設的多麼大都只有一次按鍵。
示範程式,按鍵組合Ctrl+A如下:
MKKeyDown(kcLCtrl); //按下Ctrl
MKKeyPress(kcA); //擊鍵A
MKKeyUp(kcLCtrl); //放開Ctrl
9、function MKKeyInput(const Text : String; Interval : Cardinal): Boolean;
類比鍵盤輸入指定的文本,返回是否成功。文本中只能是單位元組字元(#32~#126)、Tab(#9)鍵和斷行符號鍵(#13),即可以從鍵盤上輸入的字元,不能是漢字,其它字元會被忽略。Interval為按下和放開鍵之間的時間間隔,單位毫秒。
10、function MKMouseDown(Code : TMKMouseCode): Boolean;
按下滑鼠的指定鍵,返回是否成功。
11、function MKMouseUp(Code : TMKMouseCode): Boolean;
放開滑鼠的指定鍵,返回是否成功。
12、function MKMouseClick(Code : TMKMouseCode; Interval : Cardinal): Boolean;
單擊滑鼠的指定鍵,返回是否成功。Interval為按下和放開鍵之間的時間間隔,單位毫秒。
13、function MKMouseWheel(cZ : Integer): Boolean;
滾動滑鼠的滾輪,返回是否成功。cZ為滑鼠滾輪滾動移位值,非象素值。cZ有效值的範圍在-8到+7,當cZ小於0時向上滾動,當cZ大小0向下滾動。
14、function MKMouseMove(cX,cY : Integer): Boolean;
移動滑鼠指標在螢幕上的位置,返回是否成功。cX和cY為滑鼠位移計數器的值,非象素值。當cX小於0時向左移動,當cX大小0時向右移動,當cY小於0時向下移動,當cY大於0時向上移動。cX和cY的值的範圍是-255到+255。
15、procedure MKInitConversion(var Con : TMKMoveConversion);
初始化一個滑鼠移動換算表,假設滑鼠的移動速度設為中等,沒有使用其它第三方的滑鼠加速驅動程式。
16、function MKTestConversion(var Con : TMKMoveConversion; MaxMove : Integer): Boolean;
測試並確認滑鼠移動換算表,返回是否成功。MaxMove為測試時的滑鼠移動的最大值,這個函數會對滑鼠進行對角移動,並記錄下滑鼠指標的實際移動象素量,計算出滑鼠移動換算表。在測試期間不能操作滑鼠,否則可能會出現滑鼠失控,測試不準的情況。
17、function MKConversionToIni(const Con : TMKMoveConversion; IniFile : TIniFile; const Section : String): Boolean;
將滑鼠移動換算表匯出到ini檔案的指定節中,返回是否成功。
18、function MKConversionFromIni(var Con : TMKMoveConversion; IniFile : TIniFile; const Section : String): Boolean;
從ini檔案的指定節中匯入滑鼠移動換算表,返回是否成功。
19、procedure MKLoadConversion(const Con : TMKMoveConversion);
匯入一個滑鼠移動換算表作為預設換算表。
20、function MKMouseMoveTo(X,Y : Integer; const Con : TMKMoveConversion; MaxMove : Integer; Interval : Cardinal): Boolean;
21、function MKMouseMoveTo(X,Y : Integer; MaxMove : Integer; Interval : Cardinal): Boolean;
這是重載的兩個函數,函數可以將滑鼠指標移動到指定位置,並返回是否成功。X和Y為象素值,X和Y的值的範圍不能超出螢幕。MaxMove為移動時的cX和cY的最大值。Interval為兩次移動之間的時間間隔。第1個函數使用指定的滑鼠移動換算表Con進行移動座標的計算,第2函數使用預設的滑鼠移動換算表進行移動座標的計算。如果滑鼠的移動速度沒有設為中等,或者使用其它第三方的滑鼠加速驅動程式,可能會使該函數無法將滑鼠指標移動到準確的位置,會出現一定的誤差。一些程式對滑鼠移動速度敏感,當滑鼠移動太快時無法對滑鼠做出反應,適當的設定MaxMove值可以解決這個問題。
示範程式,拖放到指定位置如下:
MKMouseDown(mcLeft); //按下滑鼠左鍵
MKMouseMoveTo(780,300); //移動到指定位置
MKMouseUp(mcLeft); //放開滑鼠左鍵
更新(2010年1月8日):
更新MouseKeyboard.pas檔案,原檔案中有個小BGU。類比鍵盤輸入“Q”時,無論大小寫,類比按下時是輸入“Q”,類比放開時輸入變成了“P”。我檢查了通斷碼,發現“Q”的斷碼居然和“P”的通碼一樣都是“$19”。這肯定是錯誤的。我的通斷碼資料都是從PS/2協議中抄寫出來的,我查看了該檔案探索資料也是一樣的錯誤。“Q”的通碼是“$10”,我嘗試將通碼的最高位置1變成“$90”作為“Q”的斷碼。這樣的測試在我的電腦上成功了,可以成功的類比放開“Q”。但是我不知道這會不會是鍵盤相容的問題。
更新後的MouseKeyboard.pas檔案只變動了一個很小的地方。在原檔案的第150行由以下內容:
(Code : kcQ; Char : ‘qQ‘; Length : $11; Make : ($10,$00,$00,$00); Break : ($19,$00,$00,$00)),
修改為
(Code : kcQ; Char : ‘qQ‘; Length : $11; Make : ($10,$00,$00,$00); Break : ($90,$00,$00,$00)), //斷碼$19改為$90
也就是將“Q”的斷碼由“$19”更改為“$90”。你也可以利用下面的連結下載更新後的MouseKeyboard.pas檔案
檔案下載:http://files.cnblogs.com/rogee/SIMouseKeyboard.pas.zip
Delphi下利用WinIo類比滑鼠鍵盤詳解