Для того чтобы при изменении состояния мыши драйвер мог прервать выполнение задачи, последняя должна с помощью специальных функций установить прерывающую подпрограмму. В данном разделе описаны варианты установки и удаления прерывающих подпрограмм, требования к их оформлению, условия вызова и данные, передаваемые драйвером.
Обычно термин "прерывающая" указывает на то, что подпрограмма вызывается при возникновении событий, независящих от выполнения основной задачи полностью или частично. В нашем случае момент вызова подпрограммы зависит от действий оператора, работающего с мышью.
Особенность описываемых ниже подпрограмм заключается в том, что в случае необходимости их может вызывать основная задача, но это уже относится к области трюков или искусства программирования.
Драйвер может обслуживать только одну основную прерывающую подпрограмму.
Для ее установки задаются адрес точки входа и маска события (или событий),
при каждом наступлении которого (которых) будет вызываться установленная
Функция 0С (set Event Handler) предназначена для установки подпрограммы, реагирующей на события, связанные с изменением состояния мыши. Перед обращением к драйверу полный адрес точки входа указывается в регистрах es:dx, а код маски помещается в младший байт регистра сх. Состояние его разрядов (0 или 1) соответствует наличию или отсутствию следующих событий:
разряд 0 — перемещение мыши; | |
разряд 1 — левая кнопка нажата; | разряд 2 — левая кнопка отпущена; |
разряд 3 — правая кнопка нажата; | разряд 4 — правая кнопка отпущена; |
разряд 5 — средняя кнопка нажата; | разряд 6 — средняя кнопка отпущена. |
Допустимо произвольное сочетание указанных признаков, в частности, при записи в регистр сх кода 7Fh подпрограмма будет вызываться при любых изменениях состояния мыши.
Особым случаем является очищенное состояние регистра сх при обращении к драйверу, оно запрещает обслуживание ранее установленной подпрограммы. При изменении состояния мыши драйвер проверяет, указан код произошедшего события в маске или нет. Ни одно из событий не имеет код 0, поэтому при очищенной маске вызов подпрограммы исключается. Для очистки маски достаточно выполнить следующие две команды:
хоr сх, сх ; очистка регистра сх
Mouse ОС ; запрос функции ОС
Если ваша задача устанавливала прерывающую подпрограмму, то не забудьте выполнить эти две команды перед возвратом в DOS. В противном случае при первом же наступлении соответствующего события драйвер обратится к тому участку памяти, в котором подпрограммы уже нет, и возникнет аварийная ситуация.
При исполнении функции ос драйвер просто копирует содержимое регистров сх, dx и es в три слова внутреннего буфера, не выполняя никаких проверок. Таким простым способом исключается возможность установки нескольких подпрограмм. В любой момент времени драйвер обслуживает только ту подпрограмму, которая была установлена последней и "обмануть" его невозможно.
Если задача должна реагировать на несколько разных событий, то в маске надо установить соответствующие разряды, а в прерывающей подпрограмме уточнять причину (или причины) прерывания. Другими словами, иногда приходится сочетать режимы прерываний и опроса состояния драйвера мыши.
Функция 14 (Exchange Event Handier) выполняет те же действия, что и функция ос, кроме того, драйвер возвращает в регистрах es:dx адрес ранее установленной подпрограммы, а в регистре сх маску событий, на которые она реагировала. Эта функция может быть полезна в тех случаях, когда по каким-то причинам надо заменить прерывающую подпрограмму, а через некоторое время восстановить ее работоспособность.
Установка альтернативных подпрограмм
Учитывая, что основная подпрограмма может быть только одна, разработчики предусмотрели возможность установки трех альтернативных подпрограмм. Их принципиальное отличие в том, что в момент изменения состояния мыши должна быть нажата хотя бы одна из трех специальных клавиш.
Функция 18 (set Alternate Event Handier) устанавливает альтернативную подпрограмму, реагирующую на изменения состояний мыши при условии, что нажата одна из трех клавиш — <Alt>, <Ctrl>, <Shift>, или любая их комбинация. Перед обращением к драйверу полный адрес подпрограммы указывается в регистрах es:dx, а код маски помещается в младший байт регистра сх. Состояние его разрядов (0 или 1) соответствует наличию или отсутствию следующих событий:
разряд 0 — перемещение мыши; | разряд 1 — левая кнопка нажата; |
разряд 2 — левая кнопка отпущена; | разряд 3 — правая кнопка нажата; |
разряд 4 — правая кнопка отпущена; | разряд 5 — нажата клавиша <Shift>; |
разряд 6 — нажата клавиша <Ctrl>; | разряд 7 — нажата клавиша <Alt>. |
Три старших разряда маски отведены для указания одной из клавиш или их сочетания. Драйвер анализирует их не независимо друг от друга, а как трехразрядный код. Поэтому установка любых двух старших разрядов соответствует одновременному нажатию двух клавиш, а установка трех разрядов одновременному нажатию трех клавиш <Alt>+<Ctrl>+<Shift>.
Указание в коде маски, по крайней мере, одной клавиши обязательно. Если очищены все три старших разряда кода маски, то драйвер отвергает попытку установить подпрограмму. При этом он возвращает в регистре ах код OFFFFh.
Коды событий, связанных с изменением состояния мыши, занимают в маске пять младших разрядов, места для средней кнопки не хватает. Если установлены все младшие разряды, то подпрограмма будет вызываться при любом изменении состояния мыши, если одновременно нажата клавиша, указанная в старших разрядах кода маски.
Например, если код маски 9Fh, то подпрограмма будет вызываться, если нажата клавиша <Alt> и мышь перемещается, либо изменяется состояние ее левой или правой кнопок.
Особым случаем является очищенное состояние пяти младших разрядов кода маски, оно запрещает обслуживание установленной альтернативной подпрограммы. Обращаем ваше внимание на то, что должны быть очищены только пять младших разрядов. Например, если подпрограмма работала с клавишей <АН>, то для ее запрета выполняются две следующие команды:
mov сх, 8Oh ; код маски при работе с клавишей <Alt> Mouse 18 ; запрос функции 18
Перед завершением задачи надо обязательно запретить обслуживание как основной, так и альтернативных подпрограмм, если они были установлены.
Функция 19 (Query Alternate Event Handler) проверяет факт установки альтернативной подпрограммы, маска для поиска указывается в регистре сх. Если подпрограмма была установлена, то драйвер возвращает ее адрес в регистрах es:dx, в противном случае он помещает в регистрах код OFFFFh.
Ошибка в драйвере Mitsumi
Автор исследовал три драйвера мыши, разработанные фирмами Microsoft, Genius и Mitsumi. В последнем из них допущена трудно диагностируемая ошибка, она заключается в следующем. Если основная и альтернативная подпрограммы реагируют на одно и то же изменение состояния мыши, то драйвер отдает предпочтение основной и не вызывает альтернативную подпрограмму. В частности, если основная подпрограмма реагирует на любые изменения состояния мыши (код маски 7Fh), то альтернативные подпрограммы не будут вызваны драйвером ни при каких условиях. На этикетке установочной дискеты, прилагаемой к мыши, написано MITSUMI Mouse Driver Version 6.0.
Вызов подпрограммы драйвером
Если произошло событие, код которого указан в маске, то драйвер вызывает установленную подпрограмму. При входе в нее в регистрах bx, сх и dx находятся данные о состоянии кнопок и значениях координат, представленные в том виде, в котором они получаются после выполнения функции 3.
Три младших разряда регистра bх указывают состояние кнопок. Если разряд установлен, то соответствующая ему кнопка нажата, а если очищен, то не нажата. Разряды 0, 1, 2 соответствуют левой, правой и средней кнопкам.
Дополнительно в регистре ах находится код события, явившегося причиной вызова подпрограммы. В этом регистре может быть установлен только один из указанных в коде маски разрядов (см. описание функции ос). Например если подпрограмма вызывается при любом изменении состояния мыши (код маски 7Fh), то будет установлен один из 7 младших разрядов регистра ах.
Предположим, что оператор перемещает мышь при нажатой левой кнопке. В момент начала перемещения произойдут два вызова подпрограммы. В одном случае в регистре ах будет находиться код 1, а во втором 2. Какой из двух вызовов произойдет первым, зависит от того, что раньше сделал оператор — нажал левую кнопку или начал двигать мышь. В дальнейшем состояние левой кнопки не меняется до того момента, пока она не будет отпущена, поэтому при вызовах подпрограммы в регистре ах будет находиться код 1. При отпускании левой кнопки в регистре ах окажется код 4.
Если подпрограмма реагирует только на перемещение курсора (код маски 1), то состояние кнопок указывает код, находящийся в регистре bх.
В конце