На экране изображены буквы Qwerty и названия еще нескольких клавиш. Программа с помощью DirectInput обнаруживает нажатые клавиши и рисует их в наклонном начертании. Все остальные клавиши рисуются прямо.
В программе Qwerty, как и во всех остальных программах этой книги, специализированный класс окна порождается от базового класса DirectDrawWin. В данном случае производный класс называется QwertyWin (см. листинг 6.1).
Листинг 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() базового класса вызывается лишь в конце функции. Это сделано для того,