============================================================================
 VX-REXX Tech Note #2:

               Using the SendKeyString and PostKeyString methods in VX-REXX

                                                          February 11, 1994

                                Applies to VX-REXX Version 1.01B and higher
----------------------------------------------------------------------------

                                                       WATCOM International
                                                       tech@watcom.on.ca

============================================================================

Abstract
--------

This technical note describes some useful tasks that can be accomplished
using the SendKeyString and PostKeyString methods in VX-REXX.  It is adapted
from articles posted in the VX-REXX CFORUM on IBMLINK.  The text assumes that
you are running VX-REXX version 1.01B or higher.


Syntax
------

Although the syntax for both methods is documented online, we repeat them
here for clarity:

    call VRMethod 'Application', 'SendKeyString', <object>, <string>
    call VRMethod 'Application', 'PostKeyString', <object>, <string>

where

       <object> is either 1) the name of a VX-REXX object;
                          2) the internal name of a VX-REXX object;
                          3) a Presentation Manager window as returned
                             by the ListWindows method or the HWnd property;
                          4) in the case of SendKeyString only, a null
                             string, which indicates the window with input
                             focus.

and

       <string> is the a string representing the keystroke(s) to send.
       The syntax is discussed below.

For example:

    call VRMethod 'Application', 'PostKeyString', VRWindow(), '{Alt}FO'
    call VRMethod 'Application', 'SendKeyString', '', '{Enter}'

An object must always be specified with the PostKeyString method.


Keystroke Syntax
----------------

Keystrokes are described using the same syntax that the KeyString property
uses.  To send the characters 'A', 'B' and 'C' in sequence, just use
the string 'ABC'.  To send a control character, prefix the character
with the string '{Ctrl}' as in '{Ctrl}Z'.  The strings '{Alt}' and
'{Shift}' are used to specify the Alt and Shift keys, as in '{Alt}H'
or '{Shift}{F3}'.  Function keys are specified as '{F1}', '{F2}', and
so on.

You can combine the modifiers together:

         '{Ctrl}{Shift}J'
         '{Alt}{Ctrl}{F10}'

The modifiers only apply to a single keystroke.  The following string
is used to send the two keystrokes 'Alt-F' and 'O':

         '{Alt}FO'

This example is used to send 'Alt-Z' followed by 'Ctrl-X':

         '{Alt}Z{Ctrl}X'

There is no fixed limit on the number of keystrokes to send, but it is
recommended that the sequences not be too long.


Difference Between PostKeyString and SendKeyString
--------------------------------------------------

Two things differentiate these methods:

    1) PostKeyString sends keystrokes to an object but does not
       wait for them to be processed  (it is 'asynchronous') and the
       keystrokes that are 'posted' will not be translated into
       accelerator sequences.  (Accelerator sequences are sequences
       of keystrokes that an application intercepts and handles
       before they can be passed to the window with input focus.
       Accelerators are usually used as shortcut to activate menu
       items.)

    2) SendKeyString sends keystrokes to an object one at a time,
       waiting until each is processed before sending the next.
       Each keystroke will also be checked for accelerator sequences.

What this means is that if you send a keystring, a special sequence
such as '{Alt}{F4}' may be handled as an accelerator, but not if it is
posted.  On the other hand, sending keystrokes to other applications
can potentially hang your program if another application is not
responding to keystrokes.


Controlling Other Applications Using Keystrokes
-----------------------------------------------

SendKeyString and PostKeyString can be used within your VX-REXX
program to control other Presentation Manager applications.  There
are two things that you must do:

   1) Figure out what keystrokes you need to use and whether they
      involve accelerators.  If accelerators are needed, you must
      use SendKeyString.

   2) Figure out which window is to be sent the keystrokes.  If you
      want to send them to the window with input focus, you must use
      SendKeyString.

The first step requires that you run the application you wish to control
and write down the series of keystrokes you use to accomplish your task.

The second step requires some programming if you cannot simply assume
that the destination window will be the window with the input focus.
To find the window you want to send keystrokes to, use the ListWindows
method to list the top-level windows that are currently on your desktop.
Then by looking at either the 'Caption' or 'ClassName' property you
can decide which one is appropriate.  You may then have to use the
'FirstChild' and 'Sibling' properties to traverse the window tree to
find the one you're interested in.


Controlling a Multi-Line Entry Field (MLE)
------------------------------------------

The MLE object can be controlled quite extensively with keystrokes.
Here is the list of keystrokes that a MLE understands:

   {Del}         Deletes the selected section or the
                 character to the right of the cursor.
   {Shift}{Del}  Cuts the contents of the selected
                 region to the clipboard.
   {Ins}         Toggles between insert & overstrike mode.
   {Shift}{Ins}  Paste the clipboard contents into the
                 currently selected region.
   {Backspace}   Deletes the selected section or the
                 character to the left of the cursor.

   {Down}        These all move the cursor.  If you add
   {Up}          a {Shift} character, they move the cursor
   {Left}        and select text as well.
   {Right}

   {Ctrl}{Left}  Move to the previous/next word.
   {Ctrl}{Right}

   {Ctrl}{Shift}{Left}   Select until the previous/next word.
   {Ctrl}{Shift}{Right}

   {PageUp}      Move up/down a page.
   {PageDown}

   {Ctrl}{PageUp}   Scroll the screen to the left/right.
   {Ctrl}{PageDown}

   {Home}        Move to the beginning of the line.
   {End}         Move to the end of the line.

   {Shift}{Home} Select from the current point to the
   {Shift}{End}  beginning/end of the line.

   {Ctrl}{Home}  Move to the beginning/end of file.
   {Ctrl}{End}

   {Ctrl}{Shift}{Home} Select from the current point to
   {Ctrl}{Shift}{End}  the beginning/end of the file.

You can easily control an MLE in your application by defining a
procedure such as this:

    SendToMLE: procedure
        call VRMethod 'Application', 'PostKeyString', arg(1), arg(2)
        return

and calling it as follows:

    call SendToMLE 'MLE_1', '{Ctrl}{Home}'

Note that PostKeyString is used in case the control sequences the MLE
understands conflict with accelerators that you have defined in your
application.


Sending keys to DOS and OS/2 Windows
------------------------------------

Because of a limitation in OS/2 itself, only other Presentation Manager
applications can be controlled by the direct sending of keystrokes.
Windowed DOS and OS/2 sessions can be sent some keystrokes, however,
using the following method:

    1) Copy the string of keys you wish to send into the clipboard
       using the PutClipboard method.  Note that the special sequences
       '{Alt}', '{Ctrl}' and so on will not be translated.  If you wish
       to send a special character, you must do the translation yourself,
       by finding the appropriate hexadecimal value for the character.  For
       example, to add a CTRL-M (carriage return) to the end of text
       (which is what pressing ENTER would typically do) you would do
       the following:

             str = str || '0d'x

       because CTRL-M maps to 0D hexadecimal.


    2) Find the frame window for the DOS or OS/2 session that interests
       you.  The ListWindows method can be used for this.

    3) Send the string 'p' to the system menu of the frame window. You can
       use the undocumented 'Id' property to help you find the system menu.
       The characters from the clipboard are now "pasted" into the session.
       (See the example below.)

Here is a simple example of how to send the 'dir' command to a DOS or
OS/2 window, using the call:

        call TypeInWindow win, 'dir' || '0d'x

The code is:

    /*
     * This function sends a set of keystrokes to an OS/2 or DOS window.
     */
    
    TypeInWindow: procedure
       parse arg frame, keys
       if( VRGet( frame, 'ClassName' ) \= 'WC_FRAME' )then return 0
    
       call VRMethod 'Application', 'PutClipboard', keys
       call PasteToWindow frame
       return
    
    /*
     * Pass a frame window handle as the argument.  It searches for the system
     * menu and sends it an Alt-P to invoke the paste function.  Uses the 'ID'
     * property to get the window ID of the window.  All system menus have
     * a window ID of 32770.
     */
    
    PasteToWindow: procedure
       parse arg frame
       if( VRGet( frame, 'ClassName' ) \= 'WC_FRAME' )then return 0
    
       child = VRGet( frame, 'FirstChild' )
       do while( child \= '' )
           if( VRGet( child, 'ClassName' ) = 'WC_MENU' & ,
               VRGet( child, 'Id' ) = 32770 )then do
               call VRMethod 'Application', 'SendKeyString', child, 'p'
           end
           child = VRGet( child, 'Sibling' )
       end
       return 1

============================================================================
