If you were going to devise an input system...
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.
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.cpp:
Hope that helps a bit,
Matt Hughson
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
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement