home *** CD-ROM | disk | FTP | other *** search
-
- page 60,132
-
- ; Copyright (C) 1988 Mark Adler Pasadena, CA
- ; All rights reserved.
-
- title ZAP - screen saver for the EGA or VGA
-
- comment #
-
- Version history -
-
- 1.0 18 Nov 1988 First public version
- 1.1 14 Dec 1988 Fixed bug in EGAZAP
-
-
- ZAP -
-
- ZAP is a resident utility that blanks the screen after a specified
- period of inactivity. The ZAP.ASM program actually generates two
- different programs depending on the assembler options: EGAZAP and
- VGAZAP. The first is for the IBM Enhanced Graphics Adapter or
- compatibles, and the second is for IBM PS/2's, the IBM Video Graphics
- Adpater, and comaptibles. From here on, ZAP will be used to mean
- EGAZAP or VGAZAP, whichever is appropriate for your hardware.
-
- To install ZAP, simply put the command ZAP in your AUTOEXEC.BAT file.
- From then on, when there is five minutes of inactivity at the
- keyboard, ZAP will blank the screen until any key (even just a shift
- key) is hit. The time can be changed with a command line option which
- specifies the time in seconds. For example:
-
- zap 600
-
- will install ZAP (if not already installed) and change the time to 10
- minutes.
-
- You can also turn the installed ZAP on and off using ZAP. For example:
-
- zap off
-
- will turn off the installed ZAP, so it will not blank the screen. Then
- the command:
-
- zap on
-
- will turn ZAP back on.
-
- ZAP can also be installed in the "off" state, awaiting a "zap on"
- command, simply by using:
-
- zap off
-
- in AUTOEXEC.BAT. You can also specify on or off along with a new
- inactivity time. For example, the command:
-
- zap off 600
-
- in AUTOEXEC.BAT will install ZAP in the off state with a 10 minute
- inactivity time. Then a subsequent "zap on" will turn it on. The time
- must be in the range of one to 3600 seconds (one hour). Specifying a
- new time does not change whether ZAP is enabled or not and turning ZAP
- on or off does not change the time. Also, the two options can be in
- either order. For example, "zap 600 off" does the same thing as the
- example above. If ZAP is already installed, subsequent invocations of
- ZAP will not install it again. If the command:
-
- zap
-
- is entered after ZAP is already installed, this has the same effect as
- the command "zap on", that is it turns on ZAP if it was off.
-
- ZAP turns the display back on not only when any key is hit, but also if
- any video BIOS calls (int 10h) are made. Since most application
- programs seem to bypass the BIOS for video, this added feature has
- little effect.
-
- There are a few, rare programs that also completely take the keyboard
- from the BIOS, in which case ZAP can no longer find out when keystrokes
- occur. An example is STSC APL (a programming language). In this case,
- ZAP will blank your display, even though you have been merrily typing
- away for the last five minutes in the application. And the only way to
- get the display back on is to return to DOS (assuming you can get out
- while driving the application blindfolded). For such applications, you
- should include the commands "zap off" and "zap on" in a batch file that
- runs the application to disable ZAP before entering and enabling ZAP
- after leaving the application. You will quickly discover if you have
- any such applications.
-
- This program assumes that the current display is the (only) active
- display, but does not check for it either at installation or when
- running.
-
- For the EGA, the screen is blanked by setting the number of characters
- displayed to one, and the start of horizontal blanking to the first
- character. The number of displayed characters needs to be small (set
- to one for convenience) since the horizontal blanking interval is
- limited to 32 characters. The screen is restored by getting the
- current screen mode information from the BIOS and from that and the
- table of Start Horizontal Blanking values in this program (copied from
- the BIOS listing---not entirely kosher, but the only decent approach),
- the proper register values are restored.
-
- For the VGA, the screen is blanked and restored using the Screen Off
- bit in the Clocking Mode Register (port 0x3c4, address 01, bit 5).
-
- To minimize the resident memory required, this program is assembled
- separately for the EGA or VGA. When assembling, define the symbol EGA
- or VGA in the command line using /d (see the manual for MASM or TASM).
- If no symbol is defined, you will be warned and the resulting .COM file
- will be asssembled for the VGA. For example, the commands:
-
- tasm /dega zap
- tlink /t zap,egazap
- tasm /dvga zap
- tlink /t zap,vgazap
-
- will generate EGAZAP.COM and VGAZAP.COM, assuming that you have the
- Borland Turbo Assembler.
-
- The fact that the number of bytes in VGAZAP (666) is the same as
- Reagan's retirement home's address in Bel Air should be given no
- religious significance.
-
- #
-
- ifndef VGA
- ifndef EGA
- %out !No display specified---assembling for the VGA.
- endif
- endif
-
- ;
- ; Macros for blanking screens.
- ;
-
- egaoff macro
- local ismono,CRTMON,CRTCOL
- CRTMON equ 03B4h ;;CRT controller register in Mono mode.
- CRTCOL equ 03D4h ;;CRT controller register in Color mode.
- push AX ;;Save registers.
- push BX
- push CX
- push DX
- mov AH,12h ;;Get Mono/Color in BH.
- mov BL,10h
- pushf ;;Do Int 10h
- push CS
- call altvid
- mov DX,CRTMON ;;Point DX to CRT port in Mono mode.
- test BH,BH ;;See if color mode.
- jnz ismono ;;If not, then DX is correct.
- mov DX,CRTCOL ;;If color, use color address.
- ismono:
- mov AX,1 ;;Set number of characters to 1.
- out DX,AX
- inc AX ;;Set horizontal start of blanking to char 0.
- out DX,AX
- pop DX ;;Restore registers.
- pop CX
- pop BX
- pop AX
- endm
-
- egaon macro
- local ismono,enhance,shbget,tbl,CRTMON,CRTCOL
- CRTMON equ 03B4h ;;CRT controller register in Mono mode.
- CRTCOL equ 03D4h ;;CRT controller register in Color mode.
- ;;
- ;; Restore the display by getting the correct register values and
- ;; setting them.
- ;;
- ;; save registers used by routine, except AX.
- push BX
- push CX
- push DX
- ;; get CRT port, switch setting.
- mov AH,12h ;;Get switch setting into CL, Mono/Color in BH.
- mov BL,10h
- pushf ;;Do Int 10h
- push CS
- call altvid
- mov DX,CRTMON ;;Point DX to CRT port in Mono mode.
- test BH,BH ;;See if color mode.
- jnz ismono ;;If not, then DX is correct.
- mov DX,CRTCOL ;;If color, use color address.
- ismono:
- ;; get values for CRT registers 1 and 2.
- mov AH,0Fh ;;Get mode into AL, columns into AH.
- pushf ;;Do Int 10h
- push CS
- call altvid
- dec AH ;;Compute Horizontal Display End setting (1).
- cmp AL,3 ;;See if color mode.
- ja shbget ;;If not, go on to get Start Horiz Blank (2).
- cmp CL,3 ;;See if in secondary enhanced mode.
- je enhance ;;If so, use enhanced 0-3 settings.
- cmp CL,9 ;;See if in primary enhanced mode.
- jne shbget ;;If not, use normal 0-3 settings.
- enhance:
- add AL,11h ;;Add offset for table.
- shbget:
- mov BX,(offset trap)+(tbl-set) ;;Point to table.
- xlat byte ptr CS:tbl ;;Get Start Horizontal Blank setting.
- ;; Now AH is CRT register 1, AL is register 2 - set them.
- mov CL,AL ;;Save register 2 setting.
- mov AL,1 ;;Set register 1.
- out DX,AX
- mov AH,CL ;;Get register 2 setting.
- inc AX ;;Set register 2.
- out DX,AX
- ;; done, restore registers and return.
- pop DX
- pop CX
- pop BX
- ret
- ;;Start horiz blank values for modes 0-10, 0*-3*.
- tbl label byte
- db 2Dh,2Dh,5Ch,5Ch,2Dh,2Dh,59h,56h ;;0-7.
- db 2Dh,2Dh,2Dh,5Ch,56h,2Dh,59h,56h,53h ;;8-10h.
- db 2Bh,2Bh,53h,53h ;;0*-3*.
- endm
-
- vgaoff macro
- local CRTSEQ
- CRTSEQ equ 03C4h ;;CRT Sequencer register set.
- push AX ;;Save registers.
- push DX
- mov DX,CRTSeq ;;Sequencer registers.
- mov AL,1 ;;Point to Clocking Mode register.
- out DX,AL
- inc DX
- in AL,DX ;;Get current value.
- or AL,020h ;;Turn on Screen Off bit.
- out DX,AL
- pop DX ;;Restore registers.
- pop AX
- endm
-
- vgaon macro
- local CRTSEQ
- CRTSEQ equ 03C4h ;;CRT Sequencer register set.
- ;; save registers used by routine, except AX.
- push DX
- ;; turn Screen Off bit off.
- mov DX,CRTSEQ ;;Sequencer registers.
- mov AL,1 ;;Point to Clocking Mode register.
- out DX,AL
- inc DX
- in AL,DX ;;Get current value.
- and AL,0DFh ;;Turn off Screen Off bit.
- out DX,AL
- ;; done, restore registers and return.
- pop DX
- ret
- endm
-
-
- ;
- ; Interrupt vector segment definitions.
- ;
-
- ints segment at 0
- dummy label far
- org 8*4 ;Point to Int 8 (tick) vector.
- int8 label word
- org 9*4 ;Point to Int 9 (scan) vector.
- int9 label word
- org 10h*4 ;Point to Int 10h (video) vector.
- int10 label word
- ints ends
-
-
- ;
- ; Program segment.
- ;
-
- zap segment
- assume CS:zap,DS:zap,ES:zap,SS:zap
-
- ;
- ; Put service code as low as DOS will allow.
- org 5Ch
- time dw ? ;Time before blanking in ticks.
- count dw ? ;Tick countdown.
- trap label word ;Location for interrupt traps.
-
- ;
- ; Partially parsed command line.
- org 5Ch
- f1 db 12 dup(?)
- org 6Ch
- f2 db 12 dup(?)
-
- ;
- ; Constants.
- DTIME equ 5462 ;Default time of about five minutes.
-
- ;
- ; Start of .COM code - jump to installation.
- org 100h
- start:
- jmp cpyrt
- db 13,'ZAP version 1.0 Copyright (C) 1988 Mark Adler',13,10
- db 'All rights reserved.',13,10,'Z'-64
- cpyrt:
- ;
- ; process arguments.
- cld ;This stays in effect for the whole program.
- mov onoff,1 ;Set ZAP to on.
- mov id,'Z' ;So we don't find COM file in a buffer.
- mov BX,offset f1
- call chknon ;See if no arg.
- je afin
- call chkoff ;Have first arg---see if on or off.
- je do2
- call chknum ;Not on or off---see if number.
- jz erra ;If no number there, then bad args.
- do2:
- mov BX,offset f2
- call chknon ;See if second arg.
- je afin
- call chkoff ;Have second arg---see if on or off.
- je aok
- call chknum ;Not on or off---see if number.
- jz erra ;If no number there, then bad args.
- aok:
- afin:
-
- ; look to see if ZAP is installed yet.
- mov DX,DS ;Start checking backwards from this segment.
- assume ES:nothing
- search:
- dec DX
- jz nowhere ;If at bottom of memory, then it ain't loaded.
- mov SI,offset id ;Point DS:SI to id string to look for.
- mov ES,DX ;Point ES:DI to where to look.
- sub DI,DI ;The id string should be on a 16 byte boundary.
- mov CX,idlen
- repe cmpsb
- jne search ;If no match, look one back.
- ; now ES:DI point to byte after id.
- mov AL,onoff ;Set enable byte of ZAP.
- stosb
- add DI,16-(1+idlen+4) ;Point to time and count.
- dec DX
- mov ES,DX
- mov AX,newtime ;Get time setting.
- test AX,AX ;See if it is a new setting.
- jnz usenew
- mov AX,ES:[DI] ;If no new setting, use old setting.
- usenew:
- stosw
- stosw ;Reset count as well.
- mov AH,0Fh ;Turn display on in case it's off.
- int 10h ;(dummy int 10 call.)
- int 20h ;Done.
-
- ; ZAP not installed---install with specified options.
- nowhere:
- mov AX,DS ;Restore ES.
- mov ES,AX
- assume ES:zap
- mov AL,onoff ;Get on/off setting.
- mov enbl,AL ;Put in enbl flag in traps before moving.
- mov AX,newtime ;Set time and count.
- test AX,AX
- jnz timok
- mov AX,DTIME ;Get default time (five minuntes).
- timok:
- mov time,AX
- mov count,AX
- jmp copy ;Go set up traps and stay resident.
-
- erra:
- mov DX,offset err2
- jmp short errx
-
- chknon proc near
- mov SI,BX
- mov DI,offset snone
- mov CX,6
- repe cmpsw
- ret
- chknon endp
-
- chkoff proc near
- ; Compare [BX] with soff and son, return NE if neither match.
- mov SI,BX
- mov DI,offset soff
- mov CX,6
- repe cmpsw
- jne noff
- mov onoff,0
- ret
- noff:
- mov SI,BX
- mov DI,offset son
- mov CX,6
- repe cmpsw
- ret
- chkoff endp
-
- chknum proc near
- lea SI,[BX+1] ;Point to arg (BX loaded already).
- sub BX,BX ;Initial value.
- mov DI,10 ;Base for decimal.
- mov CX,8 ;Digits allowed in name.
- numlp:
- lodsb
- sub AL,'0'
- jb nend
- cmp AL,9
- ja nend
- cbw
- xchg AX,BX
- mul DI
- add BX,AX
- loop numlp
- nend:
- test BX,BX ;See if got a value.
- jz nret ;If not, just return.
- mov AX,91 ;Multiply by 18.2.
- mul BX
- shr DI,1 ;Put 5 in DI.
- cmp DX,DI
- jae errn ;If number of seconds too high, then error.
- div DI ;18.2 = 91/5.
- cmp DX,3 ;See if need to round up.
- jb rdown ;If remainder 0, 1, or 2, then round down.
- inc AX ;Else, round up.
- rdown:
- mov newtime,AX ;(Note, Z flag is false here.)
- nret:
- ret ;Return NZ if got a valid time.
- chknum endp
-
- errn:
- mov DX,offset err1
- errx:
- mov AH,9
- int 21h
- int 20h
-
- err1 db '?Seconds out of range---must be in 1..3600',13,10,'$'
- err2 db '?Invalid argument---can be "on", "off", or time'
- db 10,13,'$'
-
- soff db 0,'OFF '
- son db 0,'ON '
- snone db 0,' '
- newtime dw 0
- onoff db 1
-
- ;
- ; Traps - only assume CS points here.
- assume DS:nothing,ES:nothing,SS:nothing
- set: ;Traps.
-
- id db ' APTSR'
- idlen equ $-id
- enbl db 1 ;Enable flag.
-
- tick:
- ;
- ; Timer tick action - if tick count not at already at zero, decrement
- ; it. If this makes the count zero, blank the screen.
- ;
- cmp byte ptr trap+(enbl-set),1 ;See if enabled.
- jne tfin ;If not, skip this.
- cmp count,0 ;See if count at zero.
- je tfin ;If so, don't decrement.
- dec count ;Decrement tick count.
- jnz tfin ;Wait until counts down to zero.
- ; disable display.
- ifdef EGA
- egaoff
- else
- vgaoff
- endif
- ; go on to service routine.
- tfin:
- jmp dummy ;Go on to service routine.
- tvec equ $-4 ;Address in jmp.
-
- scan:
- ;
- ; Keyboard scan code action - reset the count to the maximum. If the
- ; count was zero, then the screen is blanked. In that case, restore
- ; the display.
- ;
- push AX
- cmp count,0 ;See if count at zero.
- jne sfin ;If not, just reset count.
- call don ;Display blanked - restore it.
- sfin:
- mov AX,time
- mov count,AX ;Reset count.
- pop AX
- jmp dummy ;Go on to service routine.
- svec equ $-4 ;Address in jmp.
-
- vid:
- ;
- ; Video service request action - reset the count to the maximum. If
- ; the count was zero, then the screen is blanked. In that case,
- ; restore the display.
- ;
- push AX
- cmp count,0 ;See if count at zero.
- jne vfin ;If not, just reset count.
- call don ;Display blanked - restore it.
- vfin:
- mov AX,time
- mov count,AX ;Reset count.
- pop AX
- altvid: ;(For using Int 10h within these routines.)
- jmp dummy ;Go on to service routine.
- vvec equ $-4 ;Address in jmp.
-
-
- don:
- ifdef EGA
- egaon
- else
- vgaon
- endif
-
- setlen equ $-set ;End of traps.
-
-
- ;
- ; Installation code - all segment registers set.
- assume DS:zap,ES:zap,SS:zap
-
- copy:
- ;
- ; Install traps and tell DOS to leave them in memory.
- ;
- ; copy traps to lower memory.
- mov SI,offset set
- mov DI,offset trap
- mov CX,setlen
- rep movsb ;Assume direction flag cleared.
- ; set up to insert traps into interrupt vectors.
- sub AX,AX
- mov ES,AX ;Point to interrupt area.
- assume ES:ints
- cli ;Disable interrupts during change.
- ; insert trap in timer tick interrupt vector.
- mov AX,int8 ;Get old vector.
- mov trap+(tvec-set),AX ;Put in jump instruction.
- mov AX,int8+2
- mov trap+(tvec+2-set),AX
- mov AX,offset trap+(tick-set)
- mov int8,AX ;Change Int 8 to the trap.
- mov AX,CS
- mov int8+2,AX
- ; insert trap in keyboard scan code interrupt vector.
- mov AX,int9 ;Get old vector.
- mov trap+(svec-set),AX ;Put in jump instruction.
- mov AX,int9+2
- mov trap+(svec+2-set),AX
- mov AX,offset trap+(scan-set)
- mov int9,AX ;Change Int 9 to the trap.
- mov AX,CS
- mov int9+2,AX
- ; insert trap in video service interrupt vector.
- mov AX,int10 ;Get old vector.
- mov trap+(vvec-set),AX ;Put in jump instruction.
- mov AX,int10+2
- mov trap+(vvec+2-set),AX
- mov AX,offset trap+(vid-set)
- mov int10,AX ;Change Int 10h to the trap.
- mov AX,CS
- mov int10+2,AX
- ; tell DOS to keep the traps in memory and exit.
- sti ;Interrupts OK now.
- mov DX,offset trap+setlen ;Amount to keep.
- int 27h ;Exit and remain resident.
-
- zap ends
-
- end start
-