Category : Files from Magazines
Archive   : VOL6N16.ZIP
Filename : KBX.ASM

 
Output of file : KBX.ASM contained in archive : VOL6N16.ZIP
;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,127,128,129,130,131,132,133,134,135,136,137,138,0
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
;
;Save page number, cursor mode, and cursor position. Then blank the cursor.
;
mov video_page,bh ;store video page number
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.
;------------------------------------------------------------------------------
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
;
;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


  3 Responses to “Category : Files from Magazines
Archive   : VOL6N16.ZIP
Filename : KBX.ASM

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/