Notes on input methods
- (Windows only) Avoid calling anything that forces reconstruction of the input field frameset on the window being processed. This includes I_SETDEL, I_SNAPSHOT (D_LOAD), I_DSPAREA, I_FRAMES, T_SETUP, S_SELLD (on an associated selection window). If you do, it will result in a U_ABORT message.
- (Windows only) Any shift of input focus is allowed and supported within %IDISPLAY_METHOD, %IEDITFMT_METHOD, and %ICHANGE_METHOD, including calling I_NEXT on the current input set.
- Changing the read-only state for a field from an input method for the field (by using I_READONLY or I_FLDMOD) won’t affect input processing. For example, if a change method for a field sets the field to read-only, Toolkit will complete the rest of the method sequence (change method, display method, and leave method). Setting a field to read-only in an input method simply prevents the user from modifying the field any further.
Additionally, note the following for edit format methods:
- If a field is read-only when it receives focus, you can’t turn off the read-only state from an edit format method. No edit format method will be invoked.
- If an edit format method sets a field to read-only, the user won’t be able to modify the field. The field will contain whatever the edit format method returns.
For all asynchronous input methods, note the following:
- The contents of g_fldnam are undefined.
- I_INPUT may not exit until after processing the arrive method for another field. Therefore, you cannot use g_fldnam to get the field’s name. Instead, use %I_GETSTRING(inp_wndid, inp_fldnam).
- Except for E_CUT, E_COPY, E_PASTE, E_CLEAR, and E_MARK, “E_” menu entries will be ignored if signaled. All other menu entries (including “I_”) will be dispatched as if signaled while performing input to the field.
- I_ENABLE and I_DISABLE can be used to change the enabled state of this or other fields.
- (Unix, OpenVMS only) Using I_ENABLE or I_DISABLE to enable or disable the next field that would be accessed changes the course of input.
- (Unix, OpenVMS only) You can use I_SETDEL and I_SNAPSHOT to modify input set context and/or contents. The behavior is exactly as if the action were performed after a break. Thus, using I_SETDEL to delete the next field to be accessed alters the context, and using I_SNAPSHOT with D_LOAD restores the context for the next input. Using I_SNAPSHOT with D_COPY saves the context that points to the next field to be accessed (if I_NEXT was not also called) because the change in context that causes the leave has not yet occurred.
- Using I_DISPLAY or I_DSPFLD marks fields as “not empty.” The behavior is exactly as if the action were performed after a break. Subsequent input set processing depends upon the previous context.
- Using I_INIT for a field marks the field as “empty.” Using I_INIT for a set resets the context to the first field in the set, as well as marks all fields in the set as “empty.”
- Performing input to the current set using I_INPUT or fields within the current set using I_INPFLD is possible but not recommended because it may cause confusion: input to the current set will alter the input context for subsequent input. Input to fields in the current set will alter their “empty” state.
For leave methods, note the following:
- Accessing (performing input to or displaying) other windows, sets, or fields, within the leave method will not affect the current input process. Accessing the current window, set, or field will affect the input process as noted above.
- If you modify the information line using E_SECT in your leave method, this will occur after restoring any information line superseded by the INFORMATION field qualifier. That is, your new information line will persist within the current environment. This is symmetrical with the arrive method, which occurs prior to overloading the information line for the field.
- The a_inpinfo record contains the following information:
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 Enter. |
True |
False |
User has modified field but has not pressed Enter. |
False |
True |
Field was not previously empty, and user only pressed Enter. |
True |
True |
The user pressed Enter and either the field was previously empty and/or the user modified the field. |
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 |
Signal I_OK.
|
change |
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 |
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).
|
change |
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:
- If any input in the currently focused field has not yet been validated, it will be. This could cause a validation message to pop up and focus to be forced back to the current field.
- If the current field is a break field and the field has been modified or the field is a “break always” field, when the user attempts to click the hyperlink prompt or drilldown button of another field, a break occurs. This effectively cancels the click, although focus naturally transfers to the new field, unless your break logic alters the input set context. Thus, in some cases with break fields, two clicks may be required to access the hyperlink for a field other than the one currently being processed.
- If the new field has an arrive method, this method is invoked before the hyperlink or drill method. If the arrive method signals a menu entry or alters the input set context, this may effectively cancel the hyperlink or drilldown click.
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