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.

prints: a is 61h (the "a" is the echo)
MOV CX, 1E61h ; "a": scan code 1Eh, ASCII 61h
MOV AH, 05h ; BIOS: store a keystroke in the keyboard buffer
INT 16h
MOV AH, 01h ; DOS: read a key, with echo
INT 21h ; prints the "a"; AL = 61h
PUSH AX
MOV DX, OFFSET MSG1
MOV AH, 09h ; DOS: print the string at DS:DX
INT 21h
POP AX
CALL HEX2
MOV DL, "h"
MOV AH, 02h ; DOS: print the character in DL
INT 21h
MSG1 DB " is $"
HEX2 PROC NEAR ; print AL as two hex digits
PUSH AX
MOV CL, 4
SHR AL, CL ; the high digit first
CALL NIB1
POP AX
AND AL, 0Fh ; then the low one
CALL NIB1
RET
HEX2 ENDP
NIB1 PROC NEAR ; print AL (0-15) as one hex digit
ADD AL, "0"
CMP AL, "9"
JBE NIB2
ADD AL, 7 ; 10-15 become "A"-"F"
NIB2:
MOV DL, AL
MOV AH, 02h
INT 21h
RET
NIB1 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:

ServiceWaits for a keyEchoCtrl+C
INT 21h AH=01hyesyes^C, INT 23h: normally the end of the program
INT 21h AH=06h (DL = FFh)no: ZF = 1 when none is waitingnoreturned as 03h
INT 21h AH=07hyesnoreturned as 03h
INT 21h AH=08hyesno^C, INT 23h
INT 21h AH=0Ahfor a whole line, up to Enteryes^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.