INPUT /  OUTPUT /  LANGUAGE





Sending Input to Your Program

So far, information has only gone one way: from your program to the screen. To write a program the user can actually interact with, information needs to come back the other way too.

In an ordinary terminal, whatever the user types is sent straight to your program. The ioL console works differently: nothing is sent to your program unless your output says so. That gives you complete control over what input your program receives, and when.


The putLn tag

The putLn tag sends a line of input to your program. Your program reads it just as it would read a line the user typed in a terminal: in Python, with input().

print('<putLn {Hello from the console}>')
line = input()
print('My program received: ' + line)
input()
My program received: Hello from the console

Here the console sends the line as soon as it reads the tag. That's not very useful by itself: the program already knew what it said! It gets interesting when the tag only runs when the user does something.

A few details:

Buttons and events

A button tag puts a button on the screen. Its primary field holds whatever appears on the button's face:

<button {Click me}>

To make the button do something, give it an onClick field. This is a new kind of field. Instead of holding a value, it holds code: tags that aren't carried out straight away, but are kept and carried out each time the user clicks the button. Clicking is an event, and fields that hold code for events are called code fields.

print('<button {Click me} onClick=<putLn {clicked}>></n>')

while True:
    line = input()
    print('The button was ' + line + '! </n>')

Each click sends the line clicked to the program, which prints a message in reply:

Click me
The button was clicked!
The button was clicked!
The button was clicked!

Notice the shape of this program. It sets up its interface, then sits in a loop waiting for input and responding to it. Most ioL programs look like this.

Doing several things in one event

A code field can hold a list of tags, separated by commas. They're carried out in order:

<button {Go} onClick=<putLn {first}>, <putLn {second}>>

Letting the user type: the input tag

An input tag gives the user a box to type in. To send what they've typed to your program, the button that submits it needs a way to refer to the input box. So you give the input box a name, by writing a name and a colon in front of the tag type:

<name:input>

Now name stands for whatever is typed in that box. (You'll learn much more about names in the next chapter.) Here's a complete program:

print('''
What's your name?</n>
<name:input>
<button {OK} onClick=<putLn name>, name.clear>
<button {Quit} onClick=<putLn {/quit}>>
</p>
''')

while True:
    line = input()
    if line == '/quit':
        break
    print('Hello, ' + line + '!</n>')
What's your name?
OK Quit

Hello, Ada!
Hello, Grace!

When the user clicks OK, two things happen. First, <putLn name> sends the typed text to the program. Then name.clear empties the box, ready for the next name.

A way to quit

Look at the Quit button. It sends the line /quit, and when the program receives it, the program leaves its loop and finishes. Because the program ends normally, the ioL console closes too. This is the proper way to let the user end your program, and you no longer need an input() at the end just to keep the window open.

Why /quit and not just quit? Because the program can't tell where a line came from. If the user typed quit as their name, the program would end. Choose commands that real input is unlikely to contain. (Can you do better than "unlikely"? There's a challenge at the end of this chapter.)

Your program is in charge

It's worth pausing on how this differs from a terminal program. A terminal program asks a question, then waits for the answer to that question. In ioL, your program sets up a screen full of things the user can do, in any order, and then waits for whatever happens next. Each line of input needs to say what happened. That's why it's common to send short commands, like /quit, and have your program check which one it received.

Putting it together: a guessing game

import random

secret = random.randint(1, 100)
tries = 0

print('''
<console.title {Guess the Number}>
<span size=18,pt bold=true {Guess the Number}></p>
I'm thinking of a number from 1 to 100.</n>
<guess:input>
<button {Guess} onClick=<putLn guess>, guess.clear>
<button {Give up} onClick=<putLn {/quit}>>
</p>
''')

while True:
    line = input()
    if line == '/quit':
        break
    if not line.isdigit():
        print('<span color={orange} {Please type a whole number.}></n>')
        continue
    tries += 1
    number = int(line)
    if number < secret:
        print(line + ' is too low.</n>')
    elif number > secret:
        print(line + ' is too high.</n>')
    else:
        print('<span bold=true color={lime} {' + line + ' is right! You took '
              + str(tries) + ' tries.}></n>')
Guess the Number

I'm thinking of a number from 1 to 100.
Guess Give up

Please type a whole number.
50 is too low.
75 is too high.
63 is right! You took 3 tries.
Be careful when you put text from the user into your output, as this program does with line. Here it's safe, because the program checks the guess is a number first. But if a user typed < or { into a name box, and your program printed it back unchanged, the console would read it as markup. You'll see how to deal with this safely later.

Try it

  1. Add a "New game" button to the guessing game that picks a new secret number and resets the count.
  2. Make a program with three buttons, Red, Green and Blue, that prints a word in the colour that was clicked.
  3. In the greeting program, what happens if you click OK without typing anything? Change the program so it asks the user to type something instead of saying "Hello, !".
  4. In the greeting program, a user who types /quit as their name will end the program. Change the program so that nothing the user types can ever be mistaken for a command. (Hint: the user controls what's typed in the box, but you control everything else the OK button sends.)