Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I am designing a keyboard class that can detect the keyboard key press only one time but I still cannot figure out the way to do it. My goal is just check and perform the action only once when the same key is keep pressing or keep holding and no action performed when 2 action keys are pressed at the same time. For example, when I keep pressing or holding key A, action 1 is only perform once. Then I keep pressing or holding another key B, action 2 is also perform once. I cannot peform any action if I press key A and B at the same time.

There is two class inside KeyboardClass header and cpp file i.e. KeyboardClientClass and 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;
}

Firstly, I create the a KeyboardServer object to keep track of the keyboard messgae from 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 ************ //
}

Then, I create a KeyboardClient object at Game class to check whether a key has been pressed or not and perform the action based on key pressed.

if ( m_Keyboard.KeyIsPressed( KEY_B ) )
    // Do action A
else if ( m_Keyboard.KeyIsPressed( KEY_N ) )
    // Do action B
share|improve this question
    
I'm not familiar to DirectX, and I don't understand all your code, but in XNA, I'd just create booleans for each key and store wheather the key is pressed or not. If you now detect "a key is down", just check "Was it down last update" and fire the event just if it wasn't. –  jalgames Sep 29 '13 at 9:31
add comment

2 Answers

up vote 1 down vote accepted

Pseudo code:

currentKeyboardState
previousKeyboardState

void UpdateInput()
    store currentstate to previousstate
    get new state to currentstate

Now that we have stored the last state and we know the current state, we can check if key was NOT pressed in last frame and is now pressed. So we know if key was pressed down just now.

if(currentKeyboardState.KeyIsPressed( KEY_B ) && !previousKeyboardState.KeyIsPressed( KEY_B ))

We can also detect if key is being held down, by checking if it was down last frame and now.

if(currentKeyboardState.KeyIsPressed( KEY_B ) && previousKeyboardState.KeyIsPressed( KEY_B ))

Checking if key was down last frame, but is not anymore, we can say that it was released.

if(!currentKeyboardState.KeyIsPressed( KEY_B ) && previousKeyboardState.KeyIsPressed( KEY_B ))

With these, i think you can create what you need.

TL;DR;

Store previous keyboard state, so you can compare current state to previous state and determine if something fishy is going on.

share|improve this answer
    
You can also detect if the key was released by checking if the key was down but isn't anymore. –  Casey Sep 29 '13 at 10:08
    
Right, somehow forgot that. I edited answer and added that as an example too. –  Katu Sep 29 '13 at 11:00
add comment

When you detect the WM_KEYDOWN message, you can use the bits in the LPARAM argument in your message handler to determine if the key stroke is repeated and also what the key's previous state was.

Store if the key is repeated as well as pressed/released. When you keep pressing or holding key A, only perform action 1 if the repeat count is 0.

if ( m_Keyboard.KeyIsPressed( KEY_A ) && !m_Keyboard.KeyIsRepeated( KEY_A ) )
    // Do action A

Note: If the keystroke is held long enough, multiple messages are sent which might change the repeat count.

To cancel out keys A and B, you can add up a count of the number of keys pressed that you want to be exclusive of each other in your keyboard client and only perform the action if there is a total of 1 key pressed.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.