INT 16h AH=05h adds the word in CX to the tail of the keyboard buffer, CL as the ASCII byte and CH as the scan code, exactly where the keyboard handler would have put a real key. To everyone reading the keyboard afterwards, the BIOS functions and DOS alike, it is indistinguishable from typing. It returns AL = 0 on success and AL = 1 when the buffer has no room.
It came with the AT's BIOS (1986 revisions) and the enhanced keyboard. Typical uses: keyboard macro programs, a menu that "types" a command into COMMAND.COM before it exits, and test programs like the examples in this chapter, which feed themselves keys instead of waiting for a person. Here DOS reads two stored keys:
MOV AH, 05h ; BIOS: store a keystrokeMOV CX, 184Fh ; "O": scan code 18h, ASCII 4FhINT 16h ; AL = 0: storedMOV AH, 05hMOV CX, 254Bh ; "K": scan code 25h, ASCII 4BhINT 16hMOV AH, 08h ; DOS: read a key without echoINT 21h ; it gets the "O" from the BIOS bufferMOV DL, ALMOV AH, 02h ; DOS: print the character in DLINT 21hMOV AH, 08hINT 21h ; and the "K"MOV DL, ALMOV AH, 02h ; DOS: print the character in DLINT 21h
How many fit
The standard buffer has 16 word slots, but one always stays free so that a full ring can be told from an empty one: 15 keys. The example fills an empty buffer until AH=05h says no, then reads everything out again so nothing is left for the command line.
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:XOR BX, BX ; keys stored so farSTORE1:MOV AH, 05hMOV CX, 3920h ; the space bar: scan 39h, ASCII 20hINT 16hTEST AL, AL ; 0 = stored, 1 = fullJNZ FULL1INC BXCMP BX, 20 ; a safety stopJB STORE1FULL1:MOV AX, BXCALL PDEC ; 15MOV DX, OFFSET FIT1MOV AH, 09h ; DOS: print the $-string at DS:DXINT 21hDRAIN1:MOV AH, 01h ; empty the buffer againINT 16hJZ DONE1MOV AH, 00hINT 16hJMP DRAIN1DONE1:FIT1 DB " keys fit in the buffer$"PDEC PROC NEAR ; print AX in decimal; keeps every registerPUSH AXPUSH BXPUSH CXPUSH DXMOV BX, 10XOR CX, CX ; digits on the stackDECD1:XOR DX, DXDIV BX ; AX = AX / 10, DX = the last digitPUSH DXINC CXTEST AX, AXJNZ DECD1DECD2:POP DX ; the digits come back first to lastADD DL, "0"MOV AH, 02hINT 21hLOOP DECD2POP DXPOP CXPOP BXPOP AXRETPDEC ENDP
Pitfalls
Pass the scan code as well as the character: many programs look only at AH, and a key stored as 0041h is an "A" with no key behind it. Any word is accepted, including ones no keyboard produces. A program that stores keys and exits without reading them leaves them for COMMAND.COM to execute, which is the trick on purpose and a nuisance by accident. The original PC and XT BIOSes do not have this function (it returns with nothing done); there a program writes the word into the buffer and moves the tail pointer at 0040:001Ch itself, with interrupts disabled.