[comp.sys.ibm.pc] solid block cursor program

sword@vu-vlsi.UUCP (Ronin) (12/01/87)

     Well, since I haven't been told where to post this, I'll
just post it here (please forgive me if this is wrong).  This
code is an example of a TSR (written the old way with INT 27H)
which intercepts INT 10H and looks for cursor calls.  It then
moves an inverse block to where the cursor is.

     There are several bugs, and I'm not a good enough 8086 programmer
to know a way around them.  That's why I'm posting it.  I'm
hoping some brave soul might be able to figure it out.

     Anyways, if posting code with some bugs is a bad thing, then
I'm sure someone will let me know.  But please, no flames.

Stats:

     Written in 8086/88 Assembly Language
     steps to use:

     ASM BLOCK;            ! uses no macro stuff, so doesn't need MASM
     LINK BLOCK,BLOCK,CON:;
     EXE2BIN BLOCK.EXE BLOCK.COM
     BLOCK

     Any question, please send mail to one of the addresses given
in the source code.

     Without further adieu, the program.


-----
Larry Esmonde, Program Director of SWORD (Students Working On R & D)
Computer Science Dept.
Villanova University
Villanova, Pa. 19085

--------------------------CUT HERE---------------------------
; BLOCK.ASM -- IBM 8086/88 Assembler -- 11.27.87 -- BLOCK.COM
;
;    This program simulates a block, non-blinking cursor (ala
; DEC VT-100/200 Series terminals) in replacement of the blinking
; IBM Personal Computer.
;
; Author: Larry Esmonde Jr.
;
; UUCP   : {cbmvax,bpa,psuvax1}!vu-vlsi!excalibur!159628317
; BITNET : 159628317@vuvaxcom, larry@villvm
; CSnet  : esmonde@villanova.edu
;
;
; *NOTE* - This code is buggy.  It will not work with Turbo Pascal
;          or PC BASIC.   Also, it has problems with the screen
;          scrolling during cursor placement.
;          You have been warned.
;
; This code may be freely modified and redistributed, as long
; as credit is given for any interim authors and modifiers.
;
; If any modifications are made, please let me know, for
; I'd be glad to know how bugs were overcome
;
;
;-----------------------------------------------------------------;
; VECTORS - Absolute Segment at 0000H                             ;
;                                                                 ;
;    This segment allows access to the interrupt vector table,    ;
; which contains the memory locations of all the interrupts       ;
; which the computer uses.                                        ;
;                                                                 ;
;-----------------------------------------------------------------;

vectors segment at 0000H
        org     10H*4                   ; the offset of the video int. 
int10   label   dword
vectors ends

;-----------------------------------------------------------------;
; MDA - Absolute Segment at B000H                                 ;
;                                                                 ;
;    This segment allows access to the monochrome screen via      ;
; direct memory access.                                           ;
;                                                                 ;
;-----------------------------------------------------------------;

mda     segment at 0B000H       ; the monochrome display adapter address
        org     0
mda     ends

;-----------------------------------------------------------------;
; CGA - Absolute Segment at B800H                                 ;
;                                                                 ;
;    This segment allows access to the color/graphics screen      ;
; via direct memory access.                                       ;
;                                                                 ;
;-----------------------------------------------------------------;

cga     segment at 0B800H       ; the color/graphics adapter address
        org     0
cga     ends

;-----------------------------------------------------------------;
; ROM_BIOS - Absolute Segment at 0040H                            ;
;                                                                 ;
;    This segment allows access to the ROM-BIOS table, which      ;
; contains various system information, like which display         ;
; adapter is currently in use.                                    ;
;                                                                 ;
;-----------------------------------------------------------------;

rom_bios        segment at 0040H
        org     10H
equip   dw      ?               ; Used to determine display type
rom_bios        ends

;-----------------------------------------------------------------;
; CODE - Relative Segment at CS                                   ;
;                                                                 ;
;    This segment contains all of the programming code for the    ;
; program.  It is also referenced when INT10, from the VECTORS    ;
; segment is loaded with the CS value.                            ;
;                                                                 ;
;-----------------------------------------------------------------;

code    segment
        assume  cs:code
        org     100H
start:  jmp     fix_int         ; fix-up the interrupt vector table
;
old10   dd      ?               ; this is the address of the old INT 10
newpos  dw      ?               ; holding area for the new cursor position
curpos  dw      ?               ;    "     "    "   "  old cursor     "
scraddr dw      ?               ; the absolute memory address on screen
scrattr db      ?               ; the attributes of the address
row     db      ?               ; row of cursor call
col     db      ?               ; column of cursor call
cursor  db      0               ; binary true/false for cursor call
inverse db      70H             ; this is the hex value of inverse

;-----------------------------------------------------------------;
; CALC_ADDRESS - Near Procedure                                   ;
;                                                                 ;
;    This procedure calculates the absolute memory value of a     ;
; given cursor coordinate (i.e. cursor location (y=2,x=6) is      ;
; equal to (2*160)+(2*6) = 326.  It returns the calculated        ;
; value in the SCRADDR variable                                   ;
;                                                                 ;
; Input  Parameters: ROW and COL                                  ;
; Output Parameters: SCRADDR                                      ;
;-----------------------------------------------------------------;

calc_address    proc    near
        push    ax
        push    bx
        push    cx
        mov     ax,0
        mov     bx,0
        mov     cx,0
        mov     al,row          ; get the row value
        mov     bl,col          ; get the column value
        mov     cl,160          ; multiply the row value by 160 (80*2)
        mul     cl
        mov     scraddr,ax      ; store the row value
        mov     al,bl           ; restore the column value
        mov     ah,0            ; zero-out the high-order bits
        mov     cl,2            ; multiply the column value by 2
        mul     cl
        add     scraddr,ax      ; add the column value to the row value
        pop     cx
        pop     bx
        pop     ax
        ret                     ; return to caller 
calc_address    endp

;-----------------------------------------------------------------;
; MOVE_BLOCK - Near Procedure                                     ;
;                                                                 ;
;    This procedure is called every time the cursor is            ;
; repositioned on the screen.  It taps directly into video        ;
; memory at either segment B000 or B800.                          ;
;                                                                 ;
;     Calls: CALC_ADDRESS                                         ;
;-----------------------------------------------------------------;

move_block      proc    near
        push    ax              ; save AX, BX, CX, DX & DS
        push    bx              ;
        push    cx              ;
        push    dx              ;
        push    ds
        mov     ax,rom_bios     ; fix up DS to the ROM_BIOS segment
        mov     ds,ax           ;
        assume  ds:rom_bios     ;
        mov     ax,equip        ; determine which adapter is active
        and     al,30H          ; isolate adapter information
        cmp     al,30H          ; is the mda active?
        jne     cga_active      ; no: setup for cga move
        mov     ax,mda          ; fix up DS to the MDA segment
        mov     ds,ax           ;
        assume  ds:mda
        jmp     change_pos      ; now move the block

cga_active:
        mov     ax,cga          ; fix up DS to the CGA segment
        mov     ds,ax           ;
        assume  ds:cga          ;

change_pos:
        mov     ax,curpos       ; first, remove the current inverse block
                                ;   and restore the original attributes
        mov     row,ah          ; row & col are value parameters for the
        mov     col,al          ;   calc_address procedure
        call    calc_address    ; calculate the address of curpos

        mov     bx,scraddr      ; the value is returned in SCRADDR
        mov     al,scrattr      ; put the old attributes for restoring in AL
        mov     byte ptr [bx+01],al

        mov     ax,newpos       ; load the new cursor position for calculation
        mov     row,ah          ; load row and col with the appropriate
        mov     col,al          ;   values
        call    calc_address    ; calculate the address of newpos

        mov     bx,scraddr      ; the value in returned in SCRADDR
        mov     al,byte ptr [bx+01]     ; get the attribute value
        mov     scrattr,al      ; store it in SCRATTR
        mov     al,inverse      ; load the inverse attr. value
        mov     byte ptr [bx+01],al     ; put it to the screen
        mov     ax,newpos       ; get the new position
        mov     curpos,ax       ; store it in CURPOS for a later call
;
        pop     ds              ; restore the registers
        pop     dx
        pop     cx
        pop     bx
        pop     ax
        ret                     ; let's go home
move_block      endp


;-----------------------------------------------------------------;
; INTERCEPT_VIDEO_INT - Near Procedure                            ;
;                                                                 ;
;    This procedure determines whether or not a change in cursor  ;
; position is being requested (AH=02H).  If not, then proceed as  ;
; usual, else allow the change, then update the position of the   ;
; inverse block.                                                  ;
;                                                                 ;
;     Calls:  MOVE_BLOCK                                          ;
;             OLD10                                               ;
;-----------------------------------------------------------------;

intercept_video_int     proc    near
;
        assume  ds:nothing
        pushf
        mov     cursor,0        ; set the case "cursor change?" to false (0)
        mov     newpos,dx       ; just in case it is a cursor change, store
                                ;   the value in newpos
        pushf                   ; save the flags
        cmp     ah,02H          ; is it a cursor change?
        jnz     not_cursor1     ; NO: don't set the true/false variable
        mov     cursor,1        ; YES: set CURSOR to true (1)
not_cursor1:
        popf                    ; restore the flags
        call    old10           ; do the cursor change
        mov     al,cursor       ; load the boolean value
        cmp     al,1            ; is this a cursor call?
        jnz     not_cursor2     ; no: exit via IRET
        call    move_block      ; yes: move the solid block

not_cursor2:
        iret                    ; do an interrupt return to caller

intercept_video_int    endp

;-----------------------------------------------------------------;
; MAKE_BLOCK - Near Procedure                                     ;
;                                                                 ;
;    This procedure initializes the value of CURPOS to the        ;
; current location of the cursor.  It also retrieves the          ;
; attributes from that location.                                  ;
;-----------------------------------------------------------------;

make_block      proc    near
        assume  ds:nothing
        push    ax              ; save the regs
        push    bx
        push    cx
        push    dx
        mov     ah,15           ; get current video state (active page in BH)
        int     10H
        mov     ah,03           ; get current cursor position on active page
        int     10H
        mov     curpos,dx       ; store this value for later
        mov     ah,08           ; get the attributes at the current position
        int     10H
        mov     scrattr,ah      ; store this value for later
        mov     ah,01           ; set the cursor "off" by setting the scan-
        mov     cx,0F0FH        ;   lines from 15 to 15, in CX
        int     10H
        pop     dx              ; restore the regs
        pop     cx
        pop     bx
        pop     ax
        ret                     ; return to caller
make_block      endp

;-----------------------------------------------------------------;
; FIX_INT - Near Procedure                                        ;
;                                                                 ;
;    This procedure initializes the interrupt vector for INT 10H  ;
; (the video interrupt), to point to our routine.  The old values ;
; in the table are stored in OLD10.                               ;
;                                                                 ;
;    Calls:  MAKE_BLOCK                                           ;
;            OLD10                                                ;
;-----------------------------------------------------------------;

fix_int proc    near
        call    make_block      ; set up the initial values for the 1st call
        mov     ax,vectors
        mov     ds,ax           ; set up data segment to vectors seg.
        assume  ds:vectors
        cli                     ; disable interrupts
        mov     ax,int10        ; save the address of the original INT 10H
        mov     old10,ax        ;  vector values in the doubleword OLD10
        mov     ax,int10[2]     ;
        mov     old10[2],ax     ;
        mov     int10,offset intercept_video_int
        mov     int10[2],cs
        sti                     ; enable interrupts
        mov     dx,offset fix_int
        int     27H             ; the TSR (Terminate but Stay Resident) int.
fix_int endp
code    ends
        end     start