Category : Assembly Language Source Code
Archive   : DSKPATCH.ZIP
Filename : KBD_IO.ASM
Output of file : KBD_IO.ASM contained in archive : DSKPATCH.ZIP
; KBD_IO.ASM Reads keyboard input and converts hex, decimal, etc. ;
; 04-30-89*CV ;
;---------------------------------------------------------------------;
CGROUP GROUP CODE_SEG, DATA_SEG
ASSUME CS:CGROUP, DS:CGROUP
BS EQU 8 ;Backspace char
CR EQU 13 ;Carriage-return char
ESC EQU 27 ;Escape char
CODE_SEG SEGMENT PUBLIC
PUBLIC STRING_TO_UPPER
;---------------------------------------------------------------------;
; This procedure converts the string, using the DOS format for strings;
; to all uppercase letters. ;
; ;
; DS:DX Address of string buffer ;
;---------------------------------------------------------------------;
STRING_TO_UPPER PROC NEAR
PUSH AX
PUSH BX
PUSH CX
MOV BX,DX
INC BX ;Point to character count
MOV CL,[BX] ;Character count in 2nd byte of buffer
XOR CH,CH ;Clear upper byte of count
UPPER_LOOP:
INC BX ;Point to next char in buffer
MOV AL,[BX]
CMP AL,'a' ;See if it is a lowercase letter
JB NOT_LOWER ;Nope
CMP AL,'z'
JA NOT_LOWER
ADD AL,'A'-'a' ;Convert to uppercase letter
MOV [BX],AL
NOT_LOWER:
LOOP UPPER_LOOP
POP CX
POP BX
POP AX
RET
STRING_TO_UPPER ENDP
;---------------------------------------------------------------------;
; This procedure converts a char from ASCII (hex) to a nibble (4 bits);
; ;
; AL Character to convert ;
; Returns: AL Nibble ;
; CF Set for error, cleared otherwise. ;
;---------------------------------------------------------------------;
CONVERT_HEX_DIGIT PROC NEAR
CMP AL,'0' ;Is it a legal digit?
JB BAD_DIGIT ;Nope
CMP AL,'9' ;Not sure yet
JA TRY_HEX ;Might be hex digit
SUB AL,'0' ;Is decimal digit, convert to nibble
CLC ;Clear the carry, no error
RET
TRY_HEX:
CMP AL,'A' ;Not sure yet
JB BAD_DIGIT ;Not hex
CMP AL,'F' ;Not sure yet
JA BAD_DIGIT ;Not hex
SUB AL,'A'-10 ;Is hex, convert to nibble
CLC ;Clear the carry, no error
RET
BAD_DIGIT:
STC ;Set the carry, error
RET
CONVERT_HEX_DIGIT ENDP
PUBLIC HEX_TO_BYTE
;---------------------------------------------------------------------;
; This procedure converts the two characters at DS:DX from hex to one ;
; byte. ;
; ;
; DS:DX Address of the two characters for hex number ;
; RETURNS: ;
; AL Byte ;
; CF Set for error, clear if no error ;
; ;
; USES: CONVERT_HEX_DIGIT ;
;---------------------------------------------------------------------;
HEX_TO_BYTE PROC NEAR
PUSH BX
PUSH CX
MOV BX,DX ;Put address in BX for indirect address
MOV AL,[BX] ;Get first digit
CALL CONVERT_HEX_DIGIT
JC BAD_HEX ;Bad hex digit if carry set
MOV CX,4 ;Now multiply by 16
SHL AL,CL
MOV AH,AL ;Retain a copy
INC BX ;Get second digit
MOV AL,[BX]
CALL CONVERT_HEX_DIGIT
JC BAD_HEX ;Bad hex digit if carry set
OR AL,AH ;Combine two nibbles
CLC ;Clear carry for no error
DONE_HEX:
POP CX
POP BX
RET
BAD_HEX:
STC ;Set carry for error
JMP DONE_HEX
HEX_TO_BYTE ENDP
PUBLIC READ_STRING
EXTRN WRITE_CHAR:NEAR
DATA_SEG SEGMENT PUBLIC
EXTRN COLOR:BYTE
EXTRN PHANTOM_COLOR:BYTE
DATA_SEG ENDS
;------------------------------------------------------------------------;
; This procedure performs a function very similar to the DOS 0Ah ;
; function. But this function will return a special character if a ;
; function of keypad key is pressed--no return for these keys. And ;
; ESC will erase the input and start over again. ;
; ;
; DS:DX Address for keyboard buffer. The first byte must ;
; contain the maximum number of characters to read (plus ;
; one for the return). And the second byte will be used ;
; by this procedure to return the number of characters ;
; actually read. ;
; 0 No characters read ;
; -1 One special character read ;
; otherwise number actually read (not including ;
; Enter key) ;
; ;
; Uses: BACK_SPACE, WRITE_CHAR ;
;------------------------------------------------------------------------;
READ_STRING PROC NEAR
PUSH AX
PUSH BX
PUSH SI
MOV BL,PHANTOM_COLOR
MOV COLOR,BL
XOR BX,BX
MOV SI,DX ;Use SI for index register and
START_OVER:
MOV BX,2 ;BX for offset to beginning of buffer
MOV AH,7 ;Call for input with no checking
INT 21h ; for CTRL-BREAK and no echo
OR AL,AL ;Is char extended ASCII?
JZ EXTENDED ;Yes, read the extended char
NOT_EXTENDED: ;Extnd char is error unless buf empty
CMP AL,CR ;Is this a carriage return?
JE END_INPUT ;Yes, we are done with input
CMP AL,BS ;Is it a backspace char?
JNE NOT_BS ;Nope
CALL BACK_SPACE ;Yes, delete character
CMP BL,2 ;Is buffer empty?
JE START_OVER ;Yes, can now read extended ASCII again
JMP SHORT READ_NEXT_CHAR ;No, continue reading normal chars
NOT_BS: CMP AL,ESC ;Is it an escape--purge buffer?
JE PURGE_BUFFER ;Yes, then purge buffer
CMP BL,[SI] ;Check to see if buffer is full
JA BUFFER_FULL ;Buffer is full
MOV [SI+BX],AL ;Else save char in buffer
INC BX ;Point to next free char in buffer
PUSH DX
MOV DL,AL ;Echo character to screen
CALL WRITE_CHAR
POP DX
READ_NEXT_CHAR:
MOV AH,7
INT 21h
OR AL,AL ;An extended ASCII char is not valid
; when the buffer is not empty
JNE NOT_EXTENDED ;Char is valid
MOV AH,7
INT 21h ;Throw out the extended char
;-----------------------------------------------------;
; Signal an error condition by sending a beep ;
; character to the display: chr$(7). ;
;-----------------------------------------------------;
SIGNAL_ERROR:
PUSH DX
MOV DL,7 ;Sound the bell by writing chr$(7)
MOV AH,2
INT 21h
POP DX
JMP SHORT READ_NEXT_CHAR ;Now read next char
;-----------------------------------------------------;
; Empty the string buffer and erase all the ;
; characters displayed on the screen. ;
;-----------------------------------------------------;
PURGE_BUFFER:
PUSH CX
MOV CL,[SI] ;Backspace over maximum number of
XOR CH,CH
PURGE_LOOP: ; characters in buffer. BACK_SPACE
CALL BACK_SPACE ; will keep the cursor from moving too
LOOP PURGE_LOOP ; far back
POP CX
JMP START_OVER ;Can now read extended ASCII chars
; since the buffer is empty
;------------------------------------------------;
; The buffer was full, so can't read another ;
; character. Send a beep to alert user of ;
; buffer-full condition. ;
;------------------------------------------------;
BUFFER_FULL:
JMP SHORT SIGNAL_ERROR ;Is buffer full, just beep
;------------------------------------------------;
; Read the extended ASCII code and place this ;
; in the buffer as the only character, then ;
; return -1 as the number of characters read. ;
;------------------------------------------------;
EXTENDED: ;Read an extended ASCII code
MOV AH,7
INT 21h
MOV [SI+2],AL ;Place just this char in buffer
MOV BL,0FFh ;Num chars read = -1 for special chars
JMP SHORT END_STRING
;------------------------------------------------;
; Save the count of the number of characters ;
; read and return. ;
;------------------------------------------------;
END_INPUT: ;Done with input
SUB BL,2 ;Count of chars read
END_STRING:
MOV [SI+1],BL ;Return number of chars read
POP SI
POP BX
POP AX
RET
READ_STRING ENDP
PUBLIC READ_BYTE
;---------------------------------------------------------------------;
; This procedure reads a single ASCII character of a hex number. ;
; ;
; Returns byte in AL Character code (unless AH = 0) ;
; AH 1 if read ASCII char or hex number ;
; 0 if no characters read ;
; -1 if read a special key ;
; ;
; Uses: HEX_TO_BYTE, STRING_TO_UPPER, READ_STRING ;
; Reads: KEYBOARD_INPUT, etc. ;
;---------------------------------------------------------------------;
READ_BYTE PROC NEAR
PUSH DX
MOV CHAR_NUM_LIMIT,3 ;Allow only two char (+ ENTER)
LEA DX,KEYBOARD_INPUT
CALL READ_STRING
CMP NUM_CHARS_READ,1 ;See how many chars
JE ASCII_INPUT ;Just one, treat as ASCII char
JB NO_CHARACTERS ;Only enter key hit
CMP BYTE PTR NUM_CHARS_READ,0FFh ;Special function key?
JE SPECIAL_KEY ;Yes
CALL STRING_TO_UPPER ;No, convert string to uppercase
LEA DX,CHARS ;Address of string to convert
CALL HEX_TO_BYTE ;Convert string from hex to byte
JC NO_CHARACTERS ;Error, so return to 'no chars read'
MOV AH,1 ;Signal read one character
DONE_READ:
POP DX
RET
NO_CHARACTERS:
XOR AH,AH ;Set to 'no chars read'
JMP DONE_READ
ASCII_INPUT:
MOV AL,CHARS ;Load character read
MOV AH,1 ;Signal read one char
JMP DONE_READ
SPECIAL_KEY:
MOV AL,CHARS[0] ;Return the scan code
MOV AH,0FFh ;Signal special key with -1
JMP DONE_READ
READ_BYTE ENDP
PUBLIC READ_DECIMAL
;---------------------------------------------------------------------;
; This procedure takes the output buffer of READ_STRING and converts ;
; the string of decimal digits to a word. ;
; ;
; AX Word converted from decimal ;
; CF Set if error, clear if no error ;
; ;
; Uses: READ_STRING ;
; Reads: KEYBOARD_INPUT, etc. ;
; Writes: KEYBOARD_INPUT, etc. ;
;---------------------------------------------------------------------;
READ_DECIMAL PROC NEAR
PUSH BX
PUSH CX
PUSH DX
MOV CHAR_NUM_LIMIT,6 ;Max number is 5 digits (65535)
LEA DX,KEYBOARD_INPUT
CALL READ_STRING
MOV CL,NUM_CHARS_READ ;Get number of char read
XOR CH,CH ;Set upper byte of count to 0
CMP CL,0 ;Return error if no chars read
JLE BAD_DECIMAL_DIGIT ;No chars read, signal error
XOR AX,AX ;Start with number set to 0
XOR BX,BX ;Start at beginning of string
CONVERT_DIGIT:
MOV DX,10 ;Multiply number by 10
MUL DX ;Multiply DX by 10
JC BAD_DECIMAL_DIGIT ;CF set if MUL overflowed one word
MOV DL,CHARS[BX] ;Get the next digit
SUB DL,'0' ;And convert to a nibble (4 bits)
JS BAD_DECIMAL_DIGIT ;Bad digit if < 0
CMP DL,9 ;Is this a bad digit?
JA BAD_DECIMAL_DIGIT ;Yes
ADD AX,DX ;No, so add it to number
INC BX ;Point to next char
LOOP CONVERT_DIGIT ;Get the next digit
DONE_DECIMAL:
POP DX
POP CX
POP BX
RET
BAD_DECIMAL_DIGIT:
STC ;Set carry to signal error
JMP DONE_DECIMAL
READ_DECIMAL ENDP
PUBLIC BACK_SPACE
EXTRN WRITE_CHAR:NEAR
;------------------------------------------------------------------------;
; This procedure deletes characters, one at a time, from the buffer and ;
; the screen when the buffer is not empty. BACK_SPACE simply returns ;
; when the buffer is empty. ;
; ;
; DS:SI+BX Most recent character still in buffer ;
; ;
; Uses: WRITE_CHAR ;
;------------------------------------------------------------------------;
BACK_SPACE PROC NEAR ;Delete one character
PUSH AX
PUSH DX
CMP BX,2 ;Is buffer empty?
JE END_BS ;Yes, read the next character
DEC BX ;Remove one character from buffer
MOV AH,2 ;Remove character from screen
MOV DL,BS
INT 21h
MOV DL,20h ;Write a space here
CALL WRITE_CHAR
MOV DL,BS ;Back up again
INT 21h
END_BS: POP DX
POP AX
RET
BACK_SPACE ENDP
CODE_SEG ENDS
DATA_SEG SEGMENT PUBLIC
KEYBOARD_INPUT LABEL BYTE
CHAR_NUM_LIMIT DB 0 ;Length of input buffer
NUM_CHARS_READ DB 0 ;Number of characters read
CHARS DB 80 DUP (0) ;A buffer for keyboard input
DATA_SEG ENDS
END
Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!
This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.
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/