home *** CD-ROM | disk | FTP | other *** search
- vectors segment at 0H ; set up segment to intercept Interrupts
-
- org 9H*4 ; the keyboard Interrupt
- keyboard_int label word
-
- org 1CH*4 ; timer interrupt
- timer_vector label word
-
- vectors ends
-
-
- screen segment at 0B000H ; a dummy segment to use as the
- screen ends ; extra segment
-
-
- rom_bios_data segment at 40H ; bios statuses held here, also keyboard buffer
-
- org 1AH
- head dw ? ; unread chars go from head to tail
- tail dw ?
- buffer dw 16 dup (?) ; the buffer itself
-
- buffer_end label word
-
- rom_bios_data ends
-
-
- code_seg segment
-
- assume cs:code_seg
-
- org 100H ; org = 100H to make this into a .COM file
-
- first: jmp load_buffer ; first time through
-
- copy_right db 'Copyright 1986 Ziff-Davis Publishing Co.'
- buff dw 0
- buff2 dw 159 dup(0)
- pad_offset dw 0 ; chooses 1st 160 bytes or 2nd
- screen_seg_offset dw 0 ; 0 for mono, 8000H for graphics
- io_char dw 1 ; holds addr of put or get_char
- old_head dw 1 ; to check for typeahead
- display_on db 0 ; 0 -> off
- status_port dw 0 ; video controller status port
- near_attrib_flag db 0 ; used in put_char
-
- old_keyboard_int_label label dword
- old_keyboard_int dw 0 ; location of old kbd interrupt
- dw 0
-
- rom_timer_label label dword
- rom_timer dw 0 ; the timer interrupt's address
- dw 0
-
-
- bufstuff proc near ; the keyboard interrupt will now come here
-
- assume cs:code_seg
-
- push ax ; save the used registers for good form
- push bx
- push cx
- push dx
- push di
- push si
- push ds
- push es
- pushf ; first, call old keyboard interrupt
- call old_keyboard_int_label
-
- assume ds:rom_bios_data ; examine the char just put in
-
- mov bx,rom_bios_data
- mov ds,bx
- mov bx,tail ; point to current tail
- cmp bx,head ; if at head, kbd int has deleted char
- jne cont
-
- jmp out ; so leave
-
- cont:
- mov dx,tail ; read a char - head advances
- sub dx,2 ; point to just read in character
- cmp dx,offset buffer ; did we undershoot buffer?
- jae nowrap ; nope
-
- mov dx,offset buffer_end ; yes - move to buffer top
- sub dx,2
-
- nowrap:
- mov bx,dx
- mov cx,[bx] ; get key in cx
- cmp cx,buff ; is it where we were before?
- jne t10
-
- mov bx,head ; has the head moved?
- cmp bx,old_head
- je t11 ; if yes, we have moved
-
- t10:
- cmp buff2,0
- jne remove ; if there's something in buff2,
-
- t11:
- cmp dx,head ; remove char in kbd buffer
- jne remove
-
- jmp out ; do nothing this pass
-
- ; more than one char in buffer - remove one
-
- remove:
- mov bx,dx
- mov tail,dx ; remove character by adjusting tail
- mov dx,[bx] ; store character in buffer
- mov cx,80
- mov bx,0 ; find end of visitype buffer
-
- check:
- cmp buff2[bx],0
- je bufend
-
- add bx,2
- loop check
-
- cmp dx,0E08H ; was this key a rubout?
- jne out ; no, and buffer filled - leave
-
- mov bx,158 ; yes, buff full but rubout last char
- mov word ptr buff[bx],0
- mov bx,head
- mov old_head,bx ; store this for next time
- mov dx,[bx] ; always load buff
- mov buff,dx
- jmp out ; can't hold more than 80
-
- bufend:
- cmp dx,0E08H ; rubout (and buffer not full)?
- jne nodel ; no, don't del
-
- del:
- sub bx,2 ; yes, delete last key
- cmp bx,0FFFEH ; gone too far?
- jl out
-
- jne paddel
-
- mov cx,tail ; del the one char in kdb buffer
- mov head,cx ; by making tail = head
- mov buff,0
- jmp short chkdis
-
- paddel:
- mov dx,0 ; dx -> 0 if we are deleting
-
- nodel:
- mov buff2[bx],dx ; load key in visitype buffer
- mov bx,head
- mov old_head,bx ; and store the old head to check later
- mov dx,[bx] ; always reload buff
- mov buff,dx
-
- chkdis:
- cmp display_on,0 ; are we on?
- jne flash ; yes, call display
-
- mov display_on,0FFH ; store what's on the screen first
- mov pad_offset,160
- lea ax,get_char ; make io use get-char so it does
- mov io_char,ax
- call io ; get top line from screen
-
- flash:
- call display ; display visitype's top line
-
- out:
- pop es ; having done pushes, here are the pops
- pop ds
- pop si
- pop di
- pop dx
- pop cx
- pop bx
- pop ax
- iret ; an interrupt needs an iret
-
- bufstuff endp
-
-
- display proc near ; puts the whole pad on the screen
-
- push ax
- mov near_attrib_flag,0
- mov pad_offset,0 ; use 1st bytes of pad memory
- lea ax,put_char ; make io use put-char so it does
- mov io_char,ax
- call io ; put result on screen
- pop ax
- ret ; leave
-
- display endp
-
-
- get_char proc near ; gets a char from screen and advances position
-
- assume es:screen,ds:rom_bios_data
-
- push dx
- mov si,2 ; loop twice, once for char, once for attribute
- mov dx,status_port ; get ready to read video controller status
-
- g_wait_low: ; start waiting for a new horizontal scan -
- in al,dx ; make sure the video controller scan status
- test al,1 ; is low
- jnz g_wait_low
-
- g_wait_high: ; after port has gone low, it must go high
- in al,dx ; before it is safe to read directly from
- test al,1 ; the screen buffer in memory
- jz g_wait_high
-
- mov ax,es:[di] ; do the move from the screen, one byte at a time
- inc di ; move to next screen location
- dec si ; decrement loop counter
- cmp si,0 ; are we done?
- je leave ; yes
-
- mov buff[bx],ax ; no - put char we got into buff
- jmp g_wait_low ; do it again
-
- leave:
- add bx,2
- pop dx
- ret
-
- get_char endp
-
-
- put_char proc near ; puts one char on screen and advances position
-
- push dx
- cli
- mov ah,byte ptr buff[bx]
- mov si,2 ; loop twice, once for char, once for attribute
- mov dx,status_port ; get ready to read video controller status
-
- p_wait_low: ; start waiting for a new horizontal scan -
- in al,dx ; make sure the video controller scan status
- test al,1 ; is low
- jnz p_wait_low
-
- p_wait_high: ; after port has gone low, it must go high
- in al,dx ; before it is safe to write directly to
- test al,1 ; the screen buffer in memory
- jz p_wait_high
-
- mov es:[di],ah ; move to screen, one byte at a time
- mov ah,byte ptr buff[bx+1]
- cmp near_attrib_flag,0
- jne incdi
-
- mov ah,byte ptr buff[bx+161]
-
- incdi:
- inc di ; point to next screen postion
- dec si ; decrement loop counter
- jnz p_wait_low ; if not zero, do it one more time
-
- add bx,2
- pop dx
- sti
- ret ; exeunt
-
- put_char endp
-
-
- io proc near ; this scans over screen positions on top line
-
- assume es:screen ; use screen as extra segment
-
- mov bx,screen
- mov es,bx
- mov di,screen_seg_offset ; di will be pointer to screen postion
- mov bx,pad_offset ; bx will be location pointer
- mov cx,80
-
- char_loop:
- call io_char ; call put-char or get-char
- loop char_loop ; if not zero, scan over next character
- ret ; finished
-
- io endp
-
-
- assume ds:code_seg
-
- intercept_timer proc near ; this completes filling the buffer
-
- ; if no keys in buffer, put next one in
-
- push ds ; save DS since we'll change it
- push cs ; put current value of CS into DS
- pop ds
- pushf
- call rom_timer_label ; make obligatory call
- cmp buff2,0
- jne go ; no, leave
-
- jmp out1
-
- go:
- cli ; yes, start by clearing interrupts
- push es
- push ds ; save these
- push si
- push di
- push dx
- push cx
- push bx
- push ax
-
- assume ds:rom_bios_data ; point to the keyboard buffer again
-
- mov ax,rom_bios_data
- mov ds,ax
- mov bx,tail ; prepare to put characters in at tail
- cmp head,bx ; if kbd buff not empty, leave
- jne finstuff
-
- stuff:
- mov ax,word ptr buff2 ; get the char to put in kbd buffer
- mov cx,79 ; now slide the rest over
- mov bx,0
-
- slide:
- mov dx,buff[bx+2] ; do this word by word
- mov buff[bx],dx
- add bx,2
- inc si
- loop slide ; slides slides buff to the left
- mov word ptr buff2[bx-2],0
- mov dx,head ; store this to check if user is typing
- mov old_head,dx ; while we drain buff
- mov dx,tail ; find position in buffer from bx
- add dx,2 ; move to next position for this word
- cmp dx,offset buffer_end ; are we past the end?
- jl no_wrap ; no, don't wrap
-
- mov dx,offset buffer ; do the wrap rap
-
- no_wrap:
- cmp dx,head ; buffer full but not yet done?
- je finstuff ; time to leave, come back later
-
- mov bx,tail ; prepare to put characters in at tail
- mov [bx],ax ; put into buffer
- mov tail,dx ; reset buffer tail
-
- finstuff:
- cmp buff2,0
- jne dis ; should we restore the screen?
- mov buff,0
- mov display_on,0
- mov pad_offset,160 ; use 1st 160 bytes of memory
- lea ax,put_char ; make io use put-char so it does
- mov io_char,ax
- mov near_attrib_flag,0FFH
- call io ; put result on screen
- jmp short odis
-
- dis:
- call display
-
- odis:
- pop ax ; restore these
- pop bx
- pop cx
- pop dx
- pop di
- pop si
- pop ds
- pop es
-
- out1:
- pop ds
- iret ; with customary iret
-
- intercept_timer endp
-
-
- load_buffer proc near ; this procedure intializes everything
-
- assume ds:vectors ; the data segment will be the Interrupt area
-
- mov ax,vectors
- mov ds,ax
- mov ax,keyboard_int ; get the old interrupt service routine
- mov old_keyboard_int,ax ; address and put it into our location
- mov ax,keyboard_int[2] ; old_keyboard_int so we can call it
- mov old_keyboard_int[2],ax
- mov keyboard_int,offset bufstuff
- mov keyboard_int[2],cs
- mov ax,timer_vector ; now same for timer
- mov rom_timer,ax
- mov ax,timer_vector[2]
- mov rom_timer[2],ax
- mov timer_vector,offset intercept_timer
- mov timer_vector[2],cs ; and intercept that too
-
- assume ds:rom_bios_data
-
- mov ax,rom_bios_data
- mov ds,ax
- mov bx,offset buffer ; clear the keyboard buffer to start
- mov head,bx
- mov old_head,bx
- mov tail,bx
- mov ah,15 ; ask for service 15 of int 10H
- int 10H ; this tells us how display is set up
- mov status_port,03BAH ; assume this is a monochrome display
- test al,4 ; is it?
- jnz exit ; yes - jump out
-
- mov screen_seg_offset,8000H ; no - set up for graphics disp-lay
- mov status_port,03DAH
-
- exit:
- mov dx,offset load_buffer ; set up everything but load_buffer to
- int 27H ; stay and attach itself to dos
-
- load_buffer endp
-
- code_seg ends
-
- end first