Click here to Skip to main content
15,891,864 members
Articles / Multimedia / DirectX

A DirectX Game: Quadrino

Rate me:
Please Sign up or sign in to vote.
4.89/5 (41 votes)
16 Oct 2008CPOL26 min read 397.4K   6.2K   125  
An interpretation of a popular falling block game implemented with DirectX that attempts to avoid any copyright infringement.
/* MainFrm.cpp ****************************************************************
Author:		Paul Watt, Copyright (c) 2002
Date:		5/4/2002
Purpose:	The main frame for the Quadrino game.
******************************************************************************/
#include "stdafx.h"
#include "DDUtil.h"
#include "DInput.h"

#include "mainfrm.h"

/* Global Variables **********************************************************/
LPDIRECTINPUT8			g_pDI;
LPDIRECTINPUTDEVICE8	g_pdidKeyboard;

DIDEVICEOBJECTDATA  g_dodBuffer[KEYBOARD_BUFFERSIZE];

#define BITDEPTH_32 32
#define BITDEPTH_24 24

/* Public *********************************************************************
Author:		Paul Watt
Date:		4/16/2002
Purpose:	Updates the current frame of the game.
Parameters:	NONE
Return:		HRESULT returns the state of this function call.
******************************************************************************/
HRESULT CMainFrame::OnUpdateFrame ()
{
			//C: Only continue if the window actually exists.
	if (!m_hWnd)
	{
		return E_FAIL;
	}
			//C: Check the users input in order to manipulate the pieces.
			//C: Only chrck if the input device is properly initialized, and this app has focus.
	if (g_pdidKeyboard && ::GetFocus())
	{
			//C: Keyboard state buffer.
	    DWORD   dwCount = KEYBOARD_BUFFERSIZE;
		HRESULT hr = GetDeviceData(dwCount);
		if (SUCCEEDED(hr))
		{
			//C: Cycle through each of the command events until the buffer is empty.
			for (DWORD index = 0; index < dwCount; ++index)
			{
			//C: Update the state of the key that was just pressed.
				DIDEVICEOBJECTDATA *data = &g_dodBuffer[index];
			//C: Get the latest timestamp for a key.
				m_dwTimeStamps[data->dwOfs] = data->dwTimeStamp;

				m_bKBState[data->dwOfs] = (BYTE)data->dwData;
			//C: The way that input is handled depends on the current mode of the game.
				if (!m_game.IsInit())
				{
					if (CQuadrinoView::OPTIONS == m_view.GetState())
					{
						hr = HandleOptionsScreenInput(*data);
					}
					else
					{
			//C: The main screen is displayed.
						hr = HandleMainScreenInput(*data);
					}
				}
				else if (m_game.IsPaused())
				{
			//C: The game is paused.
					hr = HandlePauseScreenInput(*data);
				}
				else
				{
			//C: The user is currently playing the game.
					hr = HandleGameInput(*data);
				}

			//C: Verify that input was processed successfully.
				if (FAILED(hr))
				{
					ATLASSERT(0);
				}
			}
			//C: Process any of the commands that function while the user holds down the key.
			hr = HandleContinuousInput (GetTickCount());
		}
		else
		{
			ATLTRACE("The data for the input device could not be retrieved.\n");
		}
	}
		//C: Refresh the display of the game.
	if (m_view.IsWindow())
	{
		return m_view.UpdateFrame();
	}

	return S_OK;
}


/* Public *********************************************************************
Author:		Paul Watt
Date:		5/5/2002
Purpose:	Handles the WM_CREATE message.
******************************************************************************/
LRESULT CMainFrame::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
		//C: Load the users settings from a file.
	if (0)
	{
#pragma message( REMIND( "PMW: Read the settings from a file." ) )
	}
	else
	{
		//C: Set the default values.
		SetDefaultSettings ();
	}

	InitializeQuadrinoModule ();
		//C: Create and initialize the view window that will display the game.
	m_hWndClient = m_view.Create(m_hWnd, rcDefault, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0);
	m_view.SetGame(&m_game);
		//C: Get the current working directory.
	TCHAR szDir[_MAX_PATH];

	USES_CONVERSION;
		//C: Get the directory where the current program is running.
	if (0 == ::GetModuleFileName(NULL, szDir, _MAX_PATH))
	{
		::MessageBox(m_hWnd, _T("Could not identify application resources.  Quadrino will now exit."), _T("Error"), MB_OK | MB_ICONSTOP);
		return -1;
	}

	TCHAR *szFileName = ::_tcsrchr(szDir, '\\');
	if (szFileName)
	{
		*szFileName = NULL;
	}
		//C: Initialize the Music Player.
	CComBSTR bstrMusic = T2W(szDir);
	bstrMusic += _T("\\Sounds\\Quadrino.mp3");

	m_MusicPlayer.SetCurrentFile(bstrMusic);
	m_MusicPlayer.Repeat(true);
	m_MusicPlayer.SetNotifyWindow(m_hWnd, WM_GRAPHNOTIFY, 0);

		//C: Initialize Sounds.
	m_SoundManager.Initialize(m_hWnd);

	TCHAR szSound[_MAX_PATH];
	::_tcscpy_s(szSound, szDir);
	::_tcscat_s(szSound, _T("\\Sounds\\rotate.wav"));
	m_SoundManager.CreateSound(&m_pSoundRotate, szSound, 0, 5);

	::_tcscpy_s(szSound, szDir);
	::_tcscat_s(szSound, _T("\\Sounds\\move.wav"));
	m_SoundManager.CreateSound(&m_pSoundMove, szSound, 0, 10);

	::_tcscpy_s(szSound, szDir);
	::_tcscat_s(szSound, _T("\\Sounds\\state.wav"));
	m_SoundManager.CreateSound(&m_pSoundState, szSound, 0, 4);
		//C: Set the sound levels.
	SetMusicVolume(100);
	SetSoundFXVolume(50);

	CMessageLoop* pLoop = _Module.GetMessageLoop();
	if (pLoop)
	{
		//C: Add a this window as a message filter.
		pLoop->AddMessageFilter(this);
		//C: Verify that the message loop is a game loop.  
		CGameLoop *pGameLoop = dynamic_cast<CGameLoop*>(pLoop);
		if (!pGameLoop)
		{
		//C: This window requires the loop to be a game loop for the 
			ATLTRACE2(atlTraceUI, 0, _T("The MessageLoop is not a CGameLoop.  This window cannot proceed.\n"));
			return -1;
		}
		else
		{
		//C: Add this window as the UpdateFrame window.
			pGameLoop->SetGameHandler(this);
		}
	}
		//C: Initialize the keyboard state.
	ZeroMemory(m_bKBState, sizeof(m_bKBState));
		//C: Initialize the Direct Input buffers.
	CreateDInput(m_hWnd);

	m_view.SetWindowedDisplay();
/*		//C: Set the final display mode of the window.
	if (FAILED(m_view.SetFullScreenDisplay(800, 600, BITDEPTH_32)))
	{
		//C: If 32 bits failed, then try 24.
		if (FAILED(m_view.SetFullScreenDisplay(800, 600, BITDEPTH_24)))
		{
		//C: If 24 failed, then let the user know.
			::MessageBox(m_hWnd, "Quadrino could not find a compatible video mode to run the game.  This game will now exit.", "Error", MB_OK | MB_ICONSTOP);
			return -1;
		}

	}*/

	return 0;
}

/* Public *********************************************************************
Author:		Paul Watt
Date:		5/5/2002
Purpose:	Handles the WM_DESTROY message.
******************************************************************************/
LRESULT CMainFrame::OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
	bHandled = false;
		//C: Free sound objects.
	delete m_pSoundRotate;
	m_pSoundRotate = NULL;
	delete m_pSoundMove;
	m_pSoundMove = NULL;
	delete m_pSoundState;
	m_pSoundState = NULL;
		//C: Free the Direct Input buffers.
	DestroyDInput();
	return 0;
}


/* Public *********************************************************************
Author:		Paul Watt
Date:		5/5/2002
Purpose:	Handles the WM_ACTIVATE message.  THis function will insure that 
			this app properly aquires the keyboard when the app has the focus.
******************************************************************************/
LRESULT CMainFrame::OnActivate(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
		//C: Pause or resume the game based on the activation mode.
	if (wParam == WA_INACTIVE)
	{
		Pause();
	}
	else
	{
		Resume();
	}
		//C: Synchronize access to the keyboard for this window.
	SyncAcquire();

	return 0;
}


/* Public *********************************************************************
Author:		Paul Watt
Date:		5/4/2002
Purpose:	Command handler that will toggle the application in between windowed
			and full screen mode.
******************************************************************************/
LRESULT CMainFrame::OnToggleFullScreen(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
			//C: Properly set the TOP MOST style for this window when in full screen mode.
	LONG lStyleEx = GetWindowLong(GWL_EXSTYLE);
	if (!m_view.IsWindowed())
	{
		SetWindowLong(GWL_EXSTYLE, lStyleEx & ~WS_EX_TOPMOST);
		m_view.SetWindowedDisplay();
	}
	else
	{
		SetWindowLong(GWL_EXSTYLE, lStyleEx | WS_EX_TOPMOST);
		if (FAILED(m_view.SetFullScreenDisplay(800, 600, BITDEPTH_32)))
		{
		//C: If 32 bits failed, then try 24.
			if (FAILED(m_view.SetFullScreenDisplay(800, 600, BITDEPTH_24)))
			{
		//C: If 24 failed, then let the user know.
				::MessageBox(m_hWnd, _T("Quadrino could not find a compatible video mode to run the game.  This game will now exit."), _T("Error"), MB_OK | MB_ICONSTOP);
				PostQuitMessage(0);
			}

		}
	}

	return 0;
}


/* Public *********************************************************************
Author:		Paul Watt
Date:		10/21/2002
Purpose:	Handles the case when a music Player feedback event occurs.
Parameters:	
Return:		0
******************************************************************************/
LRESULT CMainFrame::OnGraphNotify(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
	m_MusicPlayer.HandleEvents();
	return 0;
}


/* Private ********************************************************************
Author:		Paul Watt
Date:		5/4/2002
Purpose:	Retireves the data from the keyboard to process as input to the game.
Parameters:	dwCount[in/out]: The number of buffer items to retrieve, and the 
				number of items that were retrieved.
Return:		HRESULT indiating the status of the function.
******************************************************************************/
HRESULT CMainFrame::GetDeviceData (DWORD &dwCount)
{
    HRESULT hr;

    hr = g_pdidKeyboard->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), g_dodBuffer, &dwCount, 0);
    if( FAILED( hr ) )
    {
			//C: Either an error or a DI_BUFFEROVERFLOW occurred.  Continuous
			//   contact with the device has been lost, there fore it is possible
			//   that some events were lost.  
			//C: First verify that we have contact with the input device.
        if(hr == DIERR_INPUTLOST)
        {
			//C: This app no longer has control of the keyboard, The keyboard
			//   will need to be re-acquired before we can continue.
			hr = g_pdidKeyboard->Acquire();
			if (FAILED(hr))
			{
				ATLTRACE("Could not aquire the keyboard focus.");
				ATLASSERT(0);
				return hr;
			}
			//C: The state of all of the buttons will now need to be synchronized.
			hr = g_pdidKeyboard->GetDeviceState(sizeof(m_bKBState), &m_bKBState);
			if (FAILED(hr)) 
			{
				ATLTRACE("Could not synchronize the state of the keyboard.");
				return hr;
			}
			//C: The state for the keyboard will need to be retrieved again.
			return GetDeviceData(dwCount);
        }
    }

	return hr;
}

/* Private ********************************************************************
Author:		Paul Watt
Date:		4/16/2002
Purpose:	Manages the input for all of the main start screen.
Parameters:	dData[in]: A structure that indicates an event for one of the
				input devices.
Return:		HRESULT indicates the status of this function.
******************************************************************************/
HRESULT CMainFrame::HandleMainScreenInput (DIDEVICEOBJECTDATA &dData)
{
			//C: Only process the keystroke if the state of the key is down.
	if (!dData.dwData)
	{
		return S_OK;
	}
			//C: Switch on the input data button that is passed in.
	bool isCommand = false;
	if (dData.dwOfs == m_bCommands[GAME_START])
	{
			//C: Start the game.
		m_view.OnStartGame();
		m_MusicPlayer.SetVolume(m_musicLevel);
		m_MusicPlayer.Play();
			//C: This will refresh the controls to prevent the rotate button from sticking.
		UpdateCC();

		isCommand = true;
	}
	else if (dData.dwOfs == m_bCommands[GAME_OPTIONS])
	{
			//C: Set the view into options mode.
		m_view.SetState(CQuadrinoView::OPTIONS);
			//C: Make sure the music is not playing.
		m_MusicPlayer.Stop();
		m_MusicPlayer.Rewind();

		isCommand = true;
	}
	else if (dData.dwOfs == m_bCommands[GAME_EXIT])
	{
			//C: Exit the program.
		End();
		SendMessage(WM_CLOSE, 0, 0);
		isCommand = true;
	}

			//C: Play a sound if a valid command was set.
	if (isCommand && m_pSoundState)
	{
		m_pSoundState->Play();
	}

	return S_OK;
}

/* Private ********************************************************************
Author:		Paul Watt
Date:		4/16/2002
Purpose:	Manages the input for all of the options screen.
Parameters:	dData[in]: A structure that indicates an event for one of the
				input devices.
Return:		HRESULT indicates the status of this function.
******************************************************************************/
HRESULT CMainFrame::HandleOptionsScreenInput (DIDEVICEOBJECTDATA &dData)
{
			//C: Only process the keystroke if the state of the key is down.
	if (!dData.dwData)
	{
		return S_OK;
	}
			//C: Switch on the input data button that is passed in.
	m_view.SetState(CQuadrinoView::NORMAL);
	if (m_pSoundState)
	{
		m_pSoundState->Play();
	}

	return S_OK;
}

/* Private ********************************************************************
Author:		Paul Watt
Date:		4/16/2002
Purpose:	Manages the input for the pause screen.
Parameters:	dData[in]: A structure that indicates an event for one of the
				input devices.
Return:		HRESULT indicates the status of this function.
******************************************************************************/
HRESULT CMainFrame::HandlePauseScreenInput (DIDEVICEOBJECTDATA &dData)
{
			//C: Only process the keystroke if the state of the key is down.
	if (!dData.dwData)
	{
		return S_OK;
	}
			//C: Switch on the input data button that is passed in.
	bool isCommand = false;
	if (dData.dwOfs == m_bCommands[GAME_CONTINUE])
	{
			//C: Resume the game.
		Resume();
		isCommand = true;
	}
	else if (dData.dwOfs == m_bCommands[GAME_QUIT])
	{
			//C: Quit the game.
		End();
		isCommand = true;
	}
	else if (dData.dwOfs == m_bCommands[GAME_EXIT])
	{
			//C: Exit the program.
		End();
		SendMessage(WM_CLOSE, 0, 0);
		isCommand = true;
	}
			//C: Play a sound if a valid command was set.
	if (isCommand && m_pSoundState)
	{
		m_pSoundState->Play();
	}

	return S_OK;
}

/* Private ********************************************************************
Author:		Paul Watt
Date:		4/16/2002
Purpose:	Manages the input for the game.
Parameters:	dData[in]: A structure that indicates an event for one of the
				input devices.
Return:		HRESULT indicates the status of this function.
******************************************************************************/
HRESULT CMainFrame::HandleGameInput (DIDEVICEOBJECTDATA &dData)
{
			//C: Only process the keystroke if the state of the key is down.
	if (!dData.dwData)
	{
		return S_OK;
	}
			//C: Switch on the input data button that is passed in.
	if (dData.dwOfs == m_bCommands[ROTATE_PIECE_CCW])
	{
		int result = m_game.Rotate(false);
		if (SUCCESS == result && m_pSoundRotate)
		{
			m_pSoundRotate->Play();
		}
	}
	else if (dData.dwOfs == m_bCommands[ROTATE_PIECE_CW])
	{
		int result = m_game.Rotate(true);
		if (SUCCESS == result && m_pSoundRotate)
		{
			m_pSoundRotate->Play();
		}
	}
	else if (dData.dwOfs == m_bCommands[MOVE_PIECE_RIGHT])
	{
		int result = m_game.Move(1, MOVE_RIGHT);
		if (SUCCESS == result && m_pSoundMove)
		{
			m_pSoundMove->Play();
		}
	}
	else if (dData.dwOfs == m_bCommands[MOVE_PIECE_LEFT])
	{
		int result = m_game.Move(1, MOVE_LEFT);
		if (SUCCESS == result && m_pSoundMove)
		{
			m_pSoundMove->Play();
		}
	}
	else if (dData.dwOfs == m_bCommands[MOVE_PIECE_DOWN])
	{
		int result = m_game.Move(1, MOVE_DOWN);
		if (SUCCESS == result && m_pSoundMove)
		{
			m_pSoundMove->Play();
		}
	}
	else if (dData.dwOfs == m_bCommands[MOVE_PIECE_DROP])
	{
		int result = m_game.Move(1, MOVE_DROP);
#pragma message( REMIND( "PMW: Find a sound for the drop event." ) )
/*		if (SUCCESS == result && m_pSoundDrop)
		{
			m_pSoundDrop->Play();
		}
*/	}
	else if (dData.dwOfs == m_bCommands[SWAP_PIECE])
	{
			//C: If the current game piece can be swapped, activate the
			//   swap animation.
		m_view.OnSwap();
	}
	else if (dData.dwOfs == m_bCommands[GAME_PAUSE])
	{
			//C: Pause the game.
		Pause();
			//C: Play a sound if a valid command was set.
		if (m_pSoundState)
		{
			m_pSoundState->Play();
		}
	}

	return S_OK;
}

/* Private ********************************************************************
Author:		Paul Watt
Date:		4/16/2002
Purpose:	Manages the input for commands that function when a key is 
			continuously held down.
Parameters:	dwTimeStamp[in]: The time stamp for which the input test is to
				be performed.
Return:		HRESULT indicates the status of this function.
******************************************************************************/
HRESULT CMainFrame::HandleContinuousInput (DWORD dwTimeStamp)
{
			//C: There is currently only commands in the game mode that respond
			//   to continuous input.
	if (!m_game.IsInit() || m_game.IsPaused())
	{
		return S_OK;
	}
			//C: Cycle through all of the input items, and generate events if the
			//   required time has elaspsed.
	for (int index = 0; index < 5; ++index)
	{
		DWORD dwCommand = m_cc[index].dwCommand;
			
		if (m_bKBState[dwCommand] & 0x80)
		{
			//C: Calculate the length of time that the current command key has
			//   been held down.
			DWORD dwTime = dwTimeStamp - m_dwTimeStamps[dwCommand];
			//C: Check if the current key is in its initial state.
			if (true == m_cc[index].isInitial)
			{
			//C: This is the first event for the current key press, check if the 
			//   time has exceeded, the initial event time.
				if (dwTime > INITIAL_EVENT_TIME)
				{
					m_cc[index].isInitial = false;
					m_cc[index].isFire = true;
				}
			}
			else
			{
			//C: Determine how many EVENT periods the current key has been held 
			//   down for.
				DWORD count = ((dwTime - INITIAL_EVENT_TIME) / m_cc[index].dwEventTime) + 1;
			//C: If the count is greater than the number of events that have been fired,
			//   then another event must be fired.
				if (count > m_cc[index].dwEventCount)
				{
					m_cc[index].isFire = true;
				}
			}
		}
		else
		{
			//C: The key is up.  Set the command to its initial state.
			m_cc[index].isInitial = true;
			m_cc[index].dwEventCount = 0;
		}
			//C: Fire the event.
		if (true == m_cc[index].isFire)
		{
			m_cc[index].isFire = false;
			m_cc[index].dwEventCount++;

			int result;
			switch (index)
			{
			case 0:
				result = m_game.Move(1, MOVE_LEFT);
				if (SUCCESS == result && m_pSoundMove)
				{
					m_pSoundMove->Play();
				}
				break;
			case 1:
				result = m_game.Move(1, MOVE_RIGHT);
				if (SUCCESS == result && m_pSoundMove)
				{
					m_pSoundMove->Play();
				}
				break;
			case 2:
				result = m_game.Move(1, MOVE_DOWN);
				if (SUCCESS == result && m_pSoundMove)
				{
					m_pSoundMove->Play();
				}
				break;
			case 3:
				result = m_game.Rotate(false);
				if (SUCCESS == result && m_pSoundRotate)
				{
					m_pSoundRotate->Play();
				}
				break;
			case 4:
				result = m_game.Rotate(true);
				if (SUCCESS == result && m_pSoundRotate)
				{
					m_pSoundRotate->Play();
				}
				break;
			}
		}
	}
			//C: Done.
	return S_OK;
}


/* Private ********************************************************************
Author:		Paul Watt
Date:		5/4/2002
Purpose:	Set all of the user options to the default settings.	
Parameters:	NONE
Return:		-
******************************************************************************/
void CMainFrame::SetDefaultSettings ()
{
			//C: The default game display mode is windowed.
	m_isWindowed = true;
			//C: Set the keyboard commands.
	m_bCommands[GAME_CONTINUE]		= DIK_C;
	m_bCommands[GAME_EXIT]			= DIK_X;
	m_bCommands[GAME_OPTIONS]		= DIK_O;
	m_bCommands[GAME_PAUSE]			= DIK_P;
	m_bCommands[GAME_QUIT]			= DIK_Q;
	m_bCommands[GAME_START]			= DIK_S;
	m_bCommands[MOVE_PIECE_LEFT]	= DIK_LEFT;
	m_bCommands[MOVE_PIECE_RIGHT]	= DIK_RIGHT;
	m_bCommands[MOVE_PIECE_DOWN]	= DIK_DOWN;
	m_bCommands[MOVE_PIECE_DROP]	= DIK_UP;
	m_bCommands[ROTATE_PIECE_CCW]	= DIK_A;
	m_bCommands[ROTATE_PIECE_CW]	= DIK_S;
	m_bCommands[SWAP_PIECE]			= DIK_SPACE;

	m_musicLevel	= 100;
	m_soundLevel	= 75;

			//C: Update the CC structures for continuous input processing.
	UpdateCC();
}

/* Public *********************************************************************
Author:		Paul Watt
Date:		5/5/2002
Purpose:	Updates the continuous input items structure.  This is neccesary 
			in order to process the commands that generate events when the 
			keys are held down.
Parameters:	NONE
Return:		-
******************************************************************************/
void CMainFrame::UpdateCC()
{
	m_cc[0].dwCommand		= m_bCommands[MOVE_PIECE_LEFT];
	m_cc[0].dwTimeStamp		= 0;
	m_cc[0].dwEventCount	= 0;
	m_cc[0].dwEventTime		= CONTINUOUS_MOVE_TIME;
	m_cc[0].isInitial		= true;
	m_cc[0].isFire			= false;

	m_cc[1].dwCommand		= m_bCommands[MOVE_PIECE_RIGHT];
	m_cc[1].dwTimeStamp		= 0;
	m_cc[1].dwEventCount	= 0;
	m_cc[1].dwEventTime		= CONTINUOUS_MOVE_TIME;
	m_cc[1].isInitial		= true;
	m_cc[1].isFire			= false;

	m_cc[2].dwCommand		= m_bCommands[MOVE_PIECE_DOWN];
	m_cc[2].dwTimeStamp		= 0;
	m_cc[2].dwEventCount	= 0;
	m_cc[2].dwEventTime		= CONTINUOUS_MOVE_TIME;
	m_cc[2].isInitial		= true;
	m_cc[2].isFire			= false;

	m_cc[3].dwCommand		= m_bCommands[ROTATE_PIECE_CCW];
	m_cc[3].dwTimeStamp		= 0;
	m_cc[3].dwEventCount	= 0;
	m_cc[3].dwEventTime		= CONTINUOUS_ROTATE_TIME;
	m_cc[3].isInitial		= true;
	m_cc[3].isFire			= false;

	m_cc[4].dwCommand		= m_bCommands[ROTATE_PIECE_CW];
	m_cc[4].dwTimeStamp		= 0;
	m_cc[4].dwEventCount	= 0;
	m_cc[4].dwEventTime		= CONTINUOUS_ROTATE_TIME;
	m_cc[4].isInitial		= true;
	m_cc[4].isFire			= false;
}


/* Global Functions **********************************************************/
/* Global *********************************************************************
Author:		Paul Watt
Date:		4/16/2002
Purpose:	
Parameters:			
Return:		
******************************************************************************/
BOOL CreateDInput( HWND hWnd )
{
    HINSTANCE hInst = (HINSTANCE)GetWindowLongPtr( hWnd, GWLP_HINSTANCE );
    HRESULT   hr;

			//C: Register with the DirectInput subsystem.
    if (FAILED(hr = DirectInput8Create( hInst, DIRECTINPUT_VERSION, IID_IDirectInput8, (LPVOID*)&g_pDI, NULL)))
    {
        return hr;
    }

	g_pDI->Initialize(hInst, DIRECTINPUT_VERSION);
			//C: Obtain an interface to the keybord device
    if (FAILED(hr = g_pDI->CreateDevice( GUID_SysKeyboard, &g_pdidKeyboard, NULL)))
    {
        return hr;
    }

#pragma message( REMIND( "PMW: Possibly add support for other input devices." ) )
			//C: Set the data format to keyboard.
    if (FAILED(hr = g_pdidKeyboard->SetDataFormat(&c_dfDIKeyboard)))
    {
        return hr;
    }
			//C: Set the cooperative level for the keyboard.  For now 
			//   DISCL_NONEXCLUSIVE | DISCL_FOREGROUND mode will be chosen
			//   because it will be the easiest to debug.
    if (FAILED(hr = g_pdidKeyboard->SetCooperativeLevel(hWnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND)))
    {
        return hr;
    }
			//C: Set the buffer size for the input device[s].
    DIPROPDWORD dipdw = 
    { 
        {
            sizeof(DIPROPDWORD), 
            sizeof(DIPROPHEADER),
            0,                   
            DIPH_DEVICE,         
        },
        KEYBOARD_BUFFERSIZE,     
    };

    if (FAILED(hr = g_pdidKeyboard->SetProperty( DIPROP_BUFFERSIZE, &dipdw.diph)))
    {
        return hr;
    }

    return S_OK;
}


/* Global *********************************************************************
Author:		Paul Watt
Date:		4/16/2002
Purpose:	Destroys all of the resources that were aquired for processing this
			game.
Parameters:	NONE	
Return:		-
******************************************************************************/
VOID DestroyDInput()
{
			//C: Destroy the keyboard object.
    if (g_pdidKeyboard)
    {
			//C: Unacquire the device (just in case) before exitting.
        g_pdidKeyboard->Unacquire();

        g_pdidKeyboard->Release();
        g_pdidKeyboard = NULL;
    }

			//C: Destroy the DInput object
    if (g_pDI)
    {
        g_pDI->Release();
        g_pDI = NULL;
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Engineer
United States United States
I am a software architect and I have been developing software for nearly two decades. Over the years I have learned to value maintainable solutions first. This has allowed me to adapt my projects to meet the challenges that inevitably appear during development. I use the most beneficial short-term achievements to drive the software I develop towards a long-term vision.

C++ is my strongest language. However, I have also used x86 ASM, ARM ASM, C, C#, JAVA, Python, and JavaScript to solve programming problems. I have worked in a variety of industries throughout my career, which include:
• Manufacturing
• Consumer Products
• Virtualization
• Computer Infrastructure Management
• DoD Contracting

My experience spans these hardware types and operating systems:
• Desktop
o Windows (Full-stack: GUI, Application, Service, Kernel Driver)
o Linux (Application, Daemon)
• Mobile Devices
o Windows CE / Windows Phone
o Linux
• Embedded Devices
o VxWorks (RTOS)
o Greenhills Linux
o Embedded Windows XP

I am a Mentor and frequent contributor to CodeProject.com with tutorial articles that teach others about the inner workings of the Windows APIs.

I am the creator of an open source project on GitHub called Alchemy[^], which is an open-source compile-time data serialization library.

I maintain my own repository and blog at CodeOfTheDamned.com/[^], because code maintenance does not have to be a living hell.

Comments and Discussions