	TITLE	SCRN - SCREEN SAVE RESIDENT UTILITY COMMAND, Version 2.2
	PAGE	60,132				  ; JAN 21, 1984
COMMENT |
ษอออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออป
บ	       Copyright (c), 1984 by J. T. Thannum		    บ
บ	       All rights reserved.  May be copied		    บ
บ	       for personal non-commercial use only.		    บ
ศอออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออผ

SCRN n
  [options]
	n - The Delay Interval in Minutes as a single Integer from 1 to 9
	    [Default: 10 Minutes]

SCRN is a screen saver utility command which operates using the Timer,
Video and Keyboard Interrupts to monitor activity of the system user.  Upon
detecting no entry via the keyboard OR output to the monitor(s) for "n" min.
the SCRN routine will turn off the video to all monitors attached to the
system.  The idea for this program originated from an article in Softalk,
Dec.  1983 by John Socha.  However, the version presented in this article
had several limitations which needed to be corrected for a viable
permanmently resident utility.	These limitations became the design
criteria for this version, as follows:

	1. Must turn "both" color and monochrome monitors off, not
	   just the active monitor on two monitor systems.
	2. Must function in a single monitor envirnoment with either
	   monitor attached.
	3. Must be extremely frugal in execution.  Since this routine
	   will be executed at each timer interrupt,or 18.2 times/sec,
	   and at each keyboard interrupt the routine must have the
	   minimum of overhead so as not to degrade system performance.
	4. Must be able blank background on color monitor as well as
	   foreground text or graphics.
	5. Should utilize the User Exit Interrupt provided in the
	   Timer Routine. [INT 1C] (This can be considered optional)
	6. Handle the blanking of the cursor on the Monochrome display
	   more efficiently.
	7. Output to the Monitor(s) should reset the timeout counter
	   within the delay window but not turn the video back on if
	   a timeout has occurred.
	8. Optional Parameter to set Delay Interval from 1 to 10 min.

(Special Note:	The Mode register definition shown in the Softalk article
		is incorrect as well as the referenced Enable Video bit.
		The program is correct as shown in the article.)

For efficiency and execution the Screen Saver program "hard codes"
addresses and uses its own routine to set adapter parameters.  However,
this hard coding is done via equates and because of the brevity of the
program this would cause only  minor problems if changes were required.

						J. T. Thannum
						Naperville, Ill 60540
|
		PAGE
;
; System Interrupt Vectors for BIOS and DOS
;	- TIMER_INT Routine User Exit [INT 1C] redirected by SCRN
;	- KB_INT Routine [INT 9] intercepted by SCRN
;	- VIDEO_INT Routine [INT 10] intercepted by SCRN
;
INT_VECTORS	SEGMENT AT 0
		ORG	9H*4
KB_INT		LABEL	DWORD		;KEYBOARD INTERRUPT
		ORG	10H*4
VIDEO_INT	LABEL	DWORD		;VIDEO I/O INTERRUPT
		ORG	1CH*4
TIMER_EXIT	LABEL	DWORD		;TIMER USER ROUTINE EXIT

INT_VECTORS	ENDS
;
; ROM BIOS Data Area
;
DATA		SEGMENT AT 40H
		ORG	10H
EQUIP_FLAG	DW	?		;EQUIPMENT INSTALLED IN SYSTEM
		ORG	60H
CURSOR_MODE	DW	?		;CURRENT CURSOR MODE FOR ACTIVE DISPLAY
		ORG	63H
ADDR_6845	DW	?		;BASE ADDRESS OF ACTIVE ADAPTER
CRT_MODE_SET	DB	?		;CURRENT SETTING OF 3x8 REGISTER
CRT_PALLETTE	DB	?		;CURRENT COLOR SETTINGS

DATA		ENDS
		PAGE
;
; SCRN - Screen Save Program Code Segment
;	-Main Procedures:
;		-TIMER_USER_ROUTINE - Processing at each Timer Interrupt to
;				      determine if video should be turned "off"
;		-KEYBOARD_INTERCEPT - Processing at each Keyboard interrupt to
;				      determine of video should be turned "on".
;				      Resets delay counter at each invocation.
;		-VIDEO_IO_INTERCEPT - Processing at each Video I/O interrupt to
;				      keep video on by resetting delay counter.
;		-INIT_PROC	    - Initialize program and make resident. Not
;				      retained in memory with resident portion
;		-CURSOR_SET	    - Subroutine to turn Monochrome Adapter
;				      cursor on and off
;
SCREEN_SAV	SEGMENT PUBLIC 'CODE'
		ASSUME	CS:SCREEN_SAV
;
; Program Segment Prefix
;	- Location of Command Parameters
;	- For Valid Parameter String the PARM_COUNT = 2 and the
;	  PARM_DATA byte will be 1 to 9 (31H to 39H ASCII)
;
		ORG	80H
PARM_COUNT	DB	?		;NO. OF CHARACTERS IN PARAMETER STRING
SPACE		DB	?
PARM_DATA	DB	?		;DELAY VALUE PARAMETER
;
		ORG	100H
BEGIN:		JMP	INIT_PROC		;INITIALIZE & MAKE RESIDENT
;
; Program Save Area for Interrupts and Data
;
BIOS_KB_INT	DD	?		;BIOS INTERRUPT POINTERS FOR KEYBOARD
BIOS_VIDEO_INT	DD	?		;BIOS INTERRUPT POINTERS FOR VIDEO I/O
BIOS_TIMER_EXIT DD	?		;BIOS INTERRUPT POINTERS FOR TIMER EXIT
VIDEO_STATUS	DB	8		;SET BIT 4 TO ONE - INITIALIZES AS "ON"
DELAY_VALUE	DW	2AA8H		;SETS DELAY INTERVAL - DEFAULT 10 MIN
DELAY_COUNTER	DW	2AA8H		;COUNTDOWN TIMER - INIT @ DEFAULT
MESSAGE 	DB	'Screen Saver, Ver. 2.2',CR,LF,'$'
;
; Equates
;
CR		EQU	0DH		;CARRIAGE RETURN
LF		EQU	0AH		;LINE FEED
VALID_COUNT	EQU	2		;VALID COMMAND PARAMETER STRING COUNT
DELAY_1_MIN	EQU	444H		;DELAY INTERVAL FOR 1 MINUTE
VIDEO_OFF	EQU	8		;TEST VALUE FOR VIDEO OFF BIT
MONO_CUR_OFF	EQU	2B0CH		;VALUES TO WRITE TO CURSOR REGISTERS
MONO_CUR_ON	EQU	0B0CH		;    TO TURN CURSOR "ON" AND "OFF"
COLOR_MODE_REG	EQU	3D8H		;ADDRESSES FOR EACH ADAPTERS
MONO_MODE_REG	EQU	3B8H		;    6845 MODE REGISTER
ADDR_6845_MONO	EQU	3B4H		;MONOCHROME ADAP.- 6845 ADDRESS REGISTER
COLOR_SEL_REG	EQU	3D9H		;COLOR ADAP.- 6845 COLOR SELECT REGISTER
REG_10		EQU	10		;CURSOR START REGISTER - CURSOR ENABLE
REG_11		EQU	11		;CURSOR END   REGISTER
DEF_MODE_ON	EQU	29H		;DEFAULT CRT_MODE_SET FOR VIDEO ENABLED
DEF_MODE_OFF	EQU	21H		;   "     "    "   "   "    "  DISABLED
COLOR_ACTIVE	EQU	10H		;TEST FOR ACTIVE MONITOR ADAPTER
BG_BLACK	EQU	0FH		;TEST FOR BLACK BACKGROUND SETTING
		PAGE
;
; Timer Exit Routine - Determines if video should be turned off
;	-Uses INT 1C, but chains interrupt in the event additional user routines
;	 are installed
;
TIMER_USER_ROUTINE  PROC NEAR
		ASSUME CS:SCREEN_SAV,DS:DATA
		PUSH	AX
		PUSH	DS
		MOV	AX,DATA 		;ESTABLISH DATA SEGMENT
		MOV	DS,AX
		TEST	VIDEO_STATUS,VIDEO_OFF	;IS VIDEO, OFF?
		JZ	EXIT_TIMER		;  YES, NO ACTION IS REQUIRED
		DEC	DELAY_COUNTER		;HAS DELAY TIME ELAPSED?
		JNZ	EXIT_TIMER		;  NO, THEN NO ACTION IS REQ'D
;
		CLI
		PUSH	DX
		PUSH	CX
;
; Turn Monochrome Video OFF including Cursor
;
		MOV	DX,MONO_MODE_REG ;SET OUTPUT TO MODE REGISTER,
		MOV	AL,DEF_MODE_OFF  ;  GET DATA TO OUTPUT
		OUT	DX,AL		 ;  THEN TURN OFF WITH DEFAULT MODE
		MOV	CX,MONO_CUR_OFF  ;SET TO TURN CURSOR OFF,
		CALL	CURSOR_SET	 ;  THEN CALL ROUTINE TO DO IT
;
; Turn Color Video OFF
;
		TEST	EQUIP_FLAG,COLOR_ACTIVE ;IS COLOR DISPLAY ACTIVE?
		JZ	GET_MODE		;  YES, THEN GET CURRENT MODE
		MOV	AL,DEF_MODE_OFF 	;  NO,	THEN USE DEFAULT MODE
		JMP	SHORT CONT
GET_MODE:	MOV	AL,CRT_MODE_SET 	;CURRENT ACTIVE MODE SETTING
		AND	AL,0F7H 		;TURN VIDEO ENABLE BIT OFF
		MOV	CRT_MODE_SET,AL 	;SAVE NEW MODE SETTING
CONT:		MOV	DX,COLOR_MODE_REG	;GET ADDRESS OF MODE REGISTER
		OUT	DX,AL			; THEN OUTPUT TO TURN VIDEO OFF
		TEST	CRT_PALLETTE,BG_BLACK	;IS BACKGROUND COLOR BLACK?
		JZ	DONE			;  YES, THEN DONE
		MOV	AL,CRT_PALLETTE 	;  ELSE, GET CURRENT PALLETTE
		AND	AL,0F0H 		;SET FOR BLACK BACKGROUND
		MOV	DX,COLOR_SEL_REG	;GET ADDR OF COLOR SELECT REG
		OUT	DX,AL			;SET BACKGROUND TO BLACK
DONE:		AND	VIDEO_STATUS,0F7H	;SET VIDEO STATUS "OFF"
		POP	CX
		POP	DX
		STI
EXIT_TIMER:	POP	DS
		POP	AX
		JMP	BIOS_TIMER_EXIT 	;CHAIN TO NEXT ROUTINE OR EXIT
						; TO FINISH TIMER INTERRUPT
TIMER_USER_ROUTINE	ENDP
		PAGE
;
; Keyboard Intercept Routine
;	-Intercepts Keyboard INT 9, checks if video should be turned on
;	 then chains to normal keyboard processing
;
KEYBOARD_INTERCEPT PROC NEAR
		ASSUME CS:SCREEN_SAV,DS:DATA
		PUSH	AX
		PUSH	DS
		MOV	AX,DATA 		;ESTABLISH DATA SEGMENT
		MOV	DS,AX
		MOV	AX,DELAY_VALUE		;RESET,
		MOV	DELAY_COUNTER,AX	;  DELAY COUNTER
		TEST	VIDEO_STATUS,VIDEO_OFF	;IF VIDEO IS ON,
		JNZ	EXIT_KB 		;  EXIT, NO ACTION IS REQUIRED
;
		CLI
		PUSH	DX
		PUSH	CX
;
; Turn Monochrome Video ON including Cursor
;
		MOV	DX,MONO_MODE_REG ;SET OUTPUT TO MODE REGISTER,
		MOV	AL,DEF_MODE_ON	 ;  GET DATA TO OUTPUT,
		OUT	DX,AL		 ;  THEN TURN OFF WITH DEFAULT MODE
		MOV	CX,MONO_CUR_ON	 ;SET TO TURN CURSOR ON,
		CALL	CURSOR_SET	 ;  THEN CALL ROUTINE TO DO IT
;
; Turn Color Video ON
;
		TEST	EQUIP_FLAG,COLOR_ACTIVE ;IS COLOR DISPLAY ACTIVE?
		JZ	GET_MODE1		;  YES, THEN GET CURRENT MODE
		MOV	AL,DEF_MODE_ON		;  NO,	THEN USE DEFAULT MODE
		JMP	SHORT CONT1
GET_MODE1:	MOV	AL,CRT_MODE_SET 	;CURRENT ACTIVE MODE SETTING
		OR	AL,8			;TURN VIDEO ENABLE BIT ON
		MOV	CRT_MODE_SET,AL 	;SAVE NEW MODE SETTING
CONT1:		MOV	DX,COLOR_MODE_REG	;GET ADDRESS OF MODE REGISTER
		OUT	DX,AL			; THEN OUTPUT TO TURN VIDEO ON
		TEST	CRT_PALLETTE,BG_BLACK	;IS BACKGROUND COLOR BLACK?
		JZ	DONE1			;  YES, THEN DONE
		MOV	AL,CRT_PALLETTE 	;  ELSE, GET CURRENT PALLETTE
		MOV	DX,COLOR_SEL_REG	;GET ADDR OF COLOR SELECT REG
		OUT	DX,AL			;RESTORE BACKGROUND COLOR
DONE1:		OR	VIDEO_STATUS,8		;SET VIDEO STATUS "ON"
		POP	CX
		POP	DX
		STI
EXIT_KB:	POP	DS
		POP	AX
		JMP	BIOS_KB_INT		;CHAIN TO NEXT ROUTINE OR EXIT
						; TO FINISH TIMER INTERRUPT
KEYBOARD_INTERCEPT	ENDP
		PAGE
;
; Video I/O Intercept Routine
;	-Intercepts Video I/O INT 10H, resets the delay counter
;	 then chains to normal Video I/O processing
;
VIDEO_IO_INTERCEPT PROC NEAR
		ASSUME CS:SCREEN_SAV,DS:NOTHING
		PUSH	AX
		MOV	AX,DELAY_VALUE		;RESET,
		MOV	DELAY_COUNTER,AX	;  DELAY COUNTER
		POP	AX
		JMP	BIOS_VIDEO_INT		;CHAIN TO VIDEO I/O INTERRUPT
						; PROCESSING
VIDEO_IO_INTERCEPT	ENDP
;
; Subroutine to Turn Monochrome Adapter Cursor ON or OFF
;
CURSOR_SET	PROC	NEAR
		ASSUME	CS:SCREEN_SAV,DS:DATA
		MOV	DX,ADDR_6845_MONO	;SET TO WRITE ADDRESS REGISTER,
		MOV	AL,REG_10		;  SELECT CURSOR START REGISTER
		OUT	DX,AL			;  OUTPUT REGISTER SELECTION
		INC	DX			;POINT TO 6845 DATA REGISTER
		MOV	AL,CH			;GET CURSOR START VALUE, THEN
		OUT	DX,AL			;  SET START REGISTER
		DEC	DX			;POINT BACK TO ADDRESS REGISTER
		MOV	AL,REG_11		;  SELECT CURSOR END REGISTER
		OUT	DX,AL			;  OUTPUT REGISTER SELECTION
		INC	DX			;POINT AGAIN TO DATA REGISTER
		MOV	AL,CL			;GET CURSOR END VALUE, THEN
		OUT	DX,AL			;  SET END REGISTER
		RET
CURSOR_SET	ENDP
		PAGE
;
; Initialize Screen Save Program and Make Resident
;
INIT_PROC	PROC	NEAR
		ASSUME	DS:INT_VECTORS
		MOV	AX,INT_VECTORS
		MOV	DS,AX
		PUSH	ES
		CLI
		LES	AX,KB_INT		;SAVE KB_INT
		MOV	BIOS_KB_INT,AX		;  POINTERS TO
		MOV	BIOS_KB_INT[2],ES	;      BIOS KEYBOARD ROUTINE
		MOV	KB_INT,OFFSET KEYBOARD_INTERCEPT  ;SET KEYBOARD INT
		MOV	KB_INT[2],CS			  ;  TO POINT HERE
;
		LES	AX,VIDEO_INT		;SAVE VIDEO_INT
		MOV	BIOS_VIDEO_INT,AX	;  POINTERS TO
		MOV	BIOS_VIDEO_INT[2],ES	;      BIOS VIDEO I/O ROUTINE
		MOV	VIDEO_INT,OFFSET VIDEO_IO_INTERCEPT  ;SET VIDEO I/O INT
		MOV	VIDEO_INT[2],CS 		     ;	TO POINT HERE
;
		LES	AX,TIMER_EXIT		;SAVE ANY OTHER USER
		MOV	BIOS_TIMER_EXIT,AX	;  ROUTINE USING
		MOV	BIOS_TIMER_EXIT[2],ES	;      TIMER EXIT
		MOV	TIMER_EXIT,OFFSET TIMER_USER_ROUTINE ;SET TIMER EXIT
		MOV	TIMER_EXIT[2],CS		     ;	TO POINT HERE
;
		CMP	PARM_COUNT,VALID_COUNT	;CHECK FOR OPTIONS
		JNZ	DEFAULT 		;  NONE, USE DEFAULT OF 10 MIN
		MOV	AL,PARM_DATA		;GET DELAY OPTION AND
		AND	AX,000FH		;  CONVERT ASCII TO BINARY
		MOV	BX,DELAY_1_MIN		;LOAD DELAY VALUE FOR 1 MIN
		MUL	BX			;CALCULATE DELAY VALUE
		MOV	DELAY_VALUE,AX		;SAVE DELAY VALUE
		MOV	DELAY_COUNTER,AX	;SET DELAY COUNTER
DEFAULT:	STI
		ASSUME	DS:SCREEN_SAV
		MOV	AX,CS
		MOV	DS,AX
		MOV	DX,OFFSET MESSAGE	;PRINT INTRO
		MOV	AH,9
		INT	21H
		MOV	DX,OFFSET INIT_PROC	;END OF RESIDENT PORTION
		INT	27H			;  TERMINATE AND STAY RESIDENT
INIT_PROC	ENDP
SCREEN_SAV	ENDS
		END	BEGIN
