0x8000 & GetKeyState(VK_SHIFT); 這句是判斷是否有按下shift鍵
為什麼GetAsyncKeyState()&
首先說明,有好多程式或書上是0x8000f,這個f不是十六進位的f而是代表浮點數。其實& 8000才是本質。小魚我整理後自己寫了點東西,總結一下
首先介紹一下幾個概念:
按位與運算子"&":是雙目運算子,其功能是參與運算的兩數各對應的二進位相與。只有對應的兩個二進位均為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 斷行符號鍵