mead@uxh.cso.uiuc.edu (09/02/90)
A while back, I asked if there was any way to "chain" from a Turbo
Pascal (V5.5) program to another. I suggested stuffing the keyboard
buffer, but didn't know how to do this. I have since learned, and for
the people who tried to help me, as well as for the curious, here it is:
The keyboard buffer is 16 words of memory from $0040:$001e to $003c.
The buffer is a circular queue - the head pointer points to the head
of the queue from $0040:$001a and the tail from $001b. (So all
totaled, the buffer uses 17 words. As a warning, I've seen utilities
that are supposed to increase the buffer area, I'm not sure whether
this will work in these cases.)
As a consequence of this, you may clear the buffer by setting the
head and tail to $0040:$001e (the first position of the queue)
instead of: WHILE KeyPressed DO ch := ReadKey; . Hopefully, this
will be intuitive from the listing. I'm not sure which is more
efficient, but I imagine that the direct method would be superior if
you had to use it often.
======
program Demo_Chaining_Process;
{ Drives CHAIN }
procedure Chain( s : string; { The string to be outputted }
CRSwitch : boolean ); { Add a CR at the end? }
{
Places S into the keyboard buffer (thereby destroying any keystrokes
that happen to be lying around) resulting in S being operated
upon by DOS (provided that the program terminates without reading
the keyboard buffer).
Lifted from similar code in _Using Turbo Pascal_ by Michael Yester (p241)
}
const
ASCIIEnter = 13; { ENTER's ASCII value }
ExtEnter = 28; { ENTER's extended scan code }
type
KeyBufferType = array[ $1e..$3d ] of byte; { 16 words ... }
var
i, Len : byte;
HeadPointer : byte absolute $0040:$001a;
TailPointer : byte absolute $0040:$001c;
KeyBuffer : ^KeyBufferType;
begin
KeyBuffer := Ptr( $0040,$001e ); { The buffer is contiguous with the }
{ head & tail pointers at $001a & }
{ $001c. }
TailPointer := $1e; { The choice of subscripts makes }
HeadPointer := $1e; { makes life easier. }
Len := Length( s );
if CRSwitch then
if Len > 14 then { ... then it's too long - we need room for the CR }
Len := 14
else
if Len > 15 then
Len := 15;
for i := 1 to Len do
begin
KeyBuffer^[ TailPointer ] := ord( s[i] );
inc(TailPointer,2);
end;
if CRSwitch then
begin
KeyBuffer^[ TailPointer ] := ASCIIEnter;
KeyBuffer^[ TailPointer+1 ] := ExtEnter;
inc( TailPointer,2 );
end;
end;
begin { Main }
Chain( 'dir demochn.*',TRUE );
{Chain( 'demochn',TRUE );} { Try this :) }
end.
============
I'm not sure how the queue works, but as you can see from the last
assignments to the buffer (ASCIIEnter & ExtEnter), both the ASCII and
the Extended Scan Codes need to be stuffed.
Also, the buffer has 16 words of space, but strings greater than 15
bytes cause amusing results (well, not so amusing in the IDE). I guess
that (as implied by my comments above) whenever the pointers point to
the same word, that word isn't used.
Hope this helps,
-alan mead