home *** CD-ROM | disk | FTP | other *** search
- ; revised by rwt for dual-display systems, tests display type each time
- ; the window is activated. Done through calls to set-display-type, which
- ; is a re-written portion of the initialization routine. Also eliminated
- ; possibility of entering ASCII 127 (in SCR_TABLE).
- ;
- ; All changes to the program are in UPPER-case letters. Un-commented
- ; portions are closely related to the original, commented out but
- ; commented, source code. This should work with any normal two display
- ; system, e.g. mono with either cga or ega.
- ;
- ;KBX.COM for the IBM Personal Computer - 1987 by Jeff Prosise
- ;
- kb_data equ 60h ;keyboard data port
- kb_ctrl equ 61h ;keyboard control port
- eoi equ 20h ;8259 EOI value
- int_ctrl equ 20h ;8259 port address
- ;
- bios_data segment at 40h ;BIOS data area
- org 17h
- kb_status db ? ;keyboard status byte
- org 1Ah
- buffer_head dw ? ;pointer to keyboard buffer head
- buffer_tail dw ? ;pointer to keyboard buffer tail
- org 80h
- buffer_start dw ? ;starting keyboard buffer address
- buffer_end dw ? ;ending keyboard buffer address
- bios_data ends
- ;
- code segment para public 'code' ;code segment
- assume cs:code
- org 100h
- begin: jmp initialize ;goto initialization code
- ;
- copyright db 'Copyright 1987 Ziff-Davis Publishing Co.',1Ah
- enable_values db 2Ch,28h,2Dh,29h,2Ah,2Eh,1Eh
- screen_buffer dw offset initialize ;pointer to screen buffer
- aux_shift db 0 ;auxiliary keyboard status byte
- old_shift db 0 ;storage for shift status
- window_status db 0 ;window display status
- adapter db 2 ;0 = MDA, 1 = CGA, 2 = EGA
- video_segment dw 0B800h ;default video segment
- border_attr db 2Fh ;window border attribute
- text_attr db 1Bh ;window border attribute
- cursor_mode dw 0607h ;default cursor shape
- cursor_position dw ? ;saved cursor position
- video_page db ? ;saved video page number
- video_offset dw ? ;starting window offset address
- addr_6845 dw ? ;port address of CRTC
- ibm db 'IBM' ;EGA ASCII signature
- old9h label dword
- old9h_vector dw 2 dup (?) ;storage for interrupt 9 vector
- ;
- fill_parms dw 1,030Fh,12
- dw 2,050Fh,12
- dw 2,070Fh,12
- dw 2,090Fh,10
- dw 17,0537h,4
- dw 0,0737h,4
- dw 0,0937h,3
- ;
- def_table db 0,'1234567890-=',0
- db 0,'QWERTYUIOP[]',0
- db 0,'ASDFGHJKL;',39,96
- db 0,0,'ZXCVBNM,./'
- db 17 dup (0)
- db '789-456+123',0,0
- ;
- scr_table db 0,000,128,129,130,131,132,133,134,135,136,137,138,0
- ; NOTE 127 ABOVE CHANGED TO 000
- db 0,139,140,141,142,143,144,145,146,147,148,149,150,0
- db 0,151,152,153,154,155,156,157,158,159,160,161,162
- db 0,0,163,164,165,166,167,168,0,0,0,0
- db 17 dup (0)
- db 201,203,187,205,204,206,185,186,200,202,188,0,0
- ;
- num_table db 0,169,170,171,172,173,174,175,176,177,178,219,220,0
- db 0,221,222,223,224,225,226,227,228,229,230,231,232,0
- db 0,233,234,235,236,237,238,239,240,241,242,243,244
- db 0,0,245,246,247,248,249,250,251,252,253,254
- db 17 dup (0)
- db 218,194,191,196,195,197,180,179,192,193,217,0,0
- ;
- ;------------------------------------------------------------------------------
- ;Interrupt 9 handler. Execution comes here when a key is pressed or released.
- ;------------------------------------------------------------------------------
- new9h proc near
- sti ;set interrupt enable flag
- push ax ;save AX
- in al,kb_data ;get scan code from keyboard
- cmp al,69 ;NumLock key pressed?
- je numlock_down ;yes, then branch
- cmp al,69+128 ;NumLock key released?
- je numlock_up ;yes, then branch
- cmp al,70 ;ScrLock key pressed?
- je scrlock_down ;yes, then branch
- cmp al,70+128 ;ScrLock key released?
- je scrlock_up ;yes, then branch
- cmp al,57 ;spacebar pressed?
- je spacebar ;yes, then branch
- cmp aux_shift,0 ;NumLock or ScrLock depressed?
- je exit ;no, then exit
- jmp newkey ;yes, then branch
- exit: pop ax ;restore AX
- jmp old9h ;goto old interrupt handler
- ;
- ;The NumLock key was pressed. Toggle NumLock state or set shift bit.
- ;
- numlock_down: call get_status ;get main shift status byte
- test al,12 ;is either Ctrl or Alt pressed?
- jnz exit ;yes, then goto normal handler
- push ax ;save shift code
- call reset_kb ;reset the keyboard
- pop ax ;retrieve shift code
- test al,3 ;is either Shift key depressed?
- jnz numlock1 ;yes, then branch
- or aux_shift,2 ;set NumLock shift bit
- jmp end_int ;exit
- numlock1: push ds ;save DS
- mov ax,bios_data ;point DS to BIOS data area
- mov ds,ax
- assume ds:bios_data
- xor kb_status,32 ;toggle NumLock state
- pop ds ;restore DS
- assume ds:nothing
- jmp end_int ;exit
- ;
- ;The NumLock key was released. Clear the NumLock shift bit.
- ;
- numlock_up: call reset_kb ;reset the keyboard
- and aux_shift,253 ;clear shift bit
- jmp end_int ;exit
- ;
- ;The ScrLock key was pressed. Toggle ScrLock state or set shift bit.
- ;
- scrlock_down: call get_status ;get main shift status byte
- test al,12 ;is either Ctrl or Alt pressed?
- jnz exit ;yes, then goto normal handler
- push ax ;save shift code
- call reset_kb ;reset the keyboard
- pop ax ;retrieve shift code
- test al,3 ;is either Shift key depressed?
- jnz scrlock1 ;yes, then branch
- or aux_shift,1 ;set ScrLock shift bit
- jmp end_int ;exit
- scrlock1: push ds ;save DS
- mov ax,bios_data ;point DS to BIOS data area
- mov ds,ax
- assume ds:bios_data
- xor kb_status,16 ;toggle ScrLock state
- pop ds ;restore DS
- assume ds:nothing
- jmp end_int ;exit
- ;
- ;The ScrLock key was released. Clear the ScrLock shift bit.
- ;
- scrlock_up: call reset_kb ;reset the keyboard
- and aux_shift,254 ;clear shift bit
- end_int: mov al,eoi ;issue EOI to 8259 controller
- out int_ctrl,al
- pop ax ;clean up the stack
- iret ;return from interrupt
- ;
- ;The spacebar was pressed. Pop up the window if Alt is depressed.
- ;
- spacebar: call get_status ;get current shift status
- test al,8 ;is the Alt key depressed?
- jz exit ;no, then exit to normal handler
- call reset_kb ;yes, then reset keyboard
- mov al,eoi ;issue end-of-interrupt signal
- out int_ctrl,al
- cmp window_status,0 ;is the window already up?
- jne space1 ;yes, then ignore keypress
- push bx ;save BX
- call kb_display ;pop up keyboard display
- pop bx ;restore BX
- space1: pop ax ;clean up the stack
- iret ;exit
- ;
- ;A key was pressed or released with NumLock or ScrLock held down.
- ;
- newkey: push ax ;save scan code
- call reset_kb ;reset keyboard
- pop ax ;recover scan code
- test al,80h ;is the high bit set?
- jnz newkey3 ;yes, then don't process it
- push bx ;save BX
- mov bx,offset num_table ;point BX to NumLock key table
- cmp aux_shift,1 ;ScrLock depressed?
- jne newkey1 ;no, then continue
- mov bx,offset scr_table ;yes, then adjust BX
- newkey1: mov ah,al ;transfer scan code to AH
- dec al ;set AL relative to zero base
- xlat num_table ;get ASCII code from table
- or al,al ;is it zero?
- je newkey2 ;yes, then don't process this key
- call insert_char ;insert character into kb buffer
- newkey2: pop bx ;restore BX register value
- newkey3: mov al,eoi ;issue end-of-interrupt signal
- out int_ctrl,al
- pop ax ;restore AX and clean up the stack
- iret
- new9h endp
- ;
- ;------------------------------------------------------------------------------
- ;RESET_KB resets the keyboard.
- ;------------------------------------------------------------------------------
- reset_kb proc near
- in al,kb_ctrl ;get control port value
- mov ah,al ;save it
- or al,80h ;set high bit of control value
- out kb_ctrl,al ;send reset value
- mov al,ah ;get original control value
- out kb_ctrl,al ;enable keyboard
- ret ;done
- reset_kb endp
- ;
- ;------------------------------------------------------------------------------
- ;GET_STATUS returns the main keyboard shift status byte in AL.
- ;------------------------------------------------------------------------------
- get_status proc near
- push ds ;save DS
- mov ax,bios_data ;point DS to BIOS data area
- mov ds,ax
- assume ds:bios_data
- mov al,kb_status ;get status byte in AL
- pop ds ;restore DS
- assume ds:nothing
- ret ;exit
- get_status endp
- ;
- ;------------------------------------------------------------------------------
- ;INSERT_CHAR inserts the character code in AX into the keyboard buffer.
- ;Entry: AH,AL - scan code, ASCII code
- ;------------------------------------------------------------------------------
- insert_char proc near
- push dx ;save DX and DS
- push ds
- mov bx,bios_data ;point DS to BIOS data area
- mov ds,bx
- assume ds:bios_data
- mov bx,buffer_tail ;get current buffer tail address
- mov dx,bx ;transfer it to DX
- add dx,2 ;calculate next buffer position
- cmp dx,buffer_end ;did we overshoot the end?
- jne insert1 ;no, then continue
- mov dx,buffer_start ;yes, then wrap around
- insert1: cmp dx,buffer_head ;is the buffer full?
- je insert2 ;yes, then branch
- mov [bx],ax ;deposit character into buffer
- mov bx,dx ;advance buffer tail
- mov buffer_tail,bx ;record its new value
- insert2: pop ds ;restore DS
- assume ds:nothing
- pop dx ;restore DX
- ret ;exit
- insert_char endp
- ;
- ;------------------------------------------------------------------------------
- ;KB_DISPLAY opens a window showing all possible key definitions.
- ;------------------------------------------------------------------------------
- kb_display proc near
- ;
- ;Make sure current video mode is an 80-column text mode.
- ;
- mov ah,15 ;get current video mode
- int 10h
- cmp al,2 ;video mode 2?
- je kb1 ;yes, then continue
- cmp al,3 ;video mode 3?
- je kb1 ;yes, then continue
- cmp al,7 ;video mode 7 (monochrome)?
- je kb1
- ret ;unsupported mode - terminate
- kb1: mov window_status,1 ;set status flag
- push cx ;save register values
- push dx
- push si
- push di
- push ds
- push es
- push cs ;set DS and ES to the code segment
- pop ds
- assume ds:code
- push cs
- ; pop es ;THIS POP MOVED DOWN 3 LINES
- ;
- ;Save page number, cursor mode, and cursor position. Then blank the cursor.
- ;
- mov video_page,bh ;store video page number
- CALL SET_DISPLAY_TYPE ; CHECK DISPLAY TYPE EACH TIME.
- POP ES ; SEE 3 LINES UP
- mov ah,3 ;get current cursor mode
- int 10h
- mov cursor_mode,cx ;store cursor mode
- call read_cursor ;get cursor position
- mov cursor_position,ax ;save it
- mov ah,1 ;hide the cursor
- mov ch,20h
- int 10h
- ;
- ;Save the portion of video memory that will be overwritten.
- ;
- cmp adapter,1 ;disable video if this is a CGA
- jne kb2
- call disable_cga
- kb2: call save_screen ;copy video memory into buffer
- ;
- ;Open the keyboard display window.
- ;
- call open_window ;open the window
- cmp adapter,1 ;enable CGA video
- jne kb3
- call enable_cga
- kb3: lea si,def_table ;point SI to default key table
- call fill_window ;draw unshifted key definitions
- ;
- ;The window is open. Loop until the ESC key is pressed, continually monitoring
- ;the auxiliary shift byte to determine what key definition set to display.
- ;
- kb4: mov ah,1 ;check buffer for character
- int 16h
- jz kb5 ;branch if buffer is empty
- mov ah,0 ;get the character
- int 16h
- cmp al,27 ;is it the ESC key?
- je kb7 ;yes, then close window and exit
- kb5: mov al,aux_shift ;get auxiliary shift byte
- cmp al,2 ;is it <= 2?
- jna kb6 ;yes, then branch
- mov al,2 ;no, then set it to 2
- kb6: cmp al,old_shift ;has the shift status changed?
- je kb4 ;no, then loop back
- mov old_shift,al ;record current shift status
- mov bl,83 ;calculate table address from AL
- mul bl
- mov si,ax ;transfer it to SI
- add si,offset def_table ;complete offset address in SI
- call fill_window ;write key equivalents to window
- jmp kb4 ;go back for more
- ;
- ;The ESC key was pressed. Close the window and exit.
- ;
- kb7: cmp adapter,1 ;blank CGA video
- jne kb8
- call disable_cga
- kb8: call restore_screen ;restore contents of video memory
- cmp adapter,1 ;enable CGA video
- jne kb9
- call enable_cga
- kb9: mov ah,2 ;restore cursor position
- mov bh,video_page
- mov dx,cursor_position
- int 10h
- mov ah,1 ;unblank the cursor
- mov cx,cursor_mode
- int 10h
- mov window_status,0 ;reset status flag
- pop es ;restore register values
- pop ds
- pop di
- pop si
- pop dx
- pop cx
- ret ;return to calling routine
- kb_display endp
- ;
- ;------------------------------------------------------------------------------
- ;SAVE_SCREEN saves the block of video memory that will be overwritten.
- ;------------------------------------------------------------------------------
- save_screen proc near
- mov si,182 ;set zero page window offset in SI
- mov cl,video_page ;get video page in CX
- xor ch,ch
- jcxz save2 ;branch if page zero
- save1: add si,1000h ;add one page length
- loop save1 ;loop until offset is correct
- save2: mov video_offset,si ;save starting window address
- push ds ;save DS
- mov ds,video_segment ;point DS to video memory
- assume ds:nothing
- mov di,screen_buffer ;point ES:DI to screen buffer
- mov cx,11 ;11 lines to save
- save3: push cx ;save line counter
- mov cx,58 ;58 characters per line
- cld ;clear DF
- rep movsw ;transfer one line to storage
- pop cx ;retrieve counter
- add si,44 ;point SI to next line
- loop save3 ;loop until all lines are saved
- pop ds ;restore DS
- assume ds:code
- ret
- save_screen endp
- ;
- ;------------------------------------------------------------------------------
- ;RESTORE_SCREEN restores saved video memory.
- ;------------------------------------------------------------------------------
- restore_screen proc near
- mov es,video_segment ;point ES to video segment
- mov di,video_offset ;point DI to window area
- mov si,screen_buffer ;point DS:SI to screen buffer
- mov cx,11 ;11 lines to restore
- restore1: push cx ;save line count
- mov cx,58 ;58 characters per line
- rep movsw ;restore one line
- pop cx ;retrieve count
- add di,44 ;advance DI to next line
- loop restore1 ;loop until done
- ret
- restore_screen endp
- ;
- ;------------------------------------------------------------------------------
- ;DISABLE_CGA and ENABLE_CGA control CGA video output.
- ;------------------------------------------------------------------------------
- disable_cga proc near
- mov dx,3DAh ;Status Register port address
- disable1: in al,dx ;read status
- test al,8 ;vertical retrace active?
- jz disable1 ;no, then wait until it is
- sub dx,2 ;point DX to MSR
- mov al,25h ;load disable value
- out dx,al ;disable video
- ret
- disable_cga endp
- ;
- enable_cga proc near
- mov ah,15 ;get current video mode
- int 10h
- lea bx,enable_values ;point BX to table of values
- xlat enable_values ;get value to enable signal
- mov dx,3D8h ;MSR address
- out dx,al ;enable video output
- ret
- enable_cga endp
- ;
- ;------------------------------------------------------------------------------
- ;READ_CURSOR reads the cursor position directly from the CRT Controller.
- ;Exit: AH,AL - row, column
- ;------------------------------------------------------------------------------
- read_cursor proc near
- mov dx,addr_6845 ;get CRTC Address Register port
- mov al,14 ;specify register number
- out dx,al
- inc dx ;point DX to Data Register
- in al,dx ;read high byte of cursor address
- mov ah,al ;save it in AH
- dec dx ;point DX back to Address Register
- mov al,15 ;specify next register number
- out dx,al
- inc dx ;point DX to Data Register
- in al,dx ;read low byte of address
- and ax,07FFh ;strip page bits from address
- mov bl,80 ;divide by 80
- div bl
- xchg ah,al ;swap AH and AL
- ret
- read_cursor endp
- ;
- ;------------------------------------------------------------------------------
- ;OPEN_WINDOW writes the new window to video memory.
- ;------------------------------------------------------------------------------
- open_window proc near
- mov es,video_segment ;point ES to video memory
- mov di,video_offset ;point DI to start of window
- mov al,218 ;get first character code
- mov ah,border_attr ;and first attribute byte
- stosw ;write
- mov cx,56 ;do the next 56 characters
- mov al,196
- rep stosw
- mov al,191 ;finish the first line
- stosw
- add di,44 ;advance DI to next line
- mov cx,9 ;9 identical lines next
- open1: push cx ;save line counter
- mov al,179 ;do first character
- push ax ;save character/attribute
- stosw
- mov cx,56 ;do the next 56 characters
- mov al,32
- mov ah,text_attr
- rep stosw
- pop ax ;retrieve character/attribute pair
- stosw ;finish the line
- add di,44 ;advance DI to next line
- pop cx ;retrieve line count
- loop open1 ;loop until all 9 are done
- mov al,192 ;first character on last line
- stosw
- mov cx,56 ;do the next 56
- mov al,196
- rep stosw
- mov al,217 ;finish the last line
- stosw
- ret
- open_window endp
- ;
- ;------------------------------------------------------------------------------
- ;FILL_WINDOW writes a set of key definitions to the open window.
- ;Entry: DS:SI - key definition table address
- ;------------------------------------------------------------------------------
- fill_window proc near
- mov bh,video_page ;retrieve video page number
- lea di,fill_parms ;point DI to parameter table
- mov cx,7 ;7 lines to write
- fill1: push cx ;save counter
- add si,word ptr [di] ;adjust table index
- mov dx,[di+2] ;set starting cursor position
- mov cx,[di+4] ;set number of characters
- call writeln ;write one line
- add di,6 ;advance parameter table index
- pop cx ;retrieve count
- loop fill1 ;loop until done
- ret
- fill_window endp
- ;
- ;------------------------------------------------------------------------------
- ;WRITELN writes one line of key equivalents to the open window.
- ;Entry: DS:SI - character string address
- ; BH - video page
- ; CX - number of characters
- ; DH,DL - starting row and column
- ;------------------------------------------------------------------------------
- writeln proc near
- push cx ;save character counter
- mov ah,2 ;position the cursor
- int 10h
- lodsb ;get one character
- mov ah,10 ;print it
- mov cx,1
- int 10h
- add dl,3 ;advance cursor position
- pop cx ;retrieve count
- loop writeln ;loop until done
- ret
- writeln endp
- ;
- ;------------------------------------------------------------------------------
- ;INITIALIZE prepares the body of the program for residency.
- ;------------------------------------------------------------------------------
- ;
- SET_DISPLAY_TYPE PROC NEAR ; CHECKS DISPLAY TYPE FOR WINDOWING EACH TIME
- ; IT IS USED, NOT JUST AT INITIALIZATION.
- ;
- MOV AH,15
- INT 10H
- CMP AL,7
- JNZ INIT2
- MOV ADAPTER,0
- MOV VIDEO_SEGMENT,0B000H
- MOV BORDER_ATTR,70H
- MOV TEXT_ATTR,07H
- MOV CURSOR_MODE,0C0DH
- JMP INIT3
- INIT2: MOV ADAPTER,2
- MOV VIDEO_SEGMENT,0B800H
- MOV BORDER_ATTR,2FH
- MOV TEXT_ATTR,1BH
- MOV CURSOR_MODE,0607H
- MOV AX,0C000H
- MOV ES,AX
- MOV DI,1EH
- LEA SI,IBM
- MOV CX,3
- CLD
- REPE CMPSB
- JZ INIT3
- DEC ADAPTER
- INIT3: MOV AX,40H
- MOV ES,AX
- MOV DI,63H
- MOV DX,ES:[DI]
- MOV ADDR_6845,DX
- MOV CX,CURSOR_MODE
- MOV AH,1
- INT 10H
- RET
- ;
- SET_DISPLAY_TYPE ENDP
- ;
- ;
- ;initialize proc near
- ;
- ;See if the display adapter is an EGA.
- ;
- ; mov ax,0C000h ;set ES to EGA BIOS segment
- ; mov es,ax
- ; mov di,1Eh ;point DI to signature location
- ; lea si,ibm ;point SI to 'IBM' text
- ; mov cx,3 ;three bytes to compare
- ; cld ;clear DF
- ; repe cmpsb ;check three bytes
- ; je init1 ;branch if signature found
- ;
- ;Determine whether adapter is a CGA or an MDA.
- ;
- ; dec adapter ;decrement assumed value
- ; mov ah,15 ;get current video mode
- ; int 10h
- ; cmp al,7 ;is it mode 7?
- ; jne init1 ;no, then it's a CGA
- ;
- ;The display adapter is an MDA. Modify video attributes.
- ;
- ; dec adapter ;set ADAPTER value for MDA
- ; sub video_segment, 800h ;modify video segment value
- ; mov border_attr,70h ;modify border attribute
- ; mov text_attr,07h ;modify text attribute
- ; mov cursor_mode,0C0Dh ;modify default cursor shape
- ;
- ;Reset the cursor to its default shape.
- ;
- ;init1: mov cx,cursor_mode ;set scan lines in CX
- ; mov ah,1 ;video function - set cursor
- ; int 10h ;reset cursor
- ;
- ;Get and save the address of the CRT Controller.
- ;
- ; mov ax,40h ;point ES to BIOS data area
- ; mov es,ax
- ; mov di,63h ;point DI to address word
- ; mov dx,es:[di] ;get CRTC address
- ; mov addr_6845,dx ;save it
- ;
- INITIALIZE PROC NEAR
- ;
- ;Save the old interrupt 9 vector and replace it with a new one.
- ;
- mov ax,3509h ;get current interrupt 9 vector
- int 21h
- mov old9h_vector,bx ;save it
- mov old9h_vector[2],es
- mov ah,25h ;then point it to NEW9H routine
- lea dx,new9h
- int 21h
- ;
- ;Terminate, leaving additional room for screen buffering.
- ;
- mov dx,offset initialize+1276 ;set DX for exit
- int 27h ;terminate-but-stay-resident
- initialize endp
- ;
- code ends
- end begin
-