If you were going to devise an input system...

Started by
0 comments, last by matthughson 18 years, 7 months ago
If you got messages in the message pump that told you information on whether a key had been pressed or released, what key it was, and whether different modifier keys (like shift, alt, control) were being pressed, how would you store that information? I'm working on an input system right now, and need a way to store which keys are being pressed, along with information on whether keys like shift, alt, etc. were being pressed with it. I was planning on making an std::queue of key events and storing them there. However, I then remembered that (duh) people might press multiple keys and release them out of order of when they were pressed. I'm now of course reconsidering the design. I need a way to keep track of what keys are being pressed and easily add/remove information. It's going to have to be kept track of by what key is being pressed, as well as what modifier keys were being pressed. Anyways, if you have any ideas, please let me know. I don't really need code, just a general idea. Thanks.
my siteGenius is 1% inspiration and 99% perspiration
Advertisement
Here's a DirectInput wrapper I wrote. Just thought it might give you some ideas, or feel free to use it if you're using DInput.

Note: It's part of a much large system so some of the error handling and stuff might seem a little out of place.

DX_Input.h:
// DX_Input.h: interface for the CDX_Input class.////////////////////////////////////////////////////////////////////////#if !defined(AFX_DX_INPUT_H__3681CBA1_CC65_41C3_AB2C_4AE78F991043__INCLUDED_)#define AFX_DX_INPUT_H__3681CBA1_CC65_41C3_AB2C_4AE78F991043__INCLUDED_#if _MSC_VER > 1000#pragma once#endif // _MSC_VER > 1000// Defines////////////// This define just gets rid of a stupid little DX warning#define DIRECTINPUT_VERSION	0x0800// Headers////////////#include "MHResults.h"#include <DINPUT.H>// Classes////////////class CDX_Input  {private:	// Members	////////////	// By having a static m_spInstance of the class within itself we can now	// access the same m_spInstance of the class from anywhere!	// This is what makes this a singleton	static CDX_Input* m_spInstance;		// This is the main object used to interface with dinput	LPDIRECTINPUT8	m_dinObject;	// The keyboard device	LPDIRECTINPUTDEVICE8 m_dinDeviceKeyboard;	// Buffer to store the key presses	char m_rgcKeyboardState[256];	char m_rgcPrevKeyboardState[256];	// The mouse device	LPDIRECTINPUTDEVICE8 m_dinDeviceMouse;	// Something to store the state of the mouse	DIMOUSESTATE m_mouseState;	DIMOUSESTATE m_PrevmouseState;	// Methods	////////////	// We need to make the constructors private so that	// no one tries to create their own m_spInstance of the class	CDX_Input() { }	CDX_Input(const CDX_Input&) { }	CDX_Input& operator=(const CDX_Input&) { return *this; }	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////	// Function: "_createAndAquire"	//	// Input:	a_guid		The m_spInstance GUID for the desired input device 	//			a_pDinDevice	The device we are creating	//			a_format		The format of the device	//			a_dwCoopLevel	The cooperative level we want the device set to	// Returns: MHRESULT		The result of the method	//	// Purpose: Creates and acquires a device of the clients choice	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////	MHRESULT _createAndAquire(REFGUID a_guid, LPDIRECTINPUTDEVICE8 *a_pDinDevice, LPCDIDATAFORMAT a_format, DWORD a_dwCoopLevel);	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////	// Function: "_updateDeviceStates"	//	// Input:	none	// Returns: none	//	// Purpose: Updates the data structures holding each devices state	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////	void _updateDeviceStates();public:	// Methods	////////////	void clearKeys();		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////	// Function: "getm_spInstance"	//	// Input:	none	// Returns: none	//	// Purpose: Retrieves the static m_spInstance of the class.	//			If the static m_spInstance has not be dynamically allocated yet, 	//			this function will do it	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////	static CDX_Input* getInstance();	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////	// Function: "~CDX_Input"	//	// Input:	none	// Returns: none	//	// Purpose: Destructor - Called upon deletion of a CDX_Input object	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////	~CDX_Input();	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////	// Function: "initialize"	//	// Input:	none	// Returns: none	//	// Purpose: Initializes the class, including creating and aquiring our devices	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////	void initialize();	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////	// Function: "update"	//	// Input:	none	// Returns: none	//	// Purpose: Updates the data structures containing the device states	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////	void update();	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////	// Function: "shutdown"	//	// Input:	none	// Returns: none	//	// Purpose: Cleans up any memory the class may have created for itself	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////	void shutdown();	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////	// Function: "checkKeyboardButton"	//	// Input:	a_iButton	The DIK_* define corresponding to the key we are checking	// Returns: bool		True : The key has been pressed	//	// Purpose: Checks the current device state to see if a certain button has been pressed	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////	bool checkKeyboardButton(int a_iButton);	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////	// Function: "checkKeyboardButtonBuffered"	//	// Input:	a_iButton	The DIK_* define corresponding to the key we are checking	// Returns: bool		True : The key has been pressed	//	// Purpose: Same as the function checkKeyboardButton, except that it returns false if the key	//			was being pressed last frame	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////	bool checkKeyboardButtonBuffered(int a_iButton);	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////	// Function: "checkMouseButton"	//	// Input:	a_iButton	The DIK_* define corresponding to the key we are checking	// Returns: bool		True : The key has been pressed	//	// Purpose: Checks the current device state to see if a certain button has been pressed	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////	bool checkMouseButton(int a_iButton);	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////	// Function: "checkMouseButtonBuffered"	//	// Input:	a_iButton	The number define corresponding to the key we are checking	// Returns: bool		True : The key has been pressed	//	// Purpose: Sames as the unbuffered version except with this one, makes sure the key wasn't being pressed	//			last update as well	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////	bool checkMouseButtonBuffered(int a_iButton);	//////////////////////////////////////////////////////////////////////////	// Accessors | Modifiers	//////////////////////////////////////////////////////////////////////////		DIMOUSESTATE* getMouseState() {		return &m_mouseState;	}};#endif // !defined(AFX_DX_INPUT_H__3681CBA1_CC65_41C3_AB2C_4AE78F991043__INCLUDED_)


DX_Input.cpp:
// CDX_Input.cpp: implementation of the CDX_Input class.////////////////////////////////////////////////////////////////////////// Headers////////////#include "DX_Input.h"#include "DX_D3DWrapper.h"#include "MHGlobalDefines.h"#include <STDIO.H>#include "mmgr.h"// Globals////////////CDX_Input* CDX_Input::m_spInstance = NULL;// Defines////////////// Make it a little easier to switch between modes#define MOUSE_MODE DISCL_FOREGROUND | DISCL_EXCLUSIVE		// Owns mouse//#define MOUSE_MODE DISCL_BACKGROUND | DISCL_NONEXCLUSIVE	// Doesn't own mouse// Methods/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Function: "_createAndAquire"//// Purpose: Creates and aquires a device of the clients choice/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////MHRESULT CDX_Input::_createAndAquire(REFGUID a_guid, LPDIRECTINPUTDEVICE8 *a_pDinDevice, LPCDIDATAFORMAT a_format, DWORD a_dwCoopLevel){	// Singletons	CDX_D3DWrapper* d3dMan	= CDX_D3DWrapper::getInstance();	CMHResults* pErrHan	= CMHResults::getInstance();	// Create the device	if(FAILED(m_dinObject->CreateDevice(a_guid, a_pDinDevice, NULL)))		return pErrHan->processError(MHRSLT_D3DFAILED, "CDX_Input::_createAndAquire( )");	// Set the format for the device	if(FAILED((*a_pDinDevice)->SetDataFormat(a_format)))		return pErrHan->processError(MHRSLT_D3DFAILED, "CDX_Input::_createAndAquire( )");	// Set the cooperative level of the device	if(FAILED((*a_pDinDevice)->SetCooperativeLevel(d3dMan->getHwnd(), a_dwCoopLevel)))		return pErrHan->processError(MHRSLT_D3DFAILED, "CDX_Input::_createAndAquire( )");	// The final step is to aquire the device	if(FAILED((*a_pDinDevice)->Acquire()))		return pErrHan->processError(MHRSLT_D3DFAILED, "CDX_Input::_createAndAquire( )");	// If we make it all the way to here we have succeeded	return MHRSLT_OK;}/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Function: "getm_spInstance"//// Purpose: Retrieves the static m_spInstance of the class.//			If the static m_spInstance has not be dynamically allocated yet, //			this function will do it/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////CDX_Input* CDX_Input::getInstance(){	// Start by checking if we have allocated the memory for the static m_spInstance yet	if(!m_spInstance)	{		// We need to allocate the memory for the static m_spInstance		m_spInstance = new CDX_Input;	}		// Either way we need to return the static m_spInstance of the class	return m_spInstance;}/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Function: "~CDX_D3DWrapper"//// Purpose: Destructor - Called upon deletion of a CDX_D3DWrapper object/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////CDX_Input::~CDX_Input(){}void CDX_Input::clearKeys(){	memset(m_rgcKeyboardState, -1, sizeof(m_rgcKeyboardState));	memcpy(m_rgcPrevKeyboardState, m_rgcKeyboardState, sizeof(m_rgcPrevKeyboardState));	memset(&m_mouseState, -1, sizeof(m_mouseState));	memset(&m_PrevmouseState, -1, sizeof(m_PrevmouseState));}/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Function: "initialize"//// Purpose: Initializes the class, including creating and aquiring our devices/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////void CDX_Input::initialize(){	// Singletons	CMHResults* pErrHan	= CMHResults::getInstance();	// Start by setting our main interface device to NULL	m_dinObject = NULL;	// As well as the other devices	m_dinDeviceKeyboard	= NULL;	m_dinDeviceMouse	= NULL;	// Clear the states	memset(m_rgcKeyboardState, 0, sizeof(m_rgcKeyboardState));	memcpy(m_rgcPrevKeyboardState, m_rgcKeyboardState, sizeof(m_rgcPrevKeyboardState));	memset(&m_mouseState, 0, sizeof(m_mouseState));	memset(&m_PrevmouseState, 0, sizeof(m_PrevmouseState));		// Create the main input object	if(FAILED(DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&m_dinObject, NULL)))	{		// Log the error		pErrHan->processError(MHRSLT_D3DFAILED, "CDX_Input::initialize( )", "Could not initialize DirectInput");		return;	}	// Create the keyboard device	if(MHFAILED(_createAndAquire(GUID_SysKeyboard, &m_dinDeviceKeyboard, &c_dfDIKeyboard, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE)))	{		// Log the error		pErrHan->processError(MHRSLT_D3DFAILED, "CDX_Input::initialize( )", "Could not acquire keyboard");	}	// Create the mouse device	if(MHFAILED(_createAndAquire(GUID_SysMouse, &m_dinDeviceMouse, &c_dfDIMouse, MOUSE_MODE)))	{		// Log the error		pErrHan->processError(MHRSLT_D3DFAILED, "CDX_Input::initialize( )", "Could not acquire mouse");		}}/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Function: "_updateDeviceStates"//// Purpose: Updates the data structures holding each devices state/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////void CDX_Input::_updateDeviceStates(){	// Singletons	CMHResults* pErrHan	= CMHResults::getInstance();	// Check that the keyboard exists	if(m_dinDeviceKeyboard)	{		// Save the old state before we get the new one		memcpy(m_rgcPrevKeyboardState, m_rgcKeyboardState, sizeof(m_rgcPrevKeyboardState));		// Now get the new one		m_dinDeviceKeyboard->GetDeviceState(sizeof(m_rgcKeyboardState), (LPVOID)&m_rgcKeyboardState);	}	// Check that the mouse exists	if(m_dinDeviceMouse)	{		// Save the old state before we get the new one		memcpy(&m_PrevmouseState, &m_mouseState, sizeof(m_PrevmouseState));		// Now get the new one		if(FAILED(m_dinDeviceMouse->GetDeviceState(sizeof(m_mouseState), (LPVOID)&m_mouseState)))		{			// Log the error			pErrHan->processError(MHRSLT_D3DFAILED, "CDX_Input::_updateDeviceStates( )", "Lost mouse: reacquiring now");				if(MHFAILED(_createAndAquire(GUID_SysMouse, &m_dinDeviceMouse, &c_dfDIMouse, MOUSE_MODE)))			{				// Log the error				pErrHan->processError(MHRSLT_D3DFAILED, "CDX_Input::_updateDeviceStates( )", "Could not acquire mouse");				}		}	}}/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Function: "update"//// Purpose: Updates the data structures containing the device states/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////void CDX_Input::update(){	// Update the current state of the acquired devices	_updateDeviceStates();}/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Function: "shutdown"//// Purpose: Cleans up any memory the class may have created for itself/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////void CDX_Input::shutdown(){	// Check if we were able to create the keyboard	if(m_dinDeviceKeyboard)	{		// Unacquire the device		m_dinDeviceKeyboard->Unacquire();		// Release the object		m_dinDeviceKeyboard->Release();		// Set the pointer to NULL to make error checking easier		m_dinDeviceKeyboard = NULL;	}	// Do the same for the mouse	if(m_dinDeviceMouse)	{		m_dinDeviceMouse->Unacquire();		m_dinDeviceMouse->Release();		m_dinDeviceMouse = NULL;	}	// Check if we were able to create the main DInput object	if(m_dinObject)	{		// Release the object		m_dinObject->Release();		// Set it to NULL to make error checking easier		m_dinObject = NULL;	}	// Delete our device	if(m_spInstance)	{		delete m_spInstance;		m_spInstance = NULL;	}}/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Function: "checkKeyboardButton"//// Purpose: Checks the current device state to see if a certain button has been pressed/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////bool CDX_Input::checkKeyboardButton(int a_iButton){	// Check if the key has been pressed	if(m_rgcKeyboardState[a_iButton] & 0x80)	{		// The key has been pressed		return true;	}	// If we make it to here, the key was not pressed	return false;}/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Function: "checkKeyboardButtonBuffered"//// Input:	a_iButton	The DIK_* define corresponding to the key we are checking// Returns: bool		True : The key has been pressed//// Purpose: Same as the function checkKeyboardButton, except that it returns false if the key//			was being pressed last frame/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////bool CDX_Input::checkKeyboardButtonBuffered(int a_iButton){	// Check if the key has been pressed	if(m_rgcKeyboardState[a_iButton] & 0x80)	{		// Now check if it was being pressed last frame		if(m_rgcPrevKeyboardState[a_iButton] & 0x80)			return false;		// The key has been pressed		return true;	}	// If we make it to here, the key was not pressed	return false;}/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Function: "checkMouseButton"//// Purpose: Checks the current device state to see if a certain button has been pressed/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////bool CDX_Input::checkMouseButton(int a_iButton){	// Check if the button has been pressed	if(m_mouseState.rgbButtons[a_iButton] & 0x80)	{		// The button has been pressed		return true;	}	// If we make it here the button was not pressed	return false;}/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Function: "checkMouseButtonBuffered"//// Purpose: Sames as the unbuffered version except with this one, makes sure the key wasn't being pressed//			last update as well/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////bool CDX_Input::checkMouseButtonBuffered(int a_iButton){	// Check if the button has been pressed	if(m_mouseState.rgbButtons[a_iButton] & 0x80)	{		if(m_PrevmouseState.rgbButtons[a_iButton] & 0x80)			return false;		// The button has been pressed		return true;	}	// If we make it here the button was not pressed	return false;}


Hope that helps a bit,
Matt Hughson
__________________________________[ Website ] [ Résumé ] [ [email=contact[at]matthughson[dot]com]Contact[/email] ][ Have I been Helpful? Hook me up! ]

This topic is closed to new replies.

Advertisement