Графические устройства



 

Примеры прерывающих подпрограмм

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

Способы перемещения курсора

Основные действия, выполняющие перемещение курсора, были описаны в разделе на примере подпрограммы Motion. При работе в режиме прерываний задача должна иметь возможность запрещать перемещение курсора. Например, при построении нового рисунка изображение курсора временно удаляется с экрана. При этом подпрограмма не должна перемещать курсор. Задача может либо временно запрещать драйверу вызов прерывающей подпрограммы, либо устанавливать специальный признак, анализируемый при перемещении курсора.

Первый способ имеет следующий недостаток. В тот момент, когда задача удаляет изображение курсора с помощью подпрограммы Hidepnt, значения переменных winpnt, offspnt, Xpointer, Ypointer (см. пример 6.8) соответствуют значениям СПК внутреннего буфера драйвера. Если задача запретила драйверу вызывать подпрограмму перемещения курсора, а оператор в это время двигает мышь, то новые значения СПК не будут соответствовать значениям указанных переменных. Когда задача восстановит изображение курсора с помощью подпрограммы showpnt, то оно появится на старом месте. А после восстановления работы прерывающей подпрограммы, при первом движении мыши, курсор скачком переместится в новую позицию.

Второй способ избавлен от этого недостатка. Если установлен специальный признак, то прерывающая подпрограмма вычисляет текущие значения переменных winpnt, offspnt, xpointer, Ypointer, но не перемещает курсор. В результате значения этих переменных и СПК всегда будут соответствовать друг другу. Теперь, когда задача вызовет подпрограмму showpnt, изображение курсора появится на новом месте.

Подпрограмма Mousm

Текст подпрограммы, перемещающей курсор по прерываниям, приведен в примере 6.14. В нем использованы имена переменных curmp и pntstat, их следует добавить к описанным в примере 6.8, т. е. разместить в разделе данных задачи. Вполне достаточно, если они будут иметь размер байта. Советуем вам сравнить текст данной подпрограммы с описанным в примере 6.13.

Пример 6.14. Прерывающая подпрограмма для перемещения курсора

Mousm: mov ах, data ax = значение сегмента данных
mov ds , ах установка сегмента данных
mov es, Vbuff установка сегмента видеобуфера
inc curmp ! ! счетчик перемещений курсора
mov Xpointer, ex сохранение нового значения
mov Ypointer, dx сохранение нового значения
mov ax, dx ах = номер строки
mui horsize dx:ax = Ypointer*horsize
add ax, ex прибавляем к ах номер столбца
adc dx, 00 учитываем возможность переполнения
xchg ax, dx переставляем содержимое ах и dx
mov byte ptr GrUnit ах = al*GrUnit
add ax, Base win ! ! учитываем значение базового окна
test pntstat, 01 проверка состояния курсора
je msmx -> курсор удален с экрана
call Hidepnt гасим курсор
mov Offspnt, dx сохраняем смещение в Offspnt
mov Winpnt, ax сохраняем в Winpnt
call Showpnt рисуем курсор и выходим
retf возвращение в драйвер
rosmx : mov Offspnt, dx сохраняем смещение в Offspnt
mov Winpnt, ax сохраняем в Winpnt
retf возвращение в драйвер

Выполнение подпрограммы начинается с восстановления содержимого сегментных регистров ds и es, поскольку оно было изменено драйвером. Далее расположена команда, увеличивающая значение переменной curmp на 1. Она нужна для того, чтобы задача могла определить, перемещайся курсор или нет. Если при выполнении вашей задачи такая информация не нужна, то просто исключите команду из текста подпрограммы.

Затем новые значения координат присваиваются переменным xpointer н Ypointer и пересчитываются в адрес видеопамяти. В отличие от примера 6.13 вычисленные величины сразу не присваиваются переменным offspnt и winpnt, а сохраняются в регистрах dx и ах. Это делается потому, что значения указанных переменных можно изменять только после выполнения подпрограммы Hidepnt.

Перед вызовом Hidepnt проверяется состояние младшего разряда переменной pntstat. Если он установлен, то изображение курсора находится на экране, его можно удалять и перемещать. В противном случае содержимое регистров dx и ах сохраняется в переменных offspnt и winpnt и команда retf выполняет возврат в драйвер.

Таким образом, подпрограмма Mousm в любом случае изменяет значения переменных, указывающих координаты и адрес видеопамяти для изображения курсора, а само изображение перемещается только в том случае, когда установлен младший разряд переменной pntstat — признак нахождения курсора на экране.

Изменение флага состояния

Для того чтобы каждый раз не вспоминать о необходимости изменить текущее значение переменной pntstat, мы рекомендуем просто включить в текст подпрограмм showpnt (см. пример 6.5), Hidepnt (см. пример 6.6) и Tgipntr (см. пример 6.4) следующие команды:

or pntstat, 01 ; в подпрограмму Showpnt
and pntstat, OFeh ; в подпрограмму Hidepnt
xor pntstat, 01 ; в подпрограмму Tgipntr

Все три команды изменяют состояние только младшего разряда pntstat, это позволяет, в случае необходимости, использовать остальные разряды pntstat для хранения других нужных для задачи признаков.

Установка Mousm

Для установки подпрограммы Mousm после действий, описанных в примере 6,9, надо выполнить группу команд, приведенную в примере 6.15.

Пример 6.15. Установка прерывающей подпрограммы Mousm

; Дополнение к примеру 6.9
push es ; сохраняем содержимое es
push cs ; помещаем в стек содержимое cs
pop es ; и выталкиваем его в es
lea dx, Mousm ; пишем в dx адрес "Mousm"
mov ex, 01 ; код события "перемещение курсора"
mouse ОС ; обращаемся к драйверу мыши
pop es ; восстанавливаем содержимое es

Подведем итог всему сказанному в данном разделе. Перемещение курсора слабо зависит от действий основной задачи и его можно выполнять в режиме прерываний, поступающих от драйвера. Правда, в таком случае возникает вопрос о том, как задача узнает, что курсор перемещался, если для ее выполнения это необходимо знать. На этот случай мы использовали в примере 6.14 переменную curmp. Предполагается, что в нужные моменты времени задача проверяет значение этой переменной и узнает о факте перемещения курсора. Вы можете отказаться от этой переменной и ввести другой признак перемещения курсора, но в любом случае без анализа специального признака задача не узнает о факте перемещения курсора, поскольку оно выполняется без ее прямого участия.

Анализ состояния кнопок

Текущее состояние мыши, как правило, надо анализировать в тех случаях, когда это необходимо для выполнения задачи. Поэтому мы рекомендуем, по крайней мере, на первое время использовать опрос состояния. При этом вместо обращений к драйверу мыши надо проверять значения переменных LBevent и RBevent, которые формирует вызываемая драйвером подпрограмма, при наступлении соответствующих событий. Вместо 8 разных значений, перечисленных в табл. 6.2, в режиме прерываний LBevent и RBevent могут иметь только три значения 0, 1 и 2.

Переменная Mstatus имела вспомогательное значение и в данном случае она не используется. Вместо нее мы введем три новые переменные:

Noevent db 0 ; признак изменения (1) состояния кнопок
Xasevent dw 0 ; координата X в момент изменения состояния кнопок
Yasevent dw 0 ; координата Y в момент изменения состояния кнопок

При изменении состояния кнопок подпрограмма устанавливает младший разряд переменной Noevent, очищать эту переменную должна задача после обработки события. Переменные Xasevent и Yasevent введены на тот случай, когда надо знать, в каком месте находился курсор в момент нажатия или отпускания кнопок мыши.

Универсальная подпрограмма

Драйвер всегда обрабатывает только одно событие, это обстоятельство и использовано в подпрограмме Eventm. Она либо перемещает курсор, либо формирует новые значения переменных Noevent, LBevent и RBevent. Текст подпрограммы приведен в примере 6.16.

Пример 6.16 . Обслуживание прерываний от драйвера мыши

Eventm: push ax ; сохранение содержимого ах
mov ax, data ; ах = значение сегмента данных
mov ds, ax установка сегмента данных
pop ax восстановление содержимого ах
shr ax, 01 сдвиг содержимого ах на разряд вправо
jnc btnstat -> курсор не перемещался
; Сюда надо вставить текст примера 6.14, начиная с третьей команды
Btnstat: mov Noevent, 01 признак изменения состояния кнопок
mov Xasevent, ex координата X в момент события
mov Yasevent, dx координата Y в момент события
mov ah, al копируем al в ah
and ax, ОСОЗп выделяем нужные разряды
mov LBevent, al сохраняем код события в LBevent
shr ah, 02 сдвиг кода в ah на 2 разряда вправо
mov RBevent, ah сохраняем код события в RBevent
retf возвращение в драйвер

Текст примера 6.16 надо дополнить текстом подпрограммы Mousm, как это указано в комментарии. При этом получится универсальная прерывающая подпрограмма, перемещающая курсор вслед за мышью и формирующая коды событий, связанных с кнопками при изменении их состояния.

Первая команда примера 6.16 сохраняет в стеке содержимое регистра ах, потому, что его портит следующая команда. Перед началом основных действий надо поместить в регистр ds значение используемого в задаче сегмента данных, для того чтобы стали доступны расположенные в нем переменные, что и делают две следующие команды. После их выполнения восстанавливается исходное содержимое регистра ах.

Выполняемые подпрограммой действия зависят от причины ее вызова, т. е. от кода, находящегося в регистре ах. Его содержимое сдвигается на 1 разряд вправо, при этом в зависимости от состояния младшего разряда будет очищен или установлен признак переноса (флаг carry). Если он установлен, то надо перемещать курсор. В противном случае команда jnz btnstat выполняет переход на ветку с меткой btnstat.

В этой ветке формируются значения переменных Noevent, Xasevent, Yasevent, LBevent и RBevent. Выполняемые при этом действия не требуют особых пояснений. Если вам непонятен способ вычисления значений LBevent и RBevent, то вернитесь к разделу , в котором описано, что передает драйвер вызываемой подпрограмме.

Для установки подпрограммы Eventm в примере 6.15 надо изменить команды, формирующие адрес подпрограммы и маску событий, а именно:

lea dx, Eventm ; пишем в dx адрес "Eventm"
mov ex, IFh ; устанавливаем код маски событий

После установки подпрограмма будет вызываться при перемещениях мыши и при изменении состояний ее левой и правой кнопок.

Таким образом, описанная подпрограмма передает задаче все данные об изменении текущего состояния мыши, и дополнительные обращения задачи к драйверу не требуются. Надо просто анализировать значения переменных, которые формирует подпрограмма Eventm. Это упрощает структуру задачи, а взаимодействие с драйвером производится только в тех случаях, когда изменяется состояние мыши.

Замечание
Если оператор перемещает мышь или нажимает на ее кнопки в тот момент, когда задачу "не интересует" состояние мыши, то его действия будут зафиксированы в значениях переменных и не окажут никакого влияния на выполнение задачи. Но, вернувшись к опросу, задача отреагирует на последнее изменение расположения мыши и состояния ее кнопок. Для исключения ложных срабатываний задача должна очищать переменные curmp и Noevent после их использования. Не забывайте также, что в процессе выполнения задачи можно запрещать вызов ранее установленной подпрограммы или устанавливать вместо нее другую подпрограмму.

Мы закончили последнюю из четырех глав, посвященных программированию для видеорежимов PPG. Об особенностях именно этих режимов речь шла только при описании работы с рисунками и палитрой цветов. При рассмотрении работы с текстом и курсором автор стремился акцентировать внимание читателя на основных вопросах, безотносительно к видеорежимам. Поэтому приемы, описанные в главах 5 и б, могут пригодиться вам и при программировании для видеорежимов direct color.

 
Назад Начало