Чтение онлайн

ЖАНРЫ

Графика для Windows средствами DirectDraw

Трухильо Стэн

Шрифт:

 CursorWin* win=(CursorWin*)p;

 while(TRUE) {

CMultiLock mlock((CSyncObject**)mouse_event, 2);

DWORD event=mlock.Lock(INFINITE, FALSE);

if (event-WAIT_OBJECT_0==quit_event_index) {

TRACE("got quit message: quitting mouse thread\n");

return 0;

}

critsection.Lock;

oldcurx=curx;

oldcury=cury;

BOOL buffer_empty=FALSE;

while (!buffer_empty) {

DIDEVICEOBJECTDATA data;

DWORD elements=1;

if (mouse==0) {

TRACE("invalid pointer: quitting mouse thread\n");

return 0;

}

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

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

static MouseClickData mc;

switch data.dwOfs) {

case DIMOFS_X:

curx+=data.dwData;

break;

case DIMOFS_Y:

cury+=data.dwData;

break;

case DIMOFS_BUTTON0:

if (data.dwData & 0x80) {

mc.x=curx;

mc.y=cury;

mc.button=0;

mouseclickqueue.AddHead(mc);

}

break;

case DIMOFS_BUTTON1:

if (data.dwData & 0x80) {

mc.x=curx;

mc.y=cury;

mc.button=1;

mouseclickqueue.AddHead(mc);

}

break;

}

} else buffer_empty=TRUE;

}

if (curx<0) curx=0;

if (cury<0) cury=0;

if (curx>=screen_width-cursor_width) curx=screen_width-cursor_width-1;

if (cury>=screen_height-cursor_height) cury=screen_height-cursor_height-1;

if (curx==oldcurx && cury==oldcury) {

//-----
обновление курсора не требуется ------

goto nevermind;

} else if (abs(curx-oldcurx) >= cursor_width || abs(cury-oldcury) >= cursor_height) {

//----- простой случай: прямоугольники нового

// и старого курсора не перекрываются -----

win->UpdateCursorSimpleCase(curx, cury, oldcurx, oldcury);

} else {

//----- сложный случай: прямоугольники нового

// и старого курсора перекрываются -----

win->UpdateCursorComplexCase(curx, cury, oldcurx, oldcury);

}

nevermind:;

critsection.Unlock;

 }

 TRACE("leaving mouse thread\n");

 return 0;

};

Функция MouseThread

имеет один параметр — значение, передаваемое функции AfxBeginThread при создании потока (см. листинг 7.3). Мы передавали указатель this, поэтому сейчас сможем присвоить его значение указателю на класс CursorWin (переменная win). В функции MouseThread указатель win будет использоваться для доступа к членам класса CursorWin.

Функция MouseThread в цикле выполняет блокировку по двум событиям. Класс CMultiLock позволяет блокироваться как по событиям от мыши, так и по событию завершения потока. Фактическая блокировка выполняется функцией CMultiLock::Lock. По умолчанию функция Lock блокирует поток до установки всех (в данном случае - двух) заданных событий. Мы изменяем это поведение и передаем FALSE в качестве второго аргумента Lock, показывая тем самым, что функция должна снимать блокировку при установке хотя бы одного из этих событий.

Когда любое из двух событий переходит в установленное состояние, функция Lock завершается, и мы проверяем код возврата. Если выясняется, что было установлено событие завершения потока (обозначенное константой quit_event_index), мы выходим из функции MouseThread, тем самым завершая поток. В противном случае активизация потока вызвана событием мыши, поэтому мы переходим к обработке новых данных.

Однако сначала необходимо захватить критическую секцию с помощью объекта critsection. Для получения данных нам придется обращаться к очереди событий от кнопок мыши и к первичной поверхности, поэтому выполнение этого кода следует синхронизировать с основным потоком.

Мы в цикле получаем данные от объекта DirectInputDevice, представляющего мышь, с помощью функции GetDeviceData. Если получены данные о перемещении мыши, происходит обновление переменных curx и cury. Если получены данные о нажатии кнопок, они заносятся в очередь событий.

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

Наконец, мы проверяем новое положение курсора. Если перемещение курсора не обнаружено, критическая секция освобождается, а объект CMultiLock снова используется для блокировки по обоим событиям. Если курсор переместился в другое положение, мы вызываем одну из двух функций обновления курсора в зависимости от того, перекрывается ли старая область курсора с новой. Если области перекрываются, вызывается функция UpdateCursorComplexCase; в противном случае вызывается функция UpdateCursorSimpleCase.

Поделиться с друзьями: