{==============} UNIT F_Mouse; {===============}
{+---------------------------------------------+
 |  В этом модуле собраны процедуры и функции, |
 |    обеспечивающие работу устройства ввода   |
 |                типа мышь                    |
 +---------------------------------------------+}
                  INTERFACE

{Следующий тип используется для определения
 элементов, выбираемых мышью (см.SetMouseOption)}
type
  MouseItemType = record
    X1,Y1,X2,Y2: Integer;  {Координаты области}
    Butt: Word;            {Условия вызова}
    Key : Word             {Скан-код клавиши}
  end;

{Тип MouseHandlerType определяет процедуру
обработки событий от мыши}
type
  MouseHandlerType = Procedure(Mask,Buttons, 					X,Y,DX,DY: Integer);
{Константы выбора кнопок мыши}
const
  LeftButton   = 1;   		{Левая кнопка}
  RightButton  = 2;   		{Правая кнопка}
  CenterButton = 4;   		{Средняя кнопка}
  AnyButton    = 7;   		{Любая кнопка}
{Коэффициенты пересчета виртуальных координат в текстовые}
const
  TextRatioX: Byte = 8;
  TextRatioY: Byte = 8;
{+---------------------------------------------+
 |                Инициация мыши               |
 +---------------------------------------------+}
Function IsMouse: Boolean;
  {Возвращает TRUE, если мышь доступна}

Function InitMouse: Boolean;
  {Инициация мыши}

Procedure SetMousePage(Page: Byte);
  {Устанавливает страницу для указателя мыши}

Function GetMousePage: Byte;
  {Возвращает номер страницы с указателем}

Procedure SetStepToPixel(Hor,Ver: Integer);
  {Устанавливает чувствительность мыши}

Procedure GetStepToPixel(var Hor,Ver: Integer);
  {Возвращает чувствительность мыши}

Procedure SetDoubleSpeed(Speed: Word);
 {Устанавливает порог удвоения скорости перемещения указателя}

Function GetDoubleSpeed: Word;
  {Возвращает порог удвоения скорости}
{+---------------------------------------------+
 |                  Координаты                 |
 ----------------------------------------------+}
Function MouseTextCooX(X: Integer): Byte;
  {Возвращает текстовую координату по заданной виртуальной}

Function MouseTextCooY(Y: Integer): Byte;
  {Возвращает текстовую координату по заданной виртуальной}

Function MouseGraphCooX(X: Byte): Integer;
  {Возвращает виртуальную координату по заданной текстовой}

Function MouseGraphCooY(Y: Byte): Integer;
  {Возвращает виртуальную координату по заданной текстовой}

Procedure MouseWhereXY(var X,Y: Integer);
  {Возвращает виртуальные координаты мыши}

Procedure MouseGotoXY(X,Y: Integer);
  {Переводит указатель мыши в новое положение
   X,Y - виртуальные координаты}

Function MouseWhereX: Byte;
 {Возвращает горизонтальную текстовую координату}

Function MouseWhereY: Byte;
  {Возвращает вертикальную текстовую координату}

Function MouseIn(X1,Y1,X2,Y2: Integer): Boolean;
  {Возвращает TRUE, если указатель находится
   в заданном прямоугольнике}
{+---------------------------------------------+
 |             Состояние кнопок                |
 +---------------------------------------------+}
Function NumButton: Byte;
  {Возвращает количество кнопок мыши}

Procedure GetMouseState(var Butt,X,Y: Integer);
  {Возвращает текущее состояние мыши:
   BUTT - флаг состояния кнопок;
   X,Y  - текущие виртуальные координаты}

Function MousePressed: Boolean;
  {Возвращает TRUE, если нажата любая кнопка}

Procedure MouseButtPressed(Butt: Integer;
                   var Stat,Count,X,Y: Integer);
  {Возвращает информацию о нажатой клавише:
   BUTT - флаг выбора клавиши;
   STAT - состояние клавиш;
   COUNT - количество нажатий, X,Y - координаты}

Procedure MouseButtReleased(Butt: Integer;
                   var Stat,Count,X,Y: Integer);
  {Возвращает информацию об отпущенной клавише:
   BUTT - флаг выбора клавиши;
   STAT - состояние клавиш;
   COUNT - количество отпусканий;
   X,Y - координаты}
{+---------------------------------------------+
 |                   Окна                      |
 +---------------------------------------------+}
Procedure MouseWindow(X1,Y1,X2,Y2: Integer);
  {Задает координаты области перемещения
  указателя. X1...Y2 - виртуальные координаты}

Procedure MouseScreen;
  {Устанавливает окно во весь экран}
{+---------------------------------------------+
 |             Форма указателя                 |
 +---------------------------------------------+}
Procedure ShowMouse;
  {Показать указатель мыши}

Procedure HideMouse;
  {Убрать указатель мыши}

Procedure MouseTextCursor(ScrMask,CurMask: Word);
  {Устанавливает новый вид текстового указателя}

Procedure MouseBlink(YUp,YDn: Byte);
  {Задает аппаратный курсор нужного размера}

Procedure MouseGraphCursor(var ScrCurMask;X,Y: Byte);
  {Задает вид графического указателя}
{+---------------------------------------------+
 |     Сохранение/восстановление состояния     |
 +---------------------------------------------+}
Function MouseBuffSize: Word;
  {Возвращает длину буфера для сохранения параметров}

Procedure SaveMouse(var Buff);
  {Сохраняет в буфере текущее состояние мыши}

Procedure RestoreMouse(var Buff);
  {Восстанавливает сохраненное состояние мыши}
{+---------------------------------------------+
 |              Эмуляция клавиатуры            |
 +---------------------------------------------+}
Procedure SetMouseItem(NItem: Byte; var Items);
  {Устанавливает элементы для выбора мышью:
   NItem - количество элементов;
   Items - array [1..NItem] of MouseItemType;
   Старые установки сбрасываются}

Procedure AddMouseItem(Item: MouseItemType);
  {Добавляет еще один элемент для выбора мышью.
   Старые установки сохраняются}

Procedure ClearMouseItems;
  {Сбрасывает ранее установленные элементы}

Procedure GetMouseItem(var NItem: Byte; var Items);
  {Возвращает установленные элементы}

Function KeyOrMousePressed: Boolean;
  {Возвращает TRUE, если нажата клавиша или активна мышь}

Function ReadKeyOrMouse: Char;
  {Возвращает символ нажатой клавиши или выбранной опции}
{+---------------------------------------------+
 |        Обработка событий от мыши            |
 +---------------------------------------------+}
Procedure SetMouseHandler(Mask: Word; Proc: MouseHandlerType);
  {Устанавливает адрес и условия вызова обработчика}

Procedure ChangeMouseHandler(Mask: Word;  Proc: MouseHandlerType;
                        	var OldMask: Word; var OldProc: Pointer);
  {Заменяет старый обработчик новым}

Procedure ClearMouseHandler;
  {Удаляет обработчик событий}

                 IMPLEMENTATION
{+---------------------------------------------+
 |               Инициация мыши                |
 +---------------------------------------------+}
Uses DOS,CRT;
type
  MouseItems = array [1..2*MaxInt div
         SizeOf(MouseItemType)] of MouseItemType;
  PMouseIt =^MouseItems;
const
  MousePresent: Boolean = False; 	{Признак наличия мыши}
  ItemsList   : PMouseIt = NIL;  	{Массив элементов выбора}
  NMouseItem  : Byte = 0;        	{Количество элементов выбора}
  MouseVisible: Boolean = False; 	{Признак видимого указателя}
  x1m: Integer = 0;       	        {Координаты области}
  y1m: Integer = 0;       	        {перемещения указателя}
  x2m: Integer = 639;
  y2m: Integer = 199;
  Speed2: Word = 128;   		{Порог удвоения скорости}
  VerRat: Integer = 8;  		{Чувствительность мыши}
  HorRat: Integer = 8;
  NButton: Byte = 0;    		{Количество кнопок мыши}
var
  Reg: registers;

Function IsMouse: Boolean;
  {Возвращает TRUE, если мышь доступна}
var
  p    : Pointer;
  k,x,y: Integer;
  Is   : Boolean;
begin
  if NButton=0 then
    begin
      GetIntVec($33,p);
      Is := p<>NIL;
      if Is then with Reg do
        begin
          ax := $3;
          bx := $FFFF;
          Intr($33,Reg);
          Is := bx<>$FFFF
        end;
      MousePresent := Is
    end;
  IsMouse := MousePresent
end;   {IsMouse}
{-----------------------}
Function InitMouse: Boolean;
  {Инициация мыши}
begin
  with Reg do
    begin
      ax := 0;
      Intr($33,Reg);
      MousePresent := ax=$FFFF;
      NButton := bx
    end;
  ClearMouseItems;
  SetMousePage(0);
  HideMouse;
  MouseScreen
end;   {InitMouse}
{-----------------------}
Procedure SetMousePage(Page: Byte);
  {Устанавливает страницу для указателя мыши}
begin
  with Reg do
    begin
      ax := $1D;
      bl := Page;
      bh := 0;
      Intr($33,Reg)
    end
end;   {SetMousePage}
{-----------------------}
Function GetMousePage: Byte;
  {Возвращает номер страницы с указателем}
begin
  with Reg do
    begin
      ax := $1E;
      Intr($33,Reg);
      GetMousePage := bl
    end
end;   {GetMousePage}
{-----------------------}
Procedure SetStepToPixel(Hor,Ver: Integer);
  {Устанавливает чувствительность мыши}
begin
  if IsMouse then with Reg do
    begin
      ax := $0F;
      cx := Hor and $7FFF;
      dx := Ver and $7FFF;
      HorRat := cx;
      VerRat := dx;
      Intr($33,Reg)
    end
end;   {SetStepToPixel}
{-----------------------}
Procedure GetStepToPixel(var Hor,Ver: Integer);
  {Возвращает чувствительность мыши}
begin
  if IsMouse then with Reg do
    begin
      Hor := HorRat;
      Ver := VerRat
    end
end;   {GetStepToPixel}
{-----------------------}
Procedure SetDoubleSpeed(Speed: Word);
 {Устанавливает порог удвоения скорости перемещения указателя}
begin
  if IsMouse then with Reg do
    begin
      ax := $13;
      dx := Speed;
      Speed2 := Speed;
      Intr($33,Reg);
    end
end;   {SetDoubleSpped}
{-----------------------}
Function GetDoubleSpeed: Word;
  {Возвращает порог удвоения скорости}
begin
  GetDoubleSpeed := Speed2
end;   {GetDoubleSpped}
{+---------------------------------------------+
 |                  Координаты                 |
 +---------------------------------------------+}
Function MouseTextCooX(X: Integer): Byte;
  {Возвращает текстовую координату по заданной виртуальной}
begin
  MouseTextCooX := X div TextRatioX+1
end;   {MouseTextCooX}
{-----------------------}
Function MouseTextCooY(Y: Integer): Byte;
  {Возвращает текстовую координату по заданной виртуальной}
begin
  MouseTextCooY := Y div TextRatioY+1
end;   {MouseTextCooY}
{-----------------------}
Function MouseGraphCooX(X: Byte): Integer;
  {Возвращает виртуальную координату по заданной текстовой}
begin
  MouseGraphCooX := (X-1)*TextRatioX
end;   {MouseGraphCooX}
{-----------------------}
Function MouseGraphCooY(Y: Byte): Integer;
  {Возвращает виртуальную координату по заданной текстовой}
begin
  MouseGraphCooY := (Y-1)*TextRatioY
end;   {MouseGraphCooY}
{-----------------------}
Procedure MouseWhereXY(var X,Y: Integer);
  {Возвращает виртуальные координаты мыши}
begin
  if IsMouse then with Reg do
    begin
      ax := $3;
      Intr($33,Reg);
      X := cx;
      Y := dx
    end
  else
    begin
      X := -1;
      Y := -1
    end
end;   {MouseWhereXY}
{-----------------------}
Procedure MouseGotoXY(X,Y: Integer);
  {Переводит указатель мыши в новое положение
   X,Y - виртуальные координаты}
begin
  if IsMouse then with Reg do

    begin
      ax := $4;
      cx := X;
      dx := Y;
      Intr($33,Reg)
    end
end;   {MouseGotoXY}
{-----------------------}
Function MouseWhereX: Byte;
 {Возвращает горизонтальную текстовую координату}
begin
  if IsMouse then with Reg do
    begin
      ax := $3;
      Intr($33,Reg);
      MouseWhereX := MouseTextCooX(cx)
    end
  else
    MouseWhereX := 0
end;   {MouseWhereX}
{-----------------------}
Function MouseWhereY: Byte;
  {Возвращает текстовую координату по вертикали}
begin
  if IsMouse then with Reg do
    begin
      ax := $3;
      Intr($33,Reg);
      MouseWhereY := MouseTextCooY(dx)
    end
  else
    MouseWhereY := 0
end;   {MoueseWhereY}
{-----------------------}
Function MouseIn(X1,Y1,X2,Y2: Integer): Boolean;
  {Возвращает TRUE, если указатель находится
   в заданном прямоугольнике}
begin
  if IsMouse then with Reg do
    begin
      ax := $3;
      Intr($33,Reg);
      MouseIn := (cx>=X1) and (cx<=X2) and
                 (dx>=Y1) and (dx<=Y2)
    end
  else
    MouseIn := False
end;   {MouseIn}
{+--------------------------------------------+
 |            Состояние кнопок                |
 +--------------------------------------------+}
Function NumButton: Byte;
  {Возвращает количество кнопок мыши}
begin
  NumButton := NButton
end;   {NumButton}
{----------------------}
Procedure GetMouseState(var Butt,X,Y: Integer);
  {Возвращает текущее состояние мыши:
   BUTT - флаг состояния кнопок;
   X,Y  - текущие виртуальные координаты}
begin
  if IsMouse then with Reg do
    begin
      ax := $3;
      Intr($33,Reg);
      Butt := bx;
      X := cx;
      Y := dx
    end
  else
    begin
      Butt := 0;
      X := 0;
      Y := 0
    end
end;   {GetMouseState}
{-----------------------}
Function MousePressed: Boolean;
  {Возвращает TRUE, если нажата любая кнопка}
begin
  if IsMouse then with Reg do
    begin
      ax := $3;
      Intr($33,Reg);
      MousePressed := bx<>0
    end
  else
    MousePressed := False
end;   {MousePressed}
{-----------------------}
Procedure MouseButtPressed(Butt: Integer;
                   var Stat,Count,X,Y: Integer);
  {Возвращает информацию о нажатой клавише:
   BUTT - флаг выбора клавиши;
   STAT - состояние клавиш;
   COUNT - количество нажатий, X,Y - координаты}
begin
  if IsMouse then with Reg do
    begin
      ax := $5;
      bx := Butt;
      Intr($33,Reg);
      Count := bx;
      X := cx;
      Y := dx;
      Stat := bx
    end
  else
end;   {MouseButtPressed}
{-----------------------}
Procedure MouseButtReleased(Butt: Integer;
                   var Stat,Count,X,Y: Integer);
  {Возвращает информацию об отпущенной клавише:
   BUTT - флаг выбора клавиши;
   STAT - состояние клавиш;
   COUNT - количество отпусканий;
   X,Y - координаты}
begin
  if IsMouse then with Reg do
    begin
      ax := $6;
      bx := Butt;
      Intr($33,Reg);
      Count := bx;
      X := cx;
      Y := dx;
      Stat := bx
    end
  else
end;   {MouseButtReleased}
{+---------------------------------------------+
 |                   Окна                      |
 +---------------------------------------------+}
Procedure MouseWindow(X1,Y1,X2,Y2: Integer);
  {Задает координаты области перемещения указателя.
	X1...Y2 - виртуальные координаты}
begin
  if IsMouse then
    begin
      x1m := X1;
      y1m := Y1;
      x2m := X2;
      y2m := Y2;
      with Reg do
        begin
          ax := $7;
          cx := X1;
          dx := X2;
          Intr($33,Reg);
          ax := $8;
          cx := Y1;
          dx := Y2;
          Intr($33,Reg)
        end
    end
end;   {MouseWindow}
{-----------------------}
Procedure MouseScreen;
  {Устанавливает окно во весь экран}
var
  x2,y2: Integer;
begin
  if IsMouse then with Reg do
    begin
      ah := $F;
      Intr($10,Reg);
      case al of
      1,4,5,13: begin
                  x2 := 319;
                  y2 := 199
                end;
      15,16: begin
               x2 := 639;
               y2 := 349
             end;
      17,18: begin
               x2 := 639;
               y2 := 479
             end;
      else
        x2 := 639;
        y2 := 199
      end
    end;
  MouseWindow(0,0,x2,y2)
end;   {MouseScreen}
{+---------------------------------------------+
 |             Форма указателя                 |
 +---------------------------------------------+}
Procedure ShowMouse;
  {Показать указатель мыши}
begin
  if IsMouse and not MouseVisible then
    with Reg do begin
      ax := $1;
      Intr($33,Reg);
      MouseVisible := True
    end
end;   {ShowMouse}
{-----------------------}
Procedure HideMouse;
  {Убрать указатель мыши}
begin
  if IsMouse and MouseVisible then with Reg do
    begin
      ax := $2;
      Intr($33,Reg);
      MouseVisible := False
    end
end;   {HideMouse}
{-----------------------}
Procedure MouseTextCursor(ScrMask,CurMask: Word);
  {Устанавливает новый вид текстового указателя}
begin
  if IsMouse then with Reg do
    begin
      ax := $A;
      bx := 0;
      cx := ScrMask;
      dx := CurMask;
      Intr($33,Reg)
    end
end;   {MouseTextCursor}
{-----------------------}
Procedure MouseBlink(YUp,YDn: Byte);
  {Задает аппаратный курсор нужного размера}
begin
  if IsMouse then with Reg do
    begin
      ax := $A;
      bx := 1;
      cx := YUp;
      dx := YDn;
      Intr($33,Reg)
    end
end;   {MouseBlink}
{-----------------------}
Procedure MouseGraphCursor(var ScrCurMask;X,Y: Byte);
  {Задает вид графического указателя}
begin
  if IsMouse then with Reg do
    begin
      ax := $9;
      bx := X;
      cx := Y;
      es := seg(ScrCurMask);
      dx := ofs(ScrCurMask);
      Intr($33,Reg)
    end
end;   {MouseGraphCursor}
{+---------------------------------------------+
 |    Сохранение/восстановление состояния      |
 +---------------------------------------------+}
Function MouseBuffSize: Word;
  {Возвращает длину буфера для сохранения параметров}
begin
  if IsMouse then with Reg do
    begin
      ax := $15;
      bx := 0;
      Intr($33,Reg);
      MouseBuffSize := bx
    end
  else
    MouseBuffSize := 0
end;   {MouseBuffSize}
{-----------------------}
Procedure SaveMouse(var Buff);
  {Сохраняет в буфере текущее состояние мыши}
begin
  if IsMouse then with Reg do
    begin
      ax := $16;
      es := seg(Buff);
      dx := ofs(Buff);
      Intr($33,Reg)
    end
end;   {SaveMouse}
{-----------------------}
Procedure RestoreMouse(var Buff);
  {Восстанавливает сохраненное состояние мыши}
begin
  if IsMouse then with Reg do
    begin
      ax := $17;
      es := seg(Buff);
      dx := ofs(Buff);
      Intr($33,Reg)
    end
end;   {RestoreMouse}
{+---------------------------------------------+
 |              Эмуляция клавиатуры            |
 +---------------------------------------------+}
const
  DoubleChars: Boolean = False;
var
  SecChar: Char;

Procedure SetMouseItem(NItem: Byte; var Items);
  {Устанавливает элементы для выбора мышью:
   NItem - количество элементов;
   Items - array [1..NItem] of MouseItemType;
   Старые установки сбрасываются}
begin
  if IsMouse then
    begin
      ClearMouseItems;
      GetMem(ItemsList,NItem*SizeOf(MouseItemType));
      Move(Items,ItemsList^,NItem*SizeOf(MouseItemType));
      NMouseItem := NItem
    end
end;   {SetMouseItem}
{---------------------}
Procedure AddMouseItem(Item: MouseItemType);
  {Добавляет еще один элемент для выбора мышью.
   Старые установки сохраняются}
var
  p: PMouseIt;
  k: Byte;
begin
  if IsMouse then
    begin
      k := NMouseItem;
      GetMem(P,(k+1)*SizeOf(MouseItemType));
      Move(ItemsList^,P^,k*SizeOf(MouseItemType));
      Move(Item,P^[k+1],SizeOf(MouseItemType));
      ClearMouseItems;
      NMouseItem := k+1;
      ItemsList := P
    end
end;   {AddMouseItem}
{-----------------------}
Procedure ClearMouseItems;
  {Сбрасывает ранее установленные элементы}
begin
  if IsMouse and (NMouseItem <>0) then
    begin
      FreeMem(ItemsList,NMouseItem*SizeOf(MouseItemType));
      NMouseItem := 0
    end
end;   {ClearMouseItem}
{-----------------------}
Procedure GetMouseItem(var NItem: Byte; var Items);
  {Возвращает установленные элементы}
begin
  if IsMouse and (NMouseItem<>0) then
    begin
      NItem := NMouseItem;
      Move(ItemsList^,Items,NMouseItem*SizeOf(MouseItemType))
    end
end;   {GetMouseItem}
{-----------------------}
Function KeyOrMousePressed: Boolean;
  {Возвращает TRUE, если нажата клавиша
   клавиатуры или кнопка мыши}
var
  b,k: Integer;
  MouseActive: Boolean;
begin
{Сначала проверяем клавиатуру}
  if KeyPressed then
    KeyOrMousePressed := True
{Если не нажата никакая клавиша, проверяем нажатие кнопок мыши}
  else with Reg do
    begin
      ax := $3;
      Intr($33,Reg);
      if (bx<>0) and (NMouseItem<>0) then
{Да, кнопка нажата.
 Организуем цикл проверки по всем элементам}
        begin
          MouseActive := False;
          for k := 1 to NMouseItem do
          if not MouseActive then
            with ItemsList^[k] do
	   begin
              case Butt of
                LeftButton  : b :=bx and LeftButton;
                RightButton : b :=bx and RightButton;
                CenterButton: b :=bx and CenterButton;
                AnyButton   : b := bx
              else
                b := 0;
              end;  {case}
              MouseActive := (b<>0) and
                MouseIn(MouseGraphCooX(X1),MouseGraphCooY(Y1),
                        MouseGraphCooX(X2),MouseGraphCooY(Y2))
            end;  {for,if}
          KeyOrMousePressed := MouseActive
        end  {if (bx<>0) and...}
{Если не активна клавиатура или не выбран элемент, возвращаем False}
      else  {bx=0 или NMouseItem=0}
        KeyOrMousePressed := False
    end {with Reg}
end;   {KeyOrMousePressed}
{-----------------------}
Function ReadKeyOrMouse: Char;
  {Возвращает символ нажатой клавиши или выбранного элемента}
var
  k: Byte;
  b,bb: Word;
  MouseActive: Boolean;
label
  loop;
begin
{Сначала проверяем нажатие клавиши}
loop:
  if not IsMouse or KeyPressed then
    ReadKeyOrMouse := ReadKey
{Теперь проверим эмуляцию служебной клавиши}
  else if DoubleChars then
    begin
      DoubleChars := False;
      ReadKeyOrMouse := SecChar
    end
{Проверяем необходимость контроля
 элементов экрана для эмуляции клавиатуры}
  else if NMouseItem<>0 then with Reg do
    begin  {Да, нужна проверка}
      MouseActive := False;
{Контролируем выбор мышью одного из элементов}
      ax := $3;
      Intr($33,Reg); {Получаем статус кнопок}
      bb := bx;      {Запоминаем его в bb}
      if bb<>0 then  {Если нажата любая кнопка, то организуем проверку всех 
                     элементов до нужного (ActiveMouse станет True)}
      for k := 1 to NMouseItem do
        if not MouseActive then
          with ItemsList^[k] do begin
            case Butt of
              LeftButton  : b :=bb and LeftButton;
              RightButton : b :=bb and RightButton;
              CenterButton: b :=bb and CenterButton;
              AnyButton   : b := bb;
            else
              b := 0;
            end;
            if (b<>0) and MouseIn(
                   MouseGraphCooX(X1),MouseGraphCooY(Y1),
                   MouseGraphCooX(X2),MouseGraphCooY(Y2)) then
              begin              {Найден отмеченный элемент}
                MouseActive := True;
                ReadKeyOrMouse := Char(Lo(Key));
                if Lo(Key)=0 then
                  begin          {Эмуляцияслужебной клавиши}
                    DoubleChars := True;
                    SecChar := chr(Hi(Key))
                  end
              end
          end;  {for ... if not MouseActive}
{Если мышь не отметила элемент, повторяем с начала}
      if not MouseActive then
        goto loop
    end {if NMouseItem<>0}
{Если не установлен ни один элемент для мыши,
 ждем нажатия любой клавиши}
  else
    ReadKeyOrMouse := ReadKey
end;   {ReadKeyOrMouse}
{+---------------------------------------------+
 |        Обработка событий от мыши            |
 +---------------------------------------------+}
const
  OldUserProc: Pointer = NIL;
var
  UserProc: MouseHandlerType absolute OldUserProc;
  OldAX: Word;

Procedure MouseHandler; Far; Assembler;
  {Ассемблерный интерфейс для вызова обработчика}
ASM
{Сохраняем в стеке регистры}
  push bp
  push ds
  push es
  push ax
  mov  ax,SEG @DATA
  mov  ds,ax
  pop  ax
  mov  OldAX,ax
{Проверяем условия вызова}
  mov  ax,Word ptr [OldUserProc]   {ax = сегментадреса}
  or   ax,Word ptr [OldUserProc+2] {Адрес = NIL?}
  jz   @                       	   {Да - не вызывать}
{Готовим вызов процедуры пользователя}
  mov  ax,OldAX
  push ax  			{Mask := ax}
  push bx  			{Buttons := bx}
  push cx  			{X := cx}
  push dx  			{Y := dx}
  push di  			{DX := di}
  push si  			{DY := si}
{Вызываем процедуру пользователя}
  call [UserProc]
{Выход из процедуры: восстанавливаем регистры}
@:  pop  es
  pop  ds
  pop  bp
  ret  far
end;  {MouseHandler}
{---------------------}
Procedure SetMouseHandler(Mask: Word; Proc: MouseHandlerType);
  {Устанавливает адрес и условия вызова обработчика}
begin
  if IsMouse then with Reg do
    begin
      UserProc := Proc;
      ax := $0C;
      cx := Mask;
      es := seg(MouseHandler);
      dx := ofs(MouseHandler);
      Intr($33,Reg)
    end
end;   {SetMouseHandler}
{-----------------------}
Procedure ChangeMouseHandler(Mask: Word;
	Proc: MouseHandlerType;	var OldMask: Word; var OldProc: Pointer);
  {Заменяет старый обработчик новым}
begin
  if IsMouse then with Reg do
    begin
      OldProc := OldUserProc;
      ax := $14;
      cx := Mask;
      es := seg(MouseHandler);
      dx := ofs(MouseHandler);
      Intr($33,Reg);
      OldMask := cx
    end
end;   {ChangeMouseHandler}
{------------------------}
Procedure ClearMouseHandler;
  {Удаляет обработчик событий}
begin
  if IsMouse then with Reg do
    begin
      ax := $0C;
      cx := 0;
      es := 0;
      dx := 0;
      Intr($33,Reg)
    end;
end;   {ClearMouseHandler}
{==============} end. {F_Mouse} {===============}
