{$A+,B-,D-,E-,F-,G-,I-,L-,N-,R-,S-,V-,X-} unit KeyBrdP; interface function ExtKbrd : boolean; implementation uses dos; var OldInt16, OldInt60, ExitSave : pointer; procedure Int16(_Flags,_CS,_IP,_AX,_BX,_CX,_DX,_SI,_DI,_DS,_ES,_BP: Word); interrupt; var Regs : Registers; begin with Regs do begin ax := _ax; if ah <= 2 then Inc(ah, $10); Intr($60, Regs); _Flags := Flags; if (al = $E0) and (ah <> 0) then al := 0; _ax := ax; end; end; function ExtKbrd : boolean; var Regs : Registers; begin with Regs do begin AX := $1200; Intr($16, Regs); ExtKbrd := (AX <> $1200); end; end; procedure UnitExitProc; far; begin ExitProc := ExitSave; SetIntVec($16, OldInt16); SetIntVec($60, OldInt60); end; begin if ExtKbrd then begin GetIntVec($16, OldInt16); GetIntVec($60, OldInt60); SetIntVec($60, OldInt16); SetIntVec($16, @Int16); ExitSave := ExitProc; ExitProc := @UnitExitProc; end; end. As you can see, we can get by without using assembly by using the keyword interrupt, which makes writing interrupt procedures in BP/TP easy. (If you are not familiar with this keyword and the required procedure header, consult your Borland manuals). Because of the requirements of the Intr procedure, it is necessary to store the old INT $16 in a user defined interrupt. Number $60 is usually available for this purpose. Some of the enhanced cursor key's (basically, the gray keys) give an ASCII value $E0, so this is changed to $0 to give results consistent with the equivalent white keys, but not before checking that the user didn't enter Alt-224. The unit also inserts its own exit routine in the chain of exit procedures, which automatically resets the changed interrupt vectors when your program exits. To USE this unit and make ReadKey and KeyPressed recognize enhanced keystokes, simply add the unit name to the USES clause in your main program. Here's a simple test program you can use: program TestKeyb; uses crt, dos, keybrdP; var ch : char; begin ClrScr; repeat ch := ReadKey; if (ch = #0) then begin ch := ReadKey; writeln('0 ',ord(ch)); end else writeln(ord(ch)); until ch = #27; { pressing Esc key exits } end. Of course my unit is not without its drawbacks. Evidently, if you need to support enhanced keyboards on machines *without* an enhanced keyboard BIOS, (PC-XT's) then this unit won't solve your problem. In that case, you will need to write a replacement INT $9 handler. Turbo Vision programs install a replacement INT $9 handler to allow certain special key combinations to be recognized. If you have BP7 and want to know how this is done, take a look at SYSINT.ASM in the the supplied Runtime Library Source Code. Frankly, I can't see much need for this, since XT's are obsolete anyway, and many of those machines still in use don't have an enhanced keyboard. A second objection to my unit could be that it requires a user defined interrupt. The need for this can be obviated if you are willing to use the inline assembler (BASM), which is better anyway to use in an interrupt handler because it allows for more compact code. Here's a functionally equivalent version of my unit using BASM : {$A+,B-,D-,E-,F-,G-,I-,L-,N-,R-,S-,V-,X-} unit KeyBrdA; interface function ExtKbrd : boolean; implementation uses dos; var OldInt16, ExitSave : pointer; procedure Int16; assembler; asm push bp mov bp, sp push ds push ax mov ax, SEG @Data { need DS to point to data segment in order } mov ds, ax { to access Pascal variables } pop ax pushf { must push flags on stack ourselves since } cmp ah, 2 { INT expects flags to be pushed on stack, } ja @OldInt { whereas CALL only pushes return address } add ah, 10h @OldInt: call OldInt16 pushf { update flags which were originally pushed } pop word ptr [bp+6] { on stack at entry of this handler } cmp al, 0E0h jne @Exit cmp ah, 0 je @Exit xor al, al @Exit: pop ds pop bp iret end; function ExtKbrd : boolean; assembler; asm mov ax, 1200h int 16h cmp ax, 1200h mov ax, 0 je @Exit inc ax @Exit: end; procedure UnitExitProc; far; begin ExitProc := ExitSave; SetIntVec($16, OldInt16); end; begin if ExtKbrd then begin GetIntVec($16, OldInt16); SetIntVec($16, @Int16); ExitSave := ExitProc; ExitProc := @UnitExitProc; end; end.