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!!