{$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.
               (
geocities.com/SiliconValley/2926)                   (
geocities.com/SiliconValley)