[comp.sys.ibm.pc.programmer] An advance DOS question .. may be!

rhys@batserver.cs.uq.oz.au (Rhys Weatherley) (05/02/90)

lubkt@vax1.cc.lehigh.edu writes:


>Here is a DOS question:

>Suppose there  is a program which does  not permit DOS I/O-redirection
>(I don't know why).  Suppose you really want to  force this program to
>read a set of keystrokes  stored in  a file.  After reading this file,
>which can be controlled by a user, the program should read  input from
>the keyboard. Basically, the idea is to automate hitting keystrokes to
>some extent.  Any suggestions?

>I love  C, but I  could consider writing  it in assembly language if I
>have to. Thanks in advance.

Usually a program will not respond to input redirection if it bypasses 
the normal DOS input handling routines and either:

	1. Uses the BIOS ROM routines to get keypresses, through
	   interrupt 16H.
	2. Traps the interrupt 09H which is called every time a key
	   is pressed on the keyboard and retreives its keys from
	   the hardware before processing them.
	3. Accesses the keyboard hardware directly through some
	   sort of polling mechanism.

I have never come across any programs that use the last method, but if
the program does use it, there is nothing you can do unfortunately.  The
second method also gives problems since you would need to re-write the
program's interrupt 09H handler, which may not be possible unless you
have the program source, or you are a very proficient machine code
hacker :-).  The first method however, can be tackled by one of the
following methods:

	(a) Try and find some keyboard macro processor, which is
	    usually a TSR (Terminate-and-Stay-Resident) program
	    which takes over the keyboard handling of the computer
	    to allow it to insert its own characters into the
	    keyboard buffer.  These programs usually allow you
	    to define keys, for example ALT-X could be defined to
	    produce a sequence of keystrokes to exit from your
	    favourite editor.  The macro processor sits in the
	    background and when you press ALT-X it will pass the
	    required keys through instead of ALT-X itself.  If you
	    can find a macro processor that allows you to assign
	    a file's contents to a key (or even part of a file)
	    you would be right.  However, since I don't use these
	    types of programs much I cannot recommend any, sorry.

	(b) Write your own macro processor!!  You could write your
	    own TSR program which traps either interrupt 09H or
	    interrupt 16H (16H is the better one) to return your
	    file's contents when a certain "hotkey" is pressed.
	    However, this introduces the many problems associated
	    with writing TSR's, notably of keeping DOS happy so
	    that you don't try and access the file when DOS is
	    already doing something else - the roof will cave in
	    otherwise.  Various books exist on the subject of
	    writing TSR's, including 'Performance Programming under
	    MS-DOS' by 'M.J. Young', published by Sybex, but usually
	    they don't give you the whole story, keeping the "juicy"
	    bits for themselves :-).  I have written a number of
	    TSR's but to date have not written a macro processor.

	(c) The final option (that I can think of anyway) is a
	    hybrid program which combines TSR and normal programming
	    techniques, by writing a "harness" program which traps
	    the interrupt 16H keyboard service, and then runs the
	    program you want to redirect input into.  An example
	    "skeleton" Turbo C program is given below.  Many details
	    have been left out but should be pretty obvious:


#include "process.h"

int	input_done;

main ()
{
  install_int_16h ();
  /* open the input file to use here */
  input_done = 0;
  spawnv ("PATHNAME-OF-PROGRAM-TO-RUN","",0); /* or some similar call */
  /* close the input file here */
  uninstall_int_16h ();
}

install_int_16h ()
{
  /* get the old address of the INT 16H handler and save it */
  /* set the INT 16H address to point to 'key_service'	    */
}

uninstall_int_16h ()
{
  /* restore the saved INT 16H address */
}

/* Actual details of the required behaviour of the     */
/* INT 16H handler below can be found in manuals about */
/* the BIOS ROM's.				       */
void	interrupt key_service ( /* regs */ )
{
  int ch;
  if ((AH & 0x03) != 2 && !input_done)
    {
      if ((AH & 0x03) == 1)
	{
	  ZF = /* ?? - indicate key is available */
	  AX = /* some useful key value - doesn't matter to much */
	  return;
	}
      ch = /* next character from input file */
      if (ch == EOF)
	input_done = 1;
       else
	{
	  AL = ch;
	  AH = /* scan code equivalent of the character 'ch' */
	  ZF = /* ?? - indicate a key is available */
	  return;
	}
    }
  /* call the original INT 16H handler at the saved address */
}

Note that this is only a skeleton program and the actual details
need to be fleshed out, especially the setting of registers, and
the ZF (zero flag).  Also, you need a very "well-behaved" program
for this technique to work satisfactorily, otherwise you could
get a very spectacular CRASH (interrupt routines produce the
weirdest problems!!) so your best bet is still probably writing a 
real TSR with the problems it involves.

Hope this information has helped a little, and I would also be
interested in any other feedback that the original question 
generates.


Rhys Weatherley, University of Queensland, Australia.  G'day!!