Terrapin Resources

WHEN Something Happens

Programming inside a browser environment is different from a traditional programming style. In the late seventies when Logo was first created, people used punch cards and TTYs (teletypes) to enter data, and the computer responded by printing endless paper. Even the first screens kept this traditional approach.

The arrival of Windows and other graphical operating systems made things much more complicated. There were a multitude of input devices, including mice, keyboards, and even fingers, and programs were not expected to continuously run in a loop, waiting for input, because that wasted valuable CPU cycles (and battery power).

This is a traditional program:

This program checks the mouse position, moves the turtle to the mouse position, and then checks the left mouse button. If the button is pressed, the program exits; otherwise, it loops and starts over.

The program must run constantly so it does not miss any mouse movements. Therefore, it monopolizes the CPU until it stops and drains a laptop’s battery quickly. Not a good idea nowadays.

Instead, a well-behaved program should just rest, and run only if there is input to process. Once input is available, the program wakes up, processes the input and goes to sleep again. No CPU cycles are wasted, and the CPU is available for other jobs.

This is called event-driven programming.

Now, back to Logo. Wouldn’t it be wonderful if Logo could handle input the same way? This would free Logo from having to loop, and Logo could do something else while processing input on the side.

Logo proudly presents the WHEN and WHENEVER commands! WHEN and WHENEVER take two inputs. The first describes what to watch for, and the second input is a runlist (a list of commands to execute when the input is available).

WHEN vs WHENEVER

There are two types of input. Inputs like key presses or mouse movements are best processed in a running program, and processing should stop as soon as the program ends. Other inputs, like processing a menu command, should be processed whether or not a Logo program is running.

This is where the WHENEVER command is used. All code defined with WHEN stops when the program terminates. Code defined with WHENEVER continues to run even after a Logo program stops.

Everthing else that this chapter explains about WHEN is also valid for WHENEVER. Please note that you need to use WHENEVER if you try the examples in the Listener panel, because a runlist defined with WHEN would go away immediately after you typed in the command; after all, your mini-one-liner has stopped running, and all WHEN handlers are removed.

Note that a runtime error that CATCH did not catch halts all WHEN processing, but not runlists defined with WHENEVER. If you accidentally create a WHENEVER runlist that runs astray, enter the command (WHENEVER) without inputs to erase all event handlers.

But what if I need my WHEN handlers only until my program ends?

WHENEVER is often too strong for a program. It is great if you, for example, want to define additional menu items. To make a new menu item work, the handler needs to run whenever (sic!) it is clicked, even if a program does not run at all.

Most often, you want to define a WHEN command that lives as long as the program lives. Unfortunately, a program most often ends after having set up everything, including WHEN commands, causing all handlers to be deleted immediately.

The solution is to have the program wait forever until it is ready to exit. WAIT -1 does exactly this. It lets the program just sit there and wait until something causes it to end.

The only way to end such a program programmatically is to use a WHEN handler to end the program. This is actually easy — just use the TOPLEVEL command.

Here is an example to a program that exists when you click the mouse button:

See more examples below.

CHASE Redefined

The CHASE program above would look like this:

The program is much easier to read and Logo simply waits for mouse movements to happen.

Let us make this a little more sophisticated. A real doodle program would use the mouse button to draw and, if the button is not held down, the turtle does not draw. Here is the upgraded program:

Stop this program by clicking the Stop button. For the following examples, this is the best way to stop these programs.

Logo may respond to many different inputs; look below for a complete list.

Programming this way is especially convenient when programming robotic turtles like InO-Bot. ‘Bots have many sensors that provide input to Logo, so a typical InO-Bot program may be written as a list of WHEN commands.

In this program example, when InO-Bot’s light sensors report low light conditions, its headlights turn on.

InO-Bot’s LIGHT property reports the light level as a value between 0 and 1. The PPROP command turns InO-Bot’s headlights on or off. To learn about all of InO-Bot’s sensors, see the chapter about advanced floor robots.

Be careful with WHEN runlists! All Logo programs share the same environment. A WHEN runlist should not change any global names so other Logo programs can continue running.

Changing global variables can have grave consequences. Imagine a Logo program writing to :STANDARD.OUTPUT to create a file. At the same time, a Logo WHEN runlist creates another file and changes :STANDARD.OUTPUT to write to that file. As a result, all Logo programs write to the new file at the same time!

Checking Input Values

Remember this previous code?

Often, it is a good idea to have Logo check for the value of an input before running a runlist. The code above does just that. You can use any of Logo’s comparison operators (=, <>, <, <=, >, >=) to check a value.

Often, a sensor outputs values often. It does not make sense, for example, to turn the InO-Bot’s headlights on repeatedly whenever a value greater than 0.4 is detected. Therefore, Logo runs the runlist only once when the value is greater then 0.4. After that, Logo ignores values greater then 0.4 until the value drops below 0.4.

If you want to monitor all values, simply omit the comparison:

This code prints the light sensor’s value whenever that value changes, which can be quite often.

You can event monitor all input from InO-Bot, which is extensive, by leaving out the property name:

Please remember to not use quotes in the condition list, because Logo does not evaluate the contents of the list. If you, for example, would like to run a runlist when the user presses the “A” key, use [KEY = A], not [KEY = "A].

Turning Off WHEN Runlists

Sometimes you may want to turn off input processing for a for a WHEN command. Do this by repeating the WHEN command with an empty runlist, like this example for mouse movements:

Alternatively, you can also use the command (WHEN [MOUSE MOVED]) to remove processing. If you use (WHEN) without any inputs, all processing of WHEN stops.

Variables? Not Always!

A word of caution. If you use the WHEN command inside a procedure, do not use procedure inputs or local variables inside the runlist. When the WHEN runlist executes, Logo has left the procedure and all inputs or local variables are gone.

Accessed variables must be global variables for a WHEN runlist to work.

An example:

Mouse and Touch events

These programs listen to mouse events. DRAGGED means that the mouse has been moved with the button held down, Use the MOUSE and BUTTON? commands to access the mouse data,

Used on touch-enabled devices when one or more fingers touch the surface of the Graphics panel. Touch input is quite complex; see the GRAPHICS panel’s TOUCH property for details.

Keyboard input

The above examples process keyboard input. The first version monitors all pressed keys, while the second version compares the key to a value. Use the command GPROP "LISTENER "KEY to access the key value.

To learn about key values for special characters like arrow keys or the Tab key, use the KEY command, which reports the key code of a pressed key.

Want to move the turtle with single key strokes? Then try this:

Try for yourself to see what happens!

Process a menu selection. The APPENDMENUITEM command lets you define a new menu entry, and the WHENEVER command defines what happens when the menu item is selected. Try this:

Changes in the Environment

Logo executes this runlist whenever the Graphics panel is resized. Use GPROP "GRAPHICS "DRAWSIZE to access the new size.

Logo receives this input when a Bluetooth device is connected or disconnected.

Input from Buttons, Checkboxes, etc.

Controls like push buttons also produce input. A program can be notified when a user clicks a button, for example.

There are too many controls to create words for the WHEN command. Instead, controls have a RUN property. When a control is clicked, altered or changed, and wants to inform the program, it executes the runlist that is stored as the RUN property. The runlist in turn can check the control’s current value and react accordingly.

By the way, turtles also have their own RUN property that a turtle attempts to execute whenever it is clicked! Try this:

Now, you may believe that your turtle actually is a cow whenever you click it!

To see a list of all the sounds, type: (DIR "~HOME/SOUNDS)

Robot Sensors

Sophisticated devices like robots often provide input. Typical inputs are the value of a proximity sensor, whether a motor has started or stopped, and more. Robots usually have many properties that reflect the status of sensors.

The InO-Bot produces input that Logo understands. See the page about advanced floor robots for details.

Animation Frames

Logo supports animation frames with 30 frames per second. The page about animation contains a wonderful example.

Watching Property Lists

WHEN may be used to monitor any property list, not just property lists of robots. Try this command (use WHENEVER; otherwise the handler would go away again):

Now, assign different ages to JOHN:

PPROP “JOHN “AGE 25 PPROP “JOHN “AGE 51 JOHN’S AGE HAS BEEN SET TO 51 PPROP “JOHN “AGE 49 PPROP “JOHN “AGE 65 JOHN’S AGE HAS BEEN SET TO 65