{$O-,R-,I-,V-,F+}
{$IFDEF DPMI}
  {$C FIXED PRELOAD PERMANENT}
{$ENDIF}
Unit Mouse;
{$DEFINE GMOUSE}  {<-- if you are not using graphics disable this definition}

{***************************************************************************}
{*              Mouse - Turbo Pascal Mouse Unit Version 3.3                *}
{*                      by Michael Day  04/18/93                           *}
{*                                                                         *}
{*    Based on the Mouse4 unit developed by Richard Sadowsky 11/20/87      *}
{*           Graphics cursor procedure borrowed from EgaMouse              *}
{*                    by Eduardo Martins 02/02/88                          *}
{*                                                                         *}
{*           This program is released to the public domain                 *}
{*                                                                         *}
{*        This program assumes that you have a MS (or compatible)          *}
{*                 mouse driver installed on the computer.                 *}
{*                                                                         *}
{*        This unit requires Turbo Pascal V6.0 or higher to compile        *}
{*          If you are using an earlier version of Turbo Pascal,           *}
{*          use the older V3.1 version of the MOUSE unit instead.          *}
{*                                                                         *}
{***************************************************************************}

{ History }

{ V2.0 First release under this package unkown date -med}
{ V2.1 as of 09/10/88 First full release of this package -med}
{ V2.2 as of 09/15/88 Corrected Graphic cursor bug in V2.1 which had }
{ incorrect tables for some cursors. Also improved the table structure }
{ at the same time. -med }
{ V2.3 as of 09/28/88 Corrected bug in release V2.2 to fix mouse detect }
{ crash when running under DOS 2.x. -med }
{ V2.4 as of 04/08/89 fixed checkmark cursor and circle target cursor -med}
{ V3.0 as of 05/23/89 added BGI mouse emulation for EGA debugging -med}
{ V3.1 as of 05/29/89 added Hercules page control fix BGI mouse cursor}
{ to deal with BGI screen edge problem (redraws mouse at edge). -med}
{ V3.2 as of 03/20/93 converted to support DPMI}
{  TargetCross graphic cursor hot spot was incorrect}
{  Added spinning clock text and graphic cursors }
{  merged several include files into the main unit for easier maintance}
{  Fixed HideMouseArea code - apparently it never really worked - sigh...}
{  Fixed default graphic cursor hotspot - The manual lies! }
{  Reworked simulated mouse operation - it's more stable now }
{  Added a few new functions 24,25,26,27,28,35,36}
{ V3.3 as of 04/18/93 fixed bug with simulated HideMouse/ShowMouse}
{  HideMouse wasn't hiding the mouse.}

{NOTE: The following functions curently do not work in protected mode}
{ 12, 20, 24, 25 - I need to find the time to get the callback working}
{these functions work ok in real mode}

{***************************************************************************}


Interface

uses
 {$IFDEF DPMI}
     WINAPI,DPMIMOUS,    {DPMI mouse}
 {$ENDIF}
 {$IFDEF GMOUSE}
     Graph,       {Graphics or text}
 {$ENDIF}
     DOS;         {Text only}

{Note: While it was unavoidable to keep all DPMI specific code out of the }
{ MOUSE unit, only the bare minimum is here. Most of the DPMI specific    }
{ code can be found in the DPMIMOUS unit. If you are not compiling for    }
{ use with the DPMI (protected mode), you do not need the DPMIMOUS unit   }

{---------------------------------------------------------------------------}
{Externally accessable constants}

const

  MouseLeftButton   = 1;                               {what the buttons are}
  MouseRightButton  = 2;
  MouseCenterButton = 4;

  MouseStandard     = 0;                         {graphic cursor definitions}
  MouseUpArrow      = 1;
  MouseDownArrow    = 2;
  MouseLeftArrow    = 3;
  MouseRightArrow   = 4;
  MouseCheckMark    = 5;
  MouseUpHand       = 6;
  MouseDownHand     = 7;
  MouseLeftHand     = 8;
  MouseRightHand    = 9;
  MouseStopHand     = 10;
  MouseHourGlass    = 11;
  MouseDiagCross    = 12;
  MouseRectCross    = 13;
  MouseRectBox      = 14;
  MouseTargetCross  = 15;
  MouseTargetCircle = 16;
  MouseTargetBox    = 17;
  MouseQuestionMark = 18;

  MaxMouseGraphShape = 18;
  MaxMouseTextShape  = 15;
  MouseClockCursor   = MaxInt;

{---------------------------------------------------------------------------}
{Externally accessable variables}

var  CrtMode : ^byte;    {real mem $40:$49}         {BIOS Crt mode flag byte}
     CrtCols : ^word;    {real mem $40:$4A}           {BIOS Crt column count}
     CrtRows : ^byte;    {real mem $40:$84}              {BIOS Crt row count}
     SysClk  : ^word;    {real mem $40:$6C}       {BIOS system clock counter}
     CursorMode : ^word; {real mem $40:$60}        {BIOS cursor mode storage}

var
  MouseClicked     : boolean;   {ReadMouse - True if button was clicked}
  MouseButtons     : word;      {ReadMouse - Current mouse button status}
  MouseClickButton : word;      {ReadMouse - Click button status}
  MouseX           : integer;   {ReadMouse - Mouse X Position}
  MouseY           : integer;   {ReadMouse - Mouse Y Position}
  ClickMouseX      : integer;   {ReadMouse - Mouse X Click Position}
  ClickMouseY      : integer;   {ReadMouse - Mouse Y Click Position}
  MousePressX      : integer;   {last mouse button press position}
  MousePressY      : integer;
  MouseReleaseX    : integer;   {last mouse button release position}
  MouseReleaseY    : integer;


const
  MouseDriver     : boolean = false;       {InitMouse - Driver installed?}
  MouseInstalled  : boolean = false;       {InitMouse - Driver active?   }
  MouseError      : integer = MaxInt;      {InitMouse - Error code       }
  MouseType       : integer = 0;           {InitMouse - Mouse Type       }

  MouseState      : integer = -1;                {Negative = mouse hidden}
  MouseVisible    : boolean = false;   {true = mouse is visible          }
  MouseUpdate     : boolean = true;    {true = request mouse pos update  }
  MouseCondo      : boolean = false;   {true = conditional mouse hiding  }
  MouseHooked     : boolean = false;   {true = mouse hooked to clock int }
  ZeroMouse       : boolean = false;   {true = text mouse starts at 0    }
  UseSimMouse     : boolean = false;   {true = use simulated mouse cursor}
  MouseReDraw     : boolean = false;   {true = mouse needs to be redrawn }
  HercGraphMouse  : boolean = false;   {true = Herc graph mode mouse     }
  MouseTextWidth  : word = 8;           {size of text on screen for mouse}
  MouseTextHeight : word = 8;
  MaxCrtX         : word = 80;                 {screen size in characters}
  MaxCrtY         : word = 25;
  MouseImageX     : integer = 0;         {current mouse XY image position}
  MouseImageY     : integer = 0;
  MouseColor      : word = $FFFF;                     {mouse cursor color}

{This record is saved on the heap in the savemouse function}
type  MouseDataRec = record
            MouseHideX1   : integer;
            MouseHideY1   : integer;
            MouseHideX2   : integer;
            MouseHideY2   : integer;
            MouseAreaX1   : integer;
            MouseAreaY1   : integer;
            MouseAreaX2   : integer;
            MouseAreaY2   : integer;
            MouseGShape   : integer;
            MouseTShape   : integer;
            TextMouse     : boolean;
            MouseSpinerOn : boolean;
          end;

const M : MouseDataRec = (
            MouseHideX1   : -1;
            MouseHideY1   : -1;        {HideMouseArea - Mouse hide area}
            MouseHideX2   : -1;
            MouseHideY2   : -1;
            MouseAreaX1   : 0;       {SetMouseArea - Mouse bounded area}
            MouseAreaY1   : 0;
            MouseAreaX2   : 639;
            MouseAreaY2   : 199;
            MouseGShape   : 0;            {selected graphic mouse shape}
            MouseTShape   : 1;               {selected text mouse shape}
            TextMouse     : false;         {true = text mode type mouse}
            MouseSpinerOn : false         {true = spin the mouse cursor}
          );

{---------------------------------------------------------------------------}
type MaskType = record                   {mouse graphic cursor definition}
        Def: array [0..1, 0..15] of word;            {graphics cursor def}
        HotX, HotY: integer;                              { hot spot X,Y }
     end;

{ define what the mouse text cursor definition array looks like }
type MouseTextType = record
        Select : word;
        Start  : word;
        Stop   : word;
     end;

{---------------------------------------------------------------------------}
{Note: You must set the MouseTextWidth and MouseTextHeight values}
{to the current character pixel width and height to properly use the}
{mouse text X,Y coordinate system. Startup Default is 8x8.}
{To start up the mouse you should do the following: }
{InitMouse; ReadMouse; ShowMouse; - This insures that the mouse is}
{properly setup and ready to run. Additionally, if you have a Hercules}
{display, you must call SetHercPage prior to calling InitMouse to properly}
{initialize the mouse driver for the Hercules display.}

{For more information on the mouse interface and programming with }
{with a mouse refer to the MicroSoft Mouse Programmer's Reference Guide}
{Available from MicroSoft Corporation.}

{Warning: All mouse drivers are not created equal. Nor are programs that }
{use them. Be especially careful with the MouseAreaHide function, if you }
{are using an EGA display with Turbo Pascal it will not work. The area }
{hide function requires that certain EGA display calls be performed through }
{an extended video BIOS call so that it can know what to expect in how the }
{display is setup. Since Turbo Pascal does not do this, The MouseAreaHide }
{function will not currently work under Turbo Pascal. With other displays }
{you shouldn't have a problem. Also be aware that some mouse drivers do not }
{impliment all functions exactly the same, and that the early MS mouse driver}
{did not impliment all the functions listed here. If you have any questions}
{check with your mouse manufacture. The MS mouse Tech ref guide is an }
{invaluable reference if you intend to do mouse programming. You can get it}
{for $25 if you bought an MS mouse. For other mice, check with the}
{manufacture most of them provide Tech ref manuals.}

{---------------------------------------------------------------------------}
{ Function 0 - Initialize mouse software and hardware }
procedure InitMouse;

{---------------------------------------------------------------------------}
{ Function 1 - show mouse cursor }
procedure ShowMouse;

{---------------------------------------------------------------------------}
{ Function 2 - hide mouse cursor }
procedure HideMouse;

{---------------------------------------------------------------------------}
{ Function 3 - read mouse position and button status }
{ Use GetMx, GetMy to read the mouse position info in MouseX, MouseY, }
{ or ClickMouseX, ClickMouseY }
procedure ReadMouse;

{---------------------------------------------------------------------------}
{ function 4 - sets mouse position }
{ Recommended calling method: }
{ SetMousePosition(PutMx(X),PutMy(Y)); }
procedure SetMousePosition(X,Y:integer);

{---------------------------------------------------------------------------}
{ function 5 - gets button press information  }
{ Recommended calling method: }
{ Status := MousePress(Button,Count); }
{ Click position is available in vars ClickMouseX and ClickMouseY}
function MousePress(Button:word; var Count:word):word;

{---------------------------------------------------------------------------}
{ function 6 - gets button release information  }
{ Recommended calling method: }
{ Status := MouseRelease(Button,Count); }
{ Click position is available in vars ClickMouseX and ClickMouseY}
function MouseRelease(Button: word; var Count:word):word;

{---------------------------------------------------------------------------}
{ functions 7 and 8 - sets area where the mouse is allowed to run }
{ Recommended calling method: }
{ SetMouseArea(PutMx(x1),PutMy(y1),PutMx(x2),PutMy(y2)); }
procedure SetMouseArea(x1,y1,x2,y2:integer);

{---------------------------------------------------------------------------}
{ function 9 - sets the graphics cursor shape }
procedure MouseGraphicCursor(Shape:integer);

{---------------------------------------------------------------------------}
{ function 9 - sets a custom graphics cursor shape }
procedure SetMouseGraphicCursor(var Mask:MaskType);

{---------------------------------------------------------------------------}
{ function 10 - sets the text cursor shape }
procedure MouseTextCursor(Shape:integer);

{---------------------------------------------------------------------------}
{ function 10 - sets a custom text cursor shape }
procedure SetMouseTextCursor(Select,Start,Stop:word);

{---------------------------------------------------------------------------}
{ function 11 - Read Mouse Motion counters }
procedure ReadMickey(var X,Y:integer);

{---------------------------------------------------------------------------}
{ function 12 - Set Mouse Interrupt service routine and mask }
procedure SetMouseISR(Mask:word; Address:pointer);

{---------------------------------------------------------------------------}
{ function 13 and 14 - Light pen emulation on/off }
procedure LightPen(Flag:boolean);

{---------------------------------------------------------------------------}
{ function 15 - sets the mickey to pixel ratio }
procedure SetPixeltoMickey(X,Y:integer);

{---------------------------------------------------------------------------}
{ function 16 - Conditional Mouse Hide - hides mouse if in area }
{ use ShowMouse after using this function - just like regular HideMouse }
{Recommended calling method: }
{If HideMouseArea(PutMx(x1),PutMy(y1),PutMx(x2),PutMy(y2)) then DoSomething;}
procedure HideMouseArea(x1,y1,x2,y2:integer);

{---------------------------------------------------------------------------}
{ function 19 - Set Double Speed Threshold }
procedure MouseThreshold(Threshold:integer);

{---------------------------------------------------------------------------}
{ function 20 - Swap current Mouse ISR with a new one}
{ Returns old ISR and mask in the calling variables }
procedure SwapMouseISR(var Mask:word; var Address:pointer);

{---------------------------------------------------------------------------}
{ function 24 - Set Alternate Subroutine call mask and address}
function SetAltISR(Mask:word; Address:pointer):boolean;

{---------------------------------------------------------------------------}
{ function 25 - Get current Alternate Subroutine call mask and address}
function GetAltISR(var Mask:word; var Address:pointer):boolean;

{---------------------------------------------------------------------------}
{ function 26 - Set Mouse Sensitivity }
procedure SetMouseSensitivity(Horiz,Vert,Threshold:word);

{---------------------------------------------------------------------------}
{ function 27 - Get Mouse Sensitivity }
procedure GetMouseSensitivity(var Horiz,Vert,Threshold:word);

{---------------------------------------------------------------------------}
{ function 28 - Set Mouse Interrupt Rate - NOTE: works with PS/2 mouse only }
procedure SetMouseInterruptRate(Rate:word);

{---------------------------------------------------------------------------}
{ function 29 - Set Mouse Page }
procedure SetMousePage(Page:word);

{---------------------------------------------------------------------------}
{ function 30 - Get Mouse Page }
function GetMousePage:word;

{---------------------------------------------------------------------------}
{ function 35 - Get Mouse Language}
function GetMouseLanguage:word;

{---------------------------------------------------------------------------}
{ function 36 - Get Mouse Info }
procedure GetMouseInfo(var VersionHI,VersionLO,MouseType,IRQnm:byte);

{---------------------------------------------------------------------------}
{ Set Hercules Graphics page for Mouse (not a standard mouse function) }
{ 0= graph pg 0,   1= graph pg 1,   -1 = text mode  (see note in procedure) }
procedure SetHercMouse(Pg:integer);


{+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++}
{ The following procedures use the mouse functions to provide }
{ a higher level of control over the mouse }

{---------------------------------------------------------------------------}
{ Normalizes a mouse X position to standard position info }
function GetMx(X:integer):integer;

{---------------------------------------------------------------------------}
{ Normalizes a mouse Y position to standard position info }
function GetMy(Y:integer):integer;

{---------------------------------------------------------------------------}
{ converts a standard X position to a mouse X position }
function PutMx(X:integer):integer;

{---------------------------------------------------------------------------}
{ converts a standard Y position to a mouse Y position }
function PutMy(Y:integer):integer;

{---------------------------------------------------------------------------}
{ Check if a mouse point is currently in the specified area}
{ returns true if it is, false if not}
{  Recommended calling method: }
{  If MousePointIn(GetMx(Mx),GetMy(My), x1,y1,x2,y2) then DoSomething;}
function MousePointIn(Mx,My, x1,y1,x2,y2:integer):boolean;

{---------------------------------------------------------------------------}
{has the mouse been clicked recently?}
function MouseClick:boolean;

{---------------------------------------------------------------------------}
{Hooks the Mouse function to the system clock}
{State = true hooks the mouse up, State = false disconnects the mouse}
procedure BackgroundMouse(State:boolean);

{+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++}
{procedures to save and restore the mouse state}

{---------------------------------------------------------------------------}
{ function 21, 22 Save mouse driver state }
{Pushes current mouse status on the mouse stack}
{Returns false if not enough heap space to push}
function SaveMouse:boolean;

{---------------------------------------------------------------------------}
{function 23 restore mouse driver state }
{Pops mouse status from the mouse stack.}
function RestoreMouse:boolean;

{---------------------------------------------------------------------------}
{Get rid of mouse stack}
procedure ZapMouseStack;

{***************************************************************************}

implementation

{---------------------------------------------------------------------------}
{private variables}

var MouseBusy    : boolean;                {true = mouse routines are in use}
    SimMouseX    : integer;                            {Sim mouse X Position}
    SimMouseY    : integer;                            {Sim mouse Y Position}
    Old1Cvect    : pointer;                       {old 55ms interrupt vector}

{These two variables are saved on the mouse stack with SaveMouse}
var CurMouseMask : MaskType;           {storage for custom mouse cursor data}
    CurMouseText : MouseTextType;      {storage for custom text mouse cursor}


{---------------------------------------------------------------------------}
{$IFDEF GMOUSE}                 { if we are using graphics enable this stuff}
const MouseBack : pointer = nil;          {^old image under BGI mouse cursor}
      MouseMask : pointer = nil;                     {^BGI mouse cursor mask}
      MouseFore : pointer = nil;                  {^BGI mouse cursor overlay}
      MouseSize : word = 0;            {storage size for mouse image 0=emtpy}
      EndImageX : integer = 0;                         {End of Mouse X image}
      EndImageY : integer = 0;                         {End of Mouse Y image}
      OldImageX : integer = 0;                {position of image under mouse}
      OldImageY : integer = 0;
{$ENDIF}


{---------------------------------------------------------------------------}
{ mouse graphic AND text cursor definitions }
{---------------------------------------------------------------------------}

{ Mouse Graphic cursors set by - MouseGraphicCursor(Shape); }

{ define what the mouse graphic cursor definition array looks like }
type MGCarray = array [0..MaxMouseGraphShape] of MaskType;

{ Next we define the cursor array as a typed constant }

const MouseGCursor: MGCarray =   {a predefined list of mouse graphic cursors}

{ Standard }
 ((Def: (($9FFF,$8FFF,$87FF,$83FF,$81FF,$80FF,$807F,$803F,    { Screen Mask }
          $801F,$800F,$80FF,$887F,$987F,$FC3F,$FC3F,$FE3F),

         ($0000,$2000,$3000,$3800,$3C00,$3E00,$3F00,$3F80,    { Cursor Mask }
          $3FC0,$3E00,$3600,$2300,$0300,$0180,$0180,$0000));

         HotX: 1; HotY: 0),                                    { Hot Spot }

{ UpArrow }
  (Def: (($F9FF,$F0FF,$E07F,$E07F,$C03F,$C03F,$801F,$801F,
          $000F,$000F,$F0FF,$F0FF,$F0FF,$F0FF,$F0FF,$F0FF),

         ($0000,$0600,$0F00,$0F00,$1F80,$1F80,$3FC0,$3FC0,
          $7FE0,$0600,$0600,$0600,$0600,$0600,$0600,$0000));

         HotX: 5; HotY: 0),

{ DownArrow }
  (Def: (($F0FF,$F0FF,$F0FF,$F0FF,$F0FF,$F0FF,$000F,$000F,
          $801F,$801F,$C03F,$C03F,$E07F,$E07F,$F0FF,$F9FF),

         ($0000,$0600,$0600,$0600,$0600,$0600,$0600,$7FE0,
          $3FC0,$3FC0,$1F80,$1F80,$0F00,$0F00,$0600,$0000));

         HotX: 5; HotY: 15),

{ LeftArrow }
  (Def: (($FE1F,$F01F,$0000,$0000,$0000,$F01F,$FE1F,$FFFF,
          $FFFF,$FFFF,$FFFF,$FFFF,$FFFF,$FFFF,$FFFF,$FFFF),

         ($0000,$00C0,$07C0,$7FFE,$07C0,$00C0,$0000,$0000,
          $0000,$0000,$0000,$0000,$0000,$0000,$0000,$0000));

         HotX: 0; HotY: 3),

{ RightArrow }
  (Def: (($F87F,$F80F,$0000,$0000,$0000,$F80F,$F87F,$FFFF,
          $FFFF,$FFFF,$FFFF,$FFFF,$FFFF,$FFFF,$FFFF,$FFFF),

         ($0000,$0300,$03E0,$7FFE,$03E0,$0300,$0000,$0000,
          $0000,$0000,$0000,$0000,$0000,$0000,$0000,$0000));

         HotX: 15; HotY: 3),

{ CheckMark }
  (Def: (($FFF8,$FFF0,$FFE1,$FFC3,$FF87,$FF0F,$0E1F,$043F,
          $807F,$E0FF,$F1FF,$FBFF,$FFFF,$FFFF,$FFFF,$FFFF),

         ($0000,$0006,$000C,$0018,$0030,$0060,$00C0,$7180,
          $1B00,$0E00,$0400,$0000,$0000,$0000,$0000,$0000));

         HotX: 5; HotY: 11),

{ UpHand }
  (Def: (($E1FF,$E1FF,$E1FF,$E1FF,$E000,$E000,$E000,$0000,    { Screen Mask }
          $0000,$0000,$0000,$0000,$0000,$0000,$0000,$0000),

         ($1E00,$1200,$1200,$1200,$13FF,$1249,$1249,$F249,    { Cursor Mask }
          $9001,$9001,$9001,$8001,$8001,$8001,$8001,$FFFF));

         HotX: 5; HotY: 0),                                      { Hot Spot }

{ DownHand }
  (Def: (($0000,$0000,$0000,$0000,$0000,$0000,$0000,$0000,
          $0000,$E000,$E000,$E000,$E1FF,$E1FF,$E1FF,$E1FF),

         ($FFFF,$8001,$8001,$8001,$8001,$9001,$9001,$9001,
          $F249,$1249,$1249,$13FF,$1200,$1200,$1200,$1E00));

         HotX: 5; HotY: 15),

{ LeftHand }
  (Def: (($FFFF,$FF8F,$FF07,$FF03,$FF81,$8000,$0000,$0000,
          $0000,$8000,$F000,$F800,$F800,$FC00,$FC01,$FC03),

         ($0000,$0000,$0070,$0048,$0024,$0032,$7FF2,$800A,
          $7FF6,$0412,$07F2,$0212,$03F2,$0116,$01FC,$0000));

         HotX: 0; HotY: 7),

{ RightHand }
  (Def: (($FFFF,$F1FF,$E0FF,$C0FF,$81FF,$0001,$0000,$0000,
          $0000,$0001,$000F,$001F,$001F,$003F,$803F,$C03F),

         ($0000,$0000,$0E00,$1200,$2400,$4C00,$4FFE,$5001,
          $6FFE,$4820,$4FE0,$4840,$4FC0,$6880,$3F80,$0000));

         HotX: 15; HotY: 7),

{ StopHand }
  (Def: (($FE3F,$F80F,$F007,$F003,$F001,$F001,$0001,$0001,
          $0001,$0001,$8001,$C001,$C001,$E003,$F007,$F80F),

         ($0000,$01C0,$0770,$0550,$055C,$0554,$0554,$7554,
          $5554,$4FFC,$2804,$1004,$180C,$0C18,$07F0,$0000));

         HotX: 7; HotY: 7),

{ HourGlass }
  (Def: (($0000,$0000,$0000,$0000,$8001,$C003,$E007,$F00F,
          $E007,$C003,$8001,$0000,$0000,$0000,$0000,$FFFF),

         ($0000,$7FFE,$6006,$300C,$1818,$0C30,$0660,$03C0,
          $0660,$0C30,$1998,$33CC,$67E6,$7FFE,$0000,$0000));

         HotX: 7; HotY: 7),

{ DiagCross }
  (Def: (($07E0,$0180,$0000,$C003,$F00F,$C003,$0000,$0180,
          $07E0,$FFFF,$FFFF,$FFFF,$FFFF,$FFFF,$FFFF,$FFFF),

         ($0000,$700E,$1C38,$0660,$03C0,$0660,$1C38,$700E,
          $0000,$0000,$0000,$0000,$0000,$0000,$0000,$0000));

         HotX: 7; HotY: 4),

{ RectCross }
  (Def: (($FC3F,$FC3F,$FC3F,$0000,$0000,$0000,$FC3F,$FC3F,
          $FC3F,$FFFF,$FFFF,$FFFF,$FFFF,$FFFF,$FFFF,$FFFF),

         ($0000,$0180,$0180,$0180,$7FFE,$0180,$0180,$0180,
          $0000,$0000,$0000,$0000,$0000,$0000,$0000,$0000));

         HotX: 7; HotY: 4),


  { these cursors need to be updated yet }
{ RectBox }
  (Def: (($FFFF,$FFFF,$0000,$0000,$0000,$1FF8,$1FF8,$1FF8,
          $1FF8,$1FF8,$1FF8,$1FF8,$0000,$0000,$0000,$FFFF),

         ($0000,$0000,$0000,$7FFE,$4002,$4002,$4002,$4002,
          $4002,$4002,$4002,$4002,$4002,$7FFE,$0000,$0000));

         HotX: 7; HotY: 8),

{ TargetCross }
  (Def: (($FFFF,$FFFF,$FC7F,$FC7F,$FC7F,$FC7F,$FC7F,$06C1,
          $0101,$06C1,$FC7F,$FC7F,$FC7F,$FC7F,$FC7F,$FFFF),

         ($0000,$0000,$0000,$0100,$0100,$0100,$0100,$0000,
          $783C,$0000,$0100,$0100,$0100,$0100,$0000,$0000));

         HotX: 7; HotY: 8),

{ TargetCircle }
  (Def: (($FFFF,$FFFF,$F01F,$C007,$8003,$0441,$0C61,$06C1,
          $0101,$06C1,$0C61,$0441,$8003,$C007,$F01F,$FFFF),

         ($0000,$0000,$0000,$07C0,$1930,$3118,$610C,$600C,
          $783C,$600C,$610C,$3118,$1930,$07C0,$0000,$0000));

         HotX: 7; HotY: 8),

{ TargetBox }
  (Def: (($FFFF,$FFFF,$0001,$0001,$0001,$1C71,$1C71,$06C1,
          $0101,$06C1,$1C71,$1C71,$0001,$0001,$0001,$FFFF),

         ($0000,$0000,$0000,$7FFC,$4104,$4104,$4104,$4004,
          $783C,$4004,$4104,$4104,$4104,$7FFC,$0000,$0000));

         HotX: 7; HotY: 8),

{ QuestionMark }
  (Def: (($FFFF,$E00F,$C007,$8003,$0001,$0001,$0001,$0001,
          $0001,$0001,$0001,$0001,$0001,$8003,$C007,$E00F),

         ($0000,$0000,$1FF0,$3FF8,$783C,$739C,$739C,$7F3C,
          $7E7C,$7E7C,$7FFC,$7E7C,$7E7C,$3FF8,$1FF0,$0000));

         HotX: 7; HotY: 7));

{---------------------------------------------------------------------------}
{ cursor array used for spining mouse clock }

  MouseGClockArray : array[0..7] of MaskType = (
{ Clock Spiner }
  (Def: (($F83F,$E00F,$C007,$8003,$8003,$0001,$0001,$0001,  {screen mask}
          $0001,$0001,$8003,$8003,$C007,$E00F,$F83F,$FFFF),
   {0}
         ($0000,$07C0,$1930,$2008,$2008,$4004,$4004,$61FC,   {cursor}
          $4004,$4004,$2008,$2008,$1930,$07C0,$0000,$0000));

         HotX: 7; HotY: 7),

  (Def: (($F83F,$E00F,$C007,$8003,$8003,$0001,$0001,$0001,  {screen mask}
          $0001,$0001,$8003,$8003,$C007,$E00F,$F83F,$FFFF),
   {1}
         ($0000,$07C0,$1930,$2008,$2008,$4004,$4004,$610C,   {cursor}
          $4084,$4044,$2028,$2018,$1930,$07C0,$0000,$0000));

         HotX: 7; HotY: 7),


  (Def: (($F83F,$E00F,$C007,$8003,$8003,$0001,$0001,$0001,  {screen mask}
          $0001,$0001,$8003,$8003,$C007,$E00F,$F83F,$FFFF),
   {2}
         ($0000,$07C0,$1930,$2008,$2008,$4004,$4004,$610C,   {cursor}
          $4104,$4104,$2108,$2108,$1930,$07C0,$0000,$0000));

         HotX: 7; HotY: 7),


  (Def: (($F83F,$E00F,$C007,$8003,$8003,$0001,$0001,$0001,  {screen mask}
          $0001,$0001,$8003,$8003,$C007,$E00F,$F83F,$FFFF),
   {3}
         ($0000,$07C0,$1930,$2008,$2008,$4004,$4004,$610C,   {cursor}
          $4204,$4404,$2808,$3008,$1930,$07C0,$0000,$0000));

         HotX: 7; HotY: 7),


  (Def: (($F83F,$E00F,$C007,$8003,$8003,$0001,$0001,$0001,  {screen mask}
          $0001,$0001,$8003,$8003,$C007,$E00F,$F83F,$FFFF),
   {4}
         ($0000,$07C0,$1930,$2008,$2008,$4004,$4004,$7F0C,   {cursor}
          $4004,$4004,$2008,$2008,$1930,$07C0,$0000,$0000));

         HotX: 7; HotY: 7),


  (Def: (($F83F,$E00F,$C007,$8003,$8003,$0001,$0001,$0001,  {screen mask}
          $0001,$0001,$8003,$8003,$C007,$E00F,$F83F,$FFFF),
   {5}
         ($0000,$07C0,$1930,$3008,$2808,$4404,$4204,$610C,   {cursor}
          $4004,$4004,$2008,$2008,$1930,$07C0,$0000,$0000));

         HotX: 7; HotY: 7),


  (Def: (($F83F,$E00F,$C007,$8003,$8003,$0001,$0001,$0001,  {screen mask}
          $0001,$0001,$8003,$8003,$C007,$E00F,$F83F,$FFFF),
   {6}
         ($0000,$07C0,$1930,$2108,$2108,$4104,$4104,$610C,   {cursor}
          $4004,$4004,$2008,$2008,$1930,$07C0,$0000,$0000));

         HotX: 7; HotY: 7),


  (Def: (($F83F,$E00F,$C007,$8003,$8003,$0001,$0001,$0001,  {screen mask}
          $0001,$0001,$8003,$8003,$C007,$E00F,$F83F,$FFFF),
   {7}
         ($0000,$07C0,$1930,$2018,$2028,$4044,$4084,$610C,   {cursor}
          $4004,$4004,$2008,$2008,$1930,$07C0,$0000,$0000));

         HotX: 7; HotY: 7) );


{---------------------------------------------------------------------------}
{ Mouse text cursors set by -  MouseTextCursor(Select,Start,Stop) }

{ define what the mouse graphic cursor definition array looks like }
type MTCarray = array [1..MaxMouseTextShape] of MouseTextType;

{ Next we define the text cursor array as a typed constant }
const MouseTCursor: MTCarray = (  {a predefined list of mouse text cursors}
     (Select: 0;  Start: $77FF;  Stop: $7700),  {1 Standard Cursor}
     (Select: 0;  Start: $07FF;  Stop: $F800),  {2 Blink Cursor}
     (Select: 0;  Start: $7000;  Stop: $0718),  {3 Up Arrow}
     (Select: 0;  Start: $7000;  Stop: $0719),  {4 Down Arrow}
     (Select: 0;  Start: $7000;  Stop: $071B),  {5 Left Arrow}
     (Select: 0;  Start: $7000;  Stop: $071A),  {6 Right Arrow}
     (Select: 0;  Start: $7000;  Stop: $071E),  {7 Up Triangle}
     (Select: 0;  Start: $7000;  Stop: $071F),  {8 Down Triangle}
     (Select: 0;  Start: $7000;  Stop: $0711),  {9 Left Triangle}
     (Select: 0;  Start: $7000;  Stop: $0710),  {10 Right Triangle}
     (Select: 0;  Start: $7000;  Stop: $0704),  {11 Diamond}
     (Select: 0;  Start: $7000;  Stop: $0716),  {12 Square}
     (Select: 0;  Start: $7000;  Stop: $0709),  {13 Circle}
     (Select: 0;  Start: $7000;  Stop: $0707),  {14 Spot}
     (Select: 0;  Start: $7000;  Stop: $07F0)); {15 triple bar}

      MouseTClockArray: array[0..3] of MouseTextType = (
     (Select: 0;  Start: $7000;  Stop: $077C),
     (Select: 0;  Start: $7000;  Stop: $072F),
     (Select: 0;  Start: $7000;  Stop: $072D),
     (Select: 0;  Start: $7000;  Stop: $075C));


{---------------------------------------------------------------------------}
{ an inline function to limit an integer between min and max values}
function IntLimit(Val,Min,Max:integer):integer;
Inline(
   $58        {  pop AX}
  /$5B        {  pop BX}
  /$59        {  pop CX}
  /$39/$C8    {  cmp AX,CX}
  /$7C/$08    {  jl done}
  /$89/$D8    {  mov AX,BX}
  /$39/$C8    {  cmp AX,CX}
  /$7F/$02    {  jg done}
  /$89/$C8);  {  mov AX,CX}
              {done:}


{++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++}
{ mouse include files }

{$I MOUSESUB.PAS}    {include special mouse subroutines and code}

{+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++}
{ the following are the standard mouse driver interface routines }
{ these routines use a mouse driver to communicate with the attached }
{ mouse. If a mouse is not there, then you can still simulate a mouse, }
{ but you will have to do much of the handling yourself. See the }
{ MOUSE.DOC documentation file for more information on using the MOUSE unit.}


{***************************************************************************}
{ Function 0 - Initialize mouse software and hardware }
{ returns MouseError = 1 if no driver, 0 if driver but no mouse, }
{ or -1 if all ok. (I know it's messy, but you can blame MS for that.) }
{ MouseError = 2 if DPMI failure while trying to check mouse }
{ MouseError = MaxInt if mouse object not installed yet }

procedure InitMouse;
var Mint : pointer;
begin
   MouseBusy := true;       {disallow re-entrant use of routine by mouse ISR}
   HideMouse;         {if the mouse is on already and visible, hide it first}

   MouseInstalled := false;
   MouseDriver := false;              {assume mouse and driver not installed}
   MouseType := 0;
   MouseState := -1;                              {<-- clear the mouse state}
   InitMouseMode;                 {<-- Init the text/graphic mode parameters}
   MouseError := 1;              {presume driver is not installed as default}
  {$IFNDEF DPMI}           {if it is real mode, we do it like we always have}
    GetIntVec($33,Mint);          {Check if real mode mouse can be installed}
    if Mint = nil then Exit;                {<-- if vector is nil, no driver}
    if byte(Mint^) = $CF then Exit;        {<-- if points to IRET, no driver}
    MouseError := 0;
  {$ELSE}
    MouseError := DPMIMouseInstall;    {check if DPMI mouse can be installed}
    if MouseError > 0 then Exit;
  {$ENDIF}
   MouseDriver := true;                           {Mouse driver is available}
   asm
     mov AX,0                     {tell the mouse to start over from scratch}
     mov BX,0
     int $33                                {<-- check if mouse is out there}
     mov [MouseError],AX      { 0 means mouse not available, -1 means all ok}
     mov [MouseType],BX
   end;
   MouseInstalled := MouseError = -1;
   InitMousePos;                             { init the mouse position stuff}
   MouseBusy := false;
end;

{---------------------------------------------------------------------------}
{ function 1 - show mouse cursor }

procedure ShowMouse;
var OldBusy : boolean;
begin
  OldBusy := MouseBusy;                               {save old mouse status}
  MouseBusy := true;        {disallow re-entrant use of routine by mouse ISR}
  if MouseState < 0 then
    inc(MouseState)                {<-- adjust current mouse state indicator}
  else
    MouseState := 0;

  {if using mouse driver and it is available do it this way}
  if not(UseSimMouse) and MouseInstalled then
  begin
    asm
      mov AX,1                        {if mouse is out there call the driver}
      int $33                                             {to hide the mouse}
    end;
  end
  else if UseSimMouse and (MouseState >= 0) then
  begin
    { if using simulator and mouse driver available get position from mouse }
    if MouseInstalled then
    begin
      asm
        mov AX,3                               { first find out where we are}
        int $33
        mov [MouseX],CX                  { and update our location registers}
        mov [MouseY],DX
      end;
      {$IFDEF GMOUSE}
        ShowSimMouse;                         {display simulated mouse image}
      {$ENDIF}
    end;
  end;

  MouseCondo := false;                                 {clear area hide flag}
  if MouseState = 0 then
    MouseVisible := true;

  MouseBusy := OldBusy;                  {restore previous mouse busy status}
end;


{---------------------------------------------------------------------------}
{ function 2 - hide mouse cursor }

procedure HideMouse;
var OldBusy : boolean;
begin
  OldBusy := MouseBusy;                               {save old mouse status}
  MouseBusy := true;        {disallow re-entrant use of routine by mouse ISR}

  {if using mouse driver and it is available do it this way}
  if not(UseSimMouse) and MouseInstalled then
  begin
    asm
      mov AX,2                               {use mouse driver to hide mouse}
      int $33
    end;
  end
  else
  begin
    {$IFDEF GMOUSE}
      HideSimMouse;                    { If mouse was visible, hide it now}
    {$ENDIF}
  end;

  if MouseState > -32767 then
    dec(MouseState);               {<-- adjust current mouse state indicator}
  MouseVisible := false;
  MouseCondo := false;                             {clear the area hide flag}
  MouseBusy := OldBusy;                  {restore previous mouse busy status}
end;


{---------------------------------------------------------------------------}
{ function 3 - read current mouse position and button status }
{ Use GetMx, GetMy to read the mouse position info in MouseX, MouseY, }
{ or ClickMouseX, ClickMouseY }

procedure ReadMouse;
var RegBX,RegCX,RegDX : word;
begin

  MouseBusy := true;        {disallow re-entrant use of routine by mouse ISR}
  if MouseInstalled then    {if mouse installed, then use it for positioning}
  begin
    if M.MouseSpinerOn then
      SpinMouse;                      {spin the mouse?}
    asm
      mov AX,3
      int $33                                  {Get the current mouse status}
      mov [RegCX],CX
      mov [RegDX],DX
      mov [RegBX],BX
    end;
    MouseX := RegCX;                          {save new mouse X and Y values}
    MouseY := RegDX;
    if (RegBX <> MouseButtons) and (RegBX <> 0) then   {<-- new button down?}
    begin
      MouseClickButton := RegBX;              {if button down save which one}
      ClickMouseX := MouseX;                            {and the current X,Y}
      ClickMouseY := MouseY;
      MouseClicked := true;                        {tell them it was clicked}
    end;
    MouseButtons := RegBX;               {<-- save the current button status}
  end;

  if UseSimMouse and MouseVisible then      {only do this if using sim mouse}
  begin                                            {and the mouse is visible}
    if (MouseX <> SimMouseX) or
       (MouseY <> SimMouseY) or      {check if the mouse moved or update req}
       MouseUpdate then
    begin
      if MouseCondo then    {if area hide active see if mouse in hidden area}
      begin
        if (MouseX >= M.MouseHideX1) and (MouseX <= M.MouseHideX2) and
           (MouseY >= M.MouseHideY1) and (MouseY <= M.MouseHideY2) then
          HideMouse               {mouse in hidden area & visible so hide it}
        else
          ShowMouse;                     {mouse position is ok, so update it}
        MouseCondo := true;                    {restore MouseCondo condition}
      end
      else
      begin
        ShowMouse;                 {area hide is not active, so just show it}
      end;
      MouseUpdate := false;
    end;
  end;  {if UseSimMouse then}

  MouseBusy := false;                  {Polled use of read mouse is done now}
end;

{---------------------------------------------------------------------------}
{ function 4 - sets mouse position }
{ Recommended calling method: }
{ SetMousePosition(PutMx(X),PutMy(Y)); }

procedure SetMousePosition(X,Y:integer);
begin
  MouseBusy := true;        {disallow re-entrant use of routine by mouse ISR}
  MouseX := IntLimit(X,M.MouseAreaX1,M.MouseAreaX2);         {limit mouse to}
  MouseY := IntLimit(Y,M.MouseAreaY1,M.MouseAreaY2);           {defined area}
  if MouseInstalled then                        {<-- can't do this, no mouse}
  begin
    asm
      mov AX,4
      mov CX,[X]                                     {tell mouse where to go}
      mov DX,[Y]
      int $33
    end;
  end;
  MouseBusy := false;
  if UseSimMouse then ReadMouse;    {if using the simulated mouse, do update}
end;

{---------------------------------------------------------------------------}
{ function 5 - gets button press information  }
{ Recommended calling method: }
{ Status := MousePress(Button,Count); }
{ Click position is available in vars MousePressX and MousePressY}

function MousePress(Button:word; var Count:word):word;
var RegBX,RegCX,RegDX:word;
begin
  if not(MouseInstalled) then                      {check if mouse installed}
  begin
    MousePress := 0;              {if no mouse everything comes back as zero}
    Count := 0;
    Exit;
  end;
  MouseBusy := true;        {disallow re-entrant use of routine by mouse ISR}
  asm
    mov AX,5
    mov BX,[Button]                              {request info on the button}
    int $33
    mov @Result,AX                  {return release count as function result}
    mov [RegBX],BX
    mov [RegCX],CX
    mov [RegDX],DX
  end;
  Count := RegBX;                            {return the info for the button}
  MousePressX := RegCX;
  MousePressY := RegDX;                {position info returned in press vars}
  MouseBusy := false;                  {Polled use of read mouse is done now}
end;

{---------------------------------------------------------------------------}
{ function 6 - gets button release information  }
{ Recommended calling method: }
{ Status := MouseRelease(Button,Count); }
{ Click position is available in vars MouseReleaseX and MouseReleaseY}

function MouseRelease(Button:word; var Count:word):word;
var RegBX,RegCX,RegDX:word;
begin
  if not(MouseInstalled) then                      {check if mouse installed}
  begin
    MouseRelease := 0;            {if no mouse everything comes back as zero}
    Count := 0;
    Exit;
  end;
  MouseBusy := true;        {disallow re-entrant use of routine by mouse ISR}
  asm
    mov AX,6
    mov BX,[Button]                              {request info on the button}
    int $33
    mov @Result,AX                  {return release count as function result}
    mov [RegBX],BX
    mov [RegCX],CX
    mov [RegDX],DX
  end;
  Count := RegBX;
  MouseReleaseX := RegCX;
  MouseReleaseY := RegDX;            {position info returned in release vars}
  MouseBusy := false;
end;

{---------------------------------------------------------------------------}
{ functions 7 and 8 - sets area where the mouse is allowed to run }
{ Recommended calling method: }
{ SetMouseArea(PutMx(x1),PutMy(y1),PutMx(x2),PutMy(y2)); }

procedure SetMouseArea(x1,y1,x2,y2:integer);
var Tb,Tc : boolean;
begin
  MouseBusy := true;        {disallow re-entrant use of routine by mouse ISR}
  M.MouseAreaX1 := x1;                               {save active mouse area}
  M.MouseAreaY1 := y1;
  M.MouseAreaX2 := x2;
  M.MouseAreaY2 := y2;
  Tb := MouseVisible;
  Tc := MouseCondo;
  if MouseVisible then HideMouse;
  if MouseInstalled then            {if no mouse we can't send it new values}
  begin
    asm
      mov CX,[X1]                                          {set the X values}
      mov DX,[X2]
      mov AX,7
      int $33
      mov CX,[Y1]                                          {set the Y values}
      mov DX,[Y2]
      mov AX,8
      int $33
    end;
  end;
  if Tb then ShowMouse;                 {restore the mouse if it was visible}
  If Tc then HideMouseArea(M.MouseHideX1,M.MouseHideY1,     {reset area hide}
                           M.MouseHideX2,M.MouseHideY2);      {if it was set}
  MouseBusy := false;
end;

{---------------------------------------------------------------------------}
{ function 9 - sets a custom graphics cursor shape }

procedure SetMouseGraphicCursor(var Mask:MaskType);
var RegBX,RegCX,RegDX,RegES : word;
    Tb,Tc : boolean;
begin
   MouseBusy := true;       {disallow re-entrant use of routine by mouse ISR}
   Tb := MouseVisible;
   Tc := MouseCondo;
   if MouseVisible then HideMouse;
   move(Mask,CurMouseMask,sizeof(CurMouseMask));   { copy to local variable }
   M.MouseGShape := -1;                            { -1 = custom mouse cursor }
   if MouseInstalled then             {if no mouse we can't send it new data}
   begin
     with CurMouseMask do
     begin
       RegBX := HotX;
       RegCX := HotY;
       RegES := seg(Def);
       RegDX := ofs(Def);
     end;
     asm
       mov AX,9
       mov BX,RegBX                                      { set the Hot Spot }
       mov CX,RegCX
       mov ES,RegES
       mov DX,RegDX                              { set the new cursor shape }
       int $33
     end;
   end;
   M.MouseSpinerOn := false;
   MouseRedraw := true;
   MouseUpdate := true;
   if Tb then ShowMouse;                {restore the mouse if it was visible}
   If Tc then HideMouseArea(M.MouseHideX1,M.MouseHideY1,    {reset area hide}
                            M.MouseHideX2,M.MouseHideY2);     {if it was set}
   MouseBusy := false;
end;

{---------------------------------------------------------------------------}
{ function 9 - sets the graphics cursor shape }
{ Graphic cursor routine borrowed from EGAMouse }
{ (and then re-written) }

procedure MouseGraphicCursor(Shape:integer);
var RegBX,RegCX,RegDX,RegES : word;
    Tb,Tc : boolean;
begin
   if not(MouseInstalled) then Exit;            {<-- can't do this, no mouse}
   MouseBusy := true;      {disallow re-entrant use of routine by mouse ISR }
   M.MouseGShape := Shape;
   if M.MouseGShape = MouseClockCursor then
   begin
     M.MouseSpinerOn := true;
     move(MouseGClockArray[0],CurMouseMask,sizeof(CurMouseMask));
     with MouseGClockArray[0] do
     begin
       RegBX := HotX;
       RegCX := HotY;
       RegES := seg(Def);
       RegDX := ofs(Def);
     end;
   end
   else
   begin
     M.MouseSpinerOn := false;
     M.MouseGShape := IntLimit(Shape,0,MaxMouseGraphShape);  {save shape num}
     move(MouseGCursor[M.MouseGShape],CurMouseMask,sizeof(CurMouseMask));
     with MouseGCursor[M.MouseGShape] do
     begin
       RegBX := HotX;
       RegCX := HotY;
       RegES := seg(Def);
       RegDX := ofs(Def);
     end;
   end;
   Tb := MouseVisible;
   Tc := MouseCondo;
   if MouseVisible then HideMouse;
   asm
     mov AX,9
     mov BX,[RegBX] {HotX}                               { set the Hot Spot }
     mov CX,[RegCX] {HotY}
     mov ES,[RegES] {seg(Def)}
     mov DX,[RegDX] {ofs(Def)}                   { set the new cursor shape }
     int $33
   end;
   MouseUpdate := true;
   MouseRedraw := true;
   if Tb then ShowMouse;                {restore the mouse if it was visible}
   If Tc then HideMouseArea(M.MouseHideX1,M.MouseHideY1,    {reset area hide}
                            M.MouseHideX2,M.MouseHideY2);     {if it was set}
   MouseBusy := false;
end;

{---------------------------------------------------------------------------}
{ function 10 - sets a custom text cursor shape }

procedure SetMouseTextCursor(Select,Start,Stop:word);
var Tb,Tc : boolean;
begin
   if not(MouseInstalled) then Exit;            {<-- can't do this, no mouse}
   MouseBusy := true;       {disallow re-entrant use of routine by mouse ISR}
   Tb := MouseVisible;
   Tc := MouseCondo;
   if MouseVisible then HideMouse;
   M.MouseTShape := -1;                          { -1 = custom mouse cursor }
   CurMouseText.Select := Select;
   CurMouseText.Start := Start;
   CurMouseText.Stop := Stop;
   asm
     mov AX,10
     mov BX,[Select]                                 { set the select value }
     mov CX,[Start]                               { set the new start value }
     mov DX,[Stop]                                 { set the new stop value }
     int $33
   end;
   M.MouseSpinerOn := false;
   MouseUpdate := true;
   MouseRedraw := true;
   if Tb then ShowMouse;                {restore the mouse if it was visible}
   If Tc then HideMouseArea(M.MouseHideX1,M.MouseHideY1,    {reset area hide}
                            M.MouseHideX2,M.MouseHideY2);     {if it was set}
   MouseBusy := false;
end;

{---------------------------------------------------------------------------}
{ function 10 - sets the text cursor shape }

procedure MouseTextCursor(Shape:integer);
var RegBX,RegCX,RegDX:word;
    Tb,Tc : boolean;
begin
   if not(MouseInstalled) then Exit;            {<-- can't do this, no mouse}
   MouseBusy := true;       {disallow re-entrant use of routine by mouse ISR}
   M.MouseTShape := Shape;
   Tb := MouseVisible;
   Tc := MouseCondo;
   if MouseVisible then HideMouse;
   if M.MouseTShape = MouseClockCursor then
   begin
     M.MouseSpinerOn := true;
     with MouseTClockArray[0] do
     begin
       RegBX := Select;
       RegCX := Start;                               { set the select value }
       RegDX := Stop;                             { set the new start value }
     end;
   end
   else
   begin
     M.MouseSpinerOn := false;
     M.MouseTShape := IntLimit(Shape,0,MaxMouseTextShape);   {save shape num}
     if Shape > 0 then        {greater than zero means get values from array}
     begin
       with MouseTCursor[M.MouseTShape] do
       begin
         RegBX := Select;
         RegCX := Start;                             { set the select value }
         RegDX := Stop;                           { set the new start value }
       end;
     end
     else            { zero means to use current hardware cursor definition }
     begin
       RegBX := 1;                                   { set the select value }
       RegCX := hi(CursorMode^);                  { set the new start value }
       RegDX := lo(CursorMode^);                   { set the new stop value }
     end;
   end;
   CurMouseText.Select := RegBX;
   CurMouseText.Start := RegCX;
   CurMouseText.Stop := RegDX;
   asm
     mov BX,[RegBX]
     mov CX,[RegCX]
     mov DX,[RegDX]
     mov AX,10
     int $33
   end;
   MouseUpdate := true;
   MouseRedraw := true;
   if Tb then ShowMouse;                {restore the mouse if it was visible}
   If Tc then HideMouseArea(M.MouseHideX1,M.MouseHideY1,    {reset area hide}
                            M.MouseHideX2,M.MouseHideY2);     {if it was set}
   MouseBusy := false;
end;

{---------------------------------------------------------------------------}
{ function 11 - Read Mouse Motion counters }

procedure ReadMickey(var X,Y:integer);
var RegCX,RegDX : word;
begin
  if not(MouseInstalled) then                      {check if mouse installed}
  begin
    X := 0;                                  {if no mouse return zero values}
    Y := 0;
    Exit;
  end;
  MouseBusy := true;        {disallow re-entrant use of routine by mouse ISR}
  asm
    mov AX,11
    int $33
    mov [RegCX],CX
    mov [RegDX],DX
  end;
  X := RegCX;                                          {return mickey values}
  Y := RegDX;
  MouseBusy := false;
end;

{---------------------------------------------------------------------------}
{ function 12 - Set Mouse Interrupt service routine and mask }
{Note: this does not work in protected mode }

procedure SetMouseISR(Mask:word; Address:pointer);
begin
  if not(MouseInstalled) then Exit;             {<-- can't do this, no mouse}
  MouseBusy := true;        {disallow re-entrant use of routine by mouse ISR}
  asm
    mov AX,12
    mov CX,[Mask]                              {<-- set the ISR service mask}
    les DX,[Address]                            {set the ISR service address}
    int $33
  end;
  MouseBusy := false;
end;

{---------------------------------------------------------------------------}
{ function 13 and 14 - Light pen emulation on/off }

procedure LightPen(Flag:boolean);
var RegAX : word;
begin
  if not(MouseInstalled) then Exit;             {<-- can't do this, no mouse}
  MouseBusy := true;        {disallow re-entrant use of routine by mouse ISR}
  if Flag then
    RegAX := 13                                  {set light pen emulation on}
  else
    RegAX := 14;                                {set light pen emulation off}
  asm
    mov AX,[RegAX]
    int $33
  end;
  MouseBusy := false;
end;


{---------------------------------------------------------------------------}
{ function 15 - sets the mickey to pixel ratio }

procedure SetPixeltoMickey(X,Y:integer);
begin
  if not(MouseInstalled) then Exit;             {<-- can't do this, no mouse}
  MouseBusy := true;        {disallow re-entrant use of routine by mouse ISR}
  asm
    mov AX,15
    mov CX,[X]                                    {set the new mickey values}
    mov DX,[Y]
    int $33
  end;
  MouseBusy := false;
end;


{---------------------------------------------------------------------------}
{ function 16 - Conditional Mouse Hide - hides mouse if in indicated area }
{ use ShowMouse after using this function - just like regular HideMouse }
{ This function causes HideMouse to be called if the mouse ever enters the }
{ area specified. Once it becomes hidden, you have to call ShowMouse to make}
{ it visible again once it becomes hidden. Calling either ShowMouse, or}
{ Hidemouse disables the HideMouseArea function restoring normal mouse}
{ operation. Recommended calling method: }
{ HideMouseArea(PutMx(x1),PutMy(y1),PutMx(x2),PutMy(y2)); }

procedure HideMouseArea(x1,y1,x2,y2:integer);
begin
  MouseBusy := true;        {disallow re-entrant use of routine by mouse ISR}
  MouseCondo := true;                   {<-- flag conditional hideing active}
  M.MouseHideX1 := x1;
  M.MouseHideX2 := x2;                 {Save HideMouseArea - Mouse hide area}
  M.MouseHideY1 := y1;
  M.MouseHideY2 := y2;
  if MouseInstalled then                 {if mouse is out there, then set it}
  begin
    asm
      mov CX,[X1]                                    {set the X and Y values}
      mov DX,[Y1]
      mov SI,[X2]
      mov DI,[Y2]
      mov AX,16
      int $33
    end;
  end;
  MouseUpdate := true;                   {request mouse sim update as needed}
  MouseBusy := false;
  if UseSimMouse then ReadMouse;      {if using mouse sim, update the cursor}
end;

{Note: If MouseCondo is true, then the actual state of the mouse is not}
{known if the mouse driver cursor is being used. The cursor may or may not}
{be hidden depending on whether the mouse was moved into the hide area.}
{Be careful when dealing with this. If the SaveMouse/RestoreMouse functions}
{are called and the mouse was hidden as the result of moving into the hide}
{area, the RestoreMouse will redisplay the mouse if it is not in the hidden}
{area when it is restored. If the simulated mouse cursor is being used, then}
{the MouseState and MouseVisible variables will always be valid since I can}
{control the cursor. If the simulated mouse cursor is not being used (you}
{are using the mouse driver cursor), then the MouseVisible and MouseState}
{variables may not be valid since I cannot know when the mouse is hidden.}
{If MouseCondo is set, you should presume that MouseVisible and MouseState}
{are not stable. Specifically, if they say that the mouse is hidden, then}
{you may presume that it is indeed hidden. If they say it is visible, you}
{should not trust them. The HideMouseArea function will be recalled if the}
{mouse cursor is changed or the mouse limit area set. This means that like}
{the RestoreMouse function, the mouse cursor may become visible again if it}
{is outside the hide area.}

{For an operating consideration, you can presume that the mouse is hidden}
{if MouseCondo is true or MouseVisible is false.}

{---------------------------------------------------------------------------}
{ function 19 - Set Double Speed Threshold }

procedure MouseThreshold(Threshold:integer);
begin
  if not(MouseInstalled) then Exit;             {<-- can't do this, no mouse}
  MouseBusy := true;        {disallow re-entrant use of routine by mouse ISR}
  asm
    mov AX,19
    mov DX,[Threshold]                          {set the new threshold value}
    int $33
  end;
  MouseBusy := false;
end;


{---------------------------------------------------------------------------}
{ function 20 - Swap current Mouse ISR with a new one}
{ New Mask and ISR address are passed in the calling variables }
{ Returns old ISR and mask in the calling variables }
{Note: this does not work in protected mode }

procedure SwapMouseISR(var Mask:word; var Address:pointer);
var RegCX,RegES,RegDX:word;
begin
  if not(MouseInstalled) then Exit;             {<-- can't do this, no mouse}
  MouseBusy := true;        {disallow re-entrant use of routine by mouse ISR}
  RegCX := Mask;
  asm
    mov AX,20
    mov CX,[RegCX]                             {<-- set new ISR service mask}
    les DX,[Address]                            {set new ISR service address}
    int $33
    mov [RegCX],CX
    mov [RegDX],DX
    mov [RegES],ES
  end;
  Mask := RegCX;                               {<-- Get old ISR service mask}
  Address := ptr(RegES,RegDX);                  {Get old ISR service address}
  MouseBusy := false;
end;


{---------------------------------------------------------------------------}
{ function 24 - Set Alternate Subroutine call mask and address}
{ New Mask and ISR address are passed in the calling variables }
{ Returns false if failure, true is successful }
{Note: this does not work in protected mode }

function SetAltISR(Mask:word; Address:pointer):boolean;
var RegAX,RegCX,RegES,RegDX:word;
begin
  if not(MouseInstalled) then Exit;             {<-- can't do this, no mouse}
  MouseBusy := true;        {disallow re-entrant use of routine by mouse ISR}
  RegCX := Mask;
  asm
    mov AX,24
    mov CX,[RegCX]                             {<-- set new ISR service mask}
    les DX,[Address]                            {set new ISR service address}
    int $33
    mov [RegAX],AX
  end;
  if RegAX = -1 then SetAltISR := false
    else SetAltISR := true;
  MouseBusy := false;
end;


{---------------------------------------------------------------------------}
{ function 25 - Get current Alternate Subroutine call mask and address}
{ Mask and ISR address are passed back in the calling variables }
{ Returns false if failure, true is successful }
{Note: this does not work in protected mode }

function GetAltISR(var Mask:word; var Address:pointer):boolean;
var RegCX,RegBX,RegDX:word;
begin
  if not(MouseInstalled) then Exit;             {<-- can't do this, no mouse}
  MouseBusy := true;        {disallow re-entrant use of routine by mouse ISR}
  RegCX := Mask;
  asm
    mov AX,25
    mov CX,[RegCX]                             {<-- set new ISR service mask}
    int $33
    mov [RegCX],CX
    mov [RegDX],DX
    mov [RegBX],BX
  end;
  Mask := RegCX;                               {<-- Get old ISR service mask}
  Address := ptr(RegBX,RegDX);                  {Get old ISR service address}
  MouseBusy := false;
end;


{---------------------------------------------------------------------------}
{ function 26 - Set Mouse Sensitivity }

procedure SetMouseSensitivity(Horiz,Vert,Threshold:word);
begin
  if not(MouseInstalled) then Exit;             {<-- can't do this, no mouse}
  MouseBusy := true;        {disallow re-entrant use of routine by mouse ISR}
  asm
    mov AX,26
    mov BX,[Horiz]
    mov CX,[Vert]
    mov DX,[Threshold]                          {set the new threshold value}
    int $33
  end;
  MouseBusy := false;
end;


{---------------------------------------------------------------------------}
{ function 27 - Get Mouse Sensitivity }

procedure GetMouseSensitivity(var Horiz,Vert,Threshold:word);
var RegBX,RegCX,RegDX : word;
begin
  if not(MouseInstalled) then Exit;             {<-- can't do this, no mouse}
  MouseBusy := true;        {disallow re-entrant use of routine by mouse ISR}
  asm
    mov BX,0
    mov CX,0
    mov DX,0
    mov AX,27
    mov [RegBX],BX
    mov [RegCX],CX
    mov [RegDX],DX                              {set the new threshold value}
    int $33
  end;
  Horiz := RegBX;
  Vert := RegCX;
  Threshold := RegDX;
  MouseBusy := false;
end;

{---------------------------------------------------------------------------}
{ function 28 - Set Mouse Interrupt Rate - NOTE: works with PS/2 mouse only }

procedure SetMouseInterruptRate(Rate:word);
begin
  if not(MouseInstalled) then Exit;             {<-- can't do this, no mouse}
  MouseBusy := true;        {disallow re-entrant use of routine by mouse ISR}
  asm
    mov AX,28
    mov BX,[Rate]                               {set the new threshold value}
    int $33
  end;
  MouseBusy := false;
end;

{---------------------------------------------------------------------------}
{ function 29 - Set Mouse Page }

procedure SetMousePage(Page:word);
begin
  if not(MouseInstalled) then Exit;             {<-- can't do this, no mouse}
  MouseBusy := true;        {disallow re-entrant use of routine by mouse ISR}
  asm
    mov AX,29
    mov BX,[Page]                               {set the new threshold value}
    int $33
  end;
  MouseBusy := false;
end;

{---------------------------------------------------------------------------}
{ function 30 - Get Mouse Page }

function GetMousePage:word;
begin
  GetMousePage := 0;
  if not(MouseInstalled) then Exit;             {<-- can't do this, no mouse}
  MouseBusy := true;        {disallow re-entrant use of routine by mouse ISR}
  asm
    mov BX,0
    mov AX,30
    int $33
    mov @Result,BX                              {get the new threshold value}
  end;
  MouseBusy := false;
end;


{---------------------------------------------------------------------------}
{ function 31 and 32 - Mouse Interrupt Enable/Disable }

procedure MouseEnable(Flag:boolean);
var RegAX : word;
begin
  if not(MouseInstalled) then Exit;             {<-- can't do this, no mouse}
  MouseBusy := true;        {disallow re-entrant use of routine by mouse ISR}
  if Flag then
    RegAX := 32                                      {enable mouse interrupt}
  else
    RegAX := 31;                                    {disable mouse interrupt}
  asm
    mov AX,[RegAX]
    int $33
  end;
  MouseBusy := false;
end;


{---------------------------------------------------------------------------}
{ function 33 - Mouse Reset}

function MouseReset:boolean;
var RegAX : word;
begin
  MouseReset := false;
  if MouseDriver then
  begin
    HideMouse;                   {make sure the mouse is off before reseting}
    MouseBusy := true;      {disallow re-entrant use of routine by mouse ISR}
    InitMouseMode;                {<-- Init the text/graphic mode parameters}
    MouseState := -1;                             {<-- clear the mouse state}
    RegAX := 1;
    asm
      mov AX,33                                  {try to do a software reset}
      int $33
      mov [RegAX],AX
      mov [MouseType],BX
    end;
    if RegAX = -1 then
    begin
      MouseError := -1;
      MouseInstalled := true;
      InitMousePos;
      MouseBusy := false;
      MouseReset := true;
      Exit;
    end;
  end;
  MouseBusy := false;
  InitMouse;                {if software reset failed or Init not called yet}
  MouseReset := MouseInstalled;                      {do a regular MouseInit}
end;

{---------------------------------------------------------------------------}
{ function 34 - Set Mouse language}

procedure SetMouseLanguage(Language:word);
begin
  if not(MouseInstalled) then Exit;             {<-- can't do this, no mouse}
  MouseBusy := true;        {disallow re-entrant use of routine by mouse ISR}
  asm
    mov AX,34
    mov BX,[Language]                            {set the new langauge value}
    int $33
  end;
  MouseBusy := false;
end;

{---------------------------------------------------------------------------}
{ function 35 - Get Mouse Language}

function GetMouseLanguage:word;
begin
  GetMouseLanguage := 0;
  if not(MouseInstalled) then Exit;             {<-- can't do this, no mouse}
  MouseBusy := true;        {disallow re-entrant use of routine by mouse ISR}
  asm
    mov BX,0
    mov AX,35
    int $33
    mov @Result,BX                                   {get the language value}
  end;
  MouseBusy := false;
end;


{---------------------------------------------------------------------------}
{ function 36 - Get Mouse Info }

procedure GetMouseInfo(var VersionHI,VersionLO,MouseType,IRQnm:byte);
var RegBX,RegCX: word;
begin
  if not(MouseInstalled) then Exit;             {<-- can't do this, no mouse}
  MouseBusy := true;        {disallow re-entrant use of routine by mouse ISR}
  asm
    mov BX,0
    mov CX,0
    mov AX,36
    int $33
    mov [RegBX],BX
    mov [RegCX],CX
  end;
  VersionHI := hi(RegBX);
  VersionLO := lo(RegBX);
  MouseType := hi(RegCX);
  IRQnm := lo(RegCX);
  MouseBusy := false;
end;


{+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++}
{ mouse status stack procedures }
{+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++}

{ Mouse stack variables }
type
     MousePtrP   = ^MousePtrRec;               {defines a mouse stack record}
     MousePtrRec = record      {Prev points to previous stack record on heap}
        Prev  : MousePtrP;               {if nil then is top record on stack}
        Buf   : pointer;                 {Buf points to the mouse data saved}
        Size  : word;                      {Size = bytes in the mouse buffer}
        Mdata : MouseDataRec;
        Tmask : MouseTextType;
        Gmask : MaskType;
        Mcon  : boolean;                       {saved conditional hide state}
        Mstate : integer;                                 {saved mouse state}
     end;

var  MouseStack : MousePtrP;   {MouseStack points to last rec on mouse stack}
                                  {if nil then there is nothing on the stack}

{---------------------------------------------------------------------------}
function SaveMouse:boolean;  {Pushes current mouse status on the mouse stack}
var Ptemp : MousePtrP;       {Returns false if not enough heap space to push}
    RegBX : word;
    Data   : pointer;
    SegSel : longint;
begin
  SaveMouse := false;                      {<-- assume no good to begin with}
  if not(MouseInstalled) then Exit;             {<-- can't do this, no mouse}

  MouseBusy := true;        {disallow re-entrant use of routine by mouse ISR}
  asm
    mov ax,21
    int $33                                  {find out how much data to save}
    mov [RegBX],BX                     {then check to see if it can be saved}
  end;
  If MaxAvail < ( RegBX + sizeof(MousePtrRec) + 64 ) then
  begin
    MouseBusy := false;                {Polled use of read mouse is done now}
    Exit;
  end;

  Ptemp := MouseStack;                           {<-- save old stack pointer}
  GetMem(MouseStack,sizeof(MousePtrRec));      {<-- get a new pointer record}
  with MouseStack^ do
  begin
    Prev := Ptemp;                            {<-- link in old stack pointer}
    Size := RegBX;                             {<-- save how big the data is}
    GetMem(Buf,Size);               {<-- grab some buffer space for the data}
    Mdata := M;                                 {save common mouse variables}
    Gmask := CurMouseMask;                        {save graphic mouse cursor}
    Tmask := CurMouseText;                           {save text mouse cursor}
    Mstate := MouseState;                   {save Current state of the mouse}
    Mcon := MouseCondo;                         {save conditional hide state}

   {$IFDEF DPMI}
    SegSel := GlobalDosAlloc(Size);          {try to alloc DOS buffer memory}
    if SegSel = 0 then                {SegSel=0 means DPMI allocation failed}
    begin
      freemem(Buf,Size);                  {if error, release heap allocation}
      freemem(MouseStack,sizeof(MousePtrRec));          {and get out of here}
      MouseStack := Ptemp;
      MouseBusy := false;
      Exit;
    end;
    Data := ptr(loword(SegSel),0);          {pass protected mode ptr in Data}
    RegBX := hiword(SegSel);                   {pass real mode segment in BX}
   {$ELSE}
    Data := Buf;                            {Pass the buffer pointer in Data}
   {$ENDIF}

    asm
      mov AX,22
      mov BX,[RegBX]
      les DX,[Data]                       {save the Mouse data in the buffer}
      int $33
    end;
    if Mcon then
      HideMouseArea(M.MouseHideX1,M.MouseHideY1,          {conditional hide?}
                    M.MouseHideX2,M.MouseHideY2)
    else if Mstate = 0 then ShowMouse;  {if saved mouse was visible, show it}

   {$IFDEF DPMI}
    move(Data^,Buf^,Size);                        {copy the data to the heap}
    SegSel := GlobalDOSFree(loword(SegSel));         {release the DOS memory}
   {$ENDIF}
  end;

  MouseBusy := false;
  SaveMouse := true;                               {<-- tell them we made it}
end;

{---------------------------------------------------------------------------}
function RestoreMouse:boolean;      {Pops mouse status from the mouse stack.}
var Ptemp : MousePtrP;                     {Returns false if nothing to pop.}
    Data  : pointer;
    RegBX : word;
    SegSel : longint;
begin
  RestoreMouse := false;                   {<-- assume no good to begin with}
  if not(MouseInstalled) then Exit;             {<-- can't do this, no mouse}
  If MouseStack = nil then Exit;            {<-- Nothing in the stack to pop}

  HideMouse;              {make sure the mouse is hidden before restoring it}
  MouseBusy := true;        {disallow re-entrant use of routine by mouse ISR}
  with MouseStack^ do
  begin

   {$IFDEF DPMI}
    SegSel := GlobalDosAlloc(Size);         {try to alloc DOS buffer memory}
    if SegSel = 0 then               {SegSel=0 means DPMI allocation failed}
    begin
      MouseBusy := false;
      Exit;
    end;
    Data := ptr(loword(SegSel),0);         {pass protected mode ptr in Data}
    RegBX := hiword(SegSel);                  {pass real mode segment in BX}
    move(Buf^,Data^,Size);                     {copy the data to DOS memory}
   {$ELSE}
    RegBX := Size;
    Data := Buf;
   {$ENDIF}

    asm
      mov AX,23
      mov BX,[RegBX]
      les DX,[Data]                      {restore mouse data from the stack}
      int $33
    end;
    M := Mdata;                             {restore commom mouse variables}
    MouseState := Mstate;                     {restore previous mouse state}
    CurMouseMask := Gmask;                    {restore graphic mouse cursor}
    CurMouseText := Tmask;                       {restore text mouse cursor}
    if Mcon then
      HideMouseArea(M.MouseHideX1,M.MouseHideY1,         {conditional hide?}
                    M.MouseHideX2,M.MouseHideY2)
    else if Mstate = 0 then ShowMouse; {if saved mouse was visible, show it}

   {$IFDEF DPMI}
    SegSel := GlobalDOSFree(loword(SegSel));            {release DOS memory}
   {$ENDIF}

    Ptemp := Prev;                             {<-- unlink the prev pointer}
    FreeMem(Buf,Size);                          {and free up the heap space}
    FreeMem(MouseStack,sizeof(MousePtrRec));
    MouseStack := Ptemp;                          {<-- update stack pointer}
  end;

  MouseBusy := false;
  RestoreMouse := true;                           {<-- tell them we made it}
  ReadMouse;
end;

{---------------------------------------------------------------------------}
procedure ZapMouseStack;                             {Get rid of mouse stack}
var Ptemp : MousePtrP;
    Temp : word;
begin
   MouseBusy := true;       {disallow re-entrant use of routine by mouse ISR}
   while MouseStack <> nil do               {pop the stack until it is empty}
   begin
     with MouseStack^ do
     begin
       Ptemp := Prev;                           {<-- unlink the prev pointer}
       FreeMem(Buf,Size);                        {and free up the heap space}
       FreeMem(MouseStack,sizeof(MousePtrRec));
       MouseStack := Ptemp;                        {<-- update stack pointer}
     end;
   end;
   MouseBusy := false;
end;


{***************************************************************************}
{ mouse ISR routines and Exit handlers }
{***************************************************************************}
{  ****   These are special procedures -- Caution: handle with care   ****  }

{ special global variables localized to this area}
const ClkVect = $1C;                     {55ms system clock interrupt number}
var ExitSave : pointer;                      {saved previous ExitPoc pointer}

{---------------------------------------------------------------------------}
{Exit procedure}
{ restores stuff on exit from main program }

{$F+} procedure MouseExit;                                  {<-- must be far}
begin
   ExitProc := ExitSave;                   {restore next exit procedure call}
   if MouseVisible then           {make sure the mouse is off before exiting}
     HideMouse;
   if HercGraphMouse then               {turn off the Herc mouse if it is on}
     SetHercMouse(-1);
   if MouseHooked then                             {if mouse hooked to clock}
     SetIntVec(ClkVect,Old1Cvect);            {then restore old clock vector}
   ZapMouseStack;                      {make sure the mouse stack is cleared}
  {$IFDEF GMOUSE}
    ReleaseSimMouse;                   {release sim mouse memory if graphics}
  {$ENDIF}
end;

{---------------------------------------------------------------------------}
{ mouse clock ISR routine }
{ hooks the ReadMouse routine to the system clock }
{ Use the BackgroundMouse procedure to attach or detach this ISR }

{$F+} procedure BackgroundMouseRead; interrupt; {<-- must be far & interrupt}
begin
  inline($FB);                                         {re-enable interrupts}
  if not(MouseBusy) then          {if mouse is still busy, we wrapped around}
  begin
    ReadMouse;                                               {read the mouse}
    { Additional or alternate ISR code can go here - See warning note below }
  end;

  {Finally, we end the ISR with a link to the existing clock routines}
  inline($9C/$FF/$1E/Old1Cvect);   {pushf;  call far old1cvect  ;link to old}
end;

{ Warning: If you add code to this routine, or change it, use extreme care }
{ in what you do. Poorly created ISR routines can create major problems }
{ that cannot be readily detected. Remember that most debugger's }
{ (including Borland's) are not able to trace into an ISR. You will need a }
{ low-level debugger like Periscope to do that sort of thing. }
{ Caution: Since BackgroundMouseRead interrupt procedure is hooked to the }
{ system clock, it is repeated at 55ms intervals. Do not allow the code }
{ in the routine to exceed that time frame or it will cause the stack to }
{ overflow. You can add code after the ReadMouse procedure call, or replace }
{ the ReadMouse procedure call with your own, but use extreme care in doing }
{ so, since it is easy to break this code, and you can't easily debug it if }
{ something is wrong. }
{ Danger: This is an interrupt service routine. You cannot call routines }
{ which are re-entrant from within this procedure. }

{---------------------------------------------------------------------------}
{Hooks the Mouse function to the system clock}
{State = true hooks the mouse up, State = false disconnects the mouse}
{This function calls the ReadMouse function once every 55ms. This can}
{help speed up the mouse control and make it more consistant, especially}
{when using simulated BGI mouse cursor. When the mouse is hooked to the}
{system clock you do not need to continuously poll the ReadMouse procedure}

procedure BackgroundMouse(State:boolean);
begin
  if State then
  begin
    if MouseHooked then Exit;      {the mouse is already hooked to the clock}
    MouseHooked := true;                   {if the mouse is not hooked, then}
    GetIntVec(ClkVect,Old1Cvect);                 {save old clock vector and}
    SetIntVec(ClkVect,@BackgroundMouseRead);                 {attach our own}
  end
  else
  begin
    if not(MouseHooked) then Exit;       {if mouse currently hooked to clock}
    SetIntVec(ClkVect,Old1Cvect);             {then restore old clock vector}
    MouseHooked := false;                                     {and unhook it}
  end;
end;


{***************************************************************************}
{Initialization section}

begin
{$IFDEF GMOUSE}                 { if we are using graphics enable this stuff}
  MouseBack := nil;                              {start with no mouse cursor}
  MouseMask := nil;
  MouseFore := nil;
  MouseSize := 0;
{$ENDIF}
  CrtMode := ptr(Seg0040,$49);          {location of BIOS Crt mode flag byte}
  CrtCols := ptr(Seg0040,$4A);            {location of BIOS Crt column count}
  CrtRows := ptr(Seg0040,$84);               {location of BIOS Crt row count}
  SysClk  := ptr(Seg0040,$6C);        {location of BIOS system clock counter}
  CursorMode := ptr(Seg0040,$60);      {location of BIOS cursor mode storage}
  CurMouseMask := MouseGCursor[0];
  CurMouseText := MouseTCursor[1];

  move(MouseGCursor[MouseStandard],CurMouseMask,sizeof(CurMouseMask));
  MouseState := -1;
  MouseVisible := false;
  MouseHooked := false;            {mouse starts out disconnected from clock}
  MouseBusy := false;                         {start off with mouse not busy}
  GetIntVec(ClkVect,Old1CVect);     {save current vector for clock interrupt}
  ExitSave := ExitProc;                          {hook up the Exit procedure}
  ExitProc := @MouseExit;
  MouseStack := nil;                                 {no mouse stack present}
  InitMouse;                                           {initialize the mouse}
end.

{***************************************************************************}
{ EOF }

