Выбрать главу

Как и в программе Qwerty, при вызове этой функции используются флаги совместного (DISCL_NONEXCLUSIVE) и активного (DISCL_FOREGROUND) режимов доступа. Первый означает, что во время работы нашей программы другое приложение может получить монопольный доступ к мыши, а второй — что, находясь в фоновом режиме, наше приложение не получает ввод от мыши.

Остается лишь задать размер буфера данных функцией SetProperty() интерфейса DirectInputDevice. Размер буфера определяет количество событий, сохраняемых в очереди DirectInput. Если буфер слишком мал, возникает риск потери данных из-за его переполнения. Я снова привожу соответствующий фрагмент листинга 6.5:

DIPROPDWORD property;

property.diph.dwSize=sizeof(DIPROPDWORD);

property.diph.dwHeaderSize=sizeof(DIPROPHEADER);

property.diph.dwObj=0;

property.diph.dwHow=DIPH_DEVICE;

property.dwData=64;

r = mouse->SetProperty(DIPROP_BUFFERSIZE, &property.diph);

Функция SetProperty() получает два аргумента: величину, которая определяет задаваемое свойство, и адрес структуры DIPROPDWORD. Среди прочего эта структура содержит значение свойства.

В нашем случае константа DIPROP_BUFFERSIZE говорит о том, что SetProperty() задает размер буфера. Поле dwSize структуры property равно 64; это значит, что мы заказываем буфер данных из 64 элементов. Размер буфера выбирается достаточно произвольно. Он должен быть достаточно большим, чтобы избежать переполнения, и достаточно малым, чтобы не тратить память напрасно.

Подготовка мыши закончена; осталось лишь захватить ее перед получением данных. Перед тем как захватывать мышь, мы кратко рассмотрим процесс инициализации клавиатуры.

Инициализация клавиатуры

Инициализация клавиатуры выполняется функцией InitKeyboard():

BOOL SmearWin::InitKeyboard() {

 HRESULT r;

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

 if (r!=DI_OK) {

  TRACE("CreateDevice(keyboard) failed");

  return FALSE;

 }

 r = keyboard->SetDataFormat(&c_dfDIKeyboard);

 if (r!=DI_OK)  {

  TRACE("keyboard->SetDataFormat() failed\n");

  return FALSE;

 }

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

 if (r!=DI_OK) {

  TRACE("keyboard->SetCooperativeLevel() failed\n");

  return FALSE;

 }

 return TRUE;

}

Инициализация клавиатуры происходит так же, как и в программе Qwerty.

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

Перед тем как получать данные от клавиатуры или мыши, необходимо предварительно захватить их. Кроме того, устройство приходится захватывать заново, если приложение некоторое время было неактивным. И исходный, и все последующие захваты устройства выполняются в обработчике OnActivate():

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

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

 if (nState!=WA_INACTIVE) {

  if (keyboard) {

   TRACE("keyboard->Acquire()\n");

   keyboard->Acquire();

  }

  if (mouse) {

   TRACE("mouse->Acquire()\n");

   mouse->Acquire();

  }

 }

}

Функция Acquire() вызывается для каждого устройства независимо от того, уступалось ли оно. DirectInput игнорирует лишние вызовы Acquire().

Получение данных от мыши

Хлопоты с инициализацией мыши и клавиатуры закончены, теперь можно получать от них данные. Функция DrawScene() (см. листинг 6.6) через указатели mouse и keyboard обращается к обоим устройствам и получает от них данные.

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

void SmearWin::DrawScene() {

 static char key[256];

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

 if (key[DIK_ESCAPE] & 0x80) PostMessage(WM_CLOSE);

 BOOL done=FALSE;

 while (!done) {

  DIDEVICEOBJECTDATA data;

  DWORD elements=1;

  HRESULT r=mouse->GetDeviceData(sizeof(data), &data,     &elements, 0);

  if (r==DI_OK && elements==1) {

   switch(data.dwOfs) {

   case DIMOFS_X:

    x+=data.dwData;

    break;

   case DIMOFS_Y:

    y+=data.dwData;

    break;

   }

  } else if (elements==0) done=TRUE;

 }

 BltSurface(primsurf, sphere, x, y, TRUE);

}

Функция DrawScene() сначала проверяет состояние клавиатуры функцией GetDeviceState() интерфейса DirectInputDevice. Если была нажата клавиша Escape, она посылает сообщение WM_CLOSE, что приводит к завершению приложения. О функции GetDeviceState() и проверке состояния клавиш рассказано в программе Qwerty, поэтому сейчас мы займемся кодом, относящимся к мыши. DrawScene() в цикле извлекает элементы буфера мыши. Для получения данных, а также для проверки отсутствия элементов при пустом буфере используется функция GetDeviceData() интерфейса DirectInputDevice.

Каждый элемент буфера представлен структурой DIDEVICEOBJECTDATA. Эта структура используется независимо от типа устройства, поэтому ее поля были сделаны универсальными. DirectInput определяет структуру DIDEVICEOBJECTDATA следующим образом:

typedef struct {

 DWORD dwOfs;

 DWORD dwData;

 DWORD dwTimeStamp;

 DWORD dwSequence;

} DIDEVICEOBJECTDATA, *LPDIDEVICEOBJECTDATA;

Для мыши поле dwOfs определяет тип события. В DirectInput определены следующие константы, описывающие ввод от мыши:

• DIMOFS_X

• DIMOFS_Y

• DIMOFS_Z

• DIMOFS_BUTTON0