"Mark," complained a mother to her son, "every time you're
naughty, I get another gray hair!"
"Gee, Mom," the little darling replied, "you must have been a
terror! Just take a look at Grandma!"
YOUR SECOND GFA BASIC 3.XX MANUAL
- or -
HOW I LEARNED TO STOP WORRYING AND LOVE GFA-BASIC
PART 9
CHAPTER EIGHT - KEYBOARD INPUT
by Han Kempen
INKEY$
All keypresses are saved in the keyboard-buffer. If you want
INKEY$ to forget old keypresses, you should first clear the
buffer:
REPEAT
UNTIL INKEY$="" ! clear keyboard-buffer
key$="" ! clear variable key$
REPEAT
key$=INKEY$
UNTIL key$<>"" ! wait for new keypress
An alternative way to clear the keyboard-buffer uses XBIOS 14
(Iorec):
{ADD(XBIOS(14,1),6)}=0 ! clear keyboard-buffer
In the following table you'll find a few useful decimal ASCII-
codes you can use after 'key$=INKEY$'. In the third column the
hexadecimal scan-code of the key is also mentioned (see paragraph
'KEYGET').
key ASC(key$) scancode
<Backspace> 8 &H0E
<Tab> 9 &H0F
<Return> and <Enter> 13 &H1C and &H72
<Esc> 27 &H01
<Delete> 127 &H53
key ASC(RIGHT$(key$)) scancode
<F1> 59 &H3B
<F10> 68 &H44
<Shift> <F1> 84 &H54
<Shift> <F10> 93 &H5D
<Help> 98 &H62
<Undo> 97 &H61
<Insert> 82 &H52
<ClrHome> 71 &H47
<Left Arrow> 75 &H4B
<Right Arrow> 77 &H4D
<Up Arrow> 72 &H48
<Down Arrow> 80 &H50
Keys in the second part of this table return a 2-byte value
after INKEY$, although the high byte is always &H00 (e.g. <F1>
returns &H003B). This is important if you would like to define
one of these keys as a variable:
help$=CHR$(0)+CHR$(98) ! high byte is &H00
key$=INKEY$
IF key$=help$
(...) ! user pressed <Help>
ENDIF
Of course, you could also use the following method:
key$=INKEY$
IF ASC(RIGHT$(key$))=98
(...) ! <Help>
ENDIF
It's impossible to detect a <Shift> <Arrow> combination with
INKEY$, because a one-byte value of an existing (!) key is
returned: CHR$(50), (52), (54) and (56) for <Shift> <Down Arrow>,
<Left Arrow>, <Right Arrow> and <Up Arrow>. You'll need KEYGET
(page 8-5) or ON MENU (page 21-3) to detect these four
combinations.
If you are just waiting for any keypress, you could use either
of the following methods (clear the keyboard-buffer first):
~INP(2) ! my favourite (unless EVERY is active)
'
KEYGET code% ! perhaps this is clearer in a listing
'
REPEAT ! a loop is also possible
UNTIL LEN(INKEY$)
The loop-method could be used if you are waiting for any
keypress or any mouse-click :
{ADD(XBIOS(14,1),6)}=0 ! clear keyboard-buffer
WHILE MOUSEK ! mouse-buttons released?
WEND
REPEAT ! wait for any keypress or
mouse-click
UNTIL LEN(INKEY$) OR MOUSEK
INPUT
If you don't want the question mark to appear after INPUT, use:
LOCATE col,lin
INPUT "",txt$
The nullstring and the comma are essential. Most of the time
you'll probably use something like:
LOCATE col,lin
INPUT "Enter your name: ",name$
If the instruction is not on the same line as the INPUT-line,
use:
PRINT AT(col1,lin1);"Enter your name:"
LOCATE col2,lin2
INPUT "",name$
The 'Alternate-method' can be used to input character-codes 128-
255 on a (LINE) INPUT line. In the following table you'll find
some important characters with the decimal ASCII-code:
character ASCII-code character ASCII-code character ASCII-code
á - 160 é - 130 í - 161
à - 133 è - 138 ì - 141
ä - 132 ë - 137 ï - 139
â - 131 ê - 136 î - 140
ó - 162 ú - 163 ÿ - 152
ò - 149 ù - 151 ß - 158
Ö - 148 ü - 129
ô - 147 û - 150
? - 224 ? - 240 ½ - 171
? - 225 ± - 241 ¼ - 172
? - 235 ? - 242
µ - 230 ? - 243 ² - 253
? - 227 ÷ - 246
? - 231 ? - 247 ° - 248
¢ - 155 © - 189
£ - 156 § - 221
ƒ - 159
I hope your printer-driver could digest this table. If you want
to use one of these characters after (LINE) INPUT, you should
hold <Alternate> down, enter the code, and release <Alternate>.
In a compiled program you have to incorporate '$I+' if you would
like to be able to use the Alternate-method.
You can use the following keys on a (LINE) INPUT line:
<Insert> - toggle between Overwrite- and Insert-mode
<Backspace> - delete character before cursor
<Delete> - delete character under cursor
<Esc> - erase entire input-line
<Left Arrow> - cursor one position to left
<Right Arrow> - cursor one position to right
<Up Arrow> - cursor to start of input-line
<Down Arrow> - cursor to current end of line (after last
character)
The <Up Arrow> and <Down Arrow> are sadly missing if you use
Find or Replace in the editor.
Both INPUT and LINE INPUT use a special cursor, so it doesn't
make much sense to use XBIOS 21 (Curscon) to do something
interesting with the TOS-cursor.
If you enter something illegal on an INPUT-line (e.g. "A" if you
should enter a number), a bell-sound warns you that you made a
mistake. TOS will now wait for a correct entry, but unfortunately
a linefeed is executed first! Therefore I advise the use of INPUT
with strings only (or the use of LINE INPUT) so you can trap a
user-error yourself.
As you know you have to use LINE INPUT instead of INPUT if the
user is allowed to enter a comma as part of the input-string.
INPUT-bug
INPUT and LINE INPUT use the underscore (_) as the cursor in a
window. After you press <Return>, the underscore is not
completely erased: the rightmost pixel remains visible. I think
this is a GEM-bug.
INPUT$
For the input of a secret password, you could use something
like:
PRINT "Type password (5 characters): ";
code$=INPUT$(5)
The password does not appear on the screen.
FORM INPUT
If you use FORM INPUT with a default-string, the cursor appears
on the first character of the string:
PRINT "Need some input here: ";
default$="example"
FORM INPUT 20 AS default$
By pressing <Down Arrow> you jump to the end of the default-
string, but I find it more convenient to let the program do that:
KEYPRESS &H500000 ! press <Down Arrow>
FORM INPUT 20 AS default$
KEYTEST
The KEYTEST-function does not respond to keys such as <Help>,
<Undo>, etc.
KEYGET
KEYGET waits for a keypress, just like INP(2). But KEYGET is far
more flexible, because it returns the ASCII-code and the scan-
code of any key and also the state of the special keys <Shift>,
<Control>, <Alternate> and <CapsLock>. Consult your manual for
tables of ASCII-codes and scan-codes (in the paragraph 'INKEY$'
you already encountered some important codes on page 8-1). Study
the following example to get an impression of the easy way you
can examine all keypresses with KEYGET:
ABSOLUTE ascii|,V:get.code%+3 ! ASCII-code in first byte of
integer
ABSOLUTE scan|,V:get.code%+1 ! scan-code in third byte
(2nd byte=0)
ABSOLUTE status|,V:get.code% ! status of special keys in
last byte
'
DO
KEYGET get.code% ! wait for keypress
@keyget ! process keypress there
(not included)
LOOP
You will have to write your own Keyget-Procedure though. It's
usually a good idea to clear the keyboard-buffer (again) before
leaving your Keyget-Procedure. You can check if any of the
special keys has been pressed with BTST(status|,bit):
bit 0 = Right <Shift>
bit 1 = Left <Shift>
bit 2 = <Control>
bit 3 = <Alternate>
bit 4 = <CapsLock>
You could discover if the user had pressed <Control> <Down
Arrow> with:
IF scan|=&H50 AND BTST(status|,2)
(...)
ENDIF
If you are only interested in monitoring the five special keys,
you could use BIOS 11 (Kbshift) and use the same bit-table to
test if bit 0-4 is set:
status|=BIOS(11,-1)
In most cases the scan-code of a key is the same, whether you
pressed a special key (except <Control>) simultaneously or not.
Watch out for the following exceptions:
<Shift>
For <Shift> <F1> to <Shift> <F10> the scan-codes &H54 to
&H5D are returned (not &H3B to &H44). On an MS-DOS computer
these codes are used for the keys <F11> to <F20>.
<Control>
<Control> can be used to simulate other keys with the
'regular' keys, e.g. <Control> <i> = <Tab> and <Control> <h>
= <Backspace>. That's a relic from a long time ago.
<Control> <ClrHome> has code &H77 (not &H47). The
combinations <Control> <Left Arrow> (&H73) and <Control>
<Right Arrow> (&H74) also have special codes. Blame MS-DOS.
<Alternate>
The combinations <Alternate> <1> to <Alternate> <=> have the
special codes &H78 to &H83. That's 'ALT1' to 'ALT=' for MS-
DOS. <Alternate> <ClrHome> is intercepted by TOS and leads
to a screendump. <Alternate> in combination with <Insert>,
<ClrHome> or one of the arrows is also intercepted and
results in movement of the mouse-pointer on the screen (see
paragraph 'MOUSE').
A disadvantage if the described KEYGET-method is that you'll
have to ignore the mouse completely. If you want to monitor both
the keyboard and the mouse you'll have to use INKEY$ (and MOUSE)
instead of KEYGET. An alternative approach is described in the
paragraph 'ON MENU KEY' in chapter 21.
KEYLOOK-bug
KEYLOOK does not function properly with TOS 1.0, but seems to
work with later TOS-versions.
KEYPRESS
KEYPRESS uses the same 4-byte format as KEYGET: &Hccss00aa. In
it you will recognize the ASCII-code (&Haa), the scan-code (&Hss)
and the code for the special keys (&Hcc). If you want to simulate
the pressing of a key in an Alert box, you will have to send both
the ASCII-code and the scan-code. Use &H1C000D to simulate the
pressing of <Return>. Or &H04620062 for <Control> <Help>,
although that certainly won't help in an Alert box. If you don't
need the scan-code (e.g. with INPUT), use KEYPRESS &Haa.
KEYDEF
The editor always uses KEYPAD &X101110, so you will have to set
bit 4 yourself (e.g. KEYPAD &X10000) before you can use KEYDEF in
your program. Switch KEYDEF off with KEYPAD 0.
Keyboard
As far as I know, there are four different keyboards available:
USA (QWERTY), English (QWERTY), German (QWERTZ) and French
(AZERTY). Perhaps there is a Spanish keyboard, but I don't think
there exists one in the Atari-world. The key with scan-code &H2B
(to the right of <Return>) has a different ASCII-code in each
version:
version ASCII-code character
USA &H5C (92) \
English &H23 (35) #
German &H7E (126) ~
French &H40 (64) @
You could use XBIOS 16 (Keytbl) to determine the keyboard-
version:
SELECT PEEK(LPEEK(XBIOS(16,L:-1,L:-1,L:-1))+&H2B)
CASE &H5C
usa.keybrd!=TRUE
CASE &H23
english.keybrd!=TRUE
CASE &H7E
german.keybrd!=TRUE
CASE &H40
french.keybrd!=TRUE
ENDSELECT
You should take into account the differences between the
keyboard-versions if you are writing a program that should run
smoothly in any country. With certain scan-codes you should be
very careful (see table on next page). It's not nice to ask a
German user to press <Y>, but test for scan-code &H15 in your
program...
In the following table I have gathered all keys that have not
the same meaning on the four keyboard-versions:
scancode USA English German French
&H0C - - ß )
&H0D = = - '
&H10 Q Q Q A
&H11 W W W Z
&H15 Y Y Z Y
&H1A [ [ Ü [
&H1B ] ] + ]
&H1E A A A Q
&H27 ; ; ö M
&H28 ' ' Ä \
&H29 ` ` # `
&H2B \ # ~ @
&H2C Z Z Y W
&H32 M M M ,
&H33 , , , ;
&H34 . . . :
&H35 / / - =
&H60 none \ < <
If you insist on doing things the hard way, you can find the
ASCII-value that is assigned to a key with XBIOS 16. Actually
there are three tables: one for a normal keypress, one for a
shifted key and one for a keypress with CapsLock on:
keytbl%=LPEEK(XBIOS(16,L:-1,L:-1,L:-1))
shift%=keytbl%+&H80
capslock%=shift%+&H80
Now you can find the ASCII-code for any scan-code (< &H80):
ascii=PEEK(keytbl%+scancode) ! normal key
ascii=PEEK(shift%+scancode) ! shifted key
ascii=PEEK(capslock%+scancode) ! CapsLock on
You can use XBIOS 16 also to install your own keyboard-table.
Fill three 128-byte strings with the proper ASCII-values and
activate with:
~XBIOS(16,L:V:keytbl$,L:V:shift$,L:V:capslock$)
The standard keyboard-table can be activated again with XBIOS 24
(Bioskeys):
~XBIOS(24)
Please reactivate the standard keyboard-table before the user
exits your program!
Key-click, Key-repeat and CapsLock
Normally, you need the key-click as an audible feedback.
Sometimes you have to switch the key-click off, e.g. while an
XBIOS 32 song is playing. That's possible if you clear bit 0 of
the system-variable conterm (at address &H484):
SPOKE &H484,BSET(PEEK(&H484),0) ! keyclick on
SPOKE &H484,BCLR(PEEK(&H484),0) ! keyclick off
If your program reacts a bit slow after a keypress, you probably
have to switch the key-repeat temporarily off. That can be done
by clearing bit 1 of the same system-variable:
SPOKE &H484,BSET(PEEK(&H484),1) ! key-repeat on
SPOKE &H484,BCLR(PEEK(&H484),1) ! key-repeat off
If you don't switch key-repeat off, it could become active
before the user has released a key. Of course you should always
restore both key-click and key-repeat to their original settings
before exiting your program.
It's possible to change the key-wait time and the key-repeat
time with XBIOS 35 (Kbrate):
~XBIOS(35,wait|,repeat|)
Both wait- and repeat-time can have values 0-255 (byte-
variables). Divide the value by 50 to find the actual time in
seconds. E.g. wait|=50 means the keyboard will wait one second
after you pressed a key before the key-repeat is activated. And
repeat|=50 means that a keypress is registered every second if
you hold a key down. The default values on my computer are
wait|=15 (15/50 s) and repeat|=2 (2/50 s).
You can switch CapsLock on or off in your program by using BIOS
11 (Kbshift) to set/clear bit 4 of the keyboard-mode:
~BIOS(11,BSET(BIOS(11,-1),4)) ! CapsLock on
~BIOS(11,BCLR(BIOS(11,-1),4)) ! CapsLock off
You can also press the CapsLock-key, but it's a shame that you
can't tell if it's on or off (a small status-light would have
been nice).
Procedures (CHAPTER.08)
Choice_2 CHOICE_2
Use a mouse-click to pick one of two choices:
@choice_2(10,"CapsLock","On","Off",choice) ! on line 10
Either 1 (first choice: On) or 2 (second choice: Off) is
returned in choice&. If you clicked the right mouse-button, 0 is
returned.
Choice_3 CHOICE_3
Use a mouse-click to pick one of three choices:
@choice_3(10,"Choose number","one","two","three",choice)
Either 1, 2 or 3 is returned in choice&, unless the user pressed
the right button (0).
Choice_table & Choice_table_init CHOICTBL
Combination of Choice_2 and Choice_3 for a number of items. The
text for each item and the button-text for each choice must first
be loaded in the Procedure Choice_table_init. Of course you could
create more than one table.
@choice_table_init(table.1$(),choices.1())
@choice_table(5,table.1$(),choices.1()) ! start on line
5
Cursor CURSOR
The TOS-cursor can be switched on and off and it can be steady
or blinking:
@cursor(TRUE,TRUE,-1) ! switch TOS-cursor on, blinking on
Can't be used with (LINE) INPUT as GFA uses another cursor.
Dial_number & Dial_number_help DIAL_NUM
Dial a number with the mouse:
@dial_number(10,"How much:",5,5,100,1,10,FALSE,money)
On line 10 you'll see the default-number (5). You can vary this
number from 5 to 100. You can increase or decrease the number in
steps of 1 (left mouse-click) or 10 (right mouse-click). The
numbers are not cyclic (flag is FALSE). The number you picked is
returned in the variable money&. If you press <Help> you'll get a
small manual. If I'm baffled by a program I usually press <Help>.
Of course in most programs absolutely nothing will happen, but
that doesn't stop us from adopting the good habit of using the
<Help>-key.
Input_text INP_TEXT
A nice way to input text:
@input_text(TRUE,FALSE,"",20,text$)
20 dots (first flag TRUE) mark the input-line (a box is also
possible: second flag). The input is returned in text$. <Help> is
available. The arrows have no function in this Procedure (yet).
In this case the default-string was the null-string. Examine
Procedure Line_input if you need more bells and whistles.
Key_caps KEY_CAPS
Switch CapsLock on or off:
@key_caps(TRUE) ! CapsLock on
Key_click KEY_CLIK
Switch key-click on or off:
@key_click(FALSE) ! key-click off
Key_repeat KEY_REPT
Switch key-repeat on or off:
@key_repeat(FALSE) ! key-repeat off
Key_wait_repeat KEY_WAIT
Change key-wait and/or key-repeat time:
@key_wait_repeat(50,-1,w&,r&) ! activate key-repeat
after 1 s
INPUT txt$
@key_wait_repeat(-1,50,d&,d&) ! repeat pressed key
every second
INPUT txt$
@key_wait_repeat(w&,r&,d&,d&) ! restore default values
Keyget_init KEYGET
Prepare for a Keyget_processor-Procedure by declaring a few
important global variables:
@keyget_init ! asci|, scan|, stat| and keyget.code%
defined
DO
KEYGET keyget.code%
@keyget_processor ! use above variables there
LOOP
Keypress KEYPRESS
Simulate keyboard-input by user:
@keypress("this text is used",TRUE)
INPUT "No chance for you: ",t$
Because the flag is TRUE, the text is terminated with <Return>.
Line_input LINPUT
The ultimate line-input routine:
@line_input(flag%,10,4,20,1,"_","","","",in$,curs&,ret&)
In this case the input-line starts at (10,4) and is 20
characters long. The cursor starts at (relative) position 1. The
underscore is used for the input-field (other obvious candidates
are " " and "."). The cursor-sprite is not defined, so the
Procedure uses the default-cursor | (thin vertical line). There
is no default-string in this case (the second ""). All characters
are valid (the third ""), but you can supply a list of valid
characters (e.g. "yYnN"). The input-string is returned in in$ and
the last cursor-column can be found in curs&. The variable ret&
contains flag-bits that tell you how the user exited the input-
line (e.g. by pressing <Return>). The variable flag% makes this
Procedure very flexible, but also somewhat complicated. Take you
time to study and use this Procedure! And make this the
penultimate line-input routine by improving the Procedure.
Macro_init MACRO
Install macro-strings for the Function-keys:
@macro_init ! KEYPAD &X10000 is executed to activate
macro's
You'll have to define the strings yourself.
Pop_choice POPCHOIC
A table of on/off-switches is presented:
@pop_choice_init(table.1$() ! create table of choices
@pop_choice(10,10,table.1$(),choices.1!())
On-line <Help> is available. The choices are returned in the
Boolean array choices.1!().
Return_key RETURN
Wait until user presses <Return>:
@return_key(TRUE,FALSE)
The word '<Return>' will blink to catch the eye of the user
(first flag). If you would like to catch his ear as well, the
second flag should be TRUE.
Special_characters SPEC_CHR
Show table with all special characters (ASCII-code > 127):
@special_characters(50,30,code) ! corner at position
(50,30)
IF code>0
PRINT code
ENDIF
A character can be picked by clicking the mouse or by entering
the 3-digit ASCII-code. A click outside the table (or entering
"0") means the user didn't pick a special character (code&=0).
Special_vowels SPEC_VWL
Show all special vowels (ASCII-code > 127) on three lines:
@special_vowels(23) ! on line 23-25
LOCATE 1,10
LINE INPUT "Enter an exotic name: ";n$
A special vowel must be entered with the 'Alternate-method'.
Functions (CHAPTER.08)
Any_key (page 8-2) ANY_KEY
Wait until user presses any key or mouse-button:
PRINT "Press any key or mouse-button..."
~@any_key
The Function returns -1, but you can ignore that.
Ascii_scan ASC_SCAN
Return the ASCII-code that is assigned to a certain scan-code
(usually a key on your keyboard):
PRINT @ascii_scan(&H2B) ! could be 92, 35, 126 or 64
Ascii_scan_shift ) ASC_SHFT
As Ascii_scan, but with <Shift>-key pressed down:
PRINT @ascii_scan_shift(&H2B)
Ascii_scan_caps ASC_CAPS
As Ascii_scan, but with CapsLocks on:
PRINT @ascii_scan_caps(&H2B)
Input_yes_no INP_YES
User must choose between yes and no:
PRINT "Do you want to continue: ";
IF @input_yes_no ! TRUE or FALSE
' yes
ELSE
' no
ENDIF
A blinking "y/n" makes clear what is expected, but the user may
also press <Return> for yes or click a mouse-button (left is yes,
right is no). After input either "YES" or "NO" is printed at the
cursor-position and TRUE or FALSE is returned.
Key$ KEY
Wait for a valid key-press:
PRINT "Press ""Y"" or ""N"": ";
char$=@key$(FALSE,"yn") ! Y,y,N,n accepted
char$=@key$(TRUE,"YN") ! only Y,N accepted
The flag determines if the Function distinguishes between
lower/upper case.
Keyboard_version$ KEYB_VER
Return keyboard-version:
PRINT "You have a ";@keyboard_version$;"."
Disclaimer
The text of the articles is identical to the originals like they appeared
in old ST NEWS issues. Please take into consideration that the author(s)
was (were) a lot younger and less responsible back then. So bad jokes,
bad English, youthful arrogance, insults, bravura, over-crediting and
tastelessness should be taken with at least a grain of salt. Any contact
and/or payment information, as well as deadlines/release dates of any
kind should be regarded as outdated. Due to the fact that these pages are
not actually contained in an Atari executable here, references to scroll
texts, featured demo screens and hidden articles may also be irrelevant.