在Win32中确定按键和按住键的最快方法是什么?
What is the fastest way to determine a key press and key holding in Win32?
确定按下键的最快方法是什么,以及如何确定是否持有键?窗口消息传递似乎很慢。请提供一个示例,说明如何这样做,以及为什么它比其他选择更快。
要明确的是,这是一个实时循环(模拟),所以我正在寻找最快的方法来确定一个键是否已被按下,并检查它是否被持有。
GetAsyncKeyState()是你正在寻找的。不管输入队列的状态如何,它都会读取键盘的物理状态。如果设置了高位,则在呼叫时密钥处于down状态。
// Fetch tab key state.
SHORT tabKeyState = GetAsyncKeyState( VK_TAB );
// Test high bit - if set, key was down when GetAsyncKeyState was called.
if( ( 1 << 15 ) & tabKeyState )
{
// TAB key down...
}
另外,需要说明的是,Windows不是实时操作系统。如果您的应用程序需要实时精度,您可能需要选择另一个平台。
如果您只是想轮询键盘状态,以便发现哪些键是上/下以及shift/alt/ctrl状态,只需调用GetKeyboardState
(MSDN参考)。
当我在游戏工作室工作时,这正是我们如何获得每一帧的键盘状态。应该适用于您的模拟代码。
TL;DR:你可以使用GetAsyncKeyState来检查一个键是否当前按下,但为了获得最佳的应用程序对按键和释放的响应,你想使用Win32管道代码在我的文章的底部。
GetAsyncKeyState在确定键是否当前按下时工作得很好,但是在确定键是否首次按下或释放以及执行了多少次方面,GetAsyncKeyState在cpu密集型应用程序中会错过击键,即使在存储之前的键状态之后。
这就是我所尝试的:
static const unsigned int NumberOfKeys = 256U;
bool previousKeyboardState[NumberOfKeys];
//Get the current state of each key as the application starts to ensure that keys held down beforehand are not processed as pressed keys.
for (unsigned int keyNum = 0U; keyNum < NumberOfKeys; ++keyNum)
{
previousKeyboardState[keyNum] = isKeyDown(keyNum);
}
//Works fine.
bool isKeyDown(int key)
{
return (GetAsyncKeyState(key) & (1 << 16));
}
//Misses key presses when application is bogged down.
bool isKeyFirstPressed(int key)
{
bool previousState = previousKeyboardState[key];
previousKeyboardState[key] = isKeyDown(key);
return (previousKeyboardState[key] && !previousState);
}
//Misses key releases when application is bogged down.
bool isKeyFirstReleased(int key)
{
bool previousState = previousKeyboardState[key];
previousKeyboardState[key] = isKeyDown(key);
return (!previousKeyboardState[key] && previousState);
}
//Example usage:
if (isKeyDown(VK_W))
{
//W key.
}
if (isKeyFirstReleased(VK_SNAPSHOT))
{
//Print screen.
}
GetKeyboardState也不好,因为它不跟踪按键或释放的次数。正如Erik Philips在他的回答中所说,这些都是未缓冲的解决方案,如果你正在编写一款游戏,这些解决方案并不好。您必须处理所有击键的速度要比接收它们的速度快。
现在,我上面的代码工作得很好,可能适合很多人,但我更希望不要错过一个键击。我讨厌使用无响应的应用程序。我认为Win32应用程序的最佳解决方案是捕获管道中的WM_KEYDOWN和WM_KEYUP消息并处理它们。好的是WM_KEYDOWN还提供了一个自动重复计数,这对于支持输入文本的应用程序(例如聊天,IDE等)可能很有用。这也增加了一点复杂性,这在WM_KEYDOWN文档中提到:由于自动重复功能,有多个WM_KEYDOWN消息可以在WM_KEYUP消息发布之前发布。前一个键state(位30)可以用来确定是否WM_KEYDOWN消息第一次向下转换或重复向下转换。
也有Windows键盘挂钩,你可以看看,但那些更难以使用。
考虑到所有窗口间的通信都是通过windows消息传递(键盘事件,鼠标事件,几乎所有你能想象到的事件),我知道没有更低级别的方法来访问键盘事件(除非你编写自己的键盘驱动程序)。
DirectX仍然使用windows键盘消息传递,以使DirectX程序员更容易访问键盘事件。
更新我对DirectX的注意是不要使用它,但是当微软想要为程序员制作一个用于实时游戏的界面时,他们仍然在Windows Message Queue之上编写DirectX。
我建议看一下如何编写一个可以直接从消息队列中读取的程序。我相信有一个很好的例子代码项目Windows消息处理-第一部分。
您的两个选择是从消息队列中读取(缓冲)或直接从键盘状态中读取(如Bukes状态),这意味着您自己的循环可能由于各种原因在技术上错过键盘事件。
- 为不同配置设置MSVC_RUNTIME_LIBRARY的正确方法是什么
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 实现无开销push_back的最佳方法是什么
- C++从另一个类访问公共静态向量的正确方法是什么
- 在 c++ 中拥有一组结构的正确方法是什么?
- 通过JNI传递数据数组的最快方法是什么
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 使用不同的CRT将新的C++代码与旧的(二进制)组件隔离开来的最佳方法是什么
- 当无法使用模板和宏时,生成类型变体C++代码的最简单方法是什么?
- 在另一个类视图中添加最多2个图表的正确方法是什么
- 在C++中样板"冷/never_inline"错误处理技术的最佳方法是什么?
- 在 c++ 中对类中的 c 字符串动态数组进行排序的最佳方法是什么?
- 在C++中包含原型文件的正确方法是什么?
- 在 OpenCV C++ 中估计基本矩阵之前对相应点进行归一化的正确方法是什么?
- 在PostgreSQL中根据它们的ID选择大量行的最快方法是什么?
- 在OSX上使用CMake将Adobe的XMP工具包构建为共享库的最简单方法是什么?
- 将一系列整数放入类的最佳方法是什么?
- 从长整整转换为uint64_t的推荐方法是什么?
- 将此布尔值传递给此函数的最有效方法是什么?
- 通过比较C++中的行在 txt 文件中搜索的最简单方法是什么?