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
GetAsyncKeyState按键被按下后的返回值
0x8000 即0000 0000 0000 0000 1000 0000 0000 0000
GetAsyncKeyState(VK_LSHIFT) & 0x8000
那么为什么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
作用:返回键的状态,按下、释放或锁定(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
~10 = 11111111 11111111
可以通过掩码(位与) 与15位与
15 = 00000000 00000000 00000000
~10 = 00000000 00000000 00000000
附:
VK_LBUTTON
VK_RBUTTON
VK_CANCEL
VK_MBUTTON
VK_BACK
VK_TAB
VK_RETURN
VK_SHIFT
VK_CONTROL
VK_MENU
VK_PAUSE
VK_CAPITAL
VK_ESCAPE
VK_SPACE
VK_PRIOR
VK_NEXT
VK_END
VK_HOME
VK_LEFT
VK_UP
VK_RIGHT
VK_DOWN
VK_SNAPSHOT
VK_Insert
VK_Delete
'0' – '9'
'A' – 'Z'
VK_LWIN
VK_RWIN
VK_APPS
VK_NUMPAD0
VK_NUMPAD1
VK_NUMPAD2
VK_NUMPAD3
VK_NUMPAD4
VK_NUMPAD5
VK_NUMPAD6
VK_NUMPAD7
VK_NUMPAD8
VK_NUMPAD9
VK_F1 - VK_F24
VK_NUMLOCK
VK_SCROLL
转载:http://blog.sina.com.cn/s/blog_4e7834f50100qejf.html