
               PAGE     60,132
               TITLE    SCROLLCK - Use Scroll Lock key on keyboard
;------------------------------------------------------------------------
; This program intervcepts calls to the VIDEO_IO routines.  Commands to
; scroll the screen will be intercepted; all others passed through.  This
; routine is attached to DOS.
;------------------------------------------------------------------------
VECTORS        SEGMENT AT 0
               ORG     10H*4
VIDEO_INT      LABEL   DWORD
               ORG     16H*4
KEYBOARD_INT   LABEL   DWORD
VECTORS        ENDS

;------------------------------------------------------------------------
; ROM BIOS data area for keyboard
;
; Contents of KB_FLAG;
;<---   ---   ---   ---   ---   ---   ---   ---   ---   ---   --->
;   ^INS_STATE   ^NUM_STATE   ^ALT_SHIFT    ^LEFT_SHIFT
;       ^CAPS_STATE     ^SCROLL_STATE   ^CTL_SHIFT    ^RIGHT_SHIFT
;------------------------------------------------------------------------
ROM_BIOS_DATA  SEGMENT AT 40H
               ORG     17H
KB_FLAG        DB      ?               ;Bit 4 set for scroll lock
ROM_BIOS_DATA  ENDS
;-------------------------------
;Initialize vectors and attach to DOS
;-------------------------------
CSEG           SEGMENT PARA
               ASSUME  CS:CSEG
               ORG     100H            ;Set starting point for a COM file
BEGIN:         JMP     INIT_VECTORS    ;Initialize INT 10H vector and attach to DOS

;------------------------------------------------------------------------
;These memory locations store the addresses of the ROM routines for video and keybd IO
;------------------------------------------------------------------------
ROM_VIDEO_IO       DD                  ;Address of the ROM routines
ROM_KEYBOARD_IO    DD
SCROLL_COUNT       DB  0               ;Number of lines scrolled since last pause
LAST_LOCK_STATE    DB  0               ;0 if scroll lock off last time checked
MAX_LINES          DB  23              ;at the top of the screen
LAST_LINE          DB                  ;Last line the cursor was on
;------------------------------------------------------------------------
;This routine intercepts all calls to the VIDEO_IO routine in the ROM.
;Scroll Lock:
;      OFF       This routine passes control directly to the ROM BIOS
;                routine.
;      ON        Functions other than SCROLL UP or SCROLL DOWN are
;                passed directly to the ROM routines.  Otherwise, this
;                routine increments the scroll count and checks to see
;                if it exceeds the page size of 28 lines.  If so, loop
;                until either shift key pressed.
;                      left shift allows scroll of whole window
;                      right shift of one line.
;------------------------------------------------------------------------

 INTERCEPT_VIDEO       PROC    FAR
               ASSUME  CS:CSEG
               STI                     ;Turn on interrupts again
               PUSH    DS              ;Save registers used
               PUSH    BX
               PUSH    AX

               ASSUME  DS:ROM_BIOS_DATA
               MOV     BX,ROM_BIOS_DATA
               MOV     DS,BX
               MOV     AL,KB_FLAG      ;Check state of scroll lock key
               AND     AL,10H          ;Pick off scroll lock bit
               ASSUME  DS:CSEG
               MOV     BX,CS           ;Data segment for variables (above)
               MOV     DS,BX
               CMP     AL,LAST_LOCK_STATE
               JE      UN_CHANGED      ;Scroll lock key hasn't changed
               MOV     BL,MAX_LINES    ;Scroll-lock key has changed, set
               MOV     SCROLL_COUNT,BL ;to MAX_LINES to stop scrolling
               MOV     LAST_LOCK_STATE,AL ;Save the new scroll lock state
               PUSH    CX              ;Now read current cursor position and
               PUSH    DX              ;save in LAST_LINE so SCROLLK won't
               PUSH    AX              ;freeze in the middle of a line
               MOV     AH,3
               MOV     BH,0
               PUSHF
               CALL    ROM_VIDEO_IO    ;Find old cursor position
               MOV     LAST_LINE,DH    ;and save in LAST_LINE
               POP     AX
               POP     DX
               POP     CX
UN_CHANGED:
               XCHG    AX,BX           ;Recover function (AH) and retain scroll lock
               POP     AX
               OR      BL,BL           ;Is scroll lock on?
               JZ      TO_VIDEO_IO     ;No, jump to the ROM video_IO routine
               ;---------------------------------
               ;Scroll Lock on
               ;---------------------------------
               CMP     AH,2             ;Check for SET CUROR POSITION function
               JNE     NOPE
               CMP     DH,LAST_LINE     ;Is the cursor being moved to the next line?
               MOV     LAST_LINE,DH     ;Save new cursor line
               JLE     TO_VIDEO_IO      ;No, jump to ROM routine
               JMP     SHORT CHECK_LOCK         ;Yes, see if we need lock
NOPE:          CMP     AH,6             ;Scroll up?
               JNE     TO_VIDEO_IO      ;No, go to ROM routines
CHECK_LOCK:
               INC     SCROLL_COUNT     ;Take care of scroll lock
               MOV     BH,MAX_LINES
               CMP     SCROLL_COUNT,BH  ;Have we scrolled more than MAX_LINES
               JL      TO_VIDEO_IO      ;Nope, it's ok to scroll
                                        ;Yes, can't scroll until one of shift keys hit
               MOV     BL,BH            ;Set SCROLL_COUNT to MAX_LINES-1
               DEC     BL               ;so we can print one more line
               MOV     SCROLL_COUNT,BL
               ASSUME  DS:ROM_BIOS_DATA
               MOV     BX,ROM_BIOS_DATA
               MOV     DS,BX
LOOP:          MOV     BL,KB_FLAG       ;Wait until left or right shift key pressed
               TEST    BL,10H           ;Is scroll lock still on?
               JZ      TO_VIDEO_IO
               AND     BL,3             ;Pick off shift key info
               JZ      LOOP             ;Stay in loop until shift key pushed down
               CMP     BL,1             ;Right shift key hit?
               JE      SCROLL_LINE      ;Yes, allow scroll of one line
                                  ;No, must be right shift key, so reset scroll count
               XOR     BX,BX
               MOV     SCROLL_COUNT,BL
SCROLL_LINE:

TO_VIDEO_IO:
               POP     BX               ;Restore BX register
               PUSHF
               CALL    ROM_VIDEO_IO
               POP     DS
               IRET                     ;Return
INTERCEPT_VIDEO                ENDP

;------------------------------------------------------------------------
;If the keyboard function calls for a read (AH = 0) then reset the scroll count
;------------------------------------------------------------------------
INTERCEPT_KEYBOARD             PROC    FAR
               ASSUME  CS:CSEG,DS:CSEG
               STI                      ;Turn interrupts back on
               PUSH    DS               ;Save registers used by this routine
               PUSH    BX
               MOV     BX,CS            ;Set up data segment for variables
               MOV     DS,BX
               OR      AH,AH            ;Check to see if AH = 0 - read character
               JNZ     KB1              ;Nope, just branch off to keyboard IO
               XOR     BX,BX            ;Yes, set scroll count to 0
               MOV     SCROLL_COUNT,BL
KB1:           POP     BX               ;Restore BX register
               ASSUME  DS:NOTHING
               POP     DS
               JMP     ROM_KEYBOARD_IO  ;Jump to keyboard routine and return directly
                                        ;to the routine that called this routine
INTERCEPT_KEYBOARD     ENDP
;------------------------------------------------------------------------
;This section of code saves the old interrupt vectors for the keyboard and video IO routines.
;These vectors are replaced by the addresses of INTERCEPT_VIDEO_ and
;INTERCEPT_KEYBOARD
;------------------------------------------------------------------------
INIT_VECTORS           PROC    NEAR
               ASSUME  CS:CSEG,DS:CSEG
               MOV     AH,3             ;Set LAST_LINE to cursor line number
               XOR     BH,BH
               INT     10H
               MOV     LAST_LINE,DH

               ASSUME  CS:CSEG,DS:VECTORS
               MOV     AX,VECTORS
               MOV     DS,AX

               MOV     AX,VIDEO_INT     ;Save the address of the ROM routines
               MOV     ROM_VIDEO_IO,AX
               MOV     AX,VIDEO_INT[2]
               MOV     ROM_VIDEO_IO[2],AX
               MOV     AX,OFFSET INTERCEPT_VIDEO         ;Set video INT 10H to point to
               MOV     VIDEO_INT,AX      ;INTERCEPT_VIDEO above
               MOV     VIDEO_INT[2],CS

               MOV     AX,KEYBOARD_INT   ;Save the address of the ROM routines
               MOV     ROM_KEYBOARD_IO,AX
               MOV     AX,KEYBOARD_INT[2]
               MOV     ROM_KEYBOARD_IO[2],AX
               MOV     AX,OFFSET INTERCEPT_KEYBOARD  ;Set keyboard INT 16H to point
               MOV     KEYBOARD_INT,AX   ;to INTERCEPT_KEYBOARD above
               MOV     KEYBOARD_INT[2],CS

               MOV     DX,OFFSET INIT_VECTORS ;End of resident portion
               INT     27H               ;Terminate but stay resident
INIT_VECTORS           ENDP

CSEG           ENDS

               END     BEGIN
