Программирование на Паскале. Выпуск 9


Работа с мышью. Введение

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

Если Вы захотите узнать что-то другое, то пишите. Я обязательно отвечу. Адрес внизу

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

Писать постараюсь подробнее и не используя, на первых порах, ассемблера. Для тех, кому станет скучно, могу предложить несколько модулей, которые написал тогда, когда сам разбирался, как работает Turbo Vision. В них главное - это объект TCommander, используя который можно писать программы, управляемые событиями. И объект и краткое описание его, а также пример использования, находятся на сайте в виде архива. Их можно скачать. Все это я использовал для обучения объектно-ориентированному программированию школьников.


Программа, работающая с устройством "мышь" в операционной системе MS-DOS, должна использовать прерывание с номером 51 ( в десятичной системе счисления, но привычнее использовать шестнадцатеричное $33). Это специальное прерывание. Оно представляет 36 функций, обеспечивающих настройку устройства "мышь" и его указателя, а также сообщающих информацию о событиях.

Все эти функции получают требуют заполнения регистров процессора перед вызовом их. В частности, номер функции всегда заносится в регистр AX. И в регистрах процессора функции "возвращают" информацию. Конечно, удобнее всего использовать встроенный ассемблер, но сейчас этого делать не будем для якобы упрощения программы. Тогда обращение к регистрам процессора производится с помощью переменной типа REGISTERS, которая описана в модуле DOS.

type
  Registers = record
    case Integer of
    0: (AX, BX, CX, DX, BP, SI, DI, DS, ES, Flags: Word);
    1: (AL, AH, BL, BH, CL, CH, DL, DH: Byte);
  end;
Для вызова прерывания нужно заполнить регистры процессора так, как указано в описании функции, и вызвать процедуру intr. Ей передаются два параметра:
  1. номер прерывания;
  2. имя переменной типа REGISTERS.

Правила работы программы с мышью

Сначала нужно проверить поддерживается ли мышь на данной ЭВМ. Для этого используется функция с номером 0. Эта функция проверяет, имеется ли поддержка мыши на данной ЭВМ, и если имеется, то в регистр AX будет записано число $FFFF. Если нет, то 0, но не обязательно. В регистр BX. В него записывается количество кнопок мыши.

Если мышь имеется, эта функция выполняет следующие действия в текстовом режиме

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

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

Для того, чтобы определить, не произошло ли чего с мышью, в этой программе используется функция с номером 3 "Опросить положение и состояние кнопок".
Синтаксис функции 3 прерывания $33: опрос положения курсора и состояния кнопок. Здесь reg - переменная типа REGISTERS
При вызовеAX = 3
Возвращаетбиты регистра BX заполнены в соответствии с правилом:
  • бит 0 - если нажата левая кнопка мыши.
    Проверяется: if reg.BX and 1 = 1 then ...
    ИЛИ: if reg.BX and 1 <> 0 then ...
  • бит 1 - если нажата правая кнопка мыши.
    Проверяется: if reg.BX and 2 = 2 then ...
    ИЛИ: if reg.BX and 2 <> 0 then ...
  • бит 2 - если нажата центральная кнопка мыши.
    Проверяется: if reg.BX and 4 = 4 then ...
    ИЛИ: if reg.BX and 4 <> 0 then ...
CX = X координата (горизонтальная) курсора мыши. Для текстового экрана нужно делить на 8,
чтобы получить номер текстовой колонки
DX = Y координата (вертикальная) курсора мыши. Для текстового экрана нужно делить на 8,
чтобы получить номер строки

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

program mouse_01;
uses DOS, CRT;

var
 r: Registers;

BEGIN

  r.ax:=0;
  intr($33, r);
  if r.ax <> $FFFF then
   begin
     WriteLn('Мышь не обнаружена'); Halt(1)
   end;
  Writeln('Обнаружена мышь. Число кнопок = ',r.bx);
  r.ax:=1;  {Покажем указатель мыши}
  intr($33, r);
  repeat
    r.ax:=3;
    intr($33, r);
  until KeyPressed or (r.bx and 3 <> 0);
END.

Теперь, когда убедились в том, что с мышью все в порядке, что-нибудь сделаем посложнее. Например, определим, какой символ находится под указателем мыши, когда нажимаем левую кнопку мыши. Листинг программы приводится ниже. В ней все практически все то же, за исключением некоторых моментов:

  1. Задействованы регистры CX и DX, заполненные функцией 3. Но ним определяем положение курсора мыши на экране.
  2. Для определения символа обращаемся к области памяти с сегментом $B800. Это так называемый видеобуфер текстового экрана. Все, что записано там, отображается на экране. Причем организован он так, что по четным адресам находятся коды отображаемых на экране символов, а по следующим за ними нечетным - атрибуты отображения этих символов. То есть, каждую строке текстового экрана соответствует 160 байт (80 колонок).
    Для определения кода символа используется функция mem Паскаля. Она организована как массив. Индекс "массива" составляют номер сегмента (я использовал константу Паскаля SegB800), и, через двоеточие, номер ячейки памяти (смещение в сегменте). Обратите внимание, что X умножаем на два.
  3. Код символа преобразуем в символ с помощью функции chr в левом верхнем углу экрана вместе с координатами его.
  4. НО ЕСТЬ ОДНА ХИТРОСТЬ! Перед тем, как произвести чтение или запись на текстовый экран курсор мыши нужно прятать с помощью функции 2 прерывания $33. Иначе при чтении всегда будет получаться число 255 ($FF), а при записи - любой символ, который бует записан в позиции указателя мыши, пропадет, когда указатель переместится. По этой причине, перед тем, как прочитать и вывести сообщение, курсор мыши прячем, а, написав, показываем опять. Для этого используется функция 1 "мышиного" прерывания. Все происходит так быстро, что никакого мигания человеческий глаз заметить не может (если, конечно, Вы не заставляете программу выполнять какие-либо сложные и длительные расчеты. В этом случае нужно прятать курсор в самый "последний момент").
    Убедитесь сами в справедливости сказанного.
program mouse_02;
uses DOS, CRT;

var
 r: Registers;
 x, y: Word;

BEGIN

  r.ax:=0;
  intr($33, r);
  if r.ax <> $FFFF then
   begin
     WriteLn('Мышь не обнаружена'); Halt(1)
   end;
  Writeln('Мышь обнаружена с ',r.bx,' кнопками');
  r.ax:=1;
  intr($33, r);
  repeat
    r.ax:=3;
    intr($33, r);
    if  r.bx and 1 <> 0 then
    begin
      x:=r.cx div 8;
      y:=r.dx div 8;
      r.ax:=2; intr($33, r);
      gotoXY(1,1);
      Write(x:2,'  ', y:2,' ',chr(mem[SegB800:y*160+x*2]),' ');
      r.ax:=1; intr($33, r);
    end;
  until KeyPressed or (r.bx and 2 <> 0);
END.
То, что показано в этом выпуске, далеко не исчерпывает всех возможностей работы программы с мышь. Я отмечал, что функций 36, а сейчас мы использовали только первые четыре. Да и работу программы можно организовать умнее, и даже предусмотрено все, чтобы это было сделано ... но, в следующий раз :))

Свои вопросы и предложения присылайте Борису

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

По всем вопросам можно писать либо в Гостевую книгу нашего сайта на www.turbopascal.tk, либо

мне, автору этого выпуска, © Сурину Борису: surin_bp@mail.ru, ICQ: 320096696.

Постараюсь ответить на все вопросы и учесть все разумные предложения

Рассылка поддерживается сайтом www.turbopascal.tk. При перепечатке ссылка на сайт обязательна

Hosted by uCoz