INT 16h AH=01h looks at the head of the keyboard buffer and returns at once. The answer is in the zero flag: ZF = 1 means the buffer is empty, ZF = 0 means a key is there, and then AX holds it exactly as INT 16h AH=00h would return it. The key is not removed: call 01h ten times and you see the same key ten times. To consume it, follow with AH=00h, which then returns immediately.
The example empties the buffer, stores an "X", and peeks at it several times before reading it:
FLUSH1:MOV AH, 01h ; BIOS: is a key waiting?INT 16hJZ EMPTY1 ; ZF = 1: the buffer is emptyMOV AH, 00h ; take the key outINT 16hJMP FLUSH1EMPTY1:CALL PEEK1 ; empty: prints -MOV AH, 05h ; store "X": scan 2Dh, ASCII 58hMOV CX, 2D58hINT 16hCALL PEEK1 ; 2D58CALL PEEK1 ; 2D58 again: 01h leaves the key where it isMOV AH, 00h ; now take it outINT 16hCALL PEEK1 ; empty again: -PEEK1 PROC NEAR ; INT 16h AH=01h, then print the key or "-"MOV AH, 01hINT 16h ; ZF = 1: nothing waitingJZ NONE1CALL PHEX4 ; the key, still in the bufferJMP GAP1NONE1:MOV DL, "-"MOV AH, 02hINT 21hGAP1:MOV DL, " "MOV AH, 02hINT 21hRETPEEK1 ENDPPHEX4 PROC NEAR ; print AX as four hex digits; keeps every registerPUSH AXMOV AL, AHCALL PHEX2 ; the high byte firstPOP AXCALL PHEX2 ; then the low byteRETPHEX4 ENDPPHEX2 PROC NEAR ; print AL as two hex digits; keeps every registerPUSH AXPUSH CXPUSH DXMOV DH, AL ; keep the byteMOV CL, 4SHR AL, CL ; the high nibbleCALL HEXN1MOV AL, DHAND AL, 0Fh ; the low nibbleCALL HEXN1POP DXPOP CXPOP AXRETHEXN1:ADD AL, "0"CMP AL, "9"JBE HEXN2ADD AL, 7 ; past "9": "A".."F"HEXN2:MOV DL, ALMOV AH, 02hINT 21hRETPHEX2 ENDP
The polling loop
This is how a program does its own work and still reacts to keys: check, do one step, check again. The loop below never blocks; when a key turns up it is read and handled, and the work goes on.
MAIN1:; ... one frame of work: move, draw ...MOV AH, 01h ; a key?INT 16hJZ MAIN1 ; no: carry onMOV AH, 00h ; yes: take itINT 16hCMP AL, 1Bh ; Esc ends the loopJNE MAIN1
Pitfalls
Test ZF straight after the INT; the BIOS returns it by changing the flags saved on the stack, and any CMP or arithmetic in between destroys the answer. The value in AX when ZF = 1 is undefined: some BIOSes leave AH = 01h, some zero it. Like 00h, this function hides the extended-keyboard keys: in DOSBox-X a waiting F11 or F12 is quietly removed from the buffer and the call reports the key after it, or none. INT 16h AH=11h is the enhanced version. The DOS equivalent is INT 21h AH=0Bh, which also checks for Ctrl+C.