; ; ; stdlib segment para public 'slcode' assume cs:stdlib,ds:nothing ; ; Keyboard input routines ; ; Released to the public domain ; Created by: Randall Hyde ; Date: 7/90 ; Updates: ; ; 8/11/90- Modifications to use DOS 3fh call and handle eof ; 2/20/91- Modified routines to eat LFs following CRs after ; call to DOS getc routine. ; 3/6/91- Modified code to use DOS raw mode for standard ; input rather than cooked mode. Added SetInBIOS, ; SetInStd, and SetInRaw routines. ; ; cr equ 0dh lf equ 0ah CtrlZ equ 1ah ; ; ; InpVector- Points at the current keyboard input routine. ; GetcAdrs dd sl_GetcStdIn GetcStkIndx dw 0 GetcStk dd 16 dup (sl_GetcStdIn) GSIsize = $-GetcStk ; ; CharBuf- Used to hold character when reading from standard input device. ; CharBuf db ? ; ; ; LastChar- Used by BIOS keyboard routine to split non-ASCII keypresses ; into two separate calls. ; LastChar dw 101h ; ; LastWasCR gets set to 1 when we read a CR. If the char read when LastWasCR ; is one is a LF, this code eats the CR. ; LastWasCR db 1 ;Assume at start last char was CR. ; ; ; public sl_Getc sl_Getc proc far jmp dword ptr stdlib:GetcAdrs sl_Getc endp ; ; ; SetInAdrs- Stores ES:DI into InpVector which sets the new keyboard vector. ; public sl_SetInAdrs sl_SetInAdrs proc far mov word ptr stdlib:GetcAdrs, di mov word ptr stdlib:GetcAdrs+2, es ret sl_SetInAdrs endp ; ; ; GetInAdrs- Returns the address of the current output routine in ES:DI. ; public sl_GetInAdrs sl_GetInAdrs proc far les di, dword ptr stdlib:GetcAdrs ret sl_GetInAdrs endp ; ; ; ; PushInAdrs- Pushes the current input address onto the input stack ; and then stores the address in es:di into the input address ; pointer. Returns carry clear if no problems. Returns carry ; set if there is an address stack overflow. Does NOT modify ; anything if the stack is full. ; public sl_PushInAdrs sl_PushInAdrs proc far push ax push di cmp stdlib:GetcStkIndx, GSIsize jae BadPush mov di, stdlib:GetcStkIndx add stdlib:GetcStkIndx, 4 mov ax, word ptr stdlib:GetcAdrs mov word ptr stdlib:GetcStk[di], ax mov ax, word ptr stdlib:GetcAdrs+2 mov word ptr stdlib:GetcStk+2[di], ax pop di mov word ptr stdlib:GetcAdrs, di mov word ptr stdlib:GetcAdrs+2, es pop ax clc ret ; BadPush: pop di pop ax stc ret sl_PushInAdrs endp ; ; ; PopInAdrs- Pops an input address off of the stack and stores it into ; the GetcAdrs variable. ; public sl_PopInAdrs sl_PopInAdrs proc far push ax mov di, stdlib:GetcStkIndx sub di, 4 jns GoodPop ; ; If this guy just went negative, set it to zero and push the address ; of the stdout routine onto the stack. ; xor di, di mov word ptr stdlib:GetcStk, offset sl_GetcStdIn mov word ptr stdlib:GetcStk+2, seg sl_GetcStdIn ; GoodPop: mov stdlib:GetcStkIndx, di mov es, word ptr GetcAdrs+2 mov ax, word ptr stdlib:GetcStk+2[di] mov word ptr stdlib:GetcAdrs+2, ax mov ax, word ptr stdlib:GetcStk[di] xchg word ptr stdlib:GetcAdrs, ax mov di, ax pop ax ret sl_PopInAdrs endp ; ; ; ; SetInBIOS- Points the input pointer at the GetcBIOS routine. ; public sl_SetInBIOS sl_SetInBIOS proc far mov word ptr cs:GetcAdrs, offset sl_GetcBIOS mov word ptr cs:GetcAdrs+2, cs ret sl_SetInBIOS endp ; ; ; ; SetInStd- Points the input pointer at the GetcStdIn routine. ; public sl_SetInStd sl_SetInStd proc far mov word ptr cs:GetcAdrs, offset sl_GetcStdIn mov word ptr cs:GetcAdrs+2, cs ret sl_SetInStd endp ; ; ; ; ; ; ; ; GetcBIOS- Reads a character from the keyboard using the BIOS routines. ; Behaves just like DOS call insofar as it returns a zero if ; the user presses a non-ASCII key and then returns the scan ; code as the next keypress. Returns 1 in AH signifying that ; we haven't reached EOF. ; public sl_GetcBIOS sl_GetcBIOS proc far cmp byte ptr stdlib:LastChar, 0 jnz GetNewChar mov ah, 1 mov al, byte ptr stdlib:LastChar+1 mov byte ptr stdlib:LastChar, al mov stdlib:LastWasCR, 0 ;BIOS doesn't convert ret ; CR-> CR/LF. ; GetNewChar: mov ah, 0 int 16h mov stdlib:LastChar, ax mov ah, 1 ;Never EOF. mov stdlib:LastWasCR, 0 ret sl_GetcBIOS endp ; ; ; ; GetcStdIn- Reads a character from DOS' standard input. ; ; On return: ah=0 if eof, 1 if not eof. AL=character. ; ; Modification 2/20/91: ; ; Modified this code to eat any line feeds which immediately follow a ; CR on the standard input. ; ; 3/8/91: ; ; Modified this code to treat reading data from a file and from a ; device as two different operations. This removed some performance ; problems and helped make the code a little "safer". ; public sl_GetcStdIn assume ds:stdlib sl_GetcStdIn proc far push bx push cx push dx push ds ; mov ax, 4400h ;IOCTL read call xor bx, bx ;Use std in handle. int 21h test dl, 80h ;See if file (0) or device (1). jz GetcAgain ; test dl, 40h ;Check for EOF on device. jz DeviceEOF ; ; At this point we're reading a character from a device. Simply call the ; DOS character input routine so we can avoid buffering and other nasty ; problems. Note we have to handle EOF ourselves here. DOS, however, ; handles ctrl-C. ; mov ah, 8 int 21h mov ah, 1 cmp al, CtrlZ jne GoodRead DeviceEOF: mov ah, 0 jmp Short GoodRead ; ; ; If we're reading from a file (rather than a device like the keyboard), ; drop down here to read the character using standard buffered I/O. ; Make sure to strip off LFs following CRs (since LFs typically follow CRs ; in a file). ; GetcAgain: mov ah, 3fh mov dx, cs mov ds, dx mov CharBuf, 0 ;Don't let LF trip us up. lea dx, CharBuf ;Put char into CharBuf. mov cx, 1 ;Read one character. mov bx, 0 ;StdIn file handle int 21h jc BadRead mov ah, al ;ah=0 if eof, 1 if not eof. mov al, CharBuf ;Get char if not eof. cmp al, LF ;Was last char a line feed? jne NotLF cmp LastWasCR, 0 mov LastWasCR, 0 jne GetcAgain ; NotLF: mov LastWasCR, 0 cmp al, CR jne GoodRead mov LastWasCR,1 ; GoodRead: clc BadRead: pop ds pop dx pop cx pop bx ret sl_GetcStdIn endp ; ; stdlib ends end