[comp.lang.pascal] Passing commands to DOS

jduarte@BONNIE.ICS.UCI.EDU (04/10/90)

Hi 'Netters!!

I was wondering if any of you know how to "put" characters into the
character queue for DOS-based machines...I'm trying to write a
program that will put these characters in the keyboard buffer.

I have tried the Interrupt #16 I believe with #5 or something like that,
but my machine refuses to recognize 'em. Any help???

Thanks,
Jose D.
P.S. - I am using TP5.0 w/DOS 3.1 on a clone.

indridi@rhi.hi.is (Indridi Bjornsson) (04/11/90)

In article <9004091113.aa22797@BONNIE.ICS.UCI.EDU> jduate@BONNIE.ICS.UCI.EDU
writes:

>Hi 'Netters!!

>I was wondering if any of you know how to "put" characters into the
>character queue for DOS-based machines...I'm trying to write a
>program that will put these characters in the keyboard buffer.

>I have tried the Interrupt #16 I believe with #5 or something like that,
>but my machine refuses to recognize 'em. Any help???


   YES ! you are right about INT 16h (AH=5h), it is Keyboard
Write, but it doesn't work with all machines. It only
works on limited numbers if XT's, but for most AT's and
386's. In IBM Technical Reference is stated that the
Keyboard Write interrupt is supported in:
   AT BIOS dated 11/15/85 and after
   XT BIOS dated 01/10/86 and after
   PC XT Model 286 and ofcourse
   PS/2

   So, if you have a BIOS that doesn't support the Keyboard
Write you just have to do it yourself.
   The keyboard buffer is implemented as circular queue, standard
32 bytes of length (When I say standard I mean there are some
program that change it), and is located in [$0040:$001E]. Each
character in the buffer take one Word, one char for itself and
one for the scan code (exept when it is a function key). In the
BIOS working area are also two pointers:

   Keyboard Buffer Head Pointer (located at [$0040:$001A])
   Keyboard Buffer Tail Pointer (located at [$0040:$001C]).

You have also two other locations in the Bios that store
information about the keyboard buffer, they are:

   Keyboard Buffer Start Offset Pointer (at [$0040:$0080])
   Keyboard Buffer End   Offset Pointer (at [$0040:$0080])

they usualy contain $1e=30 and $3e=62 which are at the
beginning and the end of the buffer.
   The Tail pointer points at next avaliable location in the
buffer but the Head pointer points at the next key to read.

           H e l l o   W o r l d
           ^                     ^
          Head                  Tail

If Head=Tail then the buffer is empty. So to put a key in
the buffer you have to:
   - check to see if the buffer is full (Head-Tail) > 2
     (BE AWARE: It's a circular queue)
   - put the char and the scan code, at the location where
     the Head is pointing to.
   - Advance the Head to the next position.
Here is a litle Demo I wrote in TP:

--cut here -- cut here --
PROGRAM KeyboardDemo;
USES Dos,CRT;
VAR
   BufferStart:WORD ABSOLUTE $0040:$0080;
   BufferEnd  :WORD ABSOLUTE $0040:$0082;
   BufferHead :WORD ABSOLUTE $0040:$001A;
   BufferTail :WORD ABSOLUTE $0040:$001C;
   Buffer     :Array[0..$3D] OF Char ABSOLUTE $0040:$0000;
   { BufferHead/Tail contain the offset in segment $0040 
     so we just let the Buffer begin at $0040:$0000     }
   Shift_Status: Byte Absolute $0000:$0417;

   FUNCTION KBPDec(HH:Word):Word;
   BEGIN
      HH:=HH-2;
      IF (HH=BufferStart) THEN
         HH:=BufferEnd;
      KBPDec:=HH;
   END;

   FUNCTION KBPInc(HH:Word):Word;
   BEGIN
      HH:=HH+2;
      IF (HH=BufferEnd) THEN
         HH:=BufferStart;
      KBPInc:=HH;
   END;

   PROCEDURE ClrKBBuffer;
   BEGIN
      BufferHead:=BufferTail;
      Shift_Status:=0;
      { Clear the SHIFT Status to }
   END;

   FUNCTION KBFull:Boolean;
   VAR
      temp:Word;
   BEGIN
      temp:=KBPInc(BufferTail);
      KBFull:=(temp=BufferHead);
   END;

   FUNCTION KBEmpty:Boolean;
   VAR
      temp:Word;
   BEGIN
      KBEmpty:=(BufferHead=BufferTail);
   END;

   PROCEDURE KBWrite(Key,Scan:Char);
   BEGIN
      Buffer[BufferTail]:=Key;
      Buffer[BufferTail+1]:=Scan;
      BufferTail:=KBPInc(BufferTail);
   END;

VAR
   temp : Integer;
   STR  : String;
BEGIN
   ClrScr;
   STR:='Hello world here I come';
   FOR temp:=1 TO Length(STR) DO
   IF Not(KBFull) THEN
      BEGIN
         { If they buffer isn't full so we can write into it }
         KBWrite(STR[temp],' ');
      END;
   Write('Here is the contenent of the Buffer : ');
   ReadLn(STR);
END.
--cut here -- cut here --

   This is a bit "Brute force" way for implementing Keyboard
Write 'cause it can conflict with the "real" one
(INT 9h). But on most occasion it will work.
   You could also fiddle with the DOS template (INT 21h AH=0Ah &
AH=0Ch), but that's another story.

Hope this will help :-)

--
    Indridi Bjornsson                 
    Ljosheimum 18A, 4h.                 Internet: indridi@rhi.hi.is
    104 Reykjavik.                          UUCP: ..!mcvax!hafro!rhi!indridi
    ICELAND                                       University of Iceland.
------------------------------------------------------------------------------

n257cl@tamunix.tamu.edu (Sean Malloy) (04/13/90)

AHEM

Interrupt #16 is actually interrupt 16h (decimal 22)...  Although PASCAL
may seem to operate in base 10 (decimal) your machine works best with
numbers which are base 2 or base 16 (hexadecimal).  Hope this helps.

-Sean