[comp.lang.pascal] Queueing multiple events in a Turbo Vision application

wolf@shaman.ingr.com (Wayne Wolf) (01/15/91)

I'm currently developing a Turbo Vision application and have encountered
a minor stumbling point in the implementation.  The application can be
run with the user at hand or can be run unattended.  Ideally it is 
desirable to produce only one set of code designed to handle the case where the
user is at the terminal.  To automate it would merely require a procedure
that would spool a series of events (mostly keyboard presses) to the main
event handler, simulating a user creating these events.  The code is there
already to handle this stream of events and no extra code is required to
process an automated request save that to spool the events into the event
queue.  My dilemma is this: I do not see a mechanism that allows me to 
queue up these events.  There exists a method for Views called PutEvent(Event)
which allows me to put an event into the event queue.  But, this is not helpful
as it only allows ONE event to be put into the queue, and placing a group of
these calls together has the net effect of only having the last call in the
list place an event in the queue.

I want to steer away from writing my own 'keyboard buffer inserter endall 
dohickey' mechanism if at all possible.  Does anyone know how to sneak into
the guts of the event handler and add new events to the end of the queue?
Or, worst case, a pointer to some example source code that will monitor the
keyboard buffer and when it drains to a sufficient level, pump in more 
keypresses (automated) from a user defined buffer.


Ideally I'd like to be able to call a method, say PlaceEventInQueue(NextEvent),
where my code would be as follows:

------

Procedure Automate;
Var
   NextEvent: TEvent;
Begin
   with NextEvent do begin
      What    := evKeyDown;
      InfoPtr := Nil;

      KeyCode := kbF3;
      PlaceEventInQueue(NextEvent);  (* simulate F3 press *)

      KeyCode := kbTab;
      PlaceEventInQueue(NextEvent);   (* simulate Tab press *)

      KeyCode := kbEnter
      PlaceEventInQueue(NextEvent);   (* simulate Enter press *)
   end; {with NextEvent}
End;

------

To the application, when calling this procedure, it would appear as if the
user had pressed F3, Tab, and then Enter.

Any suggestions are appreciated.  Thanx in advance.


..

Wayne Wolf

USENET  : ...!uunet!ingr!wyle!shaman!wolf  (try this one first)
Internet: ww@beach.cis.ufl.edu

wolf@shaman.ingr.com (Wayne Wolf) (01/16/91)

Yesterday I posted to this group, a query for some help in designing 
functionality into a Turbo Vision application to allow inserting multiple
events into the event queue.  I did not receive any response, but I did find
the solution after paging through the manual with more intensity.  There is
only a minor reference on how to accomplish this feat on page 125 under
heading "Overriding GetEvent."  I will include the source code I came up
with to perform this event queue.  The utility varies from implementing
keyboard macros, to automating your application by reading a stream of
commands and placing them into the event queue, to having one event cause
a chain of multile events to occur.  The code was written in about 30 mins
and tested briefly, but appears to work.  Any commentary is appreciated.
I hope this will help anyone else who wants to implement this sort of
functionality.  Following are the new class definition you should inherit
your application from, and then a sample program excerpt to show how the
new class and its methods are used.  Any usage questions, please send email
to either of ...!uunet!ingr!wyle!shaman!wolf or ww@beach.cis.ufl.edu.

---  Cut HERE -------

Unit AutoApp;
{$F+,O+}        (* Force far calls, allow overlaying *)

Interface

Uses
   App,
   Drivers;

Const
   MaxEventQueue = 50;
   NullEvent : TEvent = (What:evNothing);

Type
   EventQueueType = array[1..MaxEventQueue] of TEvent;

   PAutoApplication = ^TAutoApplication;
   TAutoApplication = object(TApplication)
      EventQueue : EventQueueType;
      QueueHead : word;
      QueueTail : word;

      Constructor Init;

      function    EventInQueue: boolean;
      procedure   GetEvent(var Event: TEvent); virtual;
      procedure   GetNextEventFromQueue(var Event: TEvent);
      procedure   InitEventQueue;
      procedure   PutEventIntoQueue(NewEvent: TEvent);
   End; {TAutoApplication}

Implementation

(*---------------------------------------------------------------------------*)
(*         M E T H O D S :  TAutoApplication                                 *)
(*---------------------------------------------------------------------------*)

   Constructor TAutoApplication.Init;
   Begin
      TApplication.Init;
      InitEventQueue;
   End;

(*---------------------------------------------------------------------------*)

   Function TAutoApplication.EventInQueue: boolean;
   Begin
      EventInQueue := QueueHead <> QueueTail;
   End;

(*---------------------------------------------------------------------------*)

   Procedure TAutoApplication.GetEvent(var Event: TEvent);
   Begin
      if EventInQueue then
         GetNextEventFromQueue(Event)
      else
         TApplication.GetEvent(Event);
   End;

(*---------------------------------------------------------------------------*)

   Procedure TAutoApplication.GetNextEventFromQueue(var Event: TEvent);
   Begin
      Event := EventQueue[QueueHead];
      EventQueue[QueueHead] := NullEvent;
      if QueueHead = MaxEventQueue then
         QueueHead := 1
      else
         inc(QueueHead);
   End;

(*---------------------------------------------------------------------------*)

   Procedure TAutoApplication.InitEventQueue;
   Var
      i : word;
   Begin
      QueueHead := 1;
      QueueTail := 1;
      for i := 1 to MaxEventQueue do 
         EventQueue[i] := NullEvent;
   End;

(*---------------------------------------------------------------------------*)

   Procedure TAutoApplication.PutEventIntoQueue(NewEvent: TEvent);
   Begin
      EventQueue[QueueTail] := NewEvent;
      if QueueTail = MaxEventQueue then
         QueueTail := 1
      else
         inc(QueueTail);
   End;

(*---------------------------------------------------------------------------*)

END.


-----------

To implement this new functionailty, your application object will inherit
from TAutoApplication, instead of TApplication.  Then, you could have
a procedure to perform a series of events.  For example, say the events
to open a file called foo.pas were an OpenFile command, and then the keypresses
for 'foo.pas'.  The following procedure would implement this automatically.
Note, the kb_xxx constants you will have defined somewhere within scope.

Procedure MyApplication.AutoOpenFoo;
   Const
      NumEvents = 9;
      AutoEvents: array[1..NumEvents] of TEvent = (
         (What:evCommand; Command: cmOpenFile),
         (What:evKeyDown; KeyCode: kb_f),
         (What:evKeyDown; KeyCode: kb_o),
         (What:evKeyDown; KeyCode: kb_o),
         (What:evKeyDown; KeyCode: kb_dot),
         (What:evKeyDown; KeyCode: kb_p),
         (What:evKeyDown; KeyCode: kb_a),
         (What:evKeyDown; KeyCode: kb_s),
         (What:evKeyDown; KeyCode: kbEnter),
      );

   Var
      i : word;
   Begin
      for i := 1 to NumEvents do
         PutEventIntoQueue(AutoEvents[i]);
   End;

-----------

If anyone has some $0.02 to add please do.

..

Wayne Wolf

USENET  : ...!uunet!ingr!wyle!shaman!wolf  (try this one first)
Internet: ww@beach.cis.ufl.edu             (forwards to shaman!wolf)