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 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. Would it not 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 command! WHEN takes 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).

The 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 icon at the top right of the Listener.

Logo may wait for 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:

Alternatively, you can also use the command (WHEN [MOUSE]) 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:

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 input 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.

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.

Mouse and Touch events

WHEN [MOUSE MOVED] [...]
WHEN [MOUSE CLICKED] [...]
WHEN [MOUSE DRAGGED] [...]

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,

WHEN [TOUCH TOUCHED] [...]
WHEN [TOUCH MOVED] [...]

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

WHEN [KEY] [...]
WHEN [KEY = value] [...]

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!

WHENEVER [MENU = name] [...]

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

WHEN [GRAPHICS RESIZED] [...]

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

WHEN [BLUETOOTH CONNECTED] [...]
WHEN [BLUETOOTH DISCONNECTED] [...]

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:

PPROP 0 "RUN [PLAY "~HOME/SOUNDS/COW]

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

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 and Root robots produce input that is understood by Logo. See the page about advanced floor robots for details.

Watching Property Lists

WHEN may be used to monitor any property list, not just property lists of robots. Try this command:

WHEN [JOHN AGE > 50] [PRINT "OUCH!]

Now, assign different ages to JOHN:

PPROP "JOHN "AGE 25
PPROP "JOHN "AGE 51
OUCH!
PPROP "JOHN "AGE 65
OUCH!