Данный материал взят с сайта old.shatalov.su и является его зеркалом

Создаём компьютерную игру. Создание игр на C++/DirectX

Есть вопросы?
Ошибка на сайте?
рус eng esp
Внимание! Данный сайт не обновляется. Новая версия: shatalov.su

Инициализация DirectInput

Дата создания: 2009-07-05 15:34:49
Последний раз редактировалось: 2012-02-08 10:52:17

    Дальнейшие уроки:
  1. Ввод с клавиатуры. Перейти.
  2. Ввод с мышки. Перейти.

Меня всегда удивляло следующее: в большинстве книжек по DirectX рассказывается как создавать графику, а вот чтобы эта графика ожила - не рассказывается. Где взаимодействие с пользователем? Где экшн??? Всегда считал что это есть не правильно. Вроде бы уже наложил на треугольник текстуру, напустил туману, а как теперь заставить объекты двигаться по мановению мышки или клавиатуры не знаешь. И сидишь как дурак.

Единственным правильным решением в данной ситации, будет изучение работы с клавиатурой и мышкой по ходу освоения Direct3D.

В WinAPI есть набор функций для работы с вводом с клавиатуры и мышки, но мы не будем ими пользоваться, так как для этого есть более подходящая штука - DirectInput.

DirectInput - это часть DirectX отвечающая за ввод: с клавиатуры, с мышки, с джойстика и других устройств.

Инициализация DirectInput

Для начала нужно добавить к проекту следующие библиотечные файлы: dinput8.lib, dxguid.lib. Заголовочный файл для DirectInput следующий: dinput.h.

Инициализация DirectInput включает следующие шаги:

  1. Получение интерфейса IDirectInput8.
  2. Создание устройства.
  3. Установка формата данных.
  4. Установка уровня взаимодействия с операционной системой.
  5. Получение доступа к устройству ввода.

После инициализации программа сможет принимать ввод от устройства.

Теперь по порядку:

1. Создание объекта DirectInput. Функция DirectInput8Create.

Прежде всего необходимо получить указатель на интерфейс IDirectInput8. Этот интерфейс является основным в DirectInput и c помощью него создаются устройства (клавиатура, мышь). Для создания объекта DirectInput в функцию DirectInput8Create нужно передать указатель на интерфейс IDirectInput8 (4-ый аргумент):

HRESULT DirectInput8Create(
  HINSTANCE hinst,    // экземпляр приложения
  DWORD dwVersion,    // версия DirectInput
  REFIID riidltf,     // какая-то COM'овская фигня
  LPVOID * ppvOut,    // указатель на IDirectInput8
  LPUNKNOWN pUnkOuter // тоже относится к COM
);

Как мы видим, функция DirectInput8Create сложнее аналогичной функции из Direct3D (Direct3DCreate9).

hinst
Экземпляр приложения.

dwVersion
Версия DirectInput. Всегда передавайте DIRECTINPUT_VERSION.

riidltf
Уникальный идентификатор устройства. Данный параметр относится к COM. Всегда передавайте IID_IDirectInput8.

ppvOut
указатель на IDirectInput8. Функция DirectInput8Create вызывается именно для того, чтобы создать объект DirectInput.

pUnkOuter
Ещё одно поле связанное с COM. Заполняется при агрегации. Передавайте NULL.

2. Создание устройства

После создания объекта DirectInput, через него можно создать устройство (например, клавиатуру) - получить указатель на интерфейс IDirectInputDevice8. Получить IDIrectInputDevice8 можно через метод IDirectInput8::CreateDevice:

HRESULT CreateDevice(
  REFGUID rguid, // глобальный идентификатор (COM)
  LPDIRECTINPUTDEVICE * lplpDirectInputDevice, // указатель на устройство
  LPUNKNOWN pUnkOuter // COM
);

rguid
Данный параметр относится к COM. Здесь необходимо запомнить два значения: GUID_SysMouse - мышь, GUID_SysKeyboard - клавиатура.

lplpDirectInputDevice
Адрес переменной, которая получит указатель на интерфейс IDirectInputDevice8.

pUnkOUter
Такой же параметр как и в функции DirectInput8Create. Передавайте NULL.

Теперь у нас есть переменная, которая представляет устройство. Тип устройства зависит от того, какое значение вы передали первому аргументу метода CreateDevice. В ближайшее время мы будем пользоваться клавиатурой. Соответсвенно первый параметр должен был быть таким: GUID_SysKeyboard.

3. Установка формата данных

Теперь нужно задать формат данных, который будет получать устройство. Для этого есть метод IDirectInputDevice8::SetDataFormat:

HRESULT SetDataFormat(LPCDIDATAFORMAT lpdf);

Единственным аргументом данного метода является адрес структуры, которая описывает формат данных. DirectInput предоставляет уже заполненные структуры LPCDIDATAFORMAT: для клавиатуры - c_dfDIKeyboard, для мышки - c_dfDIMouse.

4. Установка уровня взаимодействия с ОС.

Уровень взаимодействия с операционной системой задаётся через метод IDirectInputDevice8::SetCooperativeLevel:

HRESULT SetCooperativeLevel(
  HWND hwnd,
  DWORD dwFlags
);

hWnd
Первый аргумент - описатель окна, у которого нужно забирать ввод.

dwFlags
Второй аргумент - набор флагов, определящий каким образом будет происходить взаимодействие с операционной системой. Нам нужно получать данные с устройства только когда окно активно. Этому условию отвечает значение: DISCL_FOREGROUND | DISCL_NONEXCLUSIVE.

5. Получение доступа к устройству ввода.

И последнее что нужно сделать прежде чем устройство будет способно получать ввод от пользователя во время программы - "приобрести" (acquire) устройство IDirectInputDevice8::Acquire. Этот метод позволяет получить доступ к устройству ввода.

С данным методом связан вот ещё какой момент. Когда пользователь переключается на другую программу, то доступ к устройству ввода теряется. Поэтому, когда пользователь возвращается в программу, необходимо снова вызвать данный метод.

При завершении программы, до уничтожения устройства методом Release, нужно вызвать метод IDirectInputDevice8::Unacquire, чтобы отменить доступ к устройству.

А теперь посмотрим как всё это работает (создаём устройство ввода с клавиатуры):

IDirectInput8* di;           // объект DirectInput
IDirectInputDevice8* didev;  // устройство DirectInput

DirectInput8Create(hInstance,           // экземпляр приложения
                   DIRECTINPUT_VERSION, // версия DirectInput
                   IID_IDirectInput8,   // глобальный идентификатор (COM)
                   (void**)&di, // адрес указателя объекта DirectInput
                   NULL);

di->CreateDevice(GUID_SysKeyboard,  // устройство ввода с клавиатуры
                 &didev,            // адрес указателя на устройство
                 NULL);

didev->SetDataFormat(&c_dfDIKeyboard);
didev->SetCooperativeLevel(hWnd,DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);
didev->Acquire();

Теперь можно начинать ввод. Как? Скоро узнаем...