[Back to CURSOR SWAG index] [Back to Main SWAG index] [Original]

    { Updated CURSOR.SWG on May 26, 1995 }

    {
    Hi everyone.  Recently, I made a program to animate the cursor, and
    when I added support for hiding and showing the cursor, my program
    ceased to work like it should (all int 10h functions (video) didn't
    work right.)  If anyone has any suggestions, optimizations, or ways
    to get this to take up less memory, please reply.

    ----8<-cut-here-
    Program AnimateCursor;
    { AnimateCursor Copyright (C) 1995 by Jonathan Anderson }
    { This program does what it says -- it makes the cursor move up and down }
    { thanks to John Baldwin for nice description of cursor handling }

    {-$DEFINE Debug}        { Define this if changing the code }
    {$DEFINE Use286}       { Define this to use 286 code }

    {$IFDEF Debug}

    {$M $1000,0,0}   { 4K stack, no heap }
    {$A+,B-,D+,E-,F-,G-,I-,L+,N-,O-,R-,S+,V+,X-}     { TP6 compile options }

    {$ELSE}

    {$M $400,0,0}    { 1K stack, no heap }
    {$A+,B-,D-,E-,F-,G-,I-,L-,N-,O-,R-,S-,V-,X-}

    {$ENDIF}

    {$IFDEF Use286}
    {$G+}
    {$ENDIF}

    Uses Dos;

    Var OldInt1C, OldInt09 : Procedure;
        OldInt10           : Pointer;     { status = cursor blink pattern }
        x, z, status       : Byte;        { x = top scan line for cursor }
        y                  : Boolean;     { z = width (in scan lines) of cursor }
                                          { y = cursor going up (F) or down (T) }

    Procedure RemoveAnimate; Assembler;
    Asm                  { thanks to Luis Mezquita Raya for this... }
      cli
      mov   ah,1
      mov   ch,6                { this procedure (c) Jul 94 Luis Mezquita Raya }
      mov   cl,7
      int   10h
      mov   ah,49h
      mov   es,PrefixSeg
      push  es
      mov   es,es:[2ch]
      int   21h
      pop   es
      mov   ah,49h
      int   21h
      sti
    End;

    {$F+}
    Procedure NewInt09; Interrupt;      { KBD handler for unloading hotkey }
    Var KB : Byte;
    Begin
      KB := Port[$60];
      Inline($9C);                      { pushf }
      OldInt09;                         { call old interrupt }
      If KB = 88 Then                   { Use F12 to unload from memory }
        Begin
          SetIntVec($1C, @OldInt1C);
          SetIntVec($10, OldInt10);
          SetIntVec($09, @OldInt09);
          RemoveAnimate;
        End;
    End;

    Procedure NewInt10; Interrupt; Assembler;  { handler to allow programs  }
    Asm                                        { to hide & show cursor...   }
    {$IFDEF Use286}                            { right now, it doesn't work }
      pusha
    {$ELSE}
      push  ax
      push  bx
      push  cx
      push  dx
      push  si
      push  di
    {$ENDIF}
      cmp   ah,1                               { check for cursor change }
      jnz   @Skip                              { request & jump if not   }
      mov   status,ch
      and   status,60h                         { isolate bits 5 and 6 }
    @Skip:
    {$IFDEF Use286}
      popa
    {$ELSE}
      pop   ax
      pop   bx
      pop   cx
      pop   dx
      pop   si
      pop   di
    {$ENDIF}
      call  oldint10                           { call olt interrupt }
    End;

    Procedure NewInt1C; Interrupt;             { timer handler; changes cursor }
    Var ctype : Byte;
    Begin
      If (x=129) or (x=143-z) Then y := Not(y);  { reverse direction of cursor }
      If y Then Asm dec x End                  { why use Inc() and Dec() ? }
      Else Asm inc x End;
      ctype := status OR x;            { combine status bits with position bits }
      Asm
        mov  ah,1                      { request cursor change }
        mov  ch,ctype                  { set top scan line }
        mov  cl,ctype                  { set bottom scan line }
        add  cl,z
        call OldInt10      { call oldint instead of wasting time calling new one }
      End;
      Inline($9C);         { pushf }
      OldInt1C;            { call old interrupt }
    End;
    {$F-}

    Begin
      x := 129;  { had to mess with this value for use of all scan lines in char }
      z := 1;                    { cusor width = 1 }
      status := 0;               { normal cursor }
      y := True;                 { MUST be true...}
      GetIntVec($09, @OldInt09);
      SetIntVec($09, @NewInt09);
      GetIntVec($10, OldInt10);
      SetIntVec($10, @NewInt10); { comment this line for prog. to work w/o int10 }
      GetIntVec($1C, @OldInt1C);
      SetIntVec($1C, @NewInt1C);
      Keep(0);                   { terminate, stay resident }
    End.

    (*
      From: Kelly Small

    You don't restore the registers properly during the Int $10 ISR.
    You need to pop them in the reverse order that they were pushed:

    >Procedure NewInt10; Interrupt; Assembler;  { handler to allow programs  }
    >Asm                                        { to hide & show cursor...   }
    >  push  ax
    >  push  bx
    >  push  cx
    >  push  dx
    >  push  si
    >  push  di

    >  pop   ax
    >  pop   bx
    >  pop   cx
    >  pop   dx
    >  pop   si
    >  pop   di

    After this you would have ax = di
                              bx = si etc.

    Reverse the order of your pop's and it should work.
    *)

[Back to CURSOR SWAG index] [Back to Main SWAG index] [Original]