INT 21h AH=01h waits until a key is available, writes it to standard output and returns it in AL. It is the simplest way to ask a question the user should see the answer to, a Y/N prompt for example. The key is read from handle 0, the keyboard unless input is redirected; underneath, the CON driver asks the BIOS (INT 16h AH=00h), so the key returned is the oldest one in the BIOS buffer, which may have been typed long before the call.
MOV CX, 1E61h ; "a": scan code 1Eh, ASCII 61hMOV AH, 05h ; BIOS: store a keystroke in the keyboard bufferINT 16hMOV AH, 01h ; DOS: read a key, with echoINT 21h ; prints the "a"; AL = 61hPUSH AXMOV DX, OFFSET MSG1MOV AH, 09h ; DOS: print the string at DS:DXINT 21hPOP AXCALL HEX2MOV DL, "h"MOV AH, 02h ; DOS: print the character in DLINT 21hMSG1 DB " is $"HEX2 PROC NEAR ; print AL as two hex digitsPUSH AXMOV CL, 4SHR AL, CL ; the high digit firstCALL NIB1POP AXAND AL, 0Fh ; then the low oneCALL NIB1RETHEX2 ENDPNIB1 PROC NEAR ; print AL (0-15) as one hex digitADD AL, "0"CMP AL, "9"JBE NIB2ADD AL, 7 ; 10-15 become "A"-"F"NIB2:MOV DL, ALMOV AH, 02hINT 21hRETNIB1 ENDP
The example does its own typing: INT 16h AH=05h puts a keystroke into the BIOS keyboard buffer (CH = scan code, CL = ASCII code), exactly where the keyboard interrupt would have put it, so the program runs without anyone at the keyboard. Leave those lines out and it waits for you instead.
Special keys
Function keys, arrows, Home, End and Alt combinations have no ASCII code. For them the service returns AL = 0, and the next call returns the scan code: F1 is 00h then 3Bh, the up arrow 00h then 48h. A program must test for 0 and call again, or the scan code is taken for the next character. Both bytes are echoed as characters, which prints junk on the screen; read special keys with INT 21h AH=07h or INT 21h AH=08h, which do not echo.
The echo
The echo is a plain character write. Enter returns 0Dh and echoes a carriage return only: the cursor goes back to the start of the same line, and the next output overwrites the answer unless the program prints CR LF itself. Backspace returns 08h and echoes as a step to the left that erases nothing. Since DOS 2 the echo goes to standard output, so with output redirected it lands in the file and the screen shows nothing.
The five DOS services that read keys differ in three ways:
| Service | Waits for a key | Echo | Ctrl+C |
|---|---|---|---|
INT 21h AH=01h | yes | yes | ^C, INT 23h: normally the end of the program |
INT 21h AH=06h (DL = FFh) | no: ZF = 1 when none is waiting | no | returned as 03h |
INT 21h AH=07h | yes | no | returned as 03h |
INT 21h AH=08h | yes | no | ^C, INT 23h |
INT 21h AH=0Ah | for a whole line, up to Enter | yes | ^C, INT 23h |
Ctrl+C
If the key is Ctrl+C (03h), DOS prints ^C and executes INT 23h, which normally ends the program: the call never returns. Read with INT 21h AH=07h when the program has to see every key, Ctrl+C included, or install an INT 23h handler of its own.