由VB的KeyCode和KeyAscii到扫描码、虚拟码的思考
???????? 相信用VB的朋友都知道KeyCode和KeyAscii。在KeyDown和KeyUp事件中有KeyCode參數;在KeyPress事件中有KeyAscii參數。這兩個參數用的還算是比較多的。
???????? 以前也沒怎么注意,這兩個參數到底有什么區別也不太清楚,唯一明確的就是KeyCode的范圍比KeyAscii廣,因為有些按鍵不激發KeyPress事件。直到前幾天做一個模擬按鍵的程序時,發現目標程序不響應我的模擬鍵盤消息,這才提出的問題。經過查閱資料,發現這里邊還有不少說法,鑒于網上的資料比較混亂,在這我就總結一下,方便學習。
???????? KeyCode參數是指的鍵代碼,也就是虛擬碼。它用來在系統中標識一個鍵,注意,僅僅用于在系統中標識。我們通常不是直接用這個代碼(數字,直接用還是很不好記憶),而是將它定義為字符常量,比如:Home鍵的虛擬碼是&H24,在VB中用vbKeyHome這個常量表示,在C語言中用VK_HOME表示。當然,這些常量都不用你自己聲明,直接用就可以了。需要說明的是,每個鍵的虛擬碼都是唯一的,也就是不區分大小寫,只用來表示一個位置,而不表示鍵的狀態。
???????? KeyAscii參數就比較容易理解了,當然就是鍵的Ascii碼,強調表示一個字符,而不是強調鍵。在這要特別的解釋一下VB 的KeyPress事件不響應某些按鍵,比如方向鍵,是因為這些鍵沒有傳統意義上的Ascii碼(這些鍵只有虛擬碼。我從網上查閱資料的時候發現很多人都把虛擬碼并到Ascii里去了,這樣非常容易造成讀者混淆)。那么如何識別一個鍵有沒有Ascii碼呢?在這我教大家一個比較容易理解的方法,有Ascii碼的鍵都是圖形化的鍵,都是可以用符號表示的,比如字母上邊的一排數字鍵,一般情況下表示為“1”,按住shift就表示“!”,這些都是具體的。而F1、方向鍵之類的則是抽象的(我們總不能把F1表示成“F1”吧!),沒有Ascii與之對應。到這我們可以看出,Ascii碼和虛擬碼是相輔相成的,沒有從屬關系。基于這點考慮,我們使用的時候就要特別的小心。舉個簡單的例子:
Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)MsgBox KeyCode End Sub????????這段代碼識別的是虛擬碼,它強調的是位置,所以我們在按小鍵盤上的數字鍵和字母上邊的數字鍵顯示的虛擬碼是不一樣的!因為位置不同。
Private Sub Form_KeyPress(KeyAscii As Integer)MsgBox KeyAscii End Sub
???????? 這段代碼識別的是Ascii碼,所以無論你按鍵盤上的哪個數字“1”,顯示的結果都是一樣的,因為這些鍵都表示1這個數字。但是對于字母上邊的數字鍵,我們可以先按住shift,然后再按數字鍵,這時候值會不同,因為它表示的符號變了,對于數字鍵“1”來說,按住shift后這個鍵表示的符號是“!”,所以Ascii不同了(在第一段代碼中無法直接按住shift,即使按住了也不會改變按鍵的虛擬碼,仔細觀察會發現第一段代碼多一個參數Shift As Integer,它是靠這個參數識別是否按住shift、Ctrl鍵的。)。
???????? 接下來看一下什么是掃描碼(很簡單,看懂就行):
???????? 鍵盤上的每一個鍵都有兩個唯一的數值進行標志。為什么要用兩個數值而不是一個數值呢?這是因為一個鍵可以被按下,也可以被釋放。當一個鍵按下時,它們產生一個唯一的數值,當一個鍵被釋放時,它也會產生一個唯一的數值,我們把這些數值都保存在一張表里面,到時候通過查表就可以知道是哪一個鍵被敲擊,并且可以知道是它是被按下還是被釋放了。這些數值在系統中被稱為鍵盤掃描碼。
???????? 好了,到此為止,有了以上的了解,就差一個串起來的過程了,聯系起來就什么都明白了!(在上邊的討論中我強調了虛擬碼只是存在于系統中,為什么這么說,看一下鍵盤的工作機制你就什么都明白了):
???? 下面開始織網,鍵盤工作機制:
當用戶按下某個鍵時,
1.鍵盤會檢測到這個動作,并通過鍵盤控制器把掃描碼(scan code)傳送到計算機;鍵盤掃描碼跟具體的硬件有關的,不同廠商對同一個鍵的掃描碼有可能不同。
2.計算機接收到掃描碼后,將其交給鍵盤驅動程序;
3.鍵盤驅動程序把這個掃描碼轉換為鍵盤虛擬碼;虛擬碼與具體硬件無關,不同廠商的鍵盤,同一個鍵的虛擬碼總是相同的。然后,鍵盤驅動程序把該鍵盤操作的掃描碼和虛擬碼以及其它信息傳遞給操作系統;
4.操作系統將獲得的信息封裝在一個鍵盤消息中,并把該鍵盤消息插入到消息列隊。
5.通過Windows的消息系統,該鍵盤消息被送到某個窗口中;
6.窗口所在的應用程序接收到消息后,可以了解到有關鍵盤操作的信息,然后決定作出一定的響應。
????????以上就是系統接受鍵盤消息的整個過程,現在恍然大悟了吧?
????????在這還要提一下模擬鍵盤消息的函數:keybd_event(具體用法百度一下)。這個API函數是最底層的模擬鍵盤消息,所以很真實,以至于程序無法識別這個鍵盤消息到底是鍵盤發出的還是模擬的。但是使用這個函數時需要注意,有時候程序還是能識別我們偽造消息的,為什么?注意鍵盤運行機制中的這句話:“然后,鍵盤驅動程序把該鍵盤操作的掃描碼和虛擬碼以及其它信息傳遞給操作系統”,通常情況下模擬鍵盤,我們只在keybd_event函數的第一個參數傳入要模擬的按鍵的虛擬碼,一般這樣就夠了,但對于一些有防護措施的程序(比如游戲),就要在keybd_event函數的第二個參數傳入相應的掃描碼。把虛擬碼轉換成掃描碼的API函數是MapVirtualKey。一個完整的例子(模擬按回車鍵):
Private Declare Sub keybd_event Lib "user32" (ByVal bVk As Byte, ByVal Scan As Byte, ByVal dwFlags As Long, ByVal dwExtraInfo As Long) Private Declare Function MapVirtualKey Lib "user32" Alias "MapVirtualKeyA" (ByVal wCode As Long, ByVal wMapType As Long) As Long Const KEYEVENTF_KEYUP = &H2 '釋放按鍵常數 ‘以下代碼放在適當的事件中 Call keybd_event(13, MapVirtualKey("13", 0), 0, 0) '按下回車 Call keybd_event(13, MapVirtualKey("13", 0), KEYEVENTF_KEYUP, 0) '釋放回車????????另外對于KeyPress事件的一個經典應用就是有效性驗證。VB程序接受鍵盤消息時,消息首先到達KeyPress事件,在這個事件中處理完成之后,才進行后續的處理,同時VB程序允許我們在KeyPress 事件中改變KeyAscii的值,所以我們可以在這判斷輸入是否合法,如果不合法我們把KeyAscii設置為0,這樣我們就舍棄了這次輸入,表現是無法輸入允許范圍之外的字符。
總結
以上是生活随笔為你收集整理的由VB的KeyCode和KeyAscii到扫描码、虚拟码的思考的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2021 年 JavaScript 大事
- 下一篇: 前端学习(3021):vue+eleme