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

Обработка пользовательского ввода 

Давайте посмотрим, как в нашей программе организована обработка ввода. Нажатые клавиши обрабатываются функций OnKeyDown(), которая выглядит так:

void BmpViewWin::OnKeyDown(UINT key, UINT nRepCnt, UINT nFlags) {

 switch (key) {

 case VK_UP:

  Up();

  break;

 case VK_DOWN:

  Down();

  break;

 case VK_LEFT:

  Left();

  break;

 case VK_RIGHT:

  Right();

  break;

 case VK_HOME:

  Home();

  break;

 case VK_END:

  End();

  break;

 case VK_PRIOR:

  PageUp();

  break;

 case VK_NEXT:

  PageDown();

  break;

 case VK_ESCAPE:

 case VK_SPACE:

 case VK_RETURN:

  ShowDialog();

  break;

 }

 DirectDrawWin::OnKeyDown(key, nRepCnt, nFlags);

}

С первого взгляда на листинг OnKeyDown() можно разве что понять, какие клавиши обрабатываются программой, потому что вся содержательная работа поручается другим функциям. Обратите внимание — при нажатии клавиш Escape, пробел и Enter вызывается одна и та же функция ShowDialog(). Это облегчает вызов диалогового окна после вывода изображения.

Остальные восемь функций, вызываемых функцией OnKeyDown(), изменяют положение поверхности во время прокрутки:

• Up()

• Down()

• Left()

• Right()

• Home()

• End()

• PageUp()

• PageDown()

Каждая из этих функций определяет положение поверхности по значениям переменных x, y, xlimit, ylimit, xscroll и yscroll. Код всех восьми функций приведен в листинге 5.9.

Листинг 5.9. Функции смещения поверхности

void BmpViewWin::Up(int inc) {

 if (!yscroll) return;

 if (y+inc<0) {

  y+=inc;

  update_screen=TRUE;

 } else {

  y=0;

  update_screen=TRUE;

 }

}

void BmpViewWin::Down(int inc) {

 if (!yscroll) return;

 if (y-inc>=ylimit) {

  y-=inc;

  update_screen=TRUE;

 } else {

  y=ylimit;

  update_screen=TRUE;

 }

}

void BmpViewWin::Left(int inc) {

 if (!xscroll)  return;

 if (x+inc<0) {

  x+=inc;

  update_screen=TRUE;

 } else {

  x=0;

  update_screen=TRUE;

 }

}

void BmpViewWin::Right(int inc) {

 if (!xscroll) return;

 if (x-inc>=xlimit) {

  x-=inc;

  update_screen=TRUE;

 } else {

  x=xlimit;

  update_screen=TRUE;

 }

}

void BmpViewWin::Home() {

 if (xscroll && x!=0) {

  x=0;

  update_screen=TRUE;

 }

 if (yscroll && y!=0) {

  y=0;

  update_screen=TRUE;

 }

}

void BmpViewWin::End() {

 if (yscroll) {

  y=-(bmprect.Height()-displayrect.Height());

  update_screen=TRUE;

 }

 if (xscroll) {

  x=-(bmprect.Width()-displayrect.Width());

  update_screen=TRUE;

 }

}

void BmpViewWin::PageUp() {

 if (yscroll) {

  if (y-displayrect.Height()>0)   {

   y-=displayrect.Height();

   update_screen=TRUE;

  } else {

   y=0;

   update_screen=TRUE;

  }

 }

}

void BmpViewWin::PageDown() {

 if (yscroll) {

  if (y+displayrect.Height()<=ylimit) {

   y+=displayrect.Height();

   update_screen=TRUE;

  } else {

   y=ylimit;

   update_screen=TRUE;

  }

 }

}

Обработчикам клавиш со стрелками (Up(), Down(), Left(), Right()) можно передать необязательный аргумент, который определяет шаг прокрутки. Как видно из определения класса BmpViewWin (см. листинг 5.5), по умолчанию шаг прокрутки равен 4. 

Заключение 

В этой главе я упоминал о том, что загрузить растровое изображение на поверхность можно и другим, более простым способом. Вспомните — в интерфейс DirectDrawSurface входит функция GetDC(), которая позволяет работать с поверхностями с помощью обычных функций Win32. Реализующая этот подход функция может выглядеть так:

BOOL CopyBmp(LPDIRECTDRAWSURFACE surface, HBITMAP bmp, int x, int y) {

 if (bmp==0) {

  TRACE("no bmp specified\n");

  return FALSE;

 }

 if (surface==0) {

  TRACE("no surface specified\n");

  return FALSE;

 }

 HDC imageDC = CreateCompatibleDC(0);

 SelectObject(imageDC, bmp);

 BITMAP bitmap;

 GetObject(bmp, sizeof(bitmap), &bitmap);

 int w=bitmap.bmWidth;

 int h=bitmap.bnHeight;

 DDSURFACEDESC desc;

 desc.dwSize = sizeof(desc);

 desc.dwFlags = DDSD+HEIGHT |DDSC_WIDTH;

 surface->GetSurfaceDesc(&desc);

 HDC dc;

 HRESULT result;

 if ((result=surface->GetDC(&dc))==DD_OK)) {

  Stretchblt(dc, 0, 0, desc.dwWidth, desc.dwHeight, imageDC, x, y, w, h, SRCCOPY);

  surface->ReleaseDC(dc);

 }

 DeleteDC(imageDC);

 return result==DD_OK;

}

Эта функция не имеет никакого отношения к программе этой главы, ее даже нет на CD-ROM. Она приведена с единственной целью — показать, что с помощью функции GetDC() интерфейса DirectDrawSurface и функции Win32 наподобие StretchBlt() можно легко скопировать растровое изображение Windows на поверхность. Разумеется, в этом случае приходится жертвовать скоростью, поскольку механизм GDI не отличается особым быстродействием, а его функции не поддаются оптимизации.