home *** CD-ROM | disk | FTP | other *** search
- ; This program is described in BYTE, November 1983, Pages 99 - 116.
- ; Article is entitled "ENHANCING SCREEN DISPLAYS FOR THE IBM PC",
- ; author is Tim Field.
-
- ; Define interrupt vectors for both keyboard interrupt 16H and screen
- ; interrupt 10H. Both are in segment 0:
-
- KEYVECT SEGMENT AT 0 ;Define KEYBOARD int. vector
- ORG 16H*4
- KEYINT LABEL DWORD
- KEYVECT ENDS
-
- SCRVECT SEGMENT AT 0 ;Define SCREEN int. vector
- ORG 10H*4
- SCRINT LABEL DWORD
- SCRVECT ENDS
-
- ; Define constants:
-
- BW_VAL EQU 07H ;Standard B&W attribute
- EQUIP_FLAG EQU 410H ;RAM address of equipment stat
- CHK_MODE EQU 15 ;INT fn: Check screen mode
- MONO_MODE EQU 7 ;Mode 7 = monochrome monitor
- COLOR_ADPT EQU 3 ;Modes 0-3: non-graphics color
-
- ; Start code area:
-
- CODE SEGMENT PARA ;Start code at offset 100H
- ASSUME CS:CODE ;from starting segment; leaves
- ORG 100H ;room for PSP
- KEY PROC FAR
-
- ; Initialization code - used only once during startup:
-
- START:
- JMP INIT_CODE ;Call initialization routine
-
- ; Define storage areas and data structures:
- ; Define keystroke scan codes for the five SCREEN functions:
-
- FORE_INC DW 5E00H ;Foreground increment
- BACK_INC DW 6000H ;Background increment
- C80_40 DW 6200H ;80x25 to 40x25 flip-flop key
- COL_MON DW 6400H ;COLOR/MONO flip-flop key
- REPAINT DW 6600H ;Repaint scrn using curr. mode
- CUR_MODE DW COL80_AREA ;Initialize starting mode
- MONO_SET DW MONO_AREA ;Pointer to monochrome area
- COLOR_SET DW COL80_AREA ;Pointer to active color area
- SCRN_ATTR DB 70H ;Current screen attribute
- SCRN_MODE DB 255 ;Save current screen mode
-
- ; Define structure used to contain information about 40 and 80 column color
- ; modes as well as monochrome mode:
-
- S STRUC
- CORNER DW 0 ;Defines COL/ROW count of
- ;characters for the monitor
- BF DW 0 ;Colors of FORE and BACK
- EQUIP DW 0 ;Equipment setting
- MODE DW 0 ;AX value for setting the mode
- S ENDS ;of the monitor
-
- ; Now set up three screen structures with default condition:
-
- COL80_AREA S <5019H,0107H,20H,3> ;80x25 white FORE, blue BACK
- COL40_AREA S <2819H,0107H,10H,1> ;40x25 brown FORE, black BACK
- MONO_AREA S <5019H,0007H,30H,7> ;Monochrome, reverse video
-
- KEY_CALL: DB 0EAH ;Far JMP address to KEYBOARD
- DD 0 ;interrupt. See article
-
- ; Procedure KEY_RTNE intercepts keyboard interrupt and determines if the
- ; keystroke is one of the five SCREEN ones:
-
- KEY_RTNE:
- STI ;Turn on interrupts
- CMP AH,0
- JNE KEY_CALL
- PUSH DS ;Save registers
- PUSH BX
- PUSH CX
- PUSH DX
- PUSH ES
- PUSH DI
- PUSH CS ;Point DS to CS segment by
- POP DS ;PUSH / POP operation
- ASSUME DS:CODE
- INT_LOOP: ;IBM keyboard procedure
- PUSHF ;expects an interrupt call
- MOV BX,OFFSET KEY_CALL+1 ;Address to ROM keyboard code
- CALL DWORD PTR [BX] ;Call keyboard routine
- MOV BX,CUR_MODE ;Get current mode address
- CMP AX,COL_MON ;See if COLOR/MON flip flop
- JNE TEST_FORE ;key. Exit if not. Otherwise:
- CMP BX,MONO_SET ;Flip flop screen mode
- JE SET_COLOR ;If monochrome, swap to color
- CMP MONO_SET,0 ;See if monochrome installed
- JE NEXT_KEY ;Ignore command if not
- MOV BX,MONO_SET ;Otherwise set up monochrome
- JMP SHORT DO_CHG
- SET_COLOR:
- CMP COLOR_SET,0 ;See if COLOR monitor enabled
- JE NEXT_KEY ;Skip if not
- MOV BX,COLOR_SET ;Set up for color
- DO_CHG:
- CALL SCREEN_CHG ;Implement screen change
- NEXT_KEY:
- MOV AH,0 ;Set up to fetch keystroke
- JMP INT_LOOP ;Fetch next key input
- TEST_FORE:
- PUSH AX ;Save registers
- PUSH BX ;See if in GRAPHICS mode
- MOV AH,CHK_MODE
- INT 10H
- POP BX ;Restore BX register
- CMP AL,COLOR_ADPT ;If between 0-3, not graphics
- JLE NOT_GRAPH
- CMP AL,MONO_MODE ;Monochrome mode
- JGE NOT_GRAPH
- POP AX ;Restore stack
- JMP DONE ;If color-graphics mode, do
- NOT_GRAPH: ;not change modes
- POP AX ;Restore AX
- CMP AX,FORE_INC ;Increment FOREGROUND color?
- JNE TEST_BACK ;Skip if not
- CMP BX,COLOR_SET ;See if currently using color
- JNE BW_FLOP ;If not, go deal with B&W
- MOV AX,[BX].BF ;Gets BACK in AL, FORE in AH
- EQ_FORE:
- INC AL ;Increment FOREGROUND color
- AND AL,7 ;Keep it within bounds
- CMP AL,AH ;See if same as BACKGROUND
- JE EQ_FORE ;Increment again if yes
- MOV [BX].BF,AX ;Save back to structure
- JMP DO_CHG ;Redraw the screen
- TEST_BACK:
- CMP AX,BACK_INC ;Increment BACKGROUND color?
- JNE TEST_REPAINT ;Skip if not
- CMP BX,COLOR_SET ;See if currently using color
- JNE BW_FLOP ;If not, go deal with B&W
- MOV AX,[BX].BF ;Gets BACK in AL, FORE in AH
- EQ_BACK:
- INC AH ;Increment BACKGROUND color
- AND AH,7 ;Keep it within bounds
- CMP AH,AL ;See if same as FOREGROUND
- JE EQ_BACK ;Increment again if yes
- MOV [BX].BF,AX ;Save back to structure
- JMP DO_CHG ;Redraw the screen
- BW_FLOP: ;Flip flop B&W monitor
- MOV AX,[BX].BF ;BACK in AH, FORE in Al
- XCHG AH,AL ;Swap FOREGROUND, BACKGROUND
- MOV [BX].BF,AX ;Save back to structure
- JMP DO_CHG ;Redraw the screen
- TEST_REPAINT:
- CMP AX,REPAINT ;Repaint the screen?
- JE DO_CHG ;If yes, then repaint screen
- TEST_80_40:
- CMP AX,C80_40 ;80-40 flip flop key?
- JNE DONE ;Exit if not
- CMP BX,OFFSET COL40_AREA ;Is curr. pointer area 40x25?
- JNE TST80 ;Skip if not
- MOV BX,OFFSET COL80_AREA ;Otherwise, flip to 80x25
- JMP SHORT SAVE_COL ;Save to COLOR_SET
- TST80:
- CMP BX,OFFSET COL80_AREA ;Is current 80x25 color?
- JNE NEXT_KEY ;Ignore key if not
- MOV BX,OFFSET COL40_AREA
- SAVE_COL:
- MOV COLOR_SET,BX ;Save to COLOR_SET
- JMP SET_COLOR ;Implement
- DONE:
- POP DI ;Restore registers
- POP ES
- POP DX
- POP CX
- POP BX
- POP DS
- IRET ;Return from interrupt
- KEY ENDP ;End of main routine
-
- ; This routine changes current monitor screen mode. On input, BX points to
- ; the current monitor structure:
-
- SCREEN_CHG PROC NEAR
- MOV AX,0 ;Get segment address for RAM
- MOV ES,AX ;EQUIP_FLAG
- MOV AX,ES:EQUIP_FLAG ;Get set of EQUIP flags
- AND AL,0CFH ;Scrap current monitor flag
- OR AX,[BX].EQUIP ;Set up new monitor flag
- MOV ES:EQUIP_FLAG,AX ;Save back in RAM
- MOV CUR_MODE,BX ;Indicate new mode
-
- ; Now set up attribute for FOREGROUND and BACKGROUND:
-
- MOV DX,[BX].BF ;Get both FORE and BACK in DX
- MOV CL,4 ;Shift count
- SHL DH,CL ;Shift BACK into upper nibble
- OR DH,DL ;Move FORE into lower nibble
- MOV SCRN_ATTR,DH ;Save results
-
- ; See if we need to reset monitor (switching to new monitor?):
-
- MOV AX,[BX].MODE ;Get screen mode
- CMP AL,SCRN_MODE ;Compare with current mode
- JE SET_ATTR ;Skip if the same
- MOV SCRN_MODE,AL ;Otherwise, save current mode
- INT 10H ;And reset to new monitor
- SET_ATTR:
- CALL CH_ATTR ;Change attributes of current
- RET ;screen
- SCREEN_CHG ENDP
-
- ; This routine repaints the active screen so that every character on the
- ; current screen is displayed with the new attributes. On input, BX points
- ; to the current monitor structure:
-
- CH_ATTR PROC NEAR
-
- ; See if we need to redraw border for color mode
-
- CMP BX,OFFSET MONO_SET ;In color?
- JE NO_BORDER ;Skip border code if not
- PUSH AX ;Save registers
- PUSH BX
- MOV BX,[BX].BF ;Get BACKGROUND color in BL
- MOV BL,BH
- MOV BH,0 ;Select border coloring
- MOV AH,11 ;Fn. call: set color palette
- INT 10H ;Execute VIDEO I/O interrupt
- POP BX ;Restore registers
- POP AX
- NO_BORDER:
- MOV AX,[BX].CORNER ;Get COL and ROW for current
- MOV CORNR,AX ;Save in temporary data area
- MOV AH,CHK_MODE ;Get page number
- INT 10H
-
- ; BX contains the active page:
-
- MOV AH,3 ;Get current cursor position
- INT 10H
- PUSH DX ;Save position on stack
- XOR DX,DX ;Zero-out DX
- MOV CX,1 ;Set up counter
- MOV BL,SCRN_ATTR ;Get current attribute
- REP_ATTR:
- MOV AH,2 ;Set cursor position
- INT 10H
- MOV AH,8 ;Read next character
- INT 10H
-
- ; AH contains the current character attribute:
-
- AND AH,88H ;Get intensity bit
- AND BL,77H ;Ensure attr. intensity is off
- OR BL,AH ;Create current attribute
- MOV AH,9 ;Display char. with new attr.
- INT 10H
- INC DL
- CMP DL,TCOL ;Are we done with this column?
- JLE REP_ATTR ;If so, jump
- XOR DL,DL ;Otherwise, zero-out DL
- INC DH ;Move to next row
- CMP DH,TROW ;Are we done with this screen?
- JLE REP_ATTR ;Loop until done
- POP DX ;Restore orig. cursor position
- MOV AH,2
- INT 10H
- RET
- CORNR LABEL WORD
- TROW DB 0 ;Temp. store for ROW
- TCOL DB 0 ;Temp. store for COL
- CH_ATTR ENDP
-
- ; This routine replaces the SCREEN interrupt so that it can intercept B&W
- ; character writes and change the display attributes:
-
- SCR_RTNE PROC NEAR
- STI
- PUSH DS ;Save DS
- PUSH CS ;Point DS to CS segment by
- POP DS ;PUSH / POP operation
- ASSUME DS:CODE
- CMP AH,6 ;Spot SCROLLUP and SCROLLDOWN
- JL NORMAL_SCR ;calls
- CMP AH,7
- JG NOT_SCROLL
- SCROLL:
- CALL GET_CH ;Update attribute for scroll
- JMP NORMAL_SCR ;Now execute scroll
- NOT_SCROLL:
- CMP AH,9 ;Check for "WRITE ATTR / CHAR"
- JNE NORMAL_SCR ;command. Send out any other
- XCHG BH,BL ;commands as normal. Get attr.
- CALL GET_CH ;in BL and update attribute
- XCHG BH,BL ;Move attribute back to BH for
- NORMAL_SCR: ;command
- POP DS ;Restore DS segment register
- JMP_SCR: DB 0EAH ;See article
- DD 0
- SCR_RTNE ENDP
-
- ; This routine replaces the B&W character with the current replacement
- ; attributes and allows for the INTENSITY bit setting. On input, BH
- ; contains the attribute to be modified:
-
- GET_CH PROC NEAR
- MOV SAVECH,BH ;Save character
- AND BH,77H ;Remove intensity / blink bits
- CMP BH,BW_VAL ;See if cur. defined B&W value
- MOV BH,SAVECH ;Otherwise, modify to current
- JNE OUT ;attribute. Exit if not
- AND BH,88H ;Get rid of B&W part
- OR BH,SCRN_ATTR ;Move in current attr. part
- OUT:
- RET ;Done
- SAVECH DB 0 ;Temporary character store
- GET_CH ENDP
-
- ; All code after this label is freed to DOS use after this program has been
- ; initialized:
-
- LASTONE:
-
- ; This routine loads and initializes the SCREEN program. It sets up DOS to
- ; keep all code before the label LASTONE safe from overlay during normal
- ; system operation:
-
- INIT_CODE PROC NEAR
-
- ; Initialize KEYBOARD intercept code:
-
- MOV AX,KEYVECT ;Point ES to interrupt vectors
- MOV ES,AX ;(segment at 0H)
- ASSUME ES:KEYVECT
- MOV AX,ES:KEYINT ;Get address of interrupt
- MOV BX,OFFSET KEY_CALL+1 ;vector and save both the
- MOV [BX],AX ;segment and offset values of
- MOV AX,ES:KEYINT[2] ;this routine in our data area
- MOV [BX+2],AX ;Now, replace the original
- MOV ES:KEYINT,OFFSET KEY_RTNE ;interrupt vector with the
- MOV AX,CS ;address of our own routine
- MOV ES:KEYINT[2],AX
-
- ; Initialize SCREEN intercept code:
-
- MOV AX,SCRVECT ;Point ES to interrupt vectors
- MOV ES,AX ;(segment at 0H)
- ASSUME ES:SCRVECT
- MOV AX,ES:SCRINT ;Get address of interrupt
- MOV BX,OFFSET JMP_SCR+1 ;vector and save both the
- MOV [BX],AX ;segment and offset values of
- MOV AX,ES:SCRINT[2] ;this routine in our data area
- MOV [BX+2],AX ;Now, replace the original
- MOV ES:SCRINT,OFFSET SCR_RTNE ;interrupt vector with the
- MOV AX,CS ;address of our own routine
- MOV ES:SCRINT[2],AX
-
- ; Initialize screen:
-
- MOV BX,CUR_MODE ;Set up initial screen mode
- CALL SCREEN_CHG ;Initialize screen mode
-
- ; Now, terminate and stay resident:
-
- MOV DX,OFFSET LASTONE ;Save all code up to LASTONE
- INT 27H ;Terminate and stay resident
- INIT_CODE ENDP
-
- CODE ENDS
- END START