home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Programming Languages Suite
/
ProgLangD.iso
/
Assembly
/
KBD_IO.ASM
< prev
next >
Wrap
Assembly Source File
|
1986-10-07
|
13KB
|
413 lines
CGROUP GROUP CODE_SEG, DATA_SEG
ASSUME CS:CGROUP, DS:CGROUP
;-----------------------------------------------------------------------;
; This file contains procedures for working with the keyboard: ;
; ;
; READ_CHAR Read a character from the keyboard ;
; STRING_TO_UPPER Converts a string to upper case ;
; CHAR_TO_UPPER Converts a character to upper case ;
; READ_STRING Reads in a string of characters ;
; READ_DECIMAL Reads a decimal number ;
; READ_BYTE Reads a single byte ;
; HEX_TO_BYTE Converts to characters to a hex byte ;
; CONVERT_HEX_DIGIT Converts a hex digit to a nibble ;
;-----------------------------------------------------------------------;
BS EQU 8 ;Back space character
CR EQU 13 ;Carriage return character
ESC EQU 27 ;Escape character
DATA_SEG SEGMENT PUBLIC
KEY_BOARD_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
CODE_SEG SEGMENT PUBLIC
PUBLIC READ_CHAR
;-----------------------------------------------------------------------;
; This procedure reads a single character from the keyboard, without ;
; echoing it to the screen. ;
; ;
; Returns: AL Character, or 0 for special keys. ;
; AH Extended code of the special key ;
;-----------------------------------------------------------------------;
READ_CHAR PROC NEAR
MOV AH,7 ;Call for input with no checking
INT 21h ;for CTRL_BREAK and no echo.
OR AL,AL ;Is this a special key?
JNZ DONE_READ_CHAR ;No, then we're all done
INT 21h ;Yes, then read the extended code
MOV AH,AL ;Save this in AH
XOR AL,AL ;Signal that we have an extended code
DONE_READ_CHAR:
RET
READ_CHAR ENDP
PUBLIC STRING_TO_UPPER
;-----------------------------------------------------------------------;
; This procedure converts the string, using the DOS format for strings ;
; to all upper-case letters. ;
; ;
; DS:DX Address of string buffer. ;
; ;
; Uses: CHAR_TO_UPPER ;
;-----------------------------------------------------------------------;
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 character in buffer
MOV AL,[BX] ;Get one character from the string
CALL CHAR_TO_UPPER ;Convert to upper-case letter
MOV [BX],AL ;Save this character back to the string
LOOP UPPER_LOOP
POP CX
POP BX
POP AX
RET
STRING_TO_UPPER ENDP
PUBLIC CHAR_TO_UPPER
;-----------------------------------------------------------------------;
; This procedure converts a single character to upper case. ;
; ;
; On entry: AL Character to convert ;
; Returns: AL Upper-case version of the letter ;
;-----------------------------------------------------------------------;
CHAR_TO_UPPER PROC NEAR
CMP AL,'a' ;Is this a lower-case letter?
JB NOT_LOWER ;No, then we're all done
CMP AL,'z' ;Is this a lower-case letter?
JA NOT_LOWER ;No, then we're all done
ADD AL,'A'-'a' ;Convert to upper-case letter
NOT_LOWER:
RET
CHAR_TO_UPPER ENDP
PUBLIC READ_STRING
EXTRN WRITE_CHAR:NEAR
;-----------------------------------------------------------------------;
; This procedure performs a function very similar to the DOS 0AH ;
; function. But this function will return a special character if a ;
; function or key pad 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 ;
; return key). ;
; ;
; Uses: READ_CHAR, BACK_SPACE, WRITE_CHAR ;
;-----------------------------------------------------------------------;
READ_STRING PROC NEAR
PUSH AX
PUSH BX
PUSH SI
MOV SI,DX ;Use SI for index register and
START_OVER:
MOV BX,2 ;BX for offset to beginning of buffer
CALL READ_CHAR
OR AL,AL ;Is character extended ASCII?
JZ EXTENDED ;Yes, then handle it.
NOT_EXTENDED: ;Extnd char is error unless buff empty
CMP AL,CR ;Is this a carriage return?
JE END_INPUT ;Yes, we are done with input
CMP AL,BS ;Is it a back space character?
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 characters
NOT_BS: CMP AL,ESC ;Is it an ESC -- purge buffer?
JE PURGE_BUFFER ;Yes, then purge the 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 character in buffer
PUSH DX
MOV DL,AL ;Echo character to screen
CALL WRITE_CHAR
POP DX
READ_NEXT_CHAR:
CALL READ_CHAR
OR AL,AL ;An extended ASCII char is not valid
;when the buffer is not empty.
JNZ NOT_EXTENDED ;Char is valid
;Char is extended, signal error
;-----------------------------------------------;
; 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 character.
;-----------------------------------------------;
; 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 characters
;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 ;If 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:
MOV [SI+2],AH ;Place extended code into the buffer
MOV BL,0FFH ;Num chars read = -1 for special
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 characters read
END_STRING:
MOV [SI+1],BL ;Return number of chars read
POP SI
POP BX
POP AX
RET
READ_STRING 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 space there
CALL WRITE_CHAR
MOV DL,BS ;Back-up again
INT 21H
END_BS: POP DX
POP AX
RET
BACK_SPACE 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: KEY_BOARD_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,KEY_BOARD_INPUT
CALL READ_STRING
MOV CL,NUM_CHARS_READ ;Get number of characters read
XOR CH,CH ;Set upper byte of count to zero
CMP CL,0 ;Return error if no characters read
JLE BAD_DECIMAL_DIGIT ;No chars read, signal error
XOR AX,AX ;Start with number set to zero
XOR BX,BX ;Start at beginning of string
CONVERT_DIGIT:
MOV DX,10 ;Multiply number by 10
MUL DX ;Multiply AX 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 character
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 READ_BYTE
;-----------------------------------------------------------------------;
; This procedure reads either a single ASCII character. This is just ;
; a test version of READ_BYTE. ;
; ;
; Returns byte in AL Character code (unless AH = 0) ;
; AH 1 if read ASCII char ;
; 0 if no characters read ;
; -1 if read a special key ;
; ;
; Uses: HEX_TO_BYTE, STRING_TO_UPPER, READ_STRING ;
; Reads: KEY_BOARD_INPUT, etc. ;
;-----------------------------------------------------------------------;
READ_BYTE PROC NEAR
PUSH DX
MOV CHAR_NUM_LIMIT,3 ;Allow only two characters (plus enter)
LEA DX,KEY_BOARD_INPUT
CALL READ_STRING
CMP NUM_CHARS_READ,1 ;See how many characters
JE ASCII_INPUT ;Just one, treat as ASCII character
JB NO_CHARACTERS ;Only enter key hit
CMP NUM_CHARS_READ,0FFH ;Special function key?
JE SPECIAL_KEY ;Yes.
CALL STRING_TO_UPPER ;No, convert string to upper-case
LEA DX,CHARS ;Address of string to convert
CALL HEX_TO_BYTE ;Convert string from hex to byte
JC NO_CHARACTERS ;Error, so return 'no characters read'
MOV AH,1 ;Signal read one character
DONE_READ:
POP DX
RET
NO_CHARACTERS:
XOR AH,AH ;Set to 'no characters read'
JMP DONE_READ
ASCII_INPUT:
MOV AL,CHARS ;Load character read
MOV AH,1 ;Signal read one character
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 HEX_TO_BYTE
;-----------------------------------------------------------------------;
; This procedure converts the two characters at DS:DX from hex to one ;
; byte. ;
; ;
; DS:DX Address of two characters for hex number ;
;Returns: ;
; AL Byte ;
; CF Set for error, clear if no error ;
; AH changed ;
; ;
; Uses: CONVERT_HEX_DIGIT ;
;-----------------------------------------------------------------------;
HEX_TO_BYTE PROC NEAR
PUSH BX
PUSH CX
MOV BX,DX ;Put address in BX for indirect addr
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 CONVERT_HEX_DIGIT
;-----------------------------------------------------------------------;
; This procedure converts a character 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
CODE_SEG ENDS
END