FreeDOS Keyboard Hooks: INT 15h/AH=4Fh Return Semantics Across BIOSes
Compare IBM and Phoenix descriptions of BIOS INT 15h/AH=4Fh, detect documented support, and avoid assuming one carry-flag contract across machines.
Some IBM-compatible BIOSes offer a keyboard-intercept callback before their normal keyboard interrupt handler processes a scan code. A real-mode FreeDOS program or resident utility may encounter this interface as INT 15h with AH=4Fh. It is a firmware callback, not a DOS INT 21h service and not a feature installed by the FreeDOS kernel. Its availability and exact compatibility therefore depend on the machine’s BIOS.
The useful design boundary is that this hook operates on BIOS scan-code handling before the INT 16h keyboard-buffer interface. It is not an ASCII-key callback and does not replace INT 16h for ordinary application input. Do not infer that every key on every BIOS will pass through the hook.
Check support before installing a dependency
IBM documents AH=4Fh only for later XT/AT BIOS families and other listed systems. Older or unsupported models return an error instead of providing the intercept. The IBM technical reference describes querying INT 15h/AH=C0h for system-configuration parameters; feature-information byte 1, bit 4 indicates whether the keyboard-intercept sequence is called during INT 09h processing.
A defensive program should test the firmware capability before relying on the hook, then test the target BIOS family under an emulator or hardware configuration that matches deployment. A successful capability query is a compatibility signal, not proof that every other resident keyboard handler preserves the chain.
The manuals disagree about what a clear carry means
Both references describe AH=4Fh as a scan-code intercept, and both document a changed scan code in AL with carry set. Their descriptions of an unchanged code and a clear carry do not line up, however. The IBM Personal System/2 and PC BIOS Interface Technical Reference says a resident handler can replace AL and return with carry set, or process the event and clear carry so the INT 09h routine ignores the keystroke. In the same passage, its output summary labels the clear-carry result as an unchanged scan code. Phoenix’s System BIOS for IBM PC/XT/AT Computers and Compatibles first distinguishes the no-alternate-handler path: when no alternate routine intercepts the call, the BIOS returns with AL unchanged and carry clear. Its later input/output summary labels carry clear as “keystroke unchanged” and carry set as “keystroke changed.”
Do not collapse these into a portable table saying that one carry value always means “pass unchanged” or “consume.” The IBM prose describes a resident interceptor’s clear-carry action as consuming the key, while its adjacent output line and Phoenix’s summary use clear carry for an unchanged code. The Phoenix text also makes clear that an unchanged/clear-carry default return when there is no alternate handler is a different situation from a resident handler deliberately responding to the hook. These excerpts may describe different default/fall-through and intercepted-handler contexts, but that is an interpretation, not a guarantee stated consistently by both sources. The actual BIOS family and version must decide the contract.
For a handler intended to alter a key, both manuals associate a changed scan code in AL with carry set. For an unchanged key or an intentionally suppressed key, do not choose a carry-flag response from a generic online summary: verify the original manual for the target BIOS and test the actual firmware behavior. Keep the handler short and avoid DOS calls, blocking work, or assumptions about character translation while executing in the keyboard interrupt path.
The interface description is not a complete TSR implementation. A resident program still needs correct interrupt-vector ownership, chaining, register and flags preservation, and a clean unload policy. Use the conventions supported by the exact DOS and BIOS target; do not copy an INT 09h hook that reads controller ports when the goal is only to inspect a firmware-level scan-code intercept.
Keep firmware input separate from DOS input
INT 16h reads keys after BIOS processing and translation into the keyboard buffer. The INT 15h/AH=4Fh hook runs earlier and can alter or suppress the scan code before that stage. A test that only calls INT 16h cannot prove the earlier callback exists; likewise, seeing a callback does not guarantee that a later DOS or resident-driver layer leaves the translated character unchanged.
For a compatibility test, record the machine or emulator BIOS, whether the AH=C0h feature bit is set, the input scan code, AL and carry at each documented boundary, and the eventual INT 16h result. Test make and break sequences and an ordinary unaffected key. Keep the test non-resident until its behavior is understood. If the feature is absent, use a separately documented fallback rather than relying on an undocumented interrupt side effect.
This interface is relevant to FreeDOS software precisely because DOS applications can run on different firmware implementations. The manual contract provides a narrow compatibility hook; it does not promise a portable keyboard driver API across all FreeDOS machines.
Related:
- DOS BIOS Keyboard Input: INT 16h, Buffer Semantics, and Enhanced Keys
- The PC/AT 8042 Keyboard Controller: Status, Buffers, and Safe Ownership
Sources: