чтобы при неудачной инициализации DirectInput программа выводила окно сообщения и прекращала работу без инициализации DirectDraw.

Сначала функция OnCreate() инициализирует указатель dinput с помощью функции DirectInputCreate (), которой необходимо передать четыре аргумента. Вызов этой функции выглядит так:

HRESULT r=DirectInputCreate(AfxGetInstanceHandle(), DIRECTINPUT_VERSION, &dinput, 0);

Первый аргумент - логический номер экземпляра приложения, получаемый функцией AfxGetInstanceHandle(). Второй аргумент — номер версии DirectInput. В нашем случае используется константа DIRECTINPUT_VERSION, она определяется DirectInput в зависимости от версии SDK, использованной для компиляции приложения. Различные версии DirectInput более подробно рассматриваются в этой главе ниже. Третий аргумент DirectInputCreate() — адрес инициализируемого указателя, а четвертый — показатель агрегирования COM, который обычно равен нулю (агрегированием называется разновидность наследования, используемая в COM). Если инициализация DirectInput проходит успешно (то есть если DirectInputCreate() возвращает DI_OK), указатель dinput может использоваться для работы с DirectInput.

Затем мы создаем экземпляр интерфейса DirectInputDevice, который представляет клавиатуру. Я снова приведу соответствующую строку листинга 6.2:

r = dinput->CreateDevice(GUID_SysKeyboard, &keyboard, 0);

Функция CreateDevice() интерфейса DirectInput применяется для инициализации устройств DirectInput. В нашем случае первым аргументом является стандартная константа GUID_SysKeyboard, показывающая, что мы собираемся работать с системной клавиатурой. Второй аргумент — адрес указателя keyboard, через который мы впоследствии будем обращаться к клавиатуре. Третий аргумент — показатель агрегирования COM, в нашем случае он должен быть равен нулю.

Следующий шаг — выбор формата данных устройства. Для клавиатуры он выполняется просто:

r = keyboard->SetDataFormat(&c_dfDIKeyboard);

Функции SetDataFormat() интерфейса DirectInputDevice передается единственный аргумент — константа стандартного формата c_dfDIKeyboard. Программа Qwerty работает лишь с одним устройством (клавиатурой), но, как мы убедимся в программе Smear, формат данных должен задаваться отдельно для каждого устройства, используемого программой.

Затем мы задаем уровень кооперации устройства с помощью функции SetCooperativeLevel() интерфейса DirectInputDevice. Соответствующий фрагмент листинга 6.2 выглядит так:

r=keyboard->SetCooperativeLevel(GetSafeHwnd(), DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);

Функция SetCooperativeLevel() получает два аргумента: логический номер окна и набор флагов, определяющих уровень кооперации. Функция GetSafeHwnd() определяет логический номер окна, а флаги DISCL_FOREGROUND и DISCL_NONEXCLUSIVE задают нужный уровень кооперации. Флаг активного режима DISCL_FOREGROUND присутствует потому, что на время активности другого приложения нам не потребуется ввод от клавиатуры, а флаг DISCL_NONEXCLUSIVE — потому, что DirectInput не позволяет установить монопольный доступ к клавиатуре.

До получения данных с клавиатуры остался всего один шаг: мы должны захватить устройство функцией Acquire(). Эта задача решается функцией OnActivate(), которую мы рассмотрим ниже.

Функция QwertyWin::OnCreate() завершается вызовом функции DirectDrawWin::OnCreate(), инициализирующей DirectDraw. Эта функция обсуждалась в главе 3.

Захват клавиатуры

Итак, мы инициализировали DirectInput и подготовили клавиатуру к работе; теперь необходимо захватить ее. Для этой цели используется функция OnActivate(), потому что клавиатуру приходится захватывать при каждой активизации нашего приложения. Функция OnActivate () выглядит так:

void QwertyWin::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized) {

 DirectDrawWin::OnActivate(nState, pWndOther, bMinimized);

 if (nState!=WA_INACTIVE && keyboard) {

  TRACE('keyboard->Acquire() ');

  keyboard->Acquire();

 }

}

После вызова версии OnActivate() базового класса мы проверяем, происходит ли активизация приложения (функция OnActivate() вызывается и в случае деактивизации, когда активным становится другое приложение). Если проверка дает положительный результат, мы вызываем функцию Acquire() интерфейса DirectInputDevice.

Перед вызовом Acquire() можно проверить, не была ли клавиатура захвачена ранее, но в этом нет необходимости. DirectInput игнорирует лишние вызовы функции Acquire().

Определение состояния клавиш

Теперь по указателю на интерфейс клавиатуры можно определить состояние отдельных клавиш. В нашей программе это происходит в функции DrawScene(), перед обновлением экрана. Функция DrawScene() приведена в листинге 6.3.

Листинг 6.3. Функция QwertyWin::DrawScene()

void QwertyWin::DrawScene() {

 static char key[256];

 keyboard->GetDeviceState(sizeof(key), &key);

 //---------- Клавиши QWERTY --------

 if (key[DIK_Q] & 0x80) BltSurface(backsurf, q_dn, 213, 70);

 else BltSurface(backsurf, q_up, 213, 70);

 if (key[DIK_W] & 0x80) BltSurface(backsurf, w_dn, 251, 70);

 else BltSurface(backsurf, w_up, 251, 70);

 if (key[DIK_E] & 0x80) BltSurface(backsurf, e_dn, 298, 70);

 else BltSurface(backsurf, e_up, 298, 70);

 if (key[DIK_R] & 0x80) BltSurface(backsurf, r_dn, 328, 70);

 else BltSurface(backsurf, r_up, 328, 70);

 if (key[DIK_T] & 0x80) BltSurface(backsurf, t_dn, 361, 70);

 else BltSurface(backsurf, t_up, 361, 70);

 if (key[DIK_Y] & 0x80) BltSurface(backsurf, y_dn, 393, 70);

 else BltSurface(backsurf, y_up, 393, 70);

 //---------------- LEFT CONTROL ---------------

 if (key[DIK_LCONTROL] & 0x80) BltSurface(backsurf, lctrl_dn, 50, 180);

 else BltSurface(backsurf, lctrl_up, 49, 180);

 //---------------- RIGHT CONTROL ---------------

 if (key[DIK_RCONTROL] & 0x80) BltSurface(backsurf, rctrl_dn, 490, 180);

 else BltSurface(backsurf, rctrl_up, 490, 180);

 //---------------- LEFT ALT ---------------

 if (key[DIK_LMENU] & 0x80) BltSurface(backsurf, lalt_dn, 100, 260);

 else BltSurface(backsurf, lalt_up, 100, 260);

 //---------------- RIGHT ALT ---------------

 if (key[DIK_RMENU] & 0x80) BltSurface(backsurf, ralt_dn, 440, 260);

 else BltSurface(backsurf, ralt_up, 440, 260);

 //---------------- SPACE -----------------

 if (key[DIK_SPACE] & 0x80) BltSurface(backsurf, space_dn, 170, 340);

 else BltSurface(backsurf, space_up, 170, 340);

 //---------- ESCAPE -------------

 if (key[DIK_ESCAPE] & 0x80) {

  BltSurface(backsurf, esc_dn, 0, 0);

  esc_pressed=TRUE;

 } else {

  BltSurface(backsurf, esc_up, 0, 0);

  if (esc_pressed) PostMessage(WM_CLOSE);

 }

 primsurf->Flip(0, DDFLIP_WAIT);

}

Состояние устройства определяется функцией GetDeviceState() интерфейса DirectInputDevice. Тип и размер второго аргумента GetDeviceState() зависят от типа устройства, а также от формата данных, заданного функцией SetDataFormat().

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

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

Отметить Добавить цитату