Jump to content
  • Advertisement
Sign in to follow this  
silverphyre673

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

This topic is 4811 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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.

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!