Only Human Series Part 1

The start of our series on user-friendly programs, with the emphasis on education.

Volume 1

Number 12

February 1984

After all, you're only human

By IAN MURRAY

EXCRUTIATING ... UGH! ... what on earth does that mean ... Oh no - not again!

These are some of the more printable cries of frustration that a typical home micro user is likely to utter when trying to run much of the software currently available.

Nor is the home micro user alone in his frustration. There is a wealth of useless software available for the educational market as well.

This yields comments such as: "Oi Sir - look what this does". Or: "Is it meant to do that Miss?"

Or, more insidiously, just silence as the youthful scholar finds that the program has crashed and begins to roam around the operating system as if it were a huge doodle-pad.

A user friendly program is one that accepts that the user is actually a mortal human. Which means he is quite capable of acting like a demented maniac in charge of a cruise missile.

It assumes that each and every key on the keyboard will be pressed, in any combination, at some time - even if it is only done 'just for fun'.

Ideally this should extend to the ON/ OFF switch at the back of the BBC Micro. But for the purposes of this article I take it that you have already guarded against that particular act of malevolence.

User friendliness can be divided into three main areas:

Anticipating the actions of human beings.

Helpfully correcting the actions of human beings.

Making the human being feel he is not dealing with a computer.

The first is the subject of this article while the latter two will be covered in future issues of The Micro User.

The first two keys to deal with are BREAK and ESCAPE. If you have version 1.0 of the operating system or later, then your options are slightly wider. Find out which you have by typing *FX0.

As the BREAK key resets the whole system, this should be dealt with at the earliest opportunity in any program. The method shown in the User Guide is probably the best:

10 *KEY10 OLD¦MRUN¦M

The only major problem is if you have used the permanently resident integer variables (A% to Z%) and assume that they are reset to zero when you run. They are not.

Your next lines of Basic must then assign the start values you want to any of these variables, such as:

20 B%=0:D%=0

Now on pressing BREAK your program will not let the user have a tour of the operating system and will re-run successfully. Provided, of course, that you haven't used any clever tricks such as deleting part of the program as you run.

The easiest way of dealing with the ESCAPE key - and this is applicable to all operating systems - is to trap it with the ON ERROR command.

This, like trapping the BREAK key, must occur at a very early stage in the program. For example:

10 ON ERROR GOTO 500

As the ESCAPE key is considered as error message 17, pressing it directs you to line 500. Subsequent lines at 500 could be as follows:

500 IF ERR = 17 THEN RUN
520 MODE7
530 REPORT
540 PRINT;" at line "ERL
550 END

The solution is fundamentally unsatisfactory as we now have two keys on the keyboard which will re-run the program.

Because we reached line 500 via an absolute jump we cannot retrace our steps to where we came from.

But fear not! Sir Galahad Acorn has provided a solution to the gallant knights with OS 1.0 and OS 1.2.

We may either 'hang up' the ESCAPE key entirely or re-assign it to another key:

10 ON ERROR GOTO 1000
20 *FX229,1
30 REPEAT
40 PRINT"PRESS ESCAPE"
50 PRINT"No luck!!"
60 PRINT"Press Q to exit"
70 A$=GET$
80 UNTIL A$="Q"
90 PRINT MISTAKE
1000 MODE 7
1010 REPORT
1020 PRINT;" at line "ERL
1030 *FX229,0
1040 END

The *FX229 call has been used to turn off the ESCAPE key at line 20 and turn it on again at line 1030, which presumably you would wish to do. When you run the program you will notice that the ON ERROR has not been affected and correctly traps the deliberate error at line 90.

You may, of course, decide that your programs should still have an ESCAPE get-out. This is possible by assigning the ESCAPE key to another key, again at line 20.

You ought to choose a key that has no conceivable use. I suggest CTRL-O:

20 *FX220,0

This is keys CTRL and @ pressed down together. To restore ESCAPE to its rightful key, line 1030 should be:

1030 *FX220,27

I personally would avoid *FX220 calls in the finished program as it still provides the user with a combination of keys with which to experiment, and sooner or later some latent Einstein will find them.

I suggest using the *FX220 call while developing pre-release versions of the program.

When using the ON ERROR command make certain that you direct it to a line that exists. If you don't you will get a program that gives an impression of locking-up, but is in fact in an endless ON ERROR loop.

Having dealt with the obvious keys, you still have to out-smart the nine year old's propensity to destroy all your handiwork. Now you have to anticipate his every move across the keyboard. Can you do it? Is it even possible?

The secret is to never use the INPUT or INPUT LINE commands as up to 255 characters can be entered with these commands. Someone merely repeating a key could enter a string so long that it would corrupt the screen display.

The answer is to always use the GET and GET$ commands, which only collect a single character at a time. You will need to provide your own delete routine where you think it's needed (see below).

However firstly turn off the auto repeat feature at the beginning of the program with:

10 *FX1l,0

This will at least protect you from accidental entry of more than a single character.

Where your programs are menu driven - that is, your progress through the program depends on an item selected from a screen menu - then you should lay out your display something like this:

PROGRAM OPTIONS

A) Create a File
B) Amend a File
C) Delete a File
D) Sort a File
E) Search a File
Select a letter from A to E >>

The section of program to select from the menu may look like this:

200 PRINT "Select a letter from A to E >> ";
210 REPEAT
220 LET Reply$ = GET$
230 UNTIL Reply$ >= "A" AND Reply$ < "F"

No other input will successfully get past this. However you may be locked in the wrong size letters - small instead of capitals.

Line 230 can be extended with a complicated logical expression to cater for this or you may use the following alternative:

230 UNTIL INSTR( "ABCDEabcde" , Reply$) > 0

This again is not totally satisfactory as your analysis of the menu selection will still involve you in converting the lower case letters to upper case before deciding what action your program is to take.

For this reason it is better to use numbers on the menu selection. But take the number in as a character. This would involve a change of line 230 to:

230 UNTIL Reply$ > "0" AND Reply$ < "6"

with the other obvious changes in any menu.

As a program designer you must decide whether the theory of your program will allow the user, in answering a question, to enter any character or a selection from a limited subset of characters.

This is particularly relevant when trying to get in numbers, or even names.

For example, when entering numbers you may feel that you will allow 0123456789., but not allow other valid mathematical characters such as "-/ +*". This is possible using the GET$ command, but not possible with the INPUT commands.

You will presumably still want the RETURN key to be used to signal the end of the numbers' input. The following suggestion may help your thinking:

100 PRINT "Enter a decimal number >> ";
110 REPEAT
120 REPEAT
130 R$=GET$
140 UNTIL R$ = CHR*(13) OR INSTR( "0123456789.",R$ ) > 0
150 PRINT R$;
160 IF R$ <> CHR$(13) THEN Number$ = Number$ + R$
170 UNTIL R$ = CHR$(13)
180 Number = VAL(Number$)
190 PRINT
200 PRINT Number

You can extend your control over the input by putting a restriction on its length at line 160 with the use of the LEN command. However the implication of this is that you will need to write your own delete routine.

This routine involves counting-in every character that passes any other restrictions you may have, and allowing the delete character, CHR$(127), to be printed to the screen but not added to the final accepted string of characters.

Of course you will have to remove the most right hand character from the string input.

Restricting the length of the string input creates a snag. You must allow the delete character to be the only character that can be the "length of the string + 1", so that you may delete the last character if required. A simple example of this is shown in Figure I.

With little difficulty this type of routine can be made a procedure with parameters that can be specified. This will ensure your program does not slide to an unsuitable length.

The important point is that if the programmer is to be truly user friendly in controlling and directing the user's general keyboard inputs, then the program will inevitably be lengthy.

As a rule of thumb, I believe you must expect 90 per cent of every program to be devoted to user friendliness, and only 10 per cent to the algorithm.

The cursor control and copy keys should also be taken out of action unless required in the program. From OS 1.0 onwards you may do this by using the *FX4,1 or *FX4,2 calls.

The former disables cursor editing and the latter permits redefinition of these keys similar to the red function keys. The normal mode is turned on with *FX4,0.

Subsequent articles will look at validation, helpful ways of correcting the user's errors, and how to make your BBC Micro actually seem relatively human.

Till then, a final tip: Always try your programs out on a complete dodo. In the business of friendliness there's none better than a complete idiot to discover what a fool you have been!

100 CLS
110 C=0
120 PRINT 'Enter a four digit number >> ";
130 REPEAT
140 REPEAT
150 R=GET
160 R$=CHR$(R)
170 Z=INSTR( "0123456789" , R$ )
180 UNTIL R=13 OR Z<>0 OR (R=127 AND C>0)
190 C=C+1
200 Number$ = Number$ + R$
210 IF R=13 THEN C=C-1
220 IF R=127 THEN C=C-2
230 N$ = LEFT$(N$,C)
240 IF ( C>4 AND R<>13 ) THEN C=4:R$=""
250 IF R<>13 THEN PRINT R$;
260 UNTIL R=13 AND C=4
270 Number = VAL(Number$)
280 PRINT
290 PRINT Number
Figure I