Event Handlers
Webb - all rights reserved - ©2004
spacer
Event Handlers

Event handlers can define very powerful subroutines that allow the scripts to intercept and handle RPN events in very innovative ways.  Event handlers can execute a subroutine:

         Event                              ByteCode      Stack
When the script is opened            {o}                  -->
When the script closes                 {c}                  -->
When any button is pressed         {b}    Button # -->
When any character is entered     {k}   ASCII #  -->
via graffiti or a keyboard
Or every ### ticks set by UT       {t}                  -->

When an event handler subroutine is defined in a script, each time that event occurs, RPN will execute the subroutine assigned to it.  When a script is opened, the {o} subroutine will execute.  When the script is closed, the {c} subroutine will execute.  When a button, {b} or key {k} event handler is triggered, RPN puts the number of the button pressed or the ASCII number of the character entered on the top of the stack and then executes the subroutine.  The timed {t} event requires the period set by using the 'UT' command.  The period is equal to tos / 100 seconds.  So a timed event for one second would be: 100 UT -->.  The {t} event handler must reload the time period in 'UT' if the timed event is to be reoccurring.

RPN does not automatically enter the user's input or update the display until after the handler subroutine is complete.  The subroutine should use the 'Ue' command to cause an enter and 'Ud' to update the display.  Handlers which override a default RPN event, such as a key or button action, should use 'Uh' to indicate that the handler has taken care of the event.  If 'Uh' is not executed by the subroutine, RPN will handle the event as usual when the
subroutine is finished.

This can be a little confusing so let's look at an example:

1. RPN.3.b
2. {o} D'Script is opening|OK|' 0 Xa 0 Xb 100 UT;
3. {c} D'Sript is closing|OK|' ;
4. {k} xa 2 == (handled : drop ) ;
5. {b} dup 99 > ( 100 - c(1:2:3:0) Xa : xa 1 == ( handled : drop ) ) ;
6. {t} xb 1 + Xb 100 UT xa 3 == ( h(d1) xb handled ) ;
7. [handled] Ue Ud Uh ;
8. "Event Handlers"
9. "Show Buttons" ;
~
"Show ASCII" ;
~
"Show timer" xb ;
~
"Dont Show" ;

1. The required RPN header. Defines a two global variables, 'a' and 'b'.  The 'a' global variable will be used in the script as a flag to tell the button and key event handlers whether the RPN should show no code (a = 0), the button number (a = 1)or the ASCII code for a user input event (a = 2).  The 'b' global variable will be used to store the number of seconds from the start of the script.

2. When the script opens, the subroutine event handler {o} opens a dialog with the message "Script is opening".  Of course this could be any routine you want executed when the script is opened and in this case it preloads the global variables with 0 and sets the period to the first timed event to 1 second (in hundredths of a second).  Usually, {o} doesn't need to include a Ue, Ud or Uh command.

3. When the script closes, the subroutine event handler {o} opens a dialog with the message "Script is closing".  This can also be any routine you want executed when the script is closed (e.g., the user selects another script) such as resetting the calculator to base10,
etc.  Likewise, {c} seldom needs to include Ue, Ud or Uh.

4. The key handler checks the 'a' flag and if it is set to 2, will put the ASCII code of the key or graffiti event on the stack and call the 'handled' subroutine.  The subroutine enters the code on the stack (Ue), updates the display (Ud) and tells RPN that it has handled the event (Uh).  If the 'a' flag is 0 or 1 it simply drops the ASCII code and continues.  Because {k} appears in the script before {b}, the ASCII code is dealt with first.  Note that not every button has an ASCII code.  For example, if the square root button is pressed when the ASCII code is to be returned to the stack, RPN will return the square root of whatever is on the stack or an error message will be generated because there will be nothing on the stack to find the square root of.

5. The button event handler is a little more complex.  When RPN calls this routine, the button number is duplicated and tested to see if it is greater than 99.  If the button number is greater than 99, then the button has to be one of the buttons in the script button area.  100 is subtracted from the button number which is then used to determine what value should be stored in the global flag variable 'a'.  

If the button pressed is less than 99, 'a' is called to the stack and if the button codes are to be displayed, just like the key handler, the subroutine enters, displays and handles the button number.  The graffiti input area is not a defined button so no code is returned if written input is attempted.

6. The timed event handler is called 1 second after the script opens. The subroutine adds 1 second to global variable 'b'  and resets the time to the next timed event to 100 UT (1 second).  Then the subroutine checks the 'a' global variable and if it is set to 3, it drops a possible left over 'b' variable from the "Show Timer" button (see explanation below), puts the current value of 'b' on the stack and calls the 'handled' subroutine.  As long as 'a' == 3, the value of 'b' will update on the stack every second.

7. This is the title of the script.

8. Because the button handler is handling all button events, subroutines are not needed for these script buttons.  However, the "Show Timer" button pushes the value of 'b' on the stack because if it didn't, the value of 'b' might not appear for a second in the display.

Jim Cook
James_Cook@ieee.org