`
bingtears
  • 浏览: 188400 次
  • 性别: Icon_minigender_2
  • 来自: 北京
社区版块
存档分类
最新评论

为什么GetAsyncKeyState()& 0x8000

    博客分类:
  • C++C
阅读更多
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              回车键                        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

分享到:
评论
1 楼 xucl275 2012-05-03  
谢谢,楼主讲的好详细,学习了

GetAsyncKeyState(vk_code)<0 也能判断按键是否按下吧?

相关推荐

    02-双人游戏异步输入.pptx

    如果某个键被按下,对应的位将被设置为1,与掩码`0x8000`进行按位与操作后结果会为正。 为了实现更复杂的组合键和大招,我们需要扩展这个逻辑。例如,如果玩家同时按下'A'和'S',可以触发角色的特殊技能。这可以...

    用API(GetAsyncKeyState)实现如何识别键盘左右的shift,Ctrl或Alt键

    if (GetAsyncKeyState(VK_SHIFT) & 0x8000) { // 检查Shift键是否被按下 // Shift键被按下,执行相应操作 printf("Shift键被按下\n"); } Sleep(10); // 避免过度占用CPU } return 0; } ``` 同样,你可以...

    AD键盘检测键值

    if (GetAsyncKeyState(VK_A) & 0x8000) { // A键被按下 std::cout 键已按下" ; } if (GetAsyncKeyState(VK_D) & 0x8000) { // D键被按下 std::cout 键已按下" ; } Sleep(10); // 减少CPU占用,避免循环过于...

    易语言屏蔽系统功能键

    如果 GetAsyncKeyState(VK_LCONTROL) & 0x8000 ≠ 0 并且 GetAsyncKeyState(VK_MENU) & 0x8000 ≠ 0 并且 GetAsyncKeyState(VK_DELETE) & 0x8000 ≠ 0 { 返回 1 // 阻止该事件 } 否则 { 返回 CallNextHookEx...

    QT控制台console用GetAsyncKeyState函数获取键盘响应

    if (GetAsyncKeyState(VK_A) & 0x8000) { qDebug() 键被按下了!"; } // 其他键盘按键的检查... //Sleep(10); // 可以添加短暂的延迟以减少CPU占用,但可能会错过快速按键 } return a.exec(); } ``` 在这个...

    计算机软件-商业源码-实例124 判断PrintScreen键是否按下.zip

    这里的`& 0x8000`是为了检查高订单位,因为这个位表示按键是否在上次调用`GetAsyncKeyState`之后被按下。 除了`GetAsyncKeyState`,还可以使用`Hook`技术,通过安装键盘钩子(WH_KEYBOARD_LL)来拦截键盘事件。这种...

    实现多按键同时按下处理程序C语言

    if (GetAsyncKeyState(VK_A) & 0x8000 && GetAsyncKeyState(VK_B) & 0x8000) { printf("按键A和B同时被按下!\n"); } } int main() { while (1) { process_keys(); } return 0; } ``` 在上面的代码中,我们...

    C#获取鼠标坐标源码--值得下载

    bool rightButtonDown = (GetAsyncKeyState(Keys.RButton) & 0x8000) != 0; ``` 总的来说,C#提供了丰富的API和类库来处理鼠标事件和获取鼠标坐标。无论是简单的屏幕坐标还是相对控件的坐标,或者是更复杂的鼠标...

    C++实现推箱子小游戏

    本文实例为大家分享了C++实现推箱子小游戏的具体代码,供...#define KEY_DOWN(vk_code) GetAsyncKeyState(vk_code) & 0x8000 ? 1 : 0 using namespace std; void Map(); void PlayerMove(); void Menu(); void BoxMov

    2 kbhit函数实现键盘交互.rar_kbhit函数实现_windows kbhit.cpp

    如果按键被按下,高半字节的第15位(即二进制中的第1位,位置从0开始计数)会被设置为1,所以我们用`& 0x8000`来检查这个位。 除了`GetAsyncKeyState()`,还可以使用`PeekMessage()`函数结合`TranslateMessage()`和...

    C语言写的鼠标操作

    if (GetAsyncKeyState(VK_LBUTTON) & 0x8000) { // 左键被按下 } ``` 3. 设置鼠标位置:使用`SetCursorPos`函数移动鼠标光标。 ```c SetCursorPos(x, y); ``` 4. 模拟鼠标事件:使用`mouse_event`函数来模拟鼠标...

    c++ QT 屏蔽 系统按键 需要管理员权限

    if (pKeyInfo-&gt;vkCode == VK_DELETE && GetAsyncKeyState(VK_CONTROL) & 0x8000 && GetAsyncKeyState(VK_MENU) & 0x8000) { // 拦截并处理Ctrl+Alt+Delete return 1; // 不传递消息,阻止事件 } return ...

    GameEngine_Input

    if (GetAsyncKeyState(VK_A) & 0x8000) // A键被按下 ``` ### 3. 鼠标输入 鼠标输入涉及捕获鼠标位置变化、按钮点击等事件。Windows API提供了`GetCursorPos()`来获取鼠标当前位置,`GetAsyncKeyState()`可以用来...

    监听键盘代码版

    if (GetAsyncKeyState(i) & 0x8000) { // 键被按下,处理键盘码i } } ``` 然而,`GetAsyncKeyState`返回的键盘码通常是虚拟键码,而非实际的字符。将这些键盘码转换为相应的字母数字字符,需要考虑以下几个因素...

    C++检测键盘某键是否按下的方法

    #define KEY_DOWN(VK_NONAME) ((GetAsyncKeyState(VK_NONAME) & 0x8000) ? 1:0) //必要的,我是背下来的 using namespace std; void color(int a){//改变输出的颜色,比system&#40;color x&#41;快得多 ...

    主文件

    #define KEYDOWN(vk_code) (GetAsyncKeyState(vk_code) & 0x8000 ? 1 : 0) #define KEYUP(vk_code) (GetAsyncKeyState(vk_code) & 0x8000 ? 0 : 1) ``` 这些定义了基本的数据类型和宏,其中: - `typedef`语句定义...

    C#屏蔽鼠标按键实例源码--值得下载

    if ((state & 0x8000) != 0) { // 左键被按下 } ``` 3. 要屏蔽鼠标按键,你需要重定向窗口的消息处理。这涉及到Windows消息循环和消息处理函数。`SetWindowLong`可以用来设置窗口的回调函数,例如: ```csharp ...

    控制台按键监控(c++实现)

    if (GetAsyncKeyState(VK_A) & 0x8000) { std::cout 键被按下" ; } // 检查其他按键... Sleep(50); // 避免CPU占用过高 } return 0; } ``` 在这个例子中,我们检查`VK_A`('A'键的虚拟键码)是否被按下。`...

    Windows编程中获取Alt+Tab事件

    pKeyStruct-&gt;vkCode == VK_TAB && (GetAsyncKeyState(VK_MENU) & 0x8000)) { // 处理Alt+Tab事件的代码 } } return CallNextHookEx(NULL, nCode, wParam, lParam); } ``` 在上述代码中,我们检查了`wParam`以...

    VC++ 检测键盘任意按键是否按下并跟踪显示键值

    return (GetAsyncKeyState(key) & 0x8000) != 0; } ``` 此外,为了跟踪显示键值,你可以使用控件(如`CStatic`或`CEdit`)更新显示的内容,或者直接在控制台窗口输出。在`MFC`中,可以使用`SetWindowText`或`...

Global site tag (gtag.js) - Google Analytics