Monday, July 18, 2016

c++ - how to detect same keyboard key press only once


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

Answer



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.


No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...