home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
assemblr
/
library
/
nor_asm
/
kbd_io.asm
< prev
next >
Wrap
Assembly Source File
|
1989-08-13
|
14KB
|
424 lines
.MODEL SMALL
;-----------------------------------------------------------------------;
; This file contains procedures for working with the keyboard: ;
; ;
; READ_KEY 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 ;Backspace character
CR EQU 13 ;Carriage-return character
ESCAPE EQU 27 ;Escape character
.DATA
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
.CODE
PUBLIC READ_KEY
;-----------------------------------------------------------------------;
; This procedure reads one key from the keyboard. ;
; ;
; Returns: AL Character code (unless AH = 1) ;
; AH 0 if read ASCII char ;
; 1 if read a special key ;
;-----------------------------------------------------------------------;
READ_KEY PROC
XOR AH,AH ;Ask for keyboard read function
INT 16h ;Read character/scan code from keyboard
OR AL,AL ;Is it an extended code?
JZ EXTENDED_CODE ;Yes
NOT_EXTENDED:
XOR AH,AH ;Return just the ASCII code
DONE_READING:
RET
EXTENDED_CODE:
MOV AL,AH ;Put scan code into AL
MOV AH,1 ;Signal extended code
JMP DONE_READING
READ_KEY ENDP
PUBLIC STRING_TO_UPPER
;-----------------------------------------------------------------------;
; This procedure converts the stinrg, using the DOS format for strings, ;
; to all uppercase letters. ;
; ;
; DS:DX Address of string buffer ;
;-----------------------------------------------------------------------;
STRING_TO_UPPER PROC
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
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:PROC
EXTRN UPDATE_REAL_CURSOR:PROC
;-----------------------------------------------------------------------;
; This procedure performs a function very similar to the DOS 0Ah ;
; function. But this function will return a special character if a ;
; function or keyboard 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_KEY, UPDATE_REAL_CURSOR ;
;-----------------------------------------------------------------------;
READ_STRING PROC
PUSH AX
PUSH BX
PUSH SI
MOV SI,DX ;Use SI for index register and
START_OVER:
CALL UPDATE_REAL_CURSOR ;Move to position of virtual cursor
MOV BX,2 ;BX for offset to beginning of buffer
CALL READ_KEY ;Read one key from the keyboard
OR AH,AH ;Is character extended ASCII?
JNZ EXTENDED ;Yes, then process it.
STRING_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 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,ESCAPE ;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 UPDATE_REAL_CURSOR ;Move real cursor to virtual cursor
CALL READ_KEY
OR AH,AH ;An extended ASCII char is not valid
; when the buffer is not empty
JZ STRING_NOT_EXTENDED ;Char is valid
;-----------------------------------------------;
; 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: ;Read an extended ASCII code
MOV [SI+2],AL ;Place just this char in 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:PROC
EXTRN READ_CURSOR_POSITION:PROC, GOTO_XY:PROC
;-----------------------------------------------------------------------;
; 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 ;
; ;
; Note: The version of BACK_SPACE presented in the book doesn't work ;
; with the version of WRITE_CHAR that writes directly to the ;
; screen. This version works properly with both versions. ;
; ;
; Uses: WRITE_CHAR ;
;-----------------------------------------------------------------------;
BACK_SPACE PROC ;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
CALL READ_CURSOR_POSITION ;Get the current cursor position
DEC DL ;Move cursor left one column
CALL GOTO_XY
PUSH DX ;Save new cursor position
MOV DL,20h ;Write space there
CALL WRITE_CHAR
POP DX ;Get back new cursor position
CALL GOTO_XY
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: KEYBOARD_INPUT, etc. ;
; Writes: KEYBOARD_INPUT, etc. ;
;-----------------------------------------------------------------------;
READ_DECIMAL PROC
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 characters read
XOR CH,CH ;Set upper byte of count to 0
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 0
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 or a two-digit ;
; hex number. This is just a test version of READ_BYTE. ;
; ;
; Returns byte in AL Character code (unless AH = 0) ;
; AH 0 if read ASCII char ;
; 1 if read a special key ;
; -1 if no characters read ;
; ;
; Uses: HEX_TO_BYTE, STRING_TO_UPPER, READ_STRING ;
; Reads: KEYBOARD_INPUT, etc. ;
; Writes: KEYBOARD_INPUT, etc. ;
;-----------------------------------------------------------------------;
READ_BYTE PROC
PUSH DX
MOV CHAR_NUM_LIMIT,3 ;Allow only two characters (plus Enter)
LEA DX,KEYBOARD_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 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 'no characters read'
XOR AH,AH ;Signal read one byte
DONE_READ:
POP DX
RET
NO_CHARACTERS:
XOR AH,AH ;Set to 'no characters read'
NOT AH ;Return -1 in AH
JMP DONE_READ
ASCII_INPUT:
MOV AL,CHARS ;Load character read
XOR AH,AH ;Signal read one byte
JMP DONE_READ
SPECIAL_KEY:
MOV AL,CHARS[0] ;Return the scan code
MOV AH,1 ;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
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
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
END