
Иванова Г.С. - Основы программирования
.pdf8, Управление техническими средствами и взаимодействие с MS DOS
SetColor(O); {стираем кадр}
Squarel(round(xn), round(yn), round(dx), round(dy)); dx:=dxl; {заменяем параметры квадрата}
dy: =dyl xn:=xnJ yn:=ynl
end;
CloseGraph;
end.
Прямая запись в видеобуфер. При программировании на экране дви жения объектов критичным является время перезаписи изображения: имен но из-за большого времени перезаписи движение получается прерывистым. Для уменьшения этого времени при программировании в MS DOS часто ис пользуют прямую запись информации в видеобуфер.
Как указывалось в параграфе 8.4, формат информации в видеобуфере за висит от используемого графического режима. При использовании младших режимов VGA, на которые рассчитан Borland Pascal, видеобуфер содержит 4 бита на каждую точку, причем биты расположены в параллельных битовых плоскостях и доступ к ним напрямую существенно затруднен (программиро вание таких операций обычно выполняется на ассемблере). Однако сущест вует режим VGA (режим 19: 200*320 точек 256 цветов из палитры 262 144 цвета), при котором каждой точке соответствует байт (8 бит) в видеобуфере. Именно этот режим и используется, если возникает необходимость програм мировать сложное движение с использованием прямой записи в видеобуфер.
Пример 8.8. Разработать программу, обеспечивающую вывод «бегу щей» строки. Направление движения строки по экрану - вверх-вниз.
Для создания изображения используем возможности модуля Graph, за тем перепишем изображение из видеопамяти в буфер, расположенный в ди намической памяти, и перейдя в режим 200*320, организуем циклический вывод изображения напрямую в видеобуфер. Стирание старого изображения будем выполнять чистой кромкой образа (образ «не прозрачный»).
Переход в другой, не поддерживаемый Borland Pascal графический ре жим, будем осуществлять, используя ресурсы модуля Dos, описанные далее.
Program ex;
Uses Graph, CrUDos; Type
ScreenType=array [0,.199,0..319J of byte; {массив для хранения образа экрана - формат видеобуфера}
ImageType=array[0..999]ofbyte; {развертка изображения}
ScrTypePtr=^ScreenType; {указатель на массив образа экрана} ImageTypePtr=^^ImageType; {указатель на развертку изображения}
291
Часть L Основы алгоритмизации и процедурное программирование
{процедура установки режима с номером mode}
Procedure SetBIOSMode(mode:byte); Var r:registers;
Begin
r.AL:=mode; {запись номера режима в регистр AL} кАН:=0; {запись номера функции в регистр АН} intr($10,r); {вызов 0-й функции 10-го прерывания}
End;
{основная программа}
Var
Driver,Mode.'Integer; s:string;
ij, n, m, l,y, dy:integer;
Active_Ptr:ScrTypePtr; {указатель на тип "образ экрана"} Image:ImageTypePtr; {указатель на развертку изображения}
Begin
{формирование изображения и сохранение его в памяти}
Driver: =Detect; InitGraph(Driver,Mode, "); s:='ABCDEF\-
SetColor(4); SetTextStylefGothicFont, HorizDir, 3); OutTextXY(2,2,s);
n:=TextHeight(s)+3;
m:^TextWidth(s)+3;
GetMem(Image,(n+l)*(m+])); {получение памяти для записи изображения}
1:=0;
for i:=0 to ndo for J: =0 to mdo
begin
image^[l]:=Lo(GetPixel(j,i)); {запись изображения в буфер} 1:4+1;
end;
CloseGraph;
{запись изображения «напрямую» в видеобуфер} SetBIOSMode($13); {установка 19-го графического режима}
Active_Ptr:=Ptr($AOOO,0); {стандартный адрес видеобуфера}
у:-0; dy~l;
{покадровый вывод изображения} repeat
{побайтная запись изображения в видеобуфер}
1:=0;
for i:=0 to п do
292
8. Управление техническими средствами и взаимодействие с MS DOS
forj:=Oto т do begin
Active_Ptr''[y+i+]0j+20J:=image^flJ; 1:4+1;
end;
for i:=J to 1000 do Delay(3000); {задержка}
Inc(y,dy); {смещение изображения}
if(y>120) or (y<0) then dy:='dy; {организация колебательного
движения}
until KeyPressed;
SetBIOSMode(3); {возврат к стандартному текстовому режиму}
End.
8.8. Взаимодействие с драйвером мыши
Мышь - манипулятор, движение которого по столу или другой поверх ности преобразуется в перемещение специального курсора мыши на экране. С ее помощью мы можем «указать» на какую-либо область экрана и, нажи мая клавиши мыши, заказать некоторую обработку.
Для управления мышью программы, написанные на Borland Pascal, ис пользуют драйвер мыши, предоставляемый BIOS. Вызов этого драйвера осу ществляется через инициацию прерывания с номером ЗЗ15 = 51 ю (int 33h ~ на ассемблере).
Драйвер мыши реализует выполнение основных операций с мышью:
•инициализирует мышь (с проверкой наличия);
•устанавливает курсор мыши в заданное место экрана;
•определяет местоположение курсора мыши и состояния ее клавиш (нажаты или нет);
•управляет видимостью курсора мыши.
К сожалению, библиотеки Borland Pascal не включают функций обраще ния к драйверу мыши, и его вызов приходится осуществлять через процеду ру активизации обработчиков прерываний, определенную в модуле Dos.
Процедура Intr(numlnt:byte; Var Regs:Register) - активизирует обработ чик прерывания с номером numlnt. Через параметр Regs типа Registers орга низуется доступ к содержимому регистров (внутренней памяти) процессора:
Туре Registers = record case Integer of |
|
0: (AX,BXCXDXBP^DI,DS,ES, |
Flags: word); |
J: (AL,AH,BL,BH,CL,CH,DL,DH:byte);
end;...
Обмен данными между программой и драйвером мыши выполняется че рез регистры, указанные в описании драйвера. Так, номер вызываемой функ-
293
Часть I. Основы алгоритмизации и процедурное программирование
ции помещается в регистр АХ, а для передачи или получения дополнитель ной информации используются регистры СХ, DX.
Ниже приводится текст модуля, содержащего ресурсы, которые обеспе чивают доступ к драйверу мыши.
Unit Mouse; Interface
Uses Dos;
Function ResetMouse:Boolean; {проверить наличие} Procedure ShowMouseCursor; {показать курсор мыши} Procedure HideMouseCursor; {спрятать курсор мыши}
{прочитать состояние мыши}
Procedure ReadMouseStatefVar х, у:integer;{координаты мыши}
Var LeftButton, |
{нажата левая клавиша} |
MiddleButton, |
{нажата средняя клавиша} |
RightButton:boolean); |
{нажата правая клавиша} |
Procedure MoveMouseCursor(x,y:integer); |
{установить курсор мыши |
в точку с заданными координатами}
Implementation
{проверить наличие}
Function ReSetMouse.Boolean; Var г:Registers;
Begin r.AX:^0; intr($33,r);
ReSetMouse: =r.AX=$FFFF; End;
{показать курсор мыши}
Procedure ShowMouseCursor; Var r:Registers;
Begin
KAX:=I;
intr($33,r); End;
{спрятать курсор мыши}
Procedure HideMouseCursor; Var r:Registers;
Begin
KAX:^2;
intr($33,r); End;
294
8. Управление техническими средствами и взаимодействие с MS DOS
{прочитать состояние мыши}
Procedure ReadMouseStatefVar х,у:integer;{координаты мыши}
Var LeftButton, |
{нажата левая клавиша} |
MiddleButton, |
{нажата средняя клавиша} |
RightButton:boolean); |
{нажата правая клавиша} |
Var г:Registers; |
|
Begin |
|
r.AX:=3; |
|
intr($33,r); |
|
х:=кСХ; |
|
y:==r.DX; |
|
LeftButton-fr.BXAND 1)<>0; RightButton:=(r.BXAND 2)<>0; MiddleButton:^(KBXAND 4)<>0;
End;
{установить курсор мыши}
Procedure MoveMouseCursor(x,y:integer); Var r:Registers;
Begin
KAX:=4;
r.CX:=x;
KDX:=y; intr($33,r);
End; End
Разработка программ, использующих мышь, имеет свои особенности. В отличие от клавиатуры, ввод информации с которой осуществляется пользо вателем по запросу программы, состояние мыши (перемещение и положение клавиш) может изменяться пользователем в любой момент времени, незави симо от программы. Следовательно, программы, работающие с мышью, должны циклически опрашивать состояние мыши и при его изменении осуществлять требуемые операции.
На рис. 8.12 показано, как программа определяет моменты нажатия и от пускания клавиш (при выполнении опроса, если клавиша нажата, перемен ной Left присваивается значение true, а если - не нажата, то false).
Учитывать приходится также режим экрана, который использует про грамма, так как координаты курсора мыши на экране и в текстовом и в гра фическом режимах определяются в пикселях.
Взаимодействие с мышью в текстовом режиме. Координаты мыши при работе с ней в текстовом режиме необходимо пересчитывать, причем не зависимо от реального размера знакоместа считается, что оно имеет размер 8x8 пикселей.
295
Часть L Основы алгоритмизации и процедурное программирование
Состояние |
Клавиша |
Клавиша нажата |
|
Клавиша |
не нажата Г |
|
1 |
не нажата |
|
клавиши |
Опросы |
|
|
|
|
|
|
|
|
Действия |
|
|
|
|
программы |
[ |
|
I |
|
|
^ |
Left = tme |
|
|
|
|
|
||
Состояние |
Left = false |
|
|
Left = false |
переменной |
|
|
||
|
|
|
|
Рис. 8.12. Циклический опрос состояния мыши для фиксащ{и моментов нажатия и отпускания клавиши мыши
Пример 8.9. Разработать программу, демонстрирующую особенности использования мыши в текстовом режиме. При нажатии левой клавиши мы ши программа должна высвечивать координаты точки. Выход осуществить при нажатии левой клавиши мыши, когда ее курсор находится в окне «Ко нец» (рис. 8.13).
Управление разрабатываемой программой будет реализовано только по средством мыши. Вначале проверим наличие мыши, нарисуем окно Конец («кнопка»), установим i^pcop в левый верхний угол экрана. Затем будем от слеживать перемещение курсора, мыши и нажатие ее левой клавиши. Если клавиша нажата, то определяем местоположение курсора, проверяем, не на ходится ли он над окном Конец, и если нет, то выводим его координаты. По сле этого ожидаем отпускания клавиши, чтобы повторно не выводить коор динаты курсора.
::||Щ||?|^||
iiiii^iiasSs Конец
|||||||||Щ,
-?ciif:f|§ii
Рис. 8.13. Вид экрана в процессе работы программы
296
8. Управление техническими средствами и взаимодействие с MS DOS
Program ex; |
|
|
|
|
|
|
Uses |
CrtMouse; |
|
|
|
|
|
Var x,y,xt,yt:integer; |
l,m,r:boolean; |
|
||||
exit_m:boolean; |
|
|
|
|
||
Begin |
Clrscr; |
|
|
|
|
|
|
if not ReSetMouse then |
{проверка наличия мыши} |
||||
|
begin |
|
|
|
|
|
|
WriteLn('Mbitub не загруэюена'); |
|||||
|
Halt(l); |
|
|
|
||
|
end |
|
|
|
|
|
|
else WriteLn('Mbiiub подключена, *); |
|||||
|
ShowMouseCursor; |
{покажем курсор: курсор устанавливается |
||||
|
MoveMouseCursor(0,0); |
|
в центр экрана} |
|||
|
{поместим курсор в левый |
|||||
|
Window(70,1,80,3); |
|
|
верхний угол экрана} |
||
|
{нарисуем окно-кнопку «Конец»} |
|||||
|
Textattr:=^]6*J+14; |
Clrscr; |
||||
|
Gotoxy(2,2); |
WriteCKoнeц'); |
||||
|
Windowd |
1M25); |
Gotoxy(],3); |
|||
|
Textattr:=5*]6-^9; |
|
|
|
||
|
repeat |
{цикл обработки нажатий клавиши} |
||||
|
ReadMouseState(x,y, /, т,г); |
|
||||
|
if I then |
{если нажата левая кнопка } |
||||
|
begin |
|
|
|
|
|
|
{пересчет координат курсора для текстового режима} |
|||||
|
xt:=x div 8+1; |
|
|
|||
|
yt:=y div 8+1; |
|
|
|||
|
exitjn:=(xt>=70) |
and (xt< =80) and (yt> =1) and (yt< =3); |
||||
|
if not exitjn |
then |
|
|
||
|
|
begin |
|
|
|
|
|
|
Gotoxy(xt,yt); |
|
|
||
|
|
HideMouseCursor; |
{если не убирать курсор, |
|||
|
|
|
|
|
то курсор мыши будет затерт строкой} |
|
|
|
Write('x= \ xt:4, ' у= \ yt:4); |
||||
|
|
ShowMouseCursor; |
{теперь символ под курсором |
|||
|
|
|
|
|
|
«просвечивает» другим цветом} |
end;
repeat ReadMouseState(x,y,l,m,r) until not I; {ждем отпускания левой кнопки}
end;
until exitjn; {до «нажатия кнопки» Конец}
Textattr:=7; Clrscr;
End
297
Часть 1. Основы алгоритмизации и процедурное программирование
Drawing with mouse:
? MJ.
Курсор мыши
Рис. 8.14. Вид экрана при выполнении программы
Взаимодействие с мышью в графическом режиме* При использова нии мыши в графическом режиме также приходится выполнять циклический опрос состояния мыши для определения момента нажатия клавиши.
Пример 8.10. Разработать программу рисования мышью при нажатой левой клавише: точка рисуется при каждом опросе состояния мыши, если клавиша остается нажатой. Реализовать двойное управление (с клавиатуры и мышью): выход ~ при нажатии мышью кнопки Exit на экране или клавиши Esc на клавиатуре (рис. 8.14).
Program ex;
Uses Mouse,Crt,Graph; Var
x,y:mteger;
l,m,r:boolean;
exitjn:boolean;
driver,mode:integer;
ch:char;
{процедура рисования кнопки}
Procedure Button(xI,yI,x2,y2:integer;s:string); Begin
SetColor(O); |
|
SetFillStyle(l8); |
{рисуем контур кнопки} |
Bar(xl,yl,x2,y2); |
SetFillStyleOJ);
Ваг(х1-^2,у1+2,х2'3,у2гЗ); {рисуем тени кнопки} SetFillStyle(ll5);
Bar(x],ylxl+ly2);
298
8. Управление техническими средствами и взаимодействие с MS DOS
Bar(xl+2,у]+Ixl+2,y2-J); Bar(x],yJ,x2,yI+J); Bar(xl+lyl+1x2'lyl +2); SetColor(4); SetTextStyle(lA3); OutTextXY(xl^20,yl+3,s);
End;
{основная программа}
Begin Clrscr;
if not ReSetMouse then {проверим наличие мыши} begin
WriteLnCMouse notfound, *); halt(l);
end; driver: ^'detect;
InitGraph(driver,mode,' '); SetColor(4);
OuttextXY(10,]0, 'Drawing with mouse:'); ShowMouseCursor; {покажем курсор мыши}
SetBkColor(3);
Button (500J0,600,50, 'Exit');
repeat {цикл опроса состояния клавиатуры и мыши}
if keypressed then ch:-readkey {если нажата клавиша на клавиатуре, то введем код}
else {если клавиша не нажата, то} begin
ReadMouseState(x,y,l,m,r); {опросим состояние мыши} Exitjn: ==(х> =500)and(x< =600)and(y>=10)and(y< =50); if not Exitjn and I then {если не «нажата» кнопка «Exit»
на экране}
begin {изобразим точку на экране}
HideMouseCursor;
PutPixel(x,y4);
ShowMouseCursor;
end;
end
until (exitjn and I) or (ch=#27);
repeat ReadMouseState(x,y,l,m,r) until not I; {ожидаем отпускания клавиши}
CloseGraph; End
299
Часть I. Основы алгоритмизации и процедурное программирование
Задание для самопроверки
Модернизировать профамму из задания 1 к параграфу 8.4 так, чтобы реализо вать двойное управление меню: с использованием клавиатуры и мыши.
8.9.Управление задачами. Вызов дочерних процессов
Сточки зрения MS DOS каждая программа (задача) представляет собой процесс. При запуске процессу выделяется память и передаются окружение
ипараметры командной строки MS DOS.
Окружение - это специальная область памяти, в которой размещены в виде символьных строк некоторые параметры, установленные в DOS. На пример:
COMSPEC=C:\COMMAND.COM |
{адрес интерпретатора команд |
|
PATH=C:\QEMM;C:\DOS;C:\NC |
MS DOS} |
|
{каталоги автоматического по |
||
PROMPT=$p$q |
|
иска} |
{вид запроса в командной строке MS DOS} |
Пользователь может включить в окружение другие строки, используя команду SET.
Для работы с окружением модуль DOS содержит следующие ресурсы. 1. Функция EnvCount: integer - возвращает количество переменных ок
ружения, содержащихся в среде MS DOS.
2. Функция EnvStr(Index:integer):strmg - возвращает переменную окру жения MS DOS с указанным индексом.
3. Функция GetEnv(EnvVar:string):string - возвращает переменную ок ружения MS DOS с указанным именем.
Используя эти функции, можно, например, определить в системе место положение каталога временных файлов, обычно заданного в MS DOS пара метром work:
flag:--false;
while (i<EnvCount) and not flag do begin
ifpos('work^\EnvStrli])^l then begin
path: =copy(EnvStr[i], 6, length(EnvStr[i])-5); flag:'=true;
end else inc(i);
300