program ComMouse;

uses
    Crt, Graph;

{type
  TTryData =}

var
  { Data }
  Dat0, Dat1, Dat2, Dat3, Dat4 : Byte;
  PortAdr : Word;

  { Mouse }
  LBut, MBut, RBut : Boolean;
  PX, PY : Integer;

function TryMS : boolean; far;
var
  r : Boolean;
begin
  r := False;
  asm
      MOV   DX,    PortAdr
      ADD   DX,    5
      IN    AL,    DX
      TEST  AL,    01h
      JZ    @x

      SUB   DX,    5
      IN    AL,    DX
      TEST  AL,    40h
      JZ   @x

      MOV   Dat0,  AL

      ADD   DX,    5
  @1: IN    AL,    DX
      TEST  AL,    80h
      JNZ   @x
      TEST  AL,    01h
      JZ    @1
      SUB   DX,    5

      IN    AL,    DX
      MOV   Dat1,  AL

      ADD   DX,    5
  @2: IN    AL,    DX
      TEST  AL,    80h
      JNZ   @x
      TEST  AL,    01h
      JZ    @2
      SUB   DX,    5

      IN    Al,    DX
      MOV   Dat2,  AL

      MOV   AH,    Dat0
      SHL   AH,    6
      MOV   AL,    Dat1
      AND   AL,    3Fh
      OR    AH,    AL
      SAR   AX,    8
      ADD   PX,    AX

      MOV   AH,    Dat0
      AND   AH,    0Ch
      SHL   AH,    4
      MOV   AL,    Dat2
      AND   AL,    3Fh
      OR    AH,    AL
      SAR   AX,    8
      ADD   PY,    AX

      MOV   AL,    Dat0
      MOV   LBut,  False
      TEST  Al,    20h
      JZ   @r
      MOV   LBut,  True
  @r: MOV   MBut,  False
      MOV   RBut,  False
      TEST  Al,    10h
      JZ   @t
      MOV   RBut,  True

  @t: MOV   r,     True
  @x:
  end;
  TryMS := r;
end;

function TryPC : boolean;  far;
var
  r : Boolean;
begin
  r := False;
  asm
      MOV   DX,    PortAdr
      ADD   DX,    5
      IN    AL,    DX
      TEST  AL,    01h
      JZ    @x

      SUB   DX,    5
      IN    AL,    DX
      MOV   AH,    AL
      AND   AH,    $F8
      CMP   AH,    80h
      JNE   @x

      MOV   Dat0,  AL

      ADD   DX,    5
  @1: IN    AL,    DX
      TEST  AL,    80h
      JNZ   @x
      TEST  AL,    01h
      JZ    @1
      SUB   DX,    5

      IN    AL,    DX
      MOV   Dat1,  AL

      ADD   DX,    5
  @2: IN    AL,    DX
      TEST  AL,    80h
      JNZ   @x
      TEST  AL,    01h
      JZ    @2
      SUB   DX,    5

      IN    Al,    DX
      MOV   Dat2,  AL

      ADD   DX,    5
  @3: IN    AL,    DX
      TEST  AL,    80h
      JNZ   @x
      TEST  AL,    01h
      JZ    @3
      SUB   DX,    5

      IN    Al,    DX
      MOV   Dat3,  AL

      ADD   DX,    5
  @4: IN    AL,    DX
      TEST  AL,    80h
      JNZ   @x
      TEST  AL,    01h
      JZ    @4
      SUB   DX,    5

      IN    Al,    DX
      MOV   Dat4,  AL


      MOV   AH,    Dat1
      SAR   AX,    8
      ADD   PX,    AX

      MOV   AH,    Dat2
      SAR   AX,    8
      SUB   PY,    AX

      MOV   AL,    Dat0
      MOV   RBut,  False
      TEST  Al,    01h
      JNZ   @r
      MOV   RBut,  True
  @r: MOV   MBut,  False
      TEST  Al,    02h
      JNZ   @s
      MOV   MBut,  True
  @s: MOV   LBut,  False
      TEST  Al,    04h
      JZ   @t
      MOV   LBut,  True

  @t: MOV   r,     True
  @x:
  end;
  TryPC := r;
end;

type
  TTryMouse = function : Boolean;
var
  TryMouse : TTryMouse;

procedure InitPC;
begin
     asm
        MOV   AX, 40h
        MOV   ES, AX
        MOV   DX, ES:[0]
        MOV   PortADR, DX
        ADD   DX, 3
        MOV   AL, 10000000b
        OUT   DX, AL
        SUB   DX, 2
        XOR   AL, AL
        OUT   DX, AL
        DEC   DX
        MOV   AL, 60h
        OUT   DX, AL

        MOV   AL, 00000011b
        ADD   DX, 3
        OUT   DX, AL

        SUB   DX, 2
        MOV   AL, 0
        OUT   DX, AL

        XOR   AX, AX
        MOV   PX, AX
        MOV   PY, AX
     end;
  TryMouse := TryPC;
end;

procedure InitMS;
begin
     asm
        MOV   AX, 40h
        MOV   ES, AX
        MOV   DX, ES:[0]
        MOV   PortADR, DX

        ADD   DX, 3
        MOV   AL, 10000000b
        OUT   DX, AL
        SUB   DX, 2
        XOR   AL, AL
        OUT   DX, AL
        DEC   DX
        MOV   AL, 60h
        OUT   DX, AL
        MOV   AL, 00000010b
        ADD   DX, 3
        OUT   DX, AL

        SUB   DX, 2
        MOV   AL, 0
        OUT   DX, AL

        XOR   AX, AX
        MOV   PX, AX
        MOV   PY, AX
     end;
  TryMouse := TryMS;
end;

procedure UpDatePicture;
const
  Page : integer = 0;
var
  C : Word;
  S : String;
begin
  Page := Page xor 1;
  SetActivePage(Page);
  SetBkColor(Black);
  ClearDevice;
  SetColor(White);
  OutTextXY(10,10,'Press Q to exit');
  OutTextXY(10,20,'Press P to Init PC-Mouse');
  OutTextXY(10,30,'Press M to Init MS-Mouse');
 
  Str(PX,S);
  OutTextXY(GetMaxX-80,GetMaxY-10,S);
  Str(PY,S);
  OutTextXY(GetMaxX-40,GetMaxY-10,S);
end;

var
  GrDriv, GrMode : Integer;
begin
                { Init Graph Section }
  GrDriv := VGA;
  InitGraph(GrDriv,GrMode,'С:\BP\BGI');
  UpDatePicture;
                { Maim Program Loop }
  while true do
    begin
                { Read A Command }
      if KeyPressed then
        case ReadKey of
          'Q','q' : break;
          'M','m' : InitMS;
          'P','p' : InitPC;
        end;
                { Read A Mouse }
      if Assigned(TryMouse) then
        if TryMouse then
          UpDatePicture;
    end;

  CloseGraph;
end.
