8. KEYBOARD INPUT 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', page 8-5). key ASC(key$) scancode 8 &H0E 9 &H0F and 13 &H1C and &H72 27 &H01 127 &H53 key ASC(RIGHT$(key$)) scancode 59 &H3B 68 &H44 84 &H54 93 &H5D 98 &H62 97 &H61 82 &H52 71 &H47 75 &H4B 77 &H4D 72 &H48 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. 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 ENDIF Of course, you could also use the following method: key$=INKEY$ IF ASC(RIGHT$(key$))=98 (...) ! ENDIF It's impossible to detect a combination with INKEY$, because a one-byte value of an existing (!) key is returned: CHR$(50), (52), (54) and (56) for , , and . 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 down, enter the code, and release . 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: - toggle between Overwrite- and Insert-mode - delete character before cursor - delete character under cursor - erase entire input-line - cursor one position to left - cursor one position to right - cursor to start of input-line - cursor to current end of line (after last character) The and 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 , 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 you jump to the end of the default-string, but I find it more convenient to let the program do that: KEYPRESS &H500000 ! press FORM INPUT 20 AS default$ KEYTEST The KEYTEST-function does not respond to keys such as , , 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 , , and . 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 bit 1 = Left bit 2 = bit 3 = bit 4 = You could discover if the user had pressed 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 ) simultaneously or not. Watch out for the following exceptions: For to the scan-codes &H54 to &H5D are returned (not &H3B to &H44). On an MS-DOS computer these codes are used for the keys to . can be used to simulate other keys with the 'regular' keys, e.g. = and = . That's a relic from a long time ago. has code &H77 (not &H47). The combinations (&H73) and (&H74) also have special codes. Blame MS-DOS. The combinations <1> to <=> have the special codes &H78 to &H83. That's 'ALT1' to 'ALT=' for MS-DOS. is intercepted by TOS and leads to a screendump. in combination with , or one of the arrows is also intercepted and results in movement of the mouse- pointer on the screen (see paragraph 'MOUSE', page 14-1). 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 . Or &H04620062 for , 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 ) 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 , 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 (page 8-4) 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 you'll get a small manual. If I'm baffled by a program I usually press . Of course in most programs absolutely nothing will happen, but that doesn't stop us from adopting the good habit of using the -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$. 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 (page 8-9) KEY_CAPS Switch CapsLock on or off: @key_caps(TRUE) ! CapsLock on Key_click (page 8-9) KEY_CLIK Switch key-click on or off: @key_click(FALSE) ! key-click off Key_repeat (page 8-9) KEY_REPT Switch key-repeat on or off: @key_repeat(FALSE) ! key-repeat off Key_wait_repeat (page 8-9) 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 (page 8-5) 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 (page 8-6) 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 . 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 ). 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 (page 8-7) 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 is available. The choices are returned in the Boolean array choices.1!(). Return_key RETURN Wait until user presses : @return_key(TRUE,FALSE) The word '' 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 (page 8-3) 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 (page 8-3) 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 (page 8-8) 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 (page 8-8) ASC_SHFT As Ascii_scan, but with -key pressed down: PRINT @ascii_scan_shift(&H2B) Ascii_scan_caps (page 8-8) 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 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$ (page 8-7) KEYB_VER Return keyboard-version: PRINT "You have a ";@keyboard_version$;"."