Consecutive Key Presses

From Valve Developer Community
Jump to navigation Jump to search
Wikipedia - Letter.png
This article has multiple issues. Please help improve it or discuss these issues on the talk page. (Learn how and when to remove these template messages)
Dead End - Icon.png
This article has no Wikipedia icon links to other VDC articles. Please help improve this article by adding links Wikipedia icon that are relevant to the context within the existing text.
January 2024

Overview

Below is a proposition for a system to monitor consecutive key presses within the Source engine. In the example provided, we'll monitor for two taps of the same key within a certain number of seconds. This system could be useful in a number of situations. One possible example would be a combo-based movement or combat system.

Our KeyTracker structure

First we define a structure to track various keypresses. For each key we record a flag (to monitor its state) and the LastPressTime, which is relatively self-explanatory. As far as the flag value is concerned: 0 represents the key having never been pressed. 1 represents one press and 2 represents two presses.

struct KeyTracker 
{

	int flag;
	float LastPressTime;

} doubleTap[ 2 ];

Checking for key presses

I suggest creating a simple HandleKeyPress method which would be triggered in various circumstances.

if (m_afButtonPressed & IN_FORWARD) 
{

	HandleKeyTap( 0 );

}

Handling the key presses

The following code is relatively self-explanatory, If the key has never been pressed, we set its flag to 1. If the key has already been pressed, we check to see whether the player pressed the key fast enough for it to count as a 'combo' or 'double tap'. Otherwise, we set it back to 1. After each call to HandleKeyPress we set LastPressTime to record the time of the keypress. This is used later to check if a player was fast enough in pressing that particular key a second time. In the following example, they have a 5 second window.

void HandleKeyTap( int iKeyId ) 
{

	if( !doubleTap[iKeyId].flag ) 
        {

		doubleTap[iKeyId].flag = 1;	

	} 
        else if( doubleTap[iKeyId].flag > 0 && doubleTap[iKeyId].flag < 2 ) 
        {

		// Check if the key was pressed fast enough to count as a double tap!
		if( doubleTap[iKeyId].LastPressTime + 5.0f < gpGlobals->curtime ) 
                {

                        doubleTap[iKeyId].flag = 1; // Too slow!

		} 
                else 
                {

			doubleTap[iKeyId].flag = 2; // Double tap!

		}

	} 
        else if( doubleTap[iKeyId].flag >= 2 ) 
        {

		doubleTap[iKeyId].flag = 1;

	}

	doubleTap[iKeyId].LastPressTime = gpGlobals->curtime;

}

Possible improvements

The above solution is fairly primitive and, as such, can be updated and improved upon in a number of ways. Here are a few possible suggestions:

  • Don't hard code the 'window' time value. Instead, set the value via a CON_COMMAND or a similarly flexible configuration routine.
  • Allocate the KeyTracker array in such a way as to avoid giving particula r actions numeric ID's (in this example, pressing the IN_FORWARD key was assigned the value 0). Instead, it would be far better to map thearray to keys themselves.