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

         

Формирование кодов событий

В примере 6.10 четвертая команда вызывает подпрограмму statins, текст которой приведен в примере 6.12. Она формирует и передает задаче данные о событиях, связанных с манипулятором "мышь". Выполняемые в ней действия оформлены в виде подпрограммы, для того чтобы их можно было использовать не только в управляющем алгоритме, но и в других случаях, когда нужны данные о состоянии мыши.

Прежде чем описывать подпрограмму statms, обсудим те соображения, которыми руководствовался автор при ее разработке.

Функции драйвера

Драйвер поддерживает три функции, которые позволяют получить разные данные о состоянии мыши.

Функция Mouse 3 возвращает в регистрах bх, сх и dx текущие значения счетчиков координат на экране и состояние кнопок. В сх находится номер столбца (координата х), а в dx — номер строки (координата Y). Три младших разряда регистра bх отражают состояние кнопок. Левой кнопке соответствует нулевой разряд,


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

Функция Mouse 5 возвращает данные о количестве нажатий на одну из кнопок и значение координат в момент последнего нажатия. Перед ее вызовом в регистре bх указывается номер кнопки: bх=о для левой, bx=i для правой и bх=2 для средней. В том же регистре (bх) драйвер возвращает количество нажатий на указанную кнопку, произошедших после последнего опроса ее состояния. Кроме того, в регистре ах возвращается состояние всех кнопок в том же виде, в каком эти данные возвращала функция Mouse 3 в регистре bх. При этом в регистрах сх и dx находятся значения координат в момент последнего нажатия на указанную кнопку.

Функция Mouse 6 отличается от Mouse 5 только тем, что возвращает информацию не о нажатии, а об отпускании указанной кнопки.

Функция Mouse 3 применяется наиболее часто. Функции Mouse 5 и Mouse б нужны в специальных случаях и, вообще говоря, при программировании работы с мышью без них можно обойтись.

Взаимосвязь событий

В технической документации любые изменения в состоянии мыши принято называть событиями (event). Функция Mouse з возвращает данные об элементарных событиях, в общем случае этого не достаточно для выполнения задачей конкретных действий.

Предположим, что в результате опроса драйвера установлен факт нажатия левой кнопки. Сам по себе этот факт мало что говорит, важно знать, изменилось ее состояние или нет. Если кнопка уже была нажата, то ее состояние не изменилось. Аналогичные рассуждения применимы и в случае, если кнопка не нажата. Следовательно, для оценки изменения состояния кнопки надо учитывать результаты предыдущего и текущего опросов драйвера.

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

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

В табл. 6.2 перечисленны элементарные события. Из них могут складываться более сложные события, например, во многих случаях применяется быстрое двухкратное нажатие (double-click) на кнопку. Его можно описать как повторное нажатие на одну и ту же кнопку в течение короткого отрезка времени при отсутствии перемещения мыши. Для распознания такого события задача должна спустя заданное время повторно опросить драйвер и убедиться в том, что в обоих случаях был получен код 2.

Таблица 6.2. Перечень событий для одной кнопки мыши

Код события

Движение мыши

Старое состояние

Новое состояние

0

Неподвижна

Не нажата

Не нажата

1

Неподвижна

Не нажата

Нажата

2

Неподвижна

Нажата

Не нажата

3

Неподвижна

Нажата

Нажата

4

Движется

Не нажата

Не нажата

5

Движется

Не нажата

Нажата

6

Движется

Нажата

Не нажата

7

Движется

Нажата

Нажата

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

Подпрограмма Statms опрашивает состояние мыши с помощью функции Mouse 3 и формирует коды событий в соответствии с табл. 6.2.

В качестве параметров подпрограмма, приведенная в примере 6.12, использует переменные, описанные в примере 6.8. Значения входных параметров содержат переменные xpointer, YPointer и Mstatus. Выходные параметры помещаются в те же переменные, кроме того, код события для правой кнопки возвращается в переменной RBevent, а для левой — в LBevent.

Пример 6.12. Формирование кодов событий для двух кнопок

Statms : Mouse 3 опрос текущего состояния мыши
xor al, al признак отсутствия движения
стар XPointer, ex координата X изменилась ?
jne SM 1 -> да
cmp YPointer, dx координата Y изменилась ?
je SM_2 -> нет, мышь не перемещалась
^44 / /рограммирование SVUA-графики для IbM
SM 1: or al, 04 признак перемещения мыши
mov XPointer, ex сохраняем новое значение X
mov Ypointer, dx сохраняем новое значение Y
SM 2: mov bh, Ы bh = новое состояние кнопок
xchg Mstatus, bh переставляем байты Ы и Mstatus
push bx сохраняем регистр bx
; Формирование кода события для правой кнопки
and bx, 0202h выделяем разряды состояния кнопки
shr Ы, 01 изменяем код нового состояния
or Ы, bh двумя командами or формируем
or bl, al в Ы код события для правой кнопки
mov RBevent, Ы сохраняем код события в RBevent
; Формирование кода события для левой кнопки
pop bx восстанавливаем регистр bx
and bx, 0101 выделяем разряды состояния кнопки
shl bh, 01 изменяем код старого состояния
or bl, bh и двумя командами or формируем
or bl, al в Ы код события для левой кнопки
mov LBevent, bl сохраняем код события в LBevent
eosub: ret возврат из подпрограммы

После всего сказанного текст примера 6.12 не требует оcобых пояснений. Напомним только, что код состояния формируется в соответствии с табл. 6.2, его значение может изменяться от 0 до 7. Нулевой разряд кода соответствует текущему состоянию кнопки, первый — предыдущему состоянию, а второй разряд указывает перемещение мыши.
Метка eosub, указанная перед командой ret, не имеет отношения к тексту примера. Просто в дальнейшем нам понадобится имя подпрограммы, состоящей из единственной команды ret.

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

В управляющем алгоритме выбор подпрограммы, выполняющей нужные действия, осуществляет переключатель (switch). Он применяется во многих языках программирования для выбора одного из нескольких вариантов выполняемых действий. В этом случае код события используется в качестве индекса при выборе одного из адресов, указанных в таблице переходов (transfer table), которая является списком адресов подпрограмм. Преимущество переключателя заключается в том, что количество действий, необходимых для выбора нужного адреса, не зависит от размера списка.

В управляющем алгоритме переключатель используется дважды — сначала для обработки событий, связанных с левой, а затем с правой кнопкой. В обоих случаях код события помещается в регистр bх и удваивается, поскольку списки адресов состоят из слов. После этого команда call вызывает одну из подпрограмм перечисленных в списках choiceL или choiceR. При выполнении этой команды адрес начала списка (значение меток ChoiceL или ChoiceR) суммируется с содержимым регистра bх, в стеке формируется адрес возврата и управление передается нужной подпрограмме.

Обратите внимание на то, что сразу после возвращения из подпрограммы statms код состояния левой кнопки находится в регистре bl. Поэтому при обработке событий левой кнопки нет необходимости копировать его в регистр bl из LBevent. Однако при обработке событий правой кнопки в регистр bl копируется содержимое RBevent.
Списки имен подпрограмм, обрабатывающих события, связанные с левой и правой кнопками, должны быть описаны в разделе данных программы, например, следующим способом:

ChoiceL dw eosub, namel, name2, eosub, motion, паmеЗ, name4, name5
ChoiceR dw eosub, eoprg, патеб, eosub, eosub, name7, nameS, name9

Действия, выполняемые при возникновении каждого из событий, зависят от назначения программы и фантазии программиста. Заведомо очевидны лишь два случая.

Если мышь неподвижна и состояние кнопок не изменилось (коды 0 и 3), то просто ничего не произошло. Этим кодам в обоих списках соответствует имя eosub, которое в примере 6.12 указано перед командой ret.

Если мышь движется и кнопки не нажаты (код 4), то надо просто перемешать курсор. Поэтому на пятом месте в списке choiceL указано имя подпрограммы motion, выполняющей перемещение курсора, ее подробное описание приведено в следующем разделе.

Во втором слове массива choiceR указано имя команды eoprg, начиная с которой выполняются завершающие действия (см. пример 6.11). При нажатии на правую кнопку мыши выполнение задачи прекратится и произойдет возврат в DOS.

Если при подготовке исходного текста программы вы еще не решили, как обрабатывать остальные события, то просто замените имена name1 - name9 именем eosub. Управляющий алгоритм будет игнорировать события, для обработки которых не указаны специальные подпрограммы.

Идентификация графических объектов

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

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

Замечание
Описание процедур, реагирующих на изменение состояния кнопок, выходит за рамки данной книги, поэтому мы ограничимся следующим советом. Начните с составления простой подпрограммы, которая при нажатии левой кнопки проверяет нахождение курсора в прямоугольной области с заданными границами Xmin, Xmax, Ymin, Ymax. Если курсор находится в ней, то подпрограмма завершает выполнение задачи. На экране этим координатам может соответствовать прямоугольник с надписью "Выход" или "Exit". Затем усложните подпрограмму сделав так, чтобы значения указанных границ выбирались из формируемого задачей списка. Следующий шаг — при нахождении объекта в списке выполняется подпрограмма, адрес которой хранится в том же элементе, в котором указаны границы объекта. Так постепенно вы создадите универсальную процедуру для обработки событий, связанных с левой кнопкой.

 
Содержание раздела