МАНИПУЛЯТОР МЫШЬ
Манипулятор мышь (в дальнейшем, просто мышь) является средством, позволяющим пользователю достаточно удобно осуществлять управление прикладными программами. Как правило, мышь соединена с ПЭВМ через последовательный интерфейс. Прикладные программы, связывающиеся через интерфейс с мышью, делают это через обращение к драйверу Microsoft, например GMOUSE.COM. Все обращения к драйверу происходят через прерывание 33h.
Прерывание 33h имеет ряд функций, которые выбираются с помощью загрузки номера функции в регистр AX. Основные функции будут приведены ниже.
Функция 00h: инициализация мыши. Если мышь инициализирована, то в регистре AX возвращается значение FFFFh, а в регистре BX - число клавиш мыши. Если инициализации не происходит, то в регистре AX возвращается значение 0000h.
Функция 01h: показать указатель мыши.
Функция 02h: спрятать указатель мыши.
Функция 03h: получить текущие координаты указателя мыши и состояние кнопок. Координаты указателя соответствует виртуальному экрану. На практике, обычно, они содержат положение пикселя в графическом режиме или умноженные на 8 координаты в текстовом режиме. Отсчет графических координат начинается от 0. Текстовые координаты отсчитываются от 1. Эта функция возвращает в регистре CX координату x, а в регистре DX координату y, в регистре BX - состояние кнопки (бит 0 - левая кнопка нажата, если установлена; бит 1 - средняя кнопка нажата, если установлена; бит 2 - правая кнопка нажата, если установлена).
Функция 04h: установить позицию указателя. В регистр CX пересылается координата x, а в регистр DX координата y. Установленная позиция указателя будет игнорироваться, если она находится внутри области исключения (см. функцию 07h и 08h). Координаты задаются всегда в пикселях, где (0,0) - координата верхнего левого угла виртуального экрана.
Функция 05h: получить информацию о нажатии клавиши. В регистр BX пересылается номер кнопки (0 - левая кнопка, 1 - правая кнопка, 2 - средняя кнопка). В регистр AX возвращается состояние кнопки (бит 0 - левая кнопка нажата, если установлена; бит 1 - средняя кнопка нажата, если установлена; бит 2 - правая кнопка нажата, если установлена). В регистр BX возвращается счетчик нажатия клавиши, CX - координата x последнего нажатия, DX - координата y последнего нажатия. После обращения к этой функции счетчик нажатия клавиши сбрасывается.
Функция 06h: получить информацию об отжатии клавиши. В регистр BX пересылается номер кнопки (0 - левая кнопка, 1 - правая кнопка, 2 - средняя кнопка). В регистр AX возвращается состояние кнопки (бит 0 - левая кнопка отжата, если установлена; бит 1 - средняя кнопка отжата, если установлена; бит 2 - правая кнопка отжата, если установлена). В регистр BX возвращается счетчик отжатий клавиши, CX - координата x последнего отжатия клавиши мыши, а DX - координата y последнего отжатия клавиши мыши. После обращения к этой функции счетчик отжатия клавиши сбрасывается.
Функция 07h: установить горизонтальное ограничение для указателя мыши. В регистр CX пересылается минимальное значение координаты x, в регистр DX - максимальное значение координаты x.
Функция 08h: установить вертикальное ограничение для указателя мыши. В регистр CX пересылается минимальное значение координаты y, в регистр DX - максимальное значение координаты y.
Функция 09h: установить форму указателя мыши в графическом режиме. По умолчанию используется указатель типа стрелки. В ES:DX пересылают адрес буфера изображения. Длина буфера изображения 64 байта. Байты с 32 по 64 определяют вид курсора, а байты с 0 по 31 определяют прозрачность курсора. Они рассматриваются как битовая маска 16´16 каждый бит которой маскирует пиксели экрана. При создании изображения драйвер предварительно получает информацию о 16´16 пикселях соответствующего места экрана и к каждому пикселю применяется операция AND с маской экрана, а затем к полученному результату - операция XOR с маской изображения. Приведенный ниже пример показывает формирование курсора в графическом режиме в виде прямоугольника с тонкой прозрачной полоской в середине.
program testmouse;
uses dos,graph;
var
reg:registers;
res1,res2,i,res3,res4:byte;
buf : array [0..63] of byte;
gd,gm:integer;
begin
FOR i:=32 TO 64 DO
buf[i]:=255;
FOR i:=0 TO 31 DO
buf[i]:=1;
gd:=detect;
initgraph(gd,gm,'');
reg.AX:=1;
intr($33,reg);
reg.ax:=9;
reg.es:=seg(buf);
reg.dx:=ofs(buf);
intr($33,reg);
.
.
.
closegraph;
end.
В регистр BX заносится смещение вправо (в пикселях) из левого верхнего угла указателя, пикселя изображения рассматриваемого драйвером в качестве текущей позиции. В регистр CX заносится смещение вниз (в пикселях) из левого угла указателя, пикселя изображения рассматриваемого драйвером в качестве текущей позиции.
Функция 0Ah: установить вид указателя мыши в текстовом режиме. В регистр BX заносят 0, если выбирают курсор, используемый в программе, и 1, если выбирают стандартный курсор. Если указатель генерируется программой, то в регистр CX заносятся биты определяющие маску AND, а в регистр DX заносятся биты определяющие маску XOR по следующему принципу. Биты 0-7 - код символа; биты 8-10 цвет символа; бит 11 - бит интенсивности; биты 12-14 - цвет фона; бит 15 - бит мерцания.
Функция 10h: установить область исключения указателя. В регистр CX пересылают значение левой верхней координаты x, в DX - значение левой верхней координаты y, в SI - значение правой нижней координаты x, в DI - значение правой нижней координаты y. Эта функция определяет область исключения отображения указателя мыши. Область исключения отменяется обращением к функции 00h или 01h, или другим обращением к этой функции.
Перед выполнением любых внешних программ, прикладные программы должны сохранять состояние драйвера мыши, для того, чтобы при возврате в прикладную программу все настройки мыши в прикладной программе оставались неповрежденными.
Функция 15h: получить размер сохраненного буфера состояния мыши. В регистр BX возвращается размер буфера в байтах.
Функция 16h: сохранить состояние драйвера мыши. В ES:DX заносится адрес буфера. Под буфер выделяется 64 байта.
Функция 17h: восстановить состояние драйвера мыши. В ES:DX заносится адрес буфера.
Функция 1Dh: установить текущую видеостраницу для указателя мыши. В регистр BX заносится номер видеостраницы. Допустимые номера страницы зависят от активного режима визуального отображения.
Функция 1Eh: получить текущую видеостраницу для указателя мыши. В регистр BX возвращается номер текущей видеостраницы для указателя мыши.
Функция 1Fh: отключить драйвер мыши. Если отключение драйвера прошло успешно, то в регистр AX заносится значение 001Fh, а в ES:BX - адрес драйвера. Если драйвер не отключен, то в регистр AX возвращается значение FFFFh.
Функция 20h: повторное включение драйвера мыши.
Функция 24h: получить информацию о мыши. Возвращаются следующие значения:
BH - старший номер версии драйвера; BL - младший номер версии драйвера; CH - тип мыши (1 - bus mouse, 2 - serial mouse, 3 - InPort mouse, 4 - PS/2 mouse, 5 - HP mouse); CL - номер аппаратного прерывания.
При работе с мышью было бы неэффективно сводить команды мыши к эмуляции клавиатуры, но обрабатывать сигналы мыши и клавиатуры надо согласованно. Очень часто программа состоит из длительных операций, во время которых ее не интересует мышь и клавиатура, и операций обработки команд пользователя (перемещения курсора или выбор опций меню), выполнение которых должно успевать за частотой получения сигналов. Перемещения мыши при этом надо накапливать, а из буфера клавиатуры достаточно брать последнее слово (и очищать буфер). Все сказанное реализуется в приведенной ниже программе.
Procedure test;
{чтение мыши и клавиатуры}
type signal=record
case mouse:boolean of
true:(left,right:boolean;
{состояние клавиш мыши
dx,dy:word ;{ее перемещение });
false: (asc,ext:byte;
{ ASC- и расширенный коды }
status:word;
{флаги клавиатуры});
end;
{поле mouse показывает, сигнал от мыши или клавиатуры}
var ready:boolean;
begin
ready:=false; {ожидание команды}
with signal_t(signal) do
repeat
if mouse_sig then begin
mouse:=true;
r.ax:=11;intr($33,r);dx:=r.cx;dy:=r.dx;
r.ax:=3; intr($33,r);
left:=r.bx and 1 <>0;
right:=r.bx and 2 <>0;
mouse_sig:=false;
ready:=true; end
else {если мышь не трогали - опрос клавиатуры}
begin r.ah:=$11; intr($16,r);
{если не расширенная клавиатура, вызывайте функцию 1}
if r.flags and 64 = 0 then begin
{если буфер клавиатуры не пуст}
mouse:=false;
status:=memw[$40:$17]; {флаги клавиатуры}
repeat
r.ah:=$10;intr($16,r);
asc:=r.al; ext:=r.ah;
r.ah:=$11; intr($16,r);
ready:=r.flags and 64 <>0;
{очистка буфера и запоминание кода клавиши}
until ready; end;
end
until ready;
end;