c++ - 如何只检测一次相同的键盘按键

标签 c++ winapi keyboard

我正在设计一个键盘类,它只能检测一次键盘按键,但我仍然想不出实现它的方法。我的目标是仅在按住或按住同一个键时检查并执行一次操作,并且在同时按下 2 个操作键时不执行任何操作。例如,当我一直按住 A 键时, Action 1 只执行一次。然后我一直按住另一个键B, Action 2也执行一次。如果同时按下 A 键和 B 键,我将无法执行任何操作。

在 KeyboardClass 头文件和 cpp 文件中有两个类,即 KeyboardClientClass 和 KeyboardServerClass。

////////////////////////////////////////////////////////////////////////////////
// Filename: KeyboardClass.h
////////////////////////////////////////////////////////////////////////////////
#ifndef _KEYBOARDCLASS_H_
#define _KEYBOARDCLASS_H_

////////////////////////////////////////////////////////////////////////////////
// Class prototype
////////////////////////////////////////////////////////////////////////////////
class KeyboardServerClass;


////////////////////////////////////////////////////////////////////////////////
// Class name: KeyboardClientClass
////////////////////////////////////////////////////////////////////////////////
class KeyboardClientClass
{
public:
    KeyboardClientClass( const KeyboardServerClass& KeyboardServer );
    ~KeyboardClientClass();
    bool KeyIsPressed( unsigned char keycode ) const;
    bool KeyIsPressedOnce( unsigned char keycode );

private:
    unsigned char tempKeyCode;
    const KeyboardServerClass& server;
};

class KeyboardServerClass
{
    friend KeyboardClientClass;

public:
    KeyboardServerClass();
    ~KeyboardServerClass();
    void OnKeyPressed( unsigned char keycode );
    void OnKeyReleased( unsigned char keycode );

   private:
        static const int nKeys = 256;
        bool keystates[ nKeys ];
        bool isKeyDown;
    };

    #endif


////////////////////////////////////////////////////////////////////////////////
// Filename: KeyboardClass.cpp
////////////////////////////////////////////////////////////////////////////////
#include "KeyboardClass.h"

KeyboardClientClass::KeyboardClientClass( const KeyboardServerClass& KeyboardServer ) 
: server ( KeyboardServer )
{
    tempKeyCode = 257;
}


KeyboardClientClass::~KeyboardClientClass()
{}


bool KeyboardClientClass::KeyIsPressed( unsigned char keycode ) const
{
    return server.keystates[ keycode ];
}



bool KeyboardClientClass::KeyIsPressedOnce( unsigned char keycode )
{
    if ( tempKeyCode != keycode )
    {
        tempKeyCode = keycode;
        return server.keystates[ keycode ];
    }
    else
    {
        return false;
    }
}


KeyboardServerClass::KeyboardServerClass()
{
    for ( int x = 0; x < nKeys; x++ )
    {
        keystates[ x ] = false;
    }
}


KeyboardServerClass::~KeyboardServerClass()
{
    isKeyDown = true;
}


void KeyboardServerClass::OnKeyPressed( unsigned char keycode )
{
    keystates [ keycode ] = true;
    isKeyDown = false;
}


void KeyboardServerClass::OnKeyReleased( unsigned char keycode )
{
    keystates [ keycode ] = false;
    isKeyDown = true;
}

首先,我创建了一个 KeyboardServer 对象来跟踪来自 Windows Procedure 的键盘消息。

LRESULT CALLBACK SystemClass::MessageHandler( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
    switch ( msg )
    {
        //************ KEYBOARD MESSAGES ************ //

        // Check if a key has been pressed on the keyboard
        case WM_KEYDOWN:
        {
            if ( wParam == VK_ESCAPE )
                PostQuitMessage( 0 );

            // If a key is pressed send it to the KeyboardServer object so it can record the state
            m_KeyboardServer.OnKeyPressed( wParam );
            break;
        }

        // Check if a key has been released on the keyboard
        case WM_KEYUP:
        {
            // If a key is released then send it to the KeyboardServer object so it can unset the state for that key
            m_KeyboardServer.OnKeyReleased( wParam );
            break;
        }

        // ************ END KEYBOARD MESSAGES ************ //
}

然后,我在 Game 类中创建一个 KeyboardClient 对象来检查是否按下了某个键,并根据按下的键执行操作。

if ( m_Keyboard.KeyIsPressed( KEY_B ) )
    // Do action A
else if ( m_Keyboard.KeyIsPressed( KEY_N ) )
    // Do action B

最佳答案

WM_KEYDOWNlParam 值的第 30 位消息指示生成消息时 key 是否先前已关闭。您可以使用它来区分实际按键和任何后续按键重复。

case WM_KEYDOWN:
    if (lParam & (1 << 30))
    {
        // this is a repeat
    }
    else
    {
        // first press
    }
    break;

但是,如果您正在尝试实时检查哪些键按下了,您可以使用 GetAsyncKeyState() 来完成此操作。功能,而不是依赖于通过消息循环跟踪键状态。

关于c++ - 如何只检测一次相同的键盘按键,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19076158/

相关文章:

c++ - IcmpSendEcho 失败但 "ping"成功

windows - Windows 用户模拟有哪些副作用?

delphi - 我的 delphi 应用程序与 native 键盘不兼容。我该怎么办?

C++:使用递归加倍数字

c++ - 尝试对结构 A-Z 文件进行排序时出现排序函数错误

c++ while从具有不同数据类型的文件循环

C++ 断言消息

windows - 在 Windows 服务中使用 SHFileOperation

ios - 如何从 iOS Swift 3 的键盘上删除更改语言键按钮

Android - 在用户启用输入法后关闭 IME 设置 Activity