Keyboard

As well as the touch screen, RFO-BASIC! programs can accept keyboard input. There are two types of keyboard:
 * Hard keyboard or physical keyboard is an actual hardware device wired to the Android device on which RFO-BASIC! is running. Usually, you attach a USB keyboard.
 * Some Android tablets have a full-size USB connector.
 * Most Android phones have a micro-USB connector. Provided that this connector has "On The Go (OTG)" capability (is available for attachment of devices as well as for charging), you can connect a hard keyboard here, though it will typically require a cable adaptor.
 * A Bluetooth keyboard can be "paired" with the Android device and communicate wirelessly. Other Bluetooth devices (such as a joystick and mouse) can also be paired, and the program can sense button presses on these devices.
 * Soft keyboard (on-screen keyboard) is a program that appears at the bottom of the screen. The Google Keyboard ships with many phones.  Alternatives, such as the Hacker's Keyboard, can be installed instead.  Jürgen's keyboard is pictured here; see below to get it.  The soft keyboard has a key configuration like a hard keyboard.  Most soft keyboards can be set for a variety of locales that have different key layouts.  A soft keyboard can be displayed over either the text console or the graphic display.

An RFO-BASIC! program can call on Android to display a variety of dialog windows that supervise the reading of keystrokes and return a result to the program. It can also read individual keystrokes, using an interrupt routine to detect a key-press. RFO-BASIC! buffers keystrokes in case the user presses keys faster than the BASIC program acts on them.

Dialog windows
RFO-BASIC! gives the programmer access to a variety of Android dialog windows for brief user interaction. These can be displayed on top of either the text console or the graphic display. Programs usually use these dialogs only in response to a special condition or user action.

The exact appearance of these dialogs varies from one Android version to another.

This section presents the following BASIC statements that put dialogs on the screen:


 * POPUP. A pop-up window is an output-only "dialog"; there is no user input at all.
 * DIALOG.MESSAGE displays a dialog window with up to three buttons that the user can select.
 * INPUT can display a prompt and retrieve either a string or numeric value from the user through the keyboard.
 * SELECT and DIALOG.SELECT display a list of strings and let the user tap one of them to make a selection.

POPUP
Briefly display an on-screen message

POPUP 
 * Synopsis

The POPUP statement puts a text message on top of the normal display. These messages are either "short" (typically 2 seconds) or "long" (typically 4 seconds). Pop-ups are convenient ways to get information to the user without affecting the normal display or having to work to restore it afterward.
 * Description

The  parameter is a string expression producing the text to be displayed. This parameter is required.

Normally, the message is in the center of the screen. The optional  and  parameters let the program specify the horizontal and vertical positions, respectively, of the message. These parameters specify a displacement from the center of the screen. Positive values for  are displacements rightward; positive values for  are displacements downward. Negative values are displacements in the reverse direction. Directions are based on the orientation (portrait or landscape) the device is currently using.

The optional  parameter specifies the duration of the message. If it is 0 or omitted, the message is short. If it is nonzero, the message is long. The POPUP statement does not suspend the program for this duration. However, if the program ends or malfunctions during this duration, the message might not be removed from the screen at the right time; the pop-up window will go away the next time some action clears the screen.

DIALOG.MESSAGE
Get a user choice from up to 3 options

DIALOG.MESSAGE {}, {}, {, {, {, }}}
 * Synopsis

The DIALOG.MESSAGE statement displays a dialog window with buttons to select one of up to three options, returning in  the number of the button the user tapped: 1, 2, or 3. If the user cancels the input, by tapping the screen outside of the dialog window or by pressing the BACK key, then DIALOG.MESSAGE returns 0 in .
 * Description

The dialog window can have a window title, with any text provided in , and a prompt, with any text provided in <prompt_sexp>. These strings are available to give the user specific information about the choice being made. The three string expressions following <sel_nvar> are optional. For each of these that is present, DIALOG.MESSAGE creates one button and the string expression is the label displayed on that button.

A DIALOG.MESSAGE statement specifying 0 buttons displays any title and any prompt and stops. All the user can do is cancel out, by tapping outside the dialog window or by pressing the BACK button.

Experimenting with DIALOG.MESSAGE is useful. Android style guides number the buttons from right to left, so that tapping the rightmost button returns 1, but some devices reverse this. Android style guides recommend displaying the positive action (such as "Yes" or "Confirm") on the right and the negative action (such as "No" or "Cancel") on the left.
 * Variability

INPUT
Solicit a single-line response from the user

INPUT {<prompt_sexp>}, <result_var>{, {<default_exp>}{, <canceled_lvar>}}
 * Synopsis

The INPUT statement displays a dialog window with a single-line input area and an OK button. The user may type into the input area using the keyboard, may confirm the input by tapping the OK button, and may cancel the input by tapping anywhere outside the dialog window or by tapping the BACK button. Pressing a  or comparable key on a soft keyboard dismisses the soft keyboard but does not confirm the input, though it can still be done by tapping OK. Tapping the input area redisplays the soft keyboard.
 * Description

The <prompt_sexp> becomes the dialog box title. Usually, a prompt tells the user what specific information is desired. If the prompt expression is empty ("") or omitted, the dialog box is drawn without a title area.

The INPUT statement captures a single string or numeric value. If the program provides a <default_exp> value, it appears in the input area at the start of the dialog window and the user can edit or delete it. Otherwise, the input area is blank and the user must type the desired response completely. In the case that the user confirms the input by tapping the OK button, the value entered is assigned to <result_var>. If a default is provided, the variable must be the same type (string or numeric) as <result_var>. The default and the result may be the same variable, in which case the value of the variable is updated after the user confirms the input.

If <result_var> is numeric, the input must be numeric, so the only key taps accepted are 0-9, "+", "-" and ".". If using a soft keyboard, BASIC shows a numeric keypad instead of a full typewriter keyboard.

The statement sets the optional <canceled_lvar> to 0.0 (false) if the user confirms the input by tapping the OK button, or 1.0 (true) if the user cancels the input by any means. If the user cancels the input and the INPUT statement did not provide a <canceled_lvar> to sense the cancellation, it is an error. The program can trap the error with an OnError: trap, in which case GETERROR$ contains. Otherwise, that legend appears on the screen and the program stops.

The following code produced the example illustrated in this section: GR.OPEN 255,64,255,128  % Dark green background oldname$ = "myfile.bas" INPUT "Rename the file then press OK",newname$,oldname$,canc
 * Example

SELECT
Let the user select from a list of options

SELECT       <sel_nvar>, <Array$[]>|<list_nexp> {,<title_sexp>{, <message_sexp>}}{, <press_lvar>} DIALOG.SELECT <sel_nvar>, <Array$[]>|<list_nexp> {,<title_sexp><SPAN STYLE="color: gray">{, <message_sexp>}}{, <press_lvar></SPAN>}
 * Synopsis

The SELECT and DIALOG.SELECT statements display a dialog window with a range of choices. The choices may be in an array or in a list. The user makes a choice by tapping one of the lines of text, in which case DIALOG.SELECT sets the required parameter <sel_nvar> to the index of the line the user selected (the topmost is number 1); or sets <sel_nvar> to 0 if the user cancelled the selection by tapping outside the dialog window or pressing the BACK key.
 * Description


 * The SELECT statement brings up a display that occupies the entire screen. It is in the format of the text console, but does not disturb the contents of the text console.
 * The DIALOG.SELECT statement brings up a dialog window that occupies most of the area of the screen. It can be used on top of the graphic display.

If the program provides more choices than fit in the assigned area, the range becomes scrollable, with a scroll bar on the right edge of the window.

If <title_sexp> is provided, its text is the title of the dialog window. This text can give the user additional information about the nature of the choice to be made. If this parameter is omitted or is the null string, DIALOG.SELECT displays the dialog window with no title. SELECT handles a null string by displaying a blank title line; if <title_sexp> is omitted, it displays a default title.

The mandatory second parameter is one of the following:
 * The name, followed by  of a string array that has been created and filled with elements, such as using ARRAY.LOAD.  Do not provide an index inside the square brackets.
 * The numeric handle of a list of strings.

DIALOG.SELECT allows these two parameters for compatibility, but always ignores <message_sexp> and sets <press_lvar> to 0. </DIV> The SELECT statement does not have a "prompt" parameter as INPUT does, but can display a short pop-up message. The <message_sexp> parameter is the text of this message. If the parameter is omitted, SELECT uses <title_sexp>; if both are omitted, there is no pop-up.

If the caller provides the <press_lvar> parameter, SELECT sets it to indicate the length of the user tap that selected an option: 0 (false) if the user selected the option with a short tap, and 1 (true) if the user selected the option with a long press.


 * Alternative
 * A user-defined function described at Scrolling Selection Window, which accommodates large numbers of choices, provides a mode in which multiple lines can be selected at the same time, provides more customization options, and provides a separate confirmation/cancellation step after the choices are made.

Special-purpose windows
RFO-BASIC! statements described in this section let a program interact with the user with a special-purpose window. Features such as letting the user edit the input are managed by Android rather than by the BASIC program.

TEXT.INPUT
Open a window for user editing of a string

TEXT.INPUT <result_svar>{, {<input_sexp>}, <title_sexp> }
 * Synopsis

The TEXT.INPUT statement opens a large window in which the user can edit text. The <input_sexp> parameter is a string containing the text initially in the window. If it is the null string or omitted, then the edit window is initially empty. The mandatory <result_svar> parameter holds the string as a result of the user's editing.
 * Description

If the caller passes a <title_sexp> parameter, TEXT.INPUT displays it as the title of the edit window.

The INPUT statement accepts user input to a single line, with intra-line edits using the right and left arrow and the backspace key to rub out a character. TEXT.INPUT lets the user move to any line in the edit window with the up and down arrow, and create new lines using the ENTER key. The edit window accepts touches to move the editing cursor and has a scroll bar to make movement through the text easier.

RFO-BASIC! displays a FINISHED button beneath the edit window. The user taps this button to confirm the edits. The user can press the BACK button on cancel the edits, in which case TEXT.INPUT sets <result_svar> to <input_sexp>. The calling code can compare <input_sexp> to <result_svar> to see if the user made any change. If there is no change, there is no way to tell whether the user pressed BACK or made no edits and then pressed FINISHED.

When the text editor takes over the screen, the BASIC program loses it and goes into the background. Therefore, there is a background transition when TEXT.INPUT starts, and another when it returns.

This user-defined function calls an edit window to the screen so that the user can edit, a file assumed to reside in the   directory. In the nearby illustration, a calling program puts its own code in the edit window. Therefore,  includes a path to   FN.DEF EditFile(filename$, title$, confirm) BYTE.OPEN R,f,filename$ BYTE.READ.BUFFER f,100000,s$ BYTE.CLOSE f !Last 3 lines replace GRABFILE, which stopped working in Android 9 POPUP "Press BACK to abort the edit." <SPAN STYLE="color: green">TEXT.INPUT r$,s$,title$</SPAN> IF r$ = s$ THEN IF confirm > 0 THEN POPUP "No changes made." RV = 0 ELSE BYTE.OPEN W,f,filename$ BYTE.WRITE.BUFFER f,r$ BYTE.CLOSE f  IF confirm > 0 THEN POPUP "Changes saved." RV = 1 ENDIF FN.RTN RV FN.END
 * Example

Reading individual keystrokes
On devices with Android versions 9 (Pie) and later, a soft keyboard cannot be shown using KB.SHOW. (On newer Android versions, only editable ListViews can get a virtual keyboard, but the text console is non-editable.) </DIV> A more primitive way to use the keyboard is to read individual keystrokes. In this case, any editing (such as enabling the backspace key to undo keystrokes) must be done by the keyboard itself. The program uses KB.SHOW to enable the keyboard, in case the user has only a soft keyboard. Then the program uses an OnKeyPress interrupt handler to read individual keystrokes with INKEY$.

INKEY$
Read an individual keystroke

INKEY$ <key_svar>
 * Synopsis

The INKEY$ statement returns in the specified string variable, a description of the key the user most recently pressed. It does not wait for a new key-press. If you use INKEY$ in a loop, it typically returns multiple reports of the same key-press. Typically, you use INKEY$ only in an OnKeyPress: interrupt routine, which receives control only when a new key-press occurs.
 * Description

The $ on the end of the INKEY$ statement is unusual for RFO-BASIC! but is required.

The resulting value of the string variable is as follows:
 * Reports
 * If the user has not pressed a key since the BASIC program began running: "@"
 * If the user pressed an alphanumeric key or the space bar, the variable contains a one-character string that is the (lowercase) key that was pressed. For other keys, the variable contains the string "key " followed by the Android key code, in decimal.
 * If the SHIFT or CAPS LOCK key is down, then there are two key-presses: the lowercase letter, then "key 59".
 * If the CTRL key is down, then there are two key-presses: the lowercase letter, then "key 113".
 * Symbols, such as shifted numerals, are reported likewise. For example, the @ is "key 77".
 * The D-Pad keys are reported as "up", "down", "left", "right", and "go".
 * ENTER is "key 66".
 * The volume-up and volume-down buttons on the side of the device are reported as "key 24" and "key 25", respectively. However, normally they perform their usual functions even when a BASIC program detects the key-press.

Reading keystrokes is done easily by using a list as a queue. The program creates a string list to hold the keystrokes: LIST.CREATE S Keystrokes
 * Example

It includes a key-press interrupt handler, called when a new keystroke is available. It appends the new keystroke to the queue and returns: OnKeyPress: INKEY$ mkey$ LIST.ADD Keystrokes,mkey$ KEY.RESUME

The main code, at its leisure, tests to see if any keystrokes are waiting in the list. If so, it removes the one at the head of the queue:

LIST.SIZE Keystrokes,n IF n > 0 THEN LIST.GET Keystrokes,1,k$ LIST.REMOVE Keystrokes,1 ! Process the new key, in k$ ENDIF

Controlling the soft keyboard
When you are editing an RFO-BASIC! program, the edit window calls the soft keyboard unless a hard keyboard is attached.

When an RFO-BASIC! program starts to run, the soft keyboard is not displayed until the program calls for it. The OnKbChange: interrupt handler lets the program sense a change to the displayed status of the soft keyboard.

KB.SHOW
Show the soft keyboard

KB.SHOW
 * Synopsis

The KB.SHOW statement makes RFO-BASIC! display the soft keyboard. However, the soft keyboard never appears in the following cases:
 * Description
 * A hard keyboard is attached
 * The program has not yet written to the text console with a statement such as PRINT.

If the soft keyboard was not on display but KB.SHOW puts it on display, it takes a few hundred milliseconds to update the device's screen to reflect this change. During this interval, the BASIC program is blocked. At the end of this interval, any OnKbChange: interrupt routine is triggered.

KB.HIDE
Hide the soft keyboard

KB.HIDE
 * Synopsis

The KB.HIDE statement hides the soft keyboard.
 * Description

If the soft keyboard was showing because of a KB.SHOW statement, it takes a few hundred milliseconds to update the device's screen to reflect this change. During this interval, the BASIC program is blocked. At the end of this interval, any OnKbChange: interrupt routine is triggered.


 * Automatic transitions
 * The soft keyboard is hidden when a BASIC program starts running, regardless of whether it was showing in the program edit window.
 * The soft keyboard is hidden when you use GR.OPEN to switch to Graphics Mode.
 * The soft keyboard does not show when you execute GR.CLOSE to leave Graphics Mode and return to the text console (until the program calls for it with KB.SHOW).

These automatic transitions do not trigger an OnKbChange: interrupt routine.

If the soft keyboard is showing, the user can dismiss it by pressing the BACK button. The graphic display or text console does not close, and BASIC does not return to the edit window, unless the user presses BACK again. A press of the BACK button that simply dismisses the soft keyboard is not a "keystroke" detectable with the INKEY$ statement or the OnBackKey: or OnKeyPress: interrupts. However, the change in status of the soft keyboard can be detected with the OnKbChange: interrupt.
 * The BACK button

KB.TOGGLE
Toggle the visibility of the soft keyboard

KB.TOGGLE
 * Synopsis

If the soft keyboard is hidden, KB.TOGGLE shows it, exactly as if KB.SHOW had been called. If the soft keyboard is showing, KB.TOGGLE hides it, exactly as if KB.HIDE had been called. Either transition triggers any OnKbChange: interrupt routine.

KB.SHOWING
Test the visibility of the soft keyboard

KB.SHOWING <visible_lvar>
 * Synopsis

The KB.SHOWING statement writes a logical value in the specified numeric variable. It is 1.0 (true) if the BASIC program called for display of the soft keyboard with KB.SHOW, and 0.0 (false) if the soft keyboard is hidden.
 * Description

If the BASIC program put up a dialog window, such as with the INPUT statement, the soft keyboard pertains to that window, and KB.SHOWING reports the soft keyboard to be hidden.