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