This section clarifies all aspects of controlling a program by hardware. So we are exploiting the joystick and the keyboard in your programs.
A joystick can be used to control movement around the
screen by pushing its handle in the desired direction,
and to trigger all sorts of actions by pressing one or
more buttons built in to its mechanism. Either of the
two (or four) joystick sockets at the back or side
of your computer will happily accept a joystick plug.
If two/four users want to control one joystick each
for specially written programs, all ports can be used.
To make a joystick interact with your programs, the
computer must be able to read its movements and actions.
The ugBASIC language offers a number of
useful functions to do just that.
The JOY() command inspects what is
happening with the joystick and makes a report.
The maximum number of joysticks installed in the system
can be retrieved using the JOY COUNT constant.
If the joystick you are interested in is plugged into
any joystick port, the computer must be told to look
at that port number. For example:
DO
j=JOY(1)
PRINT BIN$(j,5),j
LOOP
By running that routine, reports are given about the
movements of the joystick and the status of the
fire-button in the form of binary numbers. The pattern
of ones and zeros in the report can then be inspected.
Binary bits shown as zero indicate that nothing is
happening, whereas if any of the bits in the report
is shown as a one, it means that the joystick has
been moved in the direction that relates to that bit.
Here is a list of those bits along with their meanings:

REM functional styleleft = BIT( JOY(1), LEFT )PRINT "LEFT IS: ";leftREM declarative styleup = BIT UP OF JOY(1)PRINT "UP IS: ";upREM conditional styleIF JOY(1) HAS BIT UP THEN : PRINT "UP" : ENDIFIF JOY(1) IS UP THEN : PRINT "UP" : ENDIFREM (negative) conditional styleIF JOY(1) HAS NOT BIT UP THEN : PRINT "NOT UP" : ENDIFIF JOY(1) IS NOT UP THEN : PRINT "NOT UP" : ENDIFJLEFT - test for joystick movement towards the left;JRIGHT - test for joystick movement towards the right;JUP - test for joystick movement upwards;JDOWN - test for joystick movement downwards;JFIRE (or FIRE()) - test for joystick fire button pressed.TRUE (meaning-1) if
the joystick connected to the given port number has been pushed to the
directiong requested (or the button has been pressed), otherwise a value of
0 is returned (meaning false).DO IF JLEFT(1) THEN PRINT "WEST" IF JRIGHT(1) THEN PRINT "EAST" IF JUP(1) THEN PRINT "NORTH" IF JDOWN(1) THEN PRINT "SOUTH" IF JFIRE(1) THEN CENTRE "BANG!"LOOPFIRE button
to be pressed on the joystick, you can use the WAIT FIRE command.
The ugBASIC language generally provides two ways to read the joystick
position.
The first, which is the most precise and timely, is the so-called synchronous
readings. In this case, the value of the joystick position is read at the exact moment
in which it is requested. The advantage of this technique is that you get the
instantaneous position of the joystick, and it is less demanding on the computer.
The disadvantage is that, if you are not regular in the readings, you can get irregular
movements.
On the contrary, the asynchronous readings uses the so-called "interrupts" to perform
the reading. In other words, at regular intervals the execution is interrupted and
the position of the joystick at that moment is read. The program, when it requests
the joystick position, actually gets the last known position. The major disadvantage
of this technique is that it can be demanding on the computer, depending on the
target. However, it has the undoubted advantage of ensuring regularity in the readings
over time, and so you can get regular movements.
Both modes can be selected with a specific pragma:
The keyboard can be used to interact with your routines
once they are running. This is vital for any sort of
arcade game, adventure gaming or for more practical
items such as word processing.
The INKEY$ function checks to see if a
key has been pressed, and reports back its value in
a string. For example:
DO
k = INKEY$
IF k<>"" THEN : PRINT "YOU PRESSED A KEY!" : ENDIF
LOOP
The INKEY$ function does not wait for you to
input anything from the keyboard, so if a character is not
entered an empty string is returned. INKEY$
can only register a key-press from one of the keys that
carries its own ASCII code, and the ASCII code numbers that
represent the characters which can be printed on the screen.
It has also been explained that special keys and the function
keys do not carry as ASCII code at all, and if INKEY$
detects that this type of key has been pressed, a character
with a value of zero will be returned. When this happens,
the internal “scan codes” of these keys can be found.
The function SCANCODE returns the internal scan
code of a key that has already been entered using the INKEY$
function. The next example may be tested by pressing the function
keys, F1 and F2.
DO
WHILE k == ""
k = INKEY$
WEND
IF ASC(k)==0 THEN PRINT "NO ASCII CODE"
PRINT "THE SCAN CODE IS ";SCANCODE
k = ""
LOOP
To determine if keys are pressed at the same time as either or
both of the SHIFT keys, the SCANSHIFT
function returns the following values:
NO SHIFT (0) - if no SHIFT key pressed;LEFT SHIFT (1) - if the left SHIFT pressed;RIGHT SHIFT (2) - if the right SHIFT pressed;BOTH SHIFTS (3) - if both keys pressed.LEFT SHIFT and RIGHT SHIFT are bitmask,
you can use the previus syntax:REM functional styleleft = BIT( SCANSHIFT, LEFT SHIFT )PRINT "LEFT IS: ";leftREM declarative styleleft = BIT LEFT SHIFT OF SCANSHIFTPRINT "LEFT IS: ";upREM conditional styleIF SCANSHIFT HAS BIT LEFT SHIFT THEN : PRINT "LEFT" : ENDIFIF SCANSHIFT IS LEFT SHIFT THEN : PRINT "LEFT" : ENDIFREM (negative) conditional styleIF SCANSHIFT HAS NOT BIT LEFT SHIFT THEN : PRINT "NOT LEFT" : ENDIFIF SCANSHIFT IS NOT LEFT SHIFT THEN : PRINT "NOT LEFT" : ENDIFSHIFT keys:DO a = INKEY s = SCANSHIFT IF s <> 0 THEN PRINT s END IFLOOPKEY STATE function to check whether or
not a specific key has been pressed. The relevant scan code
should be enclosed in brackets, and when the associated key
is being pressed KEY STATE will return a
value of TRUE (-1), otherwise the result will
be given as FALSE (0). For example:DO IF KEY STATE(KEY F1) == TRUE THEN : PRINT "F1!" : ENDIF IF KEY STATE(KEY RUNSTOP) == TRUE THEN : PRINT "RUN STOP!" : ENDIFLOOPKEY SHIFT is used to report the
current status of those keys which cannot be detected by either
INKEY$ or SCANCODE because they do not
carry the relevant codes. These control keys cannot be tested
individually, or a test can be set up for any combination of
such keys pressed together. A single call to the KEY SHIFT
function can test for all eventualities, by examining a bit map
in the following format:LEFT SHIFT (0) - if the left SHIFT is pressed;RIGHT SHIFT (1) - if the right SHIFT is pressed;CAPS LOCK (2) - if it is on or offCTRL (3) - if the CTRL is pressed;LEFT ALT (4) - if the left ALT is pressed;RIGHT ALT (5) - if the right ALT is pressed;CENTRE "PLEASE PRESS SOME CONTROL KEYS"CURS OFFDO LOCATE 14,4: PRINT BIN$(KEY SHIFT, 8)LOOPINKEY$
function in order to report on key presses. CLEAR KEY
completely erases this buffer and re-sets the keyboard, making it
a very useful command at the beginning of a program when the
keyboard buffer may be filled with unwanted information.
CLEAR KEY can also be called immediately before a
WAIT KEY command, to make sure that the program
waits for a fresh key-press before proceeding.WAIT KEY command waits for a single key-press
before acting on the next instruction. For example:PRINT "PLEASE PRESS A KEY" : WAIT KEY : PRINT "THANK YOU!"INPUT$ function loads a given number of
characters into a string variable, waiting for the user to
enter each character in turn. Although characters will not
appear on the screen, similar to INKEY$, the
two instructions are totally different.CLEAR KEY : PRINT "PLEASE TYPE IN TEN CHARACTERS"v=INPUT$(10) : PRINT "YOU TYPED: ";INPUT command is used to enter information into
one or more variables. Any variable may be used, as well as any
set of variables, providing they are separated by commas.
A question mark will automatically appear at the current
cursor position as a prompt for your input.REM ASK FOR A NUMBER AND A STRINGINPUT A, K$INPUT command, and will
retain its original position after your data has been entered.
When INPUT is executed, the program will wait
for the required information to be entered via the keyboard,
and each variable in the list must be matched by a single
value entered by the user. These values must be of exactly
the same type as the original variables, and should be
separated by commas.PRINT "TYPE IN A NUMBER"INPUT aPRINT "YOUR NUMBER WAS ";aINPUT "WHAT'S YOUR NAME?";name$LOCATE 23, : PRINT "HELLO ";name$LINE INPUT is identical in usage to INPUT,
except that is uses a press of the RETURN key to
separate each value you enter via the keyboard instead of a comma.
Try this:LINE INPUT "TYPE IN THREE NUMBER";a,b,cPRINT a,b,cPUT KEY command loads a string of characters
directly into the keyboard buffer, and it is most commonly
used to set up defaults for your INPUT routines.
Note that end of line returns can be included using a CHR$(13)
character. In the next example, NO is assigned to the
default INPUT string.DO PUT KEY "NO" INPUT "DO YOU WANT TO CONTINUE, YES OR NO: ";a$ b$ = UPPER$(a$) IF b$ == "NO" THEN BOOM : WAIT 50 : EXITLOOP
The ugBASIC language provides also for keyboard two ways to read the keys.
The first, which is the most precise and timely, is the so-called synchronous
readings. In this case, the value of keyboard is read at the exact moment
in which it is requested. The advantage of this technique is that you get the
instantaneous key pressed, and it is less demanding on the computer.
The disadvantage is that, if you are not regular in the readings, you can miss
keystrokes.
On the contrary, the asynchronous readings uses the so-called "interrupts" to perform
the reading. In other words, at regular intervals the execution is interrupted and
the key pressed on keyboard at that moment is read. The program, when it requests
any key, actually gets the last pressed. The major disadvantage
of this technique is that it can be demanding on the computer, depending on the
target. However, it has the undoubted advantage of ensuring regularity in the readings
over time, and so you can avoid to lose keystrokes.
Both modes can be selected with a specific pragma:
If you have found a problem, if you think there is a bug or, more
simply, you would like something to be improved, write a topic on the official forum, or open an issue on GitHub.
Thank you!