Рейтинговые книги
Читем онлайн Графика для Windows средствами DirectDraw - Стэн Трухильо

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 36 37 38 39 40 41 42 43 44 ... 66

Листинг 6.1. Класс QwertyWin

class QwertyWin : public DirectDrawWin {

public:

 QwertyWin();

protected:

 //{{AFX_MSG(QwertyWin)

 afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);

 afx_msg void OnDestroy();

 afx_msg void OnActivate(UINT nState, CWnd* pWndOther,    BOOL bMinimized);

 //}}AFX_MSG

 DECLARE_MESSAGE_MAP()

private:

 int SelectDriver();

 int SelectInitialDisplayMode();

 BOOL CreateCustomSurfaces();

 void DrawScene();

 void RestoreSurfaces();

private:

 LPDIRECTINPUT dinput;

 LPDIRECTINPUTDEVICE keyboard;

 BOOL esc_pressed;

 LPDIRECTDRAWSURFACE esc_up, esc_dn;

 LPDIRECTDRAWSURFACE space_up, space_dn;

 LPDIRECTDRAWSURFACE q_up, q_dn;

 LPDIRECTDRAWSURFACE w_up, w_dn;

 LPDIRECTDRAWSURFACE e_up, e_dn;

 LPDIRECTDRAWSURFACE r_up, r_dn;

 LPDIRECTDRAWSURFACE t_up, t_dn;

 LPDIRECTDRAWSURFACE y_up, y_dn;

 LPDIRECTDRAWSURFACE rctrl_up, rctrl_dn;

 LPDIRECTDRAWSURFACE lctrl_up, lctrl_dn;

 LPDIRECTDRAWSURFACE lalt_up, lalt_dn;

 LPDIRECTDRAWSURFACE ralt_up, ralt_dn;

};

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

В самом начале объявляются три обработчика сообщений:

• OnCreate()

• OnDestroy()

• OnActivate()

Функция OnCreate() инициализирует и настраивает DirectInput, а функция OnDestroy() освобождает объекты DirectInput. Функция OnActivate(), вызываемая MFC при получении или потере фокуса, будет использована для повторного захвата клавиатуры.

Две следующие функции, SelectDriver() и SelectInitialDisplayMode(), присутствуют почти во всех наших программах. Они остались в том виде, в котором их создал AppWizard, и потому не требуют обсуждения.

Функции CreateCustomSurfaces() и RestoreSurfaces() делают то же, что и раньше, так что они тоже не рассматриваются. Достаточно сказать, что эти функции инициализируют и восстанавливают поверхности, указатели на которые объявляются в нижней части листинга 6.1.

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

После функций следуют переменные класса. Сначала объявляется указатель на интерфейс DirectInput(dinput), через него выполняется инициализация и осуществляются обращения к DirectInput. Переменная key — указатель на интерфейс DirectInputDevice, используемый для обращений к клавиатуре. Логическая переменная esc_pressed сигнализирует о завершении приложения.

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

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

Инициализация DirectInput и DirectDraw выполняется в функции OnCreate(). DirectInput инициализируется версией OnCreate() класса QwertyWin, а DirectDraw — версией из DirectDrawWin. Функция QwertyWin::OnCreate() приведена в листинге 6.2.

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

int QwertyWin::OnCreate(LPCREATESTRUCT lpCreateStruct) {

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

 if (r!=DI_OK) {

  AfxMessageBox("DirectInputCreate() failed");

  return -1;

 }

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

 if (r!=DI_OK) {

  AfxMessageBox("CreateDevice(keyboard) failed");

  return -1;

 }

 r = keyboard->SetDataFormat(&c_dfDIKeyboard);

 if (r!=DI_OK) {

  AfxMessageBox("keyboard->SetDataFormat() failed");

  return -1;

 }

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

 if (r!=DI_OK) {

  AfxMessageBox("keyboard->SetCooperativeLevel() failed");

  return -1;

 }

 if (DirectDrawWin::OnCreate(lpCreateStruct)==-1) return -1;

 return 0;

}

Прежде всего обратите внимание — версия OnCreate() базового класса вызывается лишь в конце функции. Это сделано для того, чтобы при неудачной инициализации 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()n");

  keyboard->Acquire();

 }

}

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

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

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

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

1 ... 36 37 38 39 40 41 42 43 44 ... 66
На этой странице вы можете бесплатно читать книгу Графика для Windows средствами DirectDraw - Стэн Трухильо бесплатно.
Похожие на Графика для Windows средствами DirectDraw - Стэн Трухильо книги

Оставить комментарий