首先介紹一下幾個概念:
按位與運算符"&":是雙目運算符,其功能是參與運算的兩數各對應的二進位相與。只有對應的兩個二進位均爲1時,結果位才爲1 ,否則爲0。參與運算的數以補碼方式出現。例如:0x11 & 0x12(即0001 0001 & 0001 0010)的結果是0x10(0001 0000);(關於vs取反參考附)
虛鍵:指的是非字母可以明確表示的鍵.(例如ESC BS TAB NumLock 等,虛鍵列表見附);
物理鍵狀態:在操作系統的控制面板中設置鼠標左右鍵的映射(實際的鼠標左鍵可以映射成右鍵點擊事件),或者通過程序也可以這樣設置,這樣就產生了(實際的)物理鍵狀態;
邏輯鍵狀態:使用 GetKeyState,GetKeyboardState,等函數得到的邏輯鍵狀態,模擬按下按鍵;
GetAsyncKeyState函數功能:讀取的是物理鍵狀態,也就是不管你怎麼鼠標鍵盤映射,它只讀取實際的按鍵狀態。MSDN上給出了例子很恰當For example, the call GetAsyncKeyState(VK_LBUTTON) always returns the state of the left physical mouse button, regardless of whether it is mapped to the left or right logical mouse button.也就是說如果你重新設置了映射,GetAsyncKeyState還是隻讀取物理狀態;
GetAsyncKeyState的返回值:表示兩個內容,一個是最高位bit的值,代表這個鍵是否被按下,按下爲1,擡起爲0;一個是最低位bit的值,在windowsCE下要忽略(參考自MSDNIf the most significant bit is set, the key is down. The least significant bit is not valid in Windows CE, and should be ignored.)
Asynchronous:英文意思是異步的
實際當中GetAsyncKeyState的返回值是什麼呢?小魚我寫了個程序來獲取返回值:
#include <Windows.h>
#include <stdio.h>
void main()
{
while(1)
{
short a = ::GetAsyncKeyState(VK_LSHIFT)
printf( "0x%x",a);
sleep(10);
}
}
當然,用MessageBox可以這樣寫:
if(short a = ::GetAsyncKeyState(VK_LSHIFT))
{
char buffer[30];
sprintf(buffer, "0x%x",a);
MessageBox(0, buffer, "a的值", MB_OK);
}
GetAsyncKeyState按鍵不按或擡起後不按的返回值0x0 即0000 0000 0000 0000 0000 0000 0000 0000
GetAsyncKeyState按鍵被按下後的返回值 返回0xffff8001 即1111 1111 1111 1111 1000 0000 0000 0001 (這裏並不是返回4字節,而是%x打印出32位,前十六位補f)
0x8000 即0000 0000 0000 0000 1000 0000 0000 0000
GetAsyncKeyState(VK_LSHIFT) & 0x8000 返回0x1 即0000 0000 0000 0000 1000 0000 0000 0000
那麼爲什麼GetAsyncKeyState要 ‘與’上 0x8000這個常數呢?
答案是:獲取按鍵狀態,屏蔽掉其他的可能狀態,按照MSDN上說低位should ignore。
網上有人這樣寫,意思很明確:
#define KEYDOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
#define KEYUP(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)
程序應該是:
if(GetAsyncKeyState(VK_LSHIFT)&&0x8000)
對於虛鍵而言下面這樣寫邏輯是不對的,雖然結果一樣:
if(GetAsyncKeyState(VK_LSHIFT))
所以讓鍵盤的"上下左右"出發事件可以這樣寫:
if( ::GetAsyncKeyState(VK_LEFT) & 0x8000 )
code...
if( ::GetAsyncKeyState(VK_RIGHT)& 0x8000 )
code...
if( ::GetAsyncKeyState(VK_UP) & 0x8000 )
code...
if( ::GetAsyncKeyState(VK_DOWN) & 0x8000 )
code...
關於GetAsyncKeyState與GetKeyState區別:
GetAsyncKeyState上面已經講差不多了,關於GetAsyncKeyState與GetKeyState二者最大區別:GetAsyncKeyState在按鍵不按的情況下爲0,而GetKeyState在按鍵不按的情況下開始爲0,當一次‘按下擡起’後變爲1,依次循環。
SHORT GetKeyState(int nVirtKey // virtual-key code);
作用:返回鍵的狀態,按下、釋放或鎖定(down、up or toggled)
參數:虛擬鍵代碼(VK_)。如果是字母a-z、A-Z 或數字0-9, 則爲其對應的ASCII碼(比如字母O的ASCII碼爲十六進制的0x4F)
返回值:返回碼的高位顯示當前是否有鍵被按下,低位(0位)則顯示NumLock、CapsLock、ScrollLock的狀態(ON或OFF,爲ON時鍵盤指示燈亮)。即高位爲1,返回值小於0,說明有鍵按下;最低位爲1表示處於鎖定(ON)狀態(參考MSDN:If the high-order bit is 1, the key is down; otherwise, it is up.
If the low-order bit is 1, the key is toggled. A key, such as the CAPS LOCK key, is toggled if it is turned on. The key is off and untoggled if the low-order bit is 0. A toggle key's indicator light (if any) on the keyboard will be on when the key is toggled, and off when the key is untoggled. )
注:此函數不應該在鍵盤消息處理程序以外使用,因爲它返回的信息只有在鍵盤消息從消息隊列中被檢索到之後纔有效。若確實需要,請使用GetAsyncKeyState
----------------------------------------
網上還找到了一些資料:
關於和其他的幾個函數的區別:
SHORT GetKeyState(int nVirtKey);
SHORT GetAsyncKeyState(int vKey);
BOOL GetKeyboardState(PBYTE lpKeyState);
三個取key status的函數的最大區別是:
第一個:是從windows消息隊列中取得鍵盤消息,返回key status.
第二個:是直接偵測鍵盤的硬件中斷,返回key status.
第三個:是當從windows消息隊列中移除鍵盤消息時,才返回key status.
keybd_event函數,是模擬鍵盤擊鍵,一次完整的擊鍵模擬事件,是"按下"和"彈起"兩個消息,所以 keybd_event(VK_F12,0,0,0);keybd_event(VK_F12,0,KEYEVENTF_KEYUP,0); 完成了一次完整的點擊 F12 的事件。
GetAsyncKeyState()函數,是直接偵測鍵盤的硬件中斷。(有些人說,是一種“實時性”的偵測,這種說法,感覺不對,比如你調用 Sleep(),就算是中斷一年的時間,只要在這期間程序還在運行,它都可以把那個鍵的狀態偵測出來)。自上一次調用GetAsyncKeyState()函數以來(在某些循環中,N次調用GetAsyncKeyState(),它每次檢查的,都是自上次調用之後,鍵的狀態),若鍵已被按過,則返回1,否則,返回0;有些資料顯示:倘若輸入焦點從屬於與調用函數的輸入線程不同的另一個線程,則返回零(例如,在另一個程序擁有輸入焦點時,應該返回零)。實驗證明,這種說法並不完全,函數實際是在大部份範圍內工作的,只有少數是另外)。
---------------
附:
VC++編譯器,計算~10,得出的結果是-11。爲什麼不是5呢
10的二進制表示爲1010,按位取反應該爲0101,也就是十進制的5,爲什麼會得出-11?
VC是32位編譯器,所以
10 = 00000000 00000000 00000000 00001010
~10 = 11111111 11111111 11111111 11110101 = -11
可以通過掩碼(位與) 與15位與
15 = 00000000 00000000 00000000 00001111
~10 = 00000000 00000000 00000000 00000101 = -11
附:
VK_LBUTTON 鼠標左鍵 0x01
VK_RBUTTON 鼠標右鍵 0x02
VK_CANCEL Ctrl + Break 0x03
VK_MBUTTON 鼠標中鍵 0x04
VK_BACK Backspace 鍵 0x08
VK_TAB Tab 鍵 0x09
VK_RETURN 回車鍵 0x0D
VK_SHIFT Shift 鍵 0x10
VK_CONTROL Ctrl 鍵 0x11
VK_MENU Alt 鍵 0x12
VK_PAUSE Pause 鍵 0x13
VK_CAPITAL Caps Lock 鍵 0x14
VK_ESCAPE Esc 鍵 0x1B
VK_SPACE 空格鍵 0x20
VK_PRIOR Page Up 鍵 0x21
VK_NEXT Page Down 鍵 0x22
VK_END End 鍵 0x23
VK_HOME Home 鍵 0x24
VK_LEFT 左箭頭鍵 0x25
VK_UP 上箭頭鍵 0x26
VK_RIGHT 右箭頭鍵 0x27
VK_DOWN 下箭頭鍵 0x28
VK_SNAPSHOT Print Screen 鍵 0x2C
VK_Insert Insert 鍵 0x2D
VK_Delete Delete 鍵 0x2E
'0' – '9' 數字 0 - 9 0x30 - 0x39
'A' – 'Z' 字母 A - Z 0x41 - 0x5A
VK_LWIN 左WinKey(104鍵盤纔有) 0x5B
VK_RWIN 右WinKey(104鍵盤纔有) 0x5C
VK_APPS AppsKey(104鍵盤纔有) 0x5D
VK_NUMPAD0 小鍵盤 0 鍵 0x60
VK_NUMPAD1 小鍵盤 1 鍵 0x61
VK_NUMPAD2 小鍵盤 2 鍵 0x62
VK_NUMPAD3 小鍵盤 3 鍵 0x63
VK_NUMPAD4 小鍵盤 4 鍵 0x64
VK_NUMPAD5 小鍵盤 5 鍵 0x65
VK_NUMPAD6 小鍵盤 6 鍵 0x66
VK_NUMPAD7 小鍵盤 7 鍵 0x67
VK_NUMPAD8 小鍵盤 8 鍵 0x68
VK_NUMPAD9 小鍵盤 9 鍵 0x69
VK_F1 - VK_F24 功能鍵F1 – F24 0x70 - 0x87
VK_NUMLOCK Num Lock 鍵 0x90
VK_SCROLL Scroll Lock 鍵 0x91