确定按键的最快方法是什么,以及如何确定按键是否被按住?窗口消息传递似乎很慢。请提供一个如何操作的示例,以及为什么它比替代方案更快。
要清楚,这是一个实时循环(模拟)所以我正在寻找最快的方法来确定是否按下了一个键,并检查它是否被保持。
答案 0 :(得分:21)
GetAsyncKeyState()正是您要找的。无论输入队列状态如何,它都会读取键盘的物理状态。如果设置了高位,则在通话时键已关闭。
// 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不是实时操作系统。如果您的应用程序需要实时精确度,您可能需要选择其他平台。
答案 1 :(得分:6)
如果您只想轮询键盘状态以便发现哪些键是向上/向下以及 shift / alt / ctrl 州,只需致电GetKeyboardState
(MSDN reference)。
当我在游戏工作室工作时,这正是我们为每一帧获得键盘状态的方式。应该适用于您的模拟代码。
答案 2 :(得分:3)
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(bit 30)可用于确定是否为WM_KEYDOWN消息 表示第一次向下转换或重复向下转换。
您还可以查看Windows键盘挂钩,但这些挂钩更难以使用。它们很适合接收全球按键。
答案 3 :(得分:2)
考虑到所有的窗口间通信都是通过Windows消息传递(键盘事件,鼠标事件,几乎所有你能想象的事件),没有一种较低级别的方式来访问键盘事件(除非你编写自己的键盘司机)我知道。
DirectX仍然使用Windows键盘消息传递来为DirectX程序员提供更轻松的键盘事件访问。
已更新
我对DirectX的注意事项不是使用它,但是当微软希望为程序员创建一个用于实时游戏的界面时,他们仍然会在Windows消息队列之上编写DirectX。
我建议看看如何编写一个可以直接从消息队列中读取的程序。我相信有一个很好的例子Code Project Windows Message Handling - Part 1。
您的两个选项是从消息队列中读取(缓冲)或直接从键盘状态读取(如Bukes状态),这意味着您自己的循环可能由于多种原因在技术上错过键盘事件。