Glulx Input Loops
version 1/101121 by Erik Temple
Chapter: Primary and secondary input loops
Usually in Inform games, there is only one input loop in process at a time: We are either getting a typed command from the player, or we are waiting for a keypress before continuing. However, if we want to create a nonstandard interface, we may find that we want to run one input loop from within another. For example, we may want to build up commands from multiple character, hyperlink, or mouse inputs (see the "Under Doom" example below). Or we may want to imitate text input in a graphics window using a combination of mouse input to select text fields and character input with which to enter text in those fields (see the "Glimmr Form Fields" extension). If we try to do this kind of things with Inform's standard input loops, we will find it difficult to control our event flow, because the two loops don't offer many control structures.
To better accommodate this kind of interaction, Glulx Input Loops introduces a new concept: primary vs. secondary loops. A secondary loop is one that runs while a primary loop is already running, and a primary loop is simply a loop that begins while no other loop is running. The main input loop is always a primary loop, as is a loop that is begun before or after that loop runs. For example, an input loop (call it A) that is invoked from within an action will be a primary loop because the action rules are called only after the main input loop has completed. However, an input loop invoked during loop A would be a secondary loop. We should not try to invoke a loop from within a secondary loop. Instead, use the primary loop to call secondary loops as needed in succession (i.e., use the primary loop as a control structure).
Note that whether a loop is primary or secondary is not determined in advance by the author; that is, we do not define a loop's status. Instead, Glulx Input Loops identifies a loop as secondary any time it is running while another loop is in effect. Again, the main input loop is always primary.
When a loop is running in secondary context, its behavior is somewhat different from a primary loop. The major difference is that secondary loops call only the input loop event-handling rulebook; they do not call the HandleGlkEvent rules (that is, the Glulx Entry Points rulebooks). Instead, by default, they defer event handling until the author's flow of instructions returns to the "parent" loop (usually after the rulebook that called the secondary loop is completed).
We can test whether the current loop is running in primary or secondary context using the "loop context" property of input-loops; this property is automatically set to "g-primary" or "g-secondary" as needed (we should not set it directly!). Example:
if the loop context of the current loop is g-primary
For the input loop event-handling and Glulx Entry Points rulebooks (and any rulebook called by these), it will be better to refer to the "current loop context", a global variable that is updated to track which loop's events we are handling in the currently running instance of the event-handling rules:
if the current loop context is g-secondary
In the input loop event-handling and Glulx Entry Points rulebooks, we can also refer to the "current child loop", which will tell us what loop we are handling input for.
if the current loop context is g-secondary:
if the current child loop is hyperlink input:
...do something specific to the hyperlink input loop...