До этого момента в наших программах для ввода мы пользовалить возможностями WinAPI. Да, с его помощью очень просто реализовать поддержку клавиатуры (и даже мышки). Но он не предназначен для игр. Сегодня мы поговорим о том, как использовать в наших программах возможности DirectInput. Это более продвинутый интерфейс для ввода, разработанный Microsoft специально для использования в играх! Вот... итак начнем...
За основу для данного урока я взял Урок #3.

Так как код этого урока будет не очень маленьким:), то для него рекомендуется завести отдельный исходной файл (*.CPP) , а также потребуется использовать файл заголовка (*.H). Я назвал их Input.cpp и Input.h соответственно. Добавляйте такие файлы в свой проект и приступаем к делу.

Сначала разберемся с файлом заголовка (хедером) Input.h:
Первым делом добавте в него следующую строку:

// Заголовочный файл  для DirectInput
#include "dinput.h"

Он нам понадобится для доступа ко всем функциям DirectInput'а
А теперь создадим удобный для нас класс для работы с ним:

//-----------------------------------------------------------------------------
// Name: class CInput
// Desc: Класс  для использования DirectInput-устройств
//-----------------------------------------------------------------------------
class CInput
{
public:
	bool Init(HWND hwnd);	// Инициализация DirectInput
	void Shutdown(void);	// Удаление DirectInput
	void Update(void);		// Обновление состояний устройств ввода

	bool isKey(BYTE in_kb);	// Проверка кнопки  на клавиатуре  на нажатость
	bool isKeyNew(BYTE in_kb);	// Проверка кнопки  на клавиатуре  на новое нажатие
	bool isMBut(BYTE in_mb);	// Проверка кнопки мыши  на нажатость
	bool isMButNew(BYTE in_mb);	// Проверка кнопки мыши  на новое нажатие

	float GetMouseSpeedX(void);	// Получаем скорость мыши  по оси X
	float GetMouseSpeedY(void);	// Получаем скорость мыши  по оси Y
	float GetMouseSpeedZ(void);	// Получаем скорость мыши  по оси Z (колесико)

private:
	HWND hwnd;
	LPDIRECTINPUT8 lpDI;			// DDX8Input Объект
	LPDIRECTINPUTDEVICE8	lpDIKeyboard,	// Интерфейс клавиатуры
				lpDIMouse;	// Интерфейс мыши

	BYTE DIks[256];		// Кнопки кла-вы
	bool kNew[256];		// Новое нажатие
	DIMOUSESTATE2 DIms;		// Состояние мышки
	bool mbNew[8];		// Новое нажатие
};

Вот и все! С Input.h закончили. Переходим к главной части нашей программы - Input.cpp
В начале файла добавляем:
#include "Input.h"

Таким образом, мы включаем текст нашего хедера в текущий файл.

Далее мы определяем все методы для нашего класса CInput. Здесь их разбирать не имеет смысла, т.к. все они просты и понятны - просто скачайте исходник!

Сейчас же я рассмотрю только главные...
Первый метод - функция инициализации CInput::Init(HWND hwnd).
При ее вызове мы просто передаем экземпляр нашего окна. Здесь создается DirectInput, а также интерфейсы клавиатуры и мыши. Далее и идет функция, Update. Она вызывается каждый кадр и обновляет состояние клавиатуры и мыши.

//-----------------------------------------------------------------------------
// Name: bool CInput::Update(void)
// Desc: Обновление состояния клавиатуры  и мыши
//-----------------------------------------------------------------------------
void CInput::Update(void)
{
	HRESULT hr;

	// Опрашиваем клавиатуру
	hr = lpDIKeyboard->GetDeviceState(sizeof(BYTE)*256, &DIks); // Данные  с кла-вы
	if(FAILED(hr))	// Если мы потеряли устройство
	{
		do{ hr = lpDIKeyboard->Acquire(); // Пытаемся захватить
		}
		while(hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED);
	}
	// Опрашиваем мышь
	hr = lpDIMouse->GetDeviceState(sizeof(DIMOUSESTATE2), &DIms); // Данные  с мыши
	if(FAILED(hr))	// Если мы потеряли устройство
	{
		do{ hr = lpDIMouse->Acquire(); // Пытаемся захватить
		}
		while(hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED);
	}
}

Далее мы определяем функции, с помощью которых мы можем получить относительную (относительно предыдущего кадра) скорость мыши:

//-----------------------------------------------------------------------------
// Name: float CInput::GetMouseSpeedX(void)
// Desc: Возвращает относительную скорость мыши  по оси X
//-----------------------------------------------------------------------------
float CInput::GetMouseSpeedX(void)
{
return (float)DIms.lX;
}

//-----------------------------------------------------------------------------
// Name: float CInput::GetMouseSpeedY(void)
// Desc: Возвращает относительную скорость мыши  по оси Y
//-----------------------------------------------------------------------------
float CInput::GetMouseSpeedY(void)
{
	return (float)DIms.lY;
}

//-----------------------------------------------------------------------------
// Name: float CInput::GetMouseSpeedZ(void)
// Desc: Возвращает относительную скорость мыши  по оси Z (колесико)
//-----------------------------------------------------------------------------
float CInput::GetMouseSpeedZ(void)
{
	return (float)DIms.lZ;
}

А как же нам добраться до наших кнопочек? Вот как:

//-----------------------------------------------------------------------------
// Name: bool CInput::isKey(BYTE in_kb)
// Desc: Проверка  на нажатие кнопок клавиатуры
//-----------------------------------------------------------------------------
bool CInput::isKey(BYTE in_kb)
{
    if(DIks[in_kb] & 0x80) return true;
    else return false;
}

//-----------------------------------------------------------------------------
// Name: bool CInput::isKeyNew(BYTE in_kb)
// Desc: Проверка кнопок кла-вы  на новое нажатие
//-----------------------------------------------------------------------------
bool CInput::isKeyNew(BYTE in_kb)
{
    if(DIks[in_kb] & 0x80)
    {
        if(kNew[in_kb]){ kNew[in_kb] = false; return true; }
    }
    else kNew[in_kb] = true;
    return false;
}

//-----------------------------------------------------------------------------
// Name: bool CInput::isMBut(BYTE in_mb)
// Desc: Проверка  на нажатие кнопок мышки
//-----------------------------------------------------------------------------
bool CInput::isMBut(BYTE in_mb)
{
    if(DIms.rgbButtons[in_mb] & 0x80) return true;
    else return false;
}

//-----------------------------------------------------------------------------
// Name: bool CInput::isMButNew(BYTE in_mb)
// Desc: Проверка кнопок мыши  на новое нажатие
//-----------------------------------------------------------------------------
bool CInput::isMButNew(BYTE in_mb)
{
    if(DIms.rgbButtons[in_mb] & 0x80)
    {
        if(mbNew[in_mb]){ mbNew[in_mb] = false; return true; }
    }
    else mbNew[in_mb] = true;
    return false;
}

И теперь нам осталось лишь освободить память из-под DirectInput:

//-----------------------------------------------------------------------------
// Name: bool CInput::Shutdown(void)
// Desc: Освобождаем память из-под интерфейса ввода
//-----------------------------------------------------------------------------
void CInput::Shutdown(void)
{
    if(lpDIKeyboard)
        lpDIKeyboard->Unacquire();
    if(lpDIMouse)
        lpDIMouse->Unacquire();
    if(lpDIKeyboard)
        lpDIKeyboard->Release();
    if(lpDIMouse)
        lpDIMouse->Release();
    if(lpDI)
        lpDI->Release();
}

Дааа... теперь как нам все это использовать?
открываем наш родной Main.cpp.

В начале файла, к списку библиотек добавим

#pragma comment(lib, "dinput8.lib"	)	// Ссылка  на dinput8.lib
#pragma comment(lib, "dxguid.lib"	)	// ССылка  на dxguid.lib

И после всех заголовков добавим:

#include "Input.h"		// Заголовок  для использования класса CInput

теперь, когда мы стали такими крутыми ;) нам больше не нужен старый массив:

bool	keys[256];	// Массив  для работы  с клавиатурой

Просто удалите эту строку. И вместо нее напишите:

CInput Input;		// наш класс  для работы  с кла-вой  и мышой через DirectInput

Теперь переходим в функцию AllInit()

// Инициируем интерфейс ввода
    if(!Input.Init(hWnd))
        return false;		// Если возникла ошибка - выйдем

А в AllShutdown() освободим его:

Input.Shutdown();		// Освобождаем интерфейс ввода

Теперь MsgProc удаляем следующие строки - они нам больше ни к чему:

 case WM_KEYDOWN:		// Если нажата клавиша
    {
        keys[wParam] = TRUE;
        return 0;
    }

    case WM_KEYUP:			// Если клавиша отпущена
    {
        keys[wParam] = FALSE;
        return 0;
    }

И сейчас в WinMain вместо

 if(keys[VK_ESCAPE])
        isProcess=false;

    if(keys[VK_F1])
    {
        fullscreen=!fullscreen;	//переключаемся  в Оконный/полноэкранный режим
        ResetWindow(Width, Height, fullscreen);
    }

Запишим

 Input.Update();				// Обновляем состояние клавиатуры  и мышки

    // Если нажали ESCAPE выходим  из цикла
    if(Input.isKey(DIK_ESCAPE))
        isProcess=false;

    if(Input.isKey(DIK_F1))			//  А если F1
    {
        fullscreen=!fullscreen;		//переключаемся  в Оконный/полноэкранный режим
        ResetWindow(Width, Height, fullscreen);
    }

У нас появилась полная поддержка DirectInput!