IPB
ЛогинПароль:

> Внимание! Действует предмодерация

Подраздел FAQ (ЧАВО, ЧАстые ВОпросы) предназначен для размещения готовых рабочих программ, реализаций алгоритмов. Это нечто вроде справочника, он наполнялся в течение 2000х годов. Ваши вопросы, особенно просьбы решить задачу, не пройдут предмодерацию. Те, кто наполнял раздел, уже не заходят на форум, а с теми, кто на форуме сейчас, лучше начинать общение в других разделах. В частности, решение задач — здесь.

> МЫШЬ. Все о программировании мыши.
сообщение
Сообщение #1


Ищущий истину
******

Группа: Пользователи
Сообщений: 4 825
Пол: Мужской
Реальное имя: Олег

Репутация: -  45  +


Все операции, связанные с мышью, в программах выполняются посредством функций
прерывания int $33. Общий формат их вызова таков:
ASM
MOV AX, Number_Function
{...}
INT $33
END;

В отличии от остальных прерываний, функции которых определяются значением в регистре AH, прерывание INT $33 используют весь регистр AX.

Первой используемой в программе функцией этого прерывания должна быть функция $00 (инициализация мыши). Обычно эта команда используется только один раз - в самом начале программы. Для того, чтобы программы могли использовать мышь, предварительно необходимо загрузить драйвер. Этот драйвер обычно запускается командой в файле CONFIG.SYS или AUTOEXEC.BAT (В среде Windows драйвер мыши загружается согласно записи в реестре).

Ниже приведены основные термины, касающиеся мыши:
  • пиксель - наименьший адресуемый элемент экрана.
  • указатель мыши - в текстовом режиме это мерцающий прямоугольник в инверсном видеорежиме, в графическом режиме его вид может быть произвольным, но обычно это стрелка.
  • микки(шаг) - наименьшее расстояние, перемещение на которое мышь может зарегистрировать (т.е. расстояние регистрируемое датчиками мыши). Обычно 0.125 мм.
  • счетчик мыши - отсчитывает число микки (шагов), на которое мышь сместилась горизонтально или вертикально. Драйвер мыши отсчитывает эти перемещения и соответственно перемещает указатель мыши на экране.
  • пороговая скорость - определенная скорость перемещения
    (микки/с), при превышении которой скорость перемещения курсора по экрану удваивается. По умолчанию - 64 микки в секунду.
Рассмотрим основные функции прерывания INT $33.

Инициализация мыши
Для инициализации мыши необходимо вызвать функцию $00. Эта функция должна вызываться первой из всех команд обработчика. Для ее вызова необходимо поместить в регистр AX значение $00 и вызвать прерывание INT $33.
Function InitMouse:boolean;
var
ResultRegAX:word;
begin
asm
mov ax,$00
int $33
mov ResultRegAX,ax
end;
If ResultRegAX=$FFFF then InitMouse:=true else InitMouse:=false
End;

Приведенная функция пробует инициализировать мышь, и если мышь инициализирована, возвращает true.
При инициализации, в регистр BX помещается количество кнопок у обнаруженной мыши. Поскольку не всегда требуется эта информация, можно вынести определение количества кнопок у мыши в отдельную функцию:
function ButtonMouse:byte;
var
ResultRegBX:word;
Begin
Asm
mov ax,$00
int $33
mov ResultRegBX,bx
End;
ButtonMouse:=ResultRegBX
end;

Функция возвращает количество кнопок у мыши. Эту функцию можно использовать в любом месте программы. (Это и есть тот случай, когда функцию $00 прерывания $33 вызывают второй раз).
При инициализации мыши, указатель не появляется на экране.

Отображение указателя мыши
Для отображения указателя мыши на экране, необходимо использовать функцию $01.
Драйвер мыши содержит флаг указателя, определяющий, должен ли указатель отображаться на экране. Указатель отображается, если флаг установлен в 0, и скрывается, если флаг установлен в любое другое значение. Изначально его значение -1. Функция $01 увеличивает его до 0, и курсор становится видим.
Procedure ShowMouse; assembler;
Asm
Mov AX,$01
Int $33
end;

Зарезервированное слово Assembler, которое было использовано в приведенной процедуре, указывает компилятору, что процедура целиком написана на ассемблере.

Cокрытие указателя мыши
Часто в процессе работы программы, требуется на время скрыть указатель мыши, например, при выводе графики. Для этого используют функцию $02.
Следующая процедура, при вызове, скрывает указатель мыши:
Procedure HideMouse; assembler;
Asm
Mov AX,$02
INT $33
End;

Перечисленные процедуры и функции можно так использовать в программе:

{...}
var
kolichestvoKnopok:byte;
{...}
begin
{...}
If InitMouse then
begin
{мышь инициализирована}
kolichestvoKnopok:=ButtonMouse;
ShowMouse;{отображение указателя}
{...}
HideMouse; {сокрытие указателя}
end else {мыши нет или не поддерживается}
{...}



Получение состояния мыши
Функция $03 позволяет получить данные о текущем состоянии мыши.
После вызова этой функции, в регистр BX помещается информация о состоянии кнопок, в регистр CX координата по горизонтали (х), а в регистр DX координата по вертикали (у)*(см. примечание!).
Следующая процедура возвращает координаты указателя.
Procedure GetMouseXY(VAR KoordX,KoordY:Word );
var
ResultCX,ResultDX:word;
begin
Asm
mov ax,$03
int $33
mov ResultCX,CX
mov ResultDX,DX
end;
KoordX:=ResultCX;
KoordY:=ResultDX
end;

При написании программ, очень часто нужно проверять не находится ли указатель в заданной прямоугольной части экрана. (например на кнопке).
Следующая процедура, возвращает true, если указатель находится в зоне x1,y1,x2,y2, где x1-левая граница зоны, x2 - правая граница, y1 - верхняя граница, y2 - нижняя граница.
Function MouseIn(X1,Y1,X2,Y2:word):boolean;
var
rdx,rcx:word;
begin
asm
mov ax,$03
int $33
mov rdx,dx
mov rcx,cx
end;
MouseIn := (rcx>=X1) and (rcx<=X2) and (rdx>=Y1) and (rdx<=Y2)
end;

Функция $03, как уже было сказано, возвращает состояние кнопок мыши.
Function ButtonPressed:byte;
var
rbl:byte;
begin
asm
mov ax,$03
int $33
mov rbl,bl
end;
ButtonPressed:=rbl
end;

Функция возвращает следующие значения:
  • 1 - если нажата левая кнопка.
  • 2 - если нажата правая кнопка.
  • 3 - если нажаты левая и правая кнопки
  • 4 - если нажата средняя кнопка (колесико)
  • 5 - если нажаты левая кнопка и колесико
  • 6 - если нажаты правая кнопка и колесико.
  • 7 - если нажаты все кнопки (2 кнопки и колесико).
------------------------------------------
* все координаты исчисляются в пикселях!!! Даже в текстовом режиме!!! Поэтому для перемещения указателя мыши, скажем на 3 стоку, надо указать координату 8*3 = 24 (на одну строку в текстовом режиме идет 8 пикселей.

Установка указателя мыши в нужную позицию
Для установки указателя мыши в нужную позицию (X,Y) используйте следующую процедуру:
Procedure GotoMouseXY(x,y:word); assembler;
asm
mov ax,$04
mov cx,x
mov dx,y
end;

Не забудте умножить координаты на 8, если вы используете текстовый режим!

Регистрация события нажатия клавиши.
В модуль CRT включена очень полезная функция, возвращающая true, если была нажата клавиша, вот ее аналог для мыши. Функция возвращает true, если была нажата любая клавиша.
Function MousePressed: Boolean;
var
resultbx:word;
begin
asm
Mov ax, $03
Int $33
mov resultbx,bx
end;
MousePressed := resultbx<>0
end;


Определение количества нажатий клавиш
Для определения количества нажатия кнопок мыши используют функцию $05.
Следующая функция возвращает количество нажатий левой(при num=0), средней(при num=2),правой(при num=1) кнопкой мыши с момента последнего вызова данной процедуры. И еще они возвращают координаты мыши при последнем нажатии данной клавиши.
Function getnum(num:word; var x,y:word):word;
var
kn,ResultCX,ResultDX:word;
begin
asm
mov ax,$05
mov bx,num
int $33
mov ResultCX,cx
mov ResultDX,dx
mov kn,bx
end;
getnum:=kn;
x:=ResultCX;
y:=ResultDX
end;

Например, если надо получить координаты мыши при последнем нажатии левой кнопки мыши, достаточно вызвать процедуру так:
getnum(0,x,y);
Для такого вызова функции, включите расширенный синтаксис директивой
компилятору {$X+} или в настройках компилятора.

Пределы перемещения указателя Если в программе требуется ограничить область перемещения указателя, то для этого необходимо использовать функции $07 и $08.
Ограничение перемещения указателя по горизонтали.
Procedure LimHor(max,min:word); assembler;
asm
mov ax,$07
mov cx,min
mov dx,max
int $33
end;

Ограничение перемещения указателя по вертикали.
Procedure LimVer(max,min:word); assembler;
asm
mov ax,$08
mov cx,min
mov dx,max
int $33
end;

Чтение содержимого счетчиков перемещения мыши
эта операция возвращает величины смещения мыши по вертикали и горизонтали (в микки) со времени последнего вызова процедуры.
Procedure GetMikki(var x,y:integer);
var
RCX,RDX:word;
begin
asm
mov ax,$0B
int $33
mov RCX,cx
mov RDX,dx
end;
x:=RCX; y:=RDX
end;
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
 
 Ответить  Открыть новую тему 
Ответов
сообщение
Сообщение #2


Ищущий истину
******

Группа: Пользователи
Сообщений: 4 825
Пол: Мужской
Реальное имя: Олег

Репутация: -  45  +


FAQ ...
...
Изменение вида курсора в графическом режиме.
Альтернативный вариант - пишем свой драйвер на паскале.

Одна из функций прерывания $33 -$0C служит для определения пользовательской процедуры, которая будет вызываться при возникновении прерывания $33 если буду выполнять условия, заданные в маске.
Маска -это двоичное число, каждый бит которого представляет логическую функцию условия.
маски:

Цитата
бит 0 вызов при перемещении мышки
бит 1 вызов при нажатии левой кнопки
бит 2 вызов при отпускании левой кнопки
бит 3 вызов при нажатии правой кнопки
бит 4 вызов при отпускании правой кнопки
бит 5 вызов при нажатии средней кнопки
бит 6 вызов при отпускании средней кнопки
бит 7 зарезервирован (оставить 0)
бит 8 зарезервирован (оставить 0)

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

------------------------------------------------------------

Реализация.
Я взял для демонстрации приема замены обработчика на свой - мой модуль, выложенный на сайте (ссылка выше). Немного изменим его. В секцию INTERFACE модуля, добавим вот такой код:
const
n=40;
Type MC=Array[1..50,1..50] of byte;
Var
_Cursor:MC;

Это описание вида курсора. (примитивно...)

и добавим процедуру
Procedure SetMouseEventManager;


Теперь в секцию IMPLEMENTATION добавим в самое начало:
Var
x,y:word;
pr:boolean;

и внизу опишем процедуры (2 - одна из них открыта для использования в основной программе, другая - сам обработчик).
Procedure SetMouseEventManager;
var
saddr,oaddr:word;
a,i,j:byte;
begin
hidemouse; {скроем стандартный курсор, что бы они не наплывали друг на друга}
pr:=true; {это логическую переменную мы ввели что бы нельзя было включить стандартный курсор. }
for i:=1 to n do for j:=1 to n do _cursor[i,j]:=15;
{здесь по идее должна создаваться форма указателя. элементами матрицы явл. значения цвета.}

a:=0; {маска - мы обрабатываем только перемещение мыши}
saddr:=seg(GrMouseVGA); {узнаем сегмент нашего обработчика}
oaddr:=ofs(GrMouseVGA); {узнаем смещение процедуры обработчика}
asm
pusha {сохраняем регистры в стеке. }
mov ax,0Ch {вызываем функцию}
lea cx,a {помещаем маску}
mov es,saddr {... ES:DX - адрес процедуры обработчика}
mov dx,oaddr
int 33h {вызываем мышиный сервис}
popa {восстанавливаем регистры из стека}
end;
end;

Я привел код процедуры из модуля но с комментариями.
------------------------------------------------------------
ВАЖНО!
Включите в настройках компилятора :
Цитата
286 instructions

------------------------------------------------------------

Все остальное можете посмотреть в коде, который я присоединил к сообщению.
Я не старался улучшить этот модуль, доведя этот способ замены обработчика до совершенства, так как вряд-ли это кому-то нужно...
Все это лишь эксперименты... Как Вы наверно заметили, этот способ довольно сложен, т.к. требует написания обработчика почти исключительно на ассемблере. так например стоит нам попробовать вызвать процедуру writeln из обработчика, произойдет ошибка Run-Time Error 1795 - вообще недокументированная :)

Одним словом, результат работы чуть неправильно составленного обработчика может быть непредсказуем. Тот код что я предоставил - стабилен, я его протестировал, но пока тестировал - Windows 2000 раз 6 останавливала работу эмулятора ДОС из-за разных ошибок. Это недостатки метода.

Теперь преимущества метода.
Теоретически, используя этот метод, можно выводить 16 цветные курсоры любой формы.


Прикрепленные файлы
Прикрепленный файл  MOUSE.PAS ( 5.77 килобайт ) Кол-во скачиваний: 1521
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 

Сообщений в этой теме


 Ответить  Открыть новую тему 
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 





- Текстовая версия 28.04.2024 19:30
500Gb HDD, 6Gb RAM, 2 Cores, 7 EUR в месяц — такие хостинги правда бывают
Связь с администрацией: bu_gen в домене octagram.name