Notes on input methods

Additionally, note the following for edit format methods:

For all asynchronous input methods, note the following:

For leave methods, note the following:

   inp_entered  ,i4  ;TRUE if data was modified in this field
   inp_return   ,i4  ;TRUE if the RETURN key was pressed on this field

Either of these fields may be true or false, as shown in the following table.

inp_entered

inp_return

Meaning

False

False

User has neither modified the field nor pressed return (enter).

True

False

User has modified field but has not pressed return (enter).

False

True

Field was not previously empty, and user only pressed return (enter).

True

True

The user pressed return (enter) and either the field was previously empty and/or the user modified the field.

Method sequences

Depending on the user’s action, Toolkit calls methods in one of the sequences listed below. These sequences start when the user moves to a new field. Note that these are the basic sequences; additional method calls from these methods will complicate the sequences.

Method Sequences

User activity

Method sequence

Enter or edit data in a field and then move to another field.

change
display
leave
break
arrive
edit format

Signal I_OK.

  • The first four methods (the first change through the first break) are for the current field if that field has been modified or is empty—even if it has a default value.
  • The last six methods are called for every subsequent empty field.

change
display
leave
break
arrive
edit format
change
display
leave
break

Click a drilldown button or hyperlink prompt for the current field (a drilldown button or hyperlink prompt whose method uses I_FORCE to modify the field’s data).

leave
drill
arrive
change
display
break
arrive
edit format

Enter or edit data in a field and then click a drilldown button or hyperlink prompt for a different field (a drilldown button or hyperlink prompt whose method uses I_FORCE to modify the second field’s data).

  • The first five methods (the first “change” through the first “arrive”) are for the field the user edited.
  • The next eight methods (the first “edit format” through the last “break”) are for the field whose drilldown button or hyperlink prompt was clicked.
  • The final two methods are for the next field in the input sequence, the field that receives focus after the field with the drilldown button or hyperlink prompt.

change
display
leave
break
arrive
edit format
leave
drill
arrive
change
display
leave
break
arrive
edit format

To be consistent with Toolkit’s handling of other internally supported menu entries (I_NEXT, I_PREV, and so on), place drill and hyperlink events after the leave event. This enables you to validate the field (or to avoid validation by testing g_select/g_entnam) in the leave method without having to duplicate it in the drill or hyperlink method. Furthermore, it provides the same sequence of events for both non‑Windows and Windows platforms.

On Windows, if the user clicks on the hyperlink prompt or drilldown button for a field other than the one currently in focus, several things could happen:

Using hyperlink and drill methods

Both hyperlink and drill methods can be used for a number of things. Primarily, they are used for some form of lookup or presentation of additional information. Your subroutine can use I_FORCE or I_DSPFLD to return data back into the field being processed. If the default type for the field is COPY and the field is empty, any change you make to the data area will affect the default value for the field. You can also alter other fields or other windows. You can perform input to another window, a list, or a selection window. You can alter the input set context on the current window using I_NEXT. You can signal a menu entry by calling %M_SIGNAL. If you signal a menu entry in your drill or hyperlink method, it will be dispatched appropriately. Menu entries beginning with “I_” are handled by the input processor. “U_” menu entries invoke any EUTILS_METHOD. “O_HELP” invokes any EHELP_METHOD. Other menu entries are returned to the calling routine outside I_INPUT.

See Method sequences above for information on the sequence of events that occur when a user clicks a hyperlink prompt or a drilldown button.

Changing focus in an input method on Windows

Although you can call I_NEXT to change the current field within the current input set, if you have a change method and %ICHANGE_METHOD returns a validation error, the context for the current input set will be forced back to the current field, even if I_NEXT has been called.

Note that if a change method signals a menu entry and the response to that menu entry causes the field to be modified (for instance, with I_FORCE), an infinite loop may occur.

In leave methods, the problems can be similar though more complex. When the leave method is called, focus has already been established on the new field. If the leave method steals focus (with U_MESSAGE, for example), focus is restored to the new field. This works well, unless the leave method also calls I_NEXT to force the input context to a different field. In this case, the original new field loses focus and invokes its leave method before arriving at the field specified by I_NEXT. Additionally, the field referenced by *NEXT* and *PREV* will be different depending on whether or not the leave method stole focus.

To work around these problems, we recommend that you avoid stealing focus or calling I_NEXT in either arrive or leave methods. You can also use %M_SIGNAL in the method to signal a menu entry (which does not have to be on a menu) that tells your program which action to take. This forces I_INPUT to exit with g_select set to true and g_entnam set to the entry name you signaled. You can then take the desired action in the calling routine and loop back into I_INPUT to continue.

To do this efficiently, we recommend creating a “wrapper” for I_INPUT that handles the problem—assuming you can sufficiently abstract the problem to create a generalized solution. For instance, let’s say you want to display a message box and/or advance to a specific field from either an arrive or leave input method. To do this, you would create the following fields in either a common or global data section. For the following example, assume these fields are defined in an include file that’s named myinput.def.

g_break_msg     ,a256
g_break_next    ,a30

Next, you would create a wrapper for I_INPUT. For example:

subroutine my_input, reentrant
; 
; Description: Wrapper for I_INPUT
; 
; Arguments: 
;
       a_inpid      ,n     ;Input window ID 
       a_inpset     ,a     ;(Optional) set name 
       a_record     ,a     ;Data record area
       . 
       . (etc., all the rest of I_INPUT's arguments) 
       .
.include "myinput.def"     ;References the global fields we need 
proc
       repeat
         begin
           xcall i_input(a_inpid, a_inpset, a_record, ...)
           if (%m_signal(entnam, D_REMOVE)) then
             using entnam select
       ("MY_BREAK "), begin
                 if (g_break_msg)
                   begin
                     xcall u_message(%atrim(g_break_msg))
                     clear g_break_msg
                   end
                 if (g_break_next)
                   begin
                     xcall i_next(a_inpid, a_inpset, g_break_next)
                     clear g_break_next
                   end
               end
       (),     begin
                 xcall m_signal(entnam, D_SIGNAL) ;Unrecognized--resignal
                 exitloop
               end
             endusing
           else
             exitloop
         end
       xreturn
endsubroutine

With the above example, you can generate a message and/or call I_NEXT from an arrive or leave input method. In the method, you can display g_break_msg as the message and/or set g_break_next to access the next field. You would then call %M_SIGNAL with the MY_BREAK argument to force a break out of I_INPUT and into the above logic. The following makes this step even simpler:

subroutine my_break, reentrant
;
; Description: Display message and/or call I_NEXT for a method
; 
; Arguments: 
;
       a_msg   ,a    ;(Optional) Message to be displayed
       a_next  ,a    ;(Optional) Next field to access
.include "myinput.def"
proc
       if (^passed(a_msg)) then
         g_break_msg = a_msg
       else
         clear g_break_msg
       if (^passed(a_next)) then
         g_break_next = a_next
       else
         clear g_break_next 
       xcall m_signal("MY_BREAK")
       xreturn
endsubroutine