Home > +-----------------------------------------------+

+-----------------------------------------------+

+-----------------------------------------------+
| File: keysdet.txt |
| Author: Mod |
| Email: fer2roc@excite.com |
| Date: 10-30-99 |
| Description: Tutorial on Keys Detection |
| for QBasic and QuickBasic |
| Level: Beginners and medium-level programmers |
+-----------------------------------------------+

This document may be freely distributed provided that I am given credit,and
that is unchanged (including this message).

KEYS DETECTION (FROM THE BEGINNING)
===================================
+-------+
| Intro |
+-------+
One of the more important points in programming is how to identify the
different keys, through which the user will interact with the program.
Although many controlling actions (such as to open menus, to make scrolling,
to input data, to quit, etc) may be accomplished with the mouse, the program
must usually allow to make the same actions through the keyboard; also the
data introduction (specially texts) is exclusively keyboard depending.
In this tutorial we'll see how to identify the different keys in order to
assign to them the functions we want, that's to say, how to represent the
keys in our code.
QBasic allows to use different ways to define the keyboard, each one has
advantages and disadvantages. We'll review first 3 different methods and
then we'll see how to choose one method depending on the characteristics of
our program. The methods are not excluding and may be combined in the same
program. Before analyzing each method, we must review some generalities
about the keyboard and about the characters thas it represents.

+--------------+
| The keyboard |
+--------------+
Today it's almost exclusively used the so called "extended keyboard", which
has at least 103 keys. We'll see that some functions in QBasic are designed
for older keyboards. Some keys are "controlling" keys, like Esc, Intro, Spc,
arrow keys, etc. Other keys represent printable characters (most 2 but also
3). The keys pressing may be combined, we keep one key depressed and then we
press another one. The Shifts, Ctrl and Alt keys make that and change the
function of the second key. Other keys like CapsLock and NumLock act as
"on/off" switches changing permanently the function of the other keys, until
they are pressed again.
It's important to say that keyboards vary in different countries. There are
some different letters, punctuations marks and even the location of the more
common letters may vary. This fact must be always considered by the
programmer in order to code in a universal way, so that their programs may
function well in any keyboard. There are keys that keep their position
constant in different keyboards, other vary from country to country.

+----------------+
| The characters |
+----------------+
The ASCII code contains the 256 symbols that constitute the characters set.
This number depends on the possibility of representing different data in a
byte (in binary numbers, the 8 bits of a byte may go from 00000000 to
11111111, which is equivalent to decimal 255). Not all the ASCII characters
are printable. Some represent actions, like beeping, carriage return, intro,
etc. and each one has its own symbol, although it's neither is used in
writing nor is drawn in the keyboard keys. The printable characters are the
capital and lower-case letters, the numbers, the punctuation marks and a lot
of symbols such as accented letters, foreign and old letters, and graphical
figures that may be used for layouting.
Each character may be identified through its ASCII number, from 0 to 255.
QBasic manages the ASC function, which returns the ASCII number for each
specified character. The opposite function is CHR$, which returns the
character for each ASCII number:

PRINT ASC("a") The result will be 97
PRINT CHR$(97) The result will be a

The expression CHR$(number) is equivalent to the ASCII character that
it represents.

Is the same to say: IF a$ = "a" THEN..
than to say: IF a$ = CHR$(97) THEN..

Some function keys have a so called "extended code", which consist in 2
ASCII characters and therefore it's stored in 2 bytes. The first one is
always the null character CHR$(0), the second one is another character from
the set. The extended code is represented as the addition of both
characters. For example, the H letter has the ASCII code #72. But the Up
arrow key has the extended code CHR$(0) + "H" or CHR$(0) + CHR$(72).
Some keys (like Ctrl, Alt, Shift) haven't an ASCII number if they are
pressed alone. They haven't an own function, they just modify the function
of the others.
As keyboards, the character set is not exactly the same in different
countries, but letters, numbers and function symbols keep constant.
Why the things must be complicated? Why not to use a single and complete
code, which include the symbols used in all countries? It exists: UNICODE.
But it needs to store each symbol in 2 bytes. That enhances the number from
256 to 65536, but it isn't practical. Usually we don't need more then 256
symbols and we would be only duplicating the memory usage in order to have
symbols which we would never use. As each language has its own necessities,
it's more
practical to introduce little variations in the character sets.

+---------------------+
| International codes |
+---------------------+
There are 24 different possibilities of keyboard and characters set
varieties. he "keyb" command in DOS allows to know both the keyboard type
and the haracter set that your system uses. In USA the "us" keyboard code
and #437 character set are used. The complete keyboard codes and character
sets list may be consulted in the DOS manuals.

+----------------+
| Keys detection |
+----------------+
Now we begin. The first thing that you have to know is, that there are 2
ways of proceeding:

(1) We may recognize the pressed "key", that's to say a key that has a
determined location in the keyboard, independently of the function that t
represent or the character that it contains. In order to do that, xist the
so called "Keyboard Scan Codes".

(2) We may recognize the entered "character", independently of the location
of the key through which it entered. In this case, we use the ASCII code.

It's important not to confuse them, because they aren't equivalent. For
example the Esc key hat the scan code #1 and the ASCII code #27. If we put
them in the wrong place the program won't function.

In this tutorial we'll study 3 key detection methods:

(1) The character detection through the INKEY$ function
(2) The key detection through the ON KEY statement
(3) The key detection through the INP function

+---------------------+
| The INKEY$ function |
+---------------------+
The INKEY$ function reads the keyboard buffer and it returns a string which
consists just in the entered character. It may be compared with INPUT, but
there are important differences. INPUT stops the program and waits that the
user enter data. It only "knows" about the data when the user press the
Intro key and enters a string that may consist in several characters. INKEY$
doesn't wait. It detects a single or extended character as soon as it was
entered, without waiting for Intro. Also INPUT "makes echo", it prints the
character on the screen and INKEY$ doesn't it. INKEY$ is excellent in a
menu:
you press the selected key and the action goes at once.

a$ = INKEY$

If we run this code, we'll see that the program just end. INKEY$ didn't wait
for an input, it just returned a null character and the program continued.
If we want that INKEY$ wait for a key pressing, we must code a loop like
this:

DO
a$ = INKEY$
LOOP UNTIL a$ <> ""

Here we indicate that the program must keep the loop until the string cease
to be a null string. This will occur when some key (with ASCII character)
has been pressed. As we know the returned ASCII number we'll be able to know
which key has been pressed, using IF or SELECT CASE structures and then we
may assign to them the actions we want. Examples:

CLS
PRINT "In this program you may detect:
PRINT "B - b - Intro - Up arrow - Down arrow"
PRINT "Esc for ending"
DO
DO: a$ = INKEY$
LOOP UNTIL a$ <> ""
SELECT CASE a$
CASE "B": PRINT "B key pressed"
CASE CHR$(98): PRINT "b key pressed"
CASE CHR$(13): PRINT "Intro pressed"
CASE CHR$(0) + "H": PRINT "Up arrow key pressed"
CASE CHR$(0) + CHR$(80): PRINT "Down arrow key pressed"
CASE CHR$(27): END
END SELECT
LOOP

The function a$ = INPUT$(1) is nearly equivalent to the INKEY$'s loop. It
doesn't need Intro pressing and doesn't makes echo on the screen, but since
it returns only one character you won't be able to differentiate the 2 bytes
extended characters. Nevertheless, it's useful in the inespecific controlled
pause "Press any key..", since it saves code.

+----------------------+
| The ON KEY statement |
+----------------------+
I used to hate ON KEY, because I used to find it capricious. Sometimes it
seemed to work perfectly, sometimes not. Then I saw that the problem was the
CapsLock and NumLock keys. I understood that, if one or both of them are
activated, the function of all the keys is changed and the keys whose
detection I programmed are not the same that those that the keyboard has
now. Since I learnt how to solve it, I love ON KEY, I found it very useful.
Its main advantage is, that I may put it at the beginning of a program (for
example, to end if Esc is pressed) and I won't worry any more: the Esc key
will be detected, although the program be running in a SUB or making a
loop.It saves considerable code. Without ON KEY we should have to code the
end
condition in many parts of the program.

ON KEY detects "keys", not characters. Therefore it uses the scan codes. But
the syntax of ON KEY demands that these codes must be written inside of
CHR$( ) functions and they will look like ASCII codes and this may be
confusing. Also the ON KEY syntax requires to use a subroutine (memories of
old basic). If we code ON KEY(15) PRINT "Hello", we'll get an "Gosub
expected" error message. We must define a label and to set there the actions
that we want and the returning instructions.

The ON KEY programming has several steps:

(1) Keys defining. Some keys are QBasic predefined. Others may be defined by
the programmer using the KEY statement.

(2) For each key to detect we must set the ON KEY statement with the syntax
ON KEY(n) GOSUB label.

(3) Each key detection must be enabled using the KEY(n) ON (also may be
disabled with the KEY(n) OFF statement, which it may be useful in some
programs).

(4) Coding of the subroutines, either one for each key or common, depending
of our necessities.

Do not confuse KEY, ON KEY(n) and KEY(n) ON, they are different statements.


Only key defining may be somewhat complicated, and we'll see it in detail.
The keys are identified through an order number, from 1 to 25 and 30 to 31
(these are KEY statement's arbitrary numbers, they are neither scan codes
nor ASCII codes). The Qbasic predefined keys are:

1 - 10 Function keys F1 to F10

11 - 14 Arrow keys (up, left, right, down). These arrow
keys are those in the numerical keyboard keys
(memories of the past again).

30 - 31 Function keys F11 and F12

The keys from 15 to 25 may be defined by the programmer. Therefore we may
define only 11 keys, and that it isn't too much, as we'll see. The syntax
is:

KEY number, CHR$(kbdFlag) + CHR$(scanCode)

The keyboardFlag indicates if the key that we're defining is combined with
another one. We must use the following values:

0 if the key is pressed alone
1 to 3 if any Shift and the key are combined
4 if Ctrl and the key are combined
8 if Alt and the key are combined
32 if NumLock is activated
64 if CapsLock is activated
128 if we are defining some extended key

Also these values may be combined each other. If we want to detect a
Ctrl+Alt+key combination, the keyboardFlag must be 4 + 8 = 12.

Other examples:
- to detect the Intro key pressed alone: KEY 15, CHR$(0) + CHR$(28)
- to detect Ctrl+Esc: KEY 16, CHR$(4) + CHR$(1)
- to detect the Alt key pressed alone: KEY 17, CHR$(0) + CHR$(56)

Notice that these codes look like extended ASCII codes, specially when the
first term is CHR$(0). But I insist: the Alt key hasn't ASCII code. If we
try to detect it with INKEY$ using
CHR$(0)+ CHR$(56) or CHR$(0) + "8", it on't work.

Now we'll see a runnable example of Alt key detection:

CLS
KEY 15, CHR$(0) + CHR$(56)
ON KEY(15) GOSUB AltKey
KEY(15) ON
FOR n = 1 to 50000
LOCATE 10, 36: PRINT n
NEXT n
END

AltKey:
LOCATE 12, 30: PRINT "Alt has been pressed"
SLEEP 1
CLS
RETURN

If this program didn't work for you, look at your NumLock and CapsLock. The
Alt key may be detected, even if the program is running a loop, but it
requires that both Locks to be inactivated. This is the reason: if one of
both Locks are activated, the meaning of the other keys changes, we must
consider them as combined. If we press now a key, we're really pressing a
combination: NumLock+key or CapsLock+key or NumLock+CapsLock+key.
NumLock+Alt is not the same key than Alt. If we defined Alt, we had not to
aspire that NumLock+Alt can be detected. If we want to detect a key in any
circumstance,
we must define the key 4 times, covering all the possibilities:

- to detect the Alt key pressed alone: KEY 15, CHR$(0) + CHR$(56)
- to detect it if Num Lock is on: KEY 16, CHR$(32) + CHR$(56)
- to detect it if Caps Lock is on: KEY 17, CHR$(64) + CHR$(56)
- to detect it if both Locks are on: KEY 18, CHR$(96) + CHR$(56)
(32 + 64 = 96)

Then we may drive all GOSUBs to the same label:

ON KEY(15) GOSUB AltKey
ON KEY(16) GOSUB AltKey
ON KEY(17) GOSUB AltKey
ON KEY(18) GOSUB AltKey

And, of course, all key detections must be enabled:

KEY(15) ON: KEY(16) ON: KEY(17) ON: KEY(18) ON

Now the program will detect the Alt key always. But notice that, since we
may define only 11 keys, we'll be able to make a complete programming of
only 2 keys. Fortunately, the Qbasic's predefined keys (F1 trough F12) work
perfectly in all cases.

Now an example of defining extended keys. We've seen above that the
predefined arrow keys are those of the numerical keybord. The "normal" arrow
keys belong to the extended keyboard and won't work as predefined keys. If
we would want to detect them, we should define them as following:

(Up arrow key: Scan code #72)
- to detect it alone: KEY 15, CHR$(128) + CHR$(72)
- with Num Lock on: KEY 16, CHR$(160) + CHR$(72)'(128 + 32 = 160)
- with Caps Lock on: KEY 17, CHR$(192) + CHR$(72)'(128 + 64 = 192)
- with both Locks on: KEY 18, CHR$(224) + CHR$(72)
'(128 + 32 + 64 = 224)

This is only an example of how to define extended keys. We couldn't define
the extended arrow keys by this method, because we would need 4 * 4 = 16
keys and we only dispose of 11. Indeed the "normal" arrow keys are detected
well with INKEY$.

+------------------+
| The INP function |
+------------------+
INP gets information through the I/O ports of the computer. If we give to it
the hexadecimal &H60 address, we'll read through the keyboard I/O port and
we'll get a value (one byte) that is the scan code of the last pressed key.
Moreover, this value will be different if the key is still pressed or if it
has been released:

If the key is still pressed: we get the key's scan code
if the key has been released: we get the key's scan code + 128

So, we may establish a key recognizing routine using the obtained value:

CLS
PRINT "In this program you may detect Ctrl y Alt"
PRINT "Esc for ending"
DO
k = INP(&H60)
LOCATE 12, 30
SELECT CASE k
CASE 1: END
CASE 29: PRINT "The Ctrl key is pressed "
CASE 56: PRINT "The Alt key is pressed "
CASE 157: PRINT "The Ctrl key has been released"
CASE 184: PRINT "The Alt key has been released "
END SELECT
LOOP

Notice that we're detecting easily Ctrl and Alt, both keys haven't ASCII
code and usually their detection is considered as difficult.
Key detection with INP is very fast. Moreover the possibility of
press/release detecting makes it very useful for games programming. As an
example, we'll see how to transform the Intro key in a Accelerator:

CLS
PRINT "Press and release Intro"
PRINT "Esc for ending"
DO
SOUND (50 + incr), .5
k = INP(&H60)
SELECT CASE k
CASE 1: END
CASE 28
inc = inc + .5
IF inc > 120 THEN inc = 120
CASE 156
inc = inc - .5
IF inc < 0 THEN inc = 0
END SELECT
DEF SEG = &H40
POKE &H1A, PEEK(&H1C)
LOOP

The 2 last lines inside the loop are a routine for discharging the
keyboard buffer, avoiding saturation and beeping.

+---------------------------------------+
| How to choose and combine the methods |
+---------------------------------------+
Each method has their own advantages and disadvantages and therefore we
couldn't say which is the best. We could say rather that a method will be
the best in each specific case. You could have the following tips as a
guide:

(1) Use INKEY$ each time as you can. Detecting characters through INKEY$ is
safer to get portability to our programs. If we ask the user for pressing
the "A" key, our code will detect it, althought in some countries the "A"
key may have another location in the keyboard. We have no limmits about how
many keys to detect, but we only can detect the keys which have ASCII code.


(2) Use ON KEY if you need keys that will be used along the whole program
(for example Esc for end, F1 for Help). It may be useful also in games
programming, if you need a repeating action along the whole program.
Practically we count on the 12 predefined function keys (F1 through F12),
since the numerical keyboard arrow keys are not to be used currently. If you
can disable NumLocK and CapsLock, you should count on 11 keys to define, on
the contrary only 2.

(3) The keys which haven't ASCII code may be detected either through ON KEY
or through INP, depending on their usage, frequent or ocasional, as it was
stated in (2). Althought you are using the scan codes, the position of the
main controlling keys is quite constant and you won't have portability
problems.

(4) If you want speed and press/release detection, as in games, use INP

Finally, here is an example about how the different method may be combined
in the same program. In the example, Intro is detected through ON KEY, Ctrl
through INP and Esc through INKEY$:

CLS
PRINT "In this program you may detect:
PRINT " - Ctrl (through INP)
PRINT " - Intro (through GOSUB)
PRINT " - Esc (through INKEY$)
KEY 15, CHR$(0) + CHR$(28)
KEY 16, CHR$(32) + CHR$(28)
KEY 17, CHR$(64) + CHR$(28)
KEY 18, CHR$(96) + CHR$(28)
ON KEY(15) GOSUB IntroKey
ON KEY(16) GOSUB IntroKey
ON KEY(17) GOSUB IntroKey
ON KEY(18) GOSUB IntroKey
KEY(15) ON: KEY(16) ON: KEY(17) ON: KEY(18) ON
DO
DO: a$ = INKEY$
k = INP(&H60)
IF k = 29 THEN
LOCATE 10, 20: PRINT "Ctrl has been pressed"
SLEEP 1
LOCATE 10, 20: PRINT STRING$(21, 32)
END IF
LOOP UNTIL a$ <> ""
IF a$ = CHR$(27) THEN
LOCATE 10, 22: PRINT "Esc has been pressed"
LOCATE 11, 20: PRINT "and the program will end"
SLEEP 1
END
END IF
LOOP

IntroKey:
LOCATE 10, 20: PRINT "Intro has been pressed"
SLEEP 1
LOCATE 10, 20: PRINT STRING$(22, 32)
RETURN

+-----------------+
| There is more.. |
+-----------------+
The methods reviewed in this tutorial aren't all we can do. We could also
detect keys looking in the memory through PEEK. We could make bit decoding
to detect, for example, if the left or the right Alt key has been pressed.
But this goes beyond the scope of this article.

+---------------------+
| The tables you need |
+---------------------+
In the Help File of QBasic 1.1 and QuickBasic 4.5 you'll find:

- The ASCII Character Codes List

- The Keyboard Scan Codes List

- I'll give you the list of the more common extended ASCII codes
(it lacks those of combined keys)

Up arrow CHR$(0) + "H" or CHR$(0) + CHR$(72)
Down arrow CHR$(0) + "P" or CHR$(0) + CHR$(80)
Left arrow CHR$(0) + "K" or CHR$(0) + CHR$(75)
Right arrow CHR$(0) + "M" or CHR$(0) + CHR$(77)
F1 CHR$(0) + ";" or CHR$(0) + CHR$(59)
F2 CHR$(0) + "<" or CHR$(0) + CHR$(60)
F3 CHR$(0) + "=" or CHR$(0) + CHR$(61)
F4 CHR$(0) + ">" or CHR$(0) + CHR$(62)
F5 CHR$(0) + "?" or CHR$(0) + CHR$(63)
F6 CHR$(0) + "@" or CHR$(0) + CHR$(64)
F7 CHR$(0) + "A" or CHR$(0) + CHR$(65)
F8 CHR$(0) + "B" or CHR$(0) + CHR$(66)
F9 CHR$(0) + "C" or CHR$(0) + CHR$(67)
F10 CHR$(0) + "D" or CHR$(0) + CHR$(68)
F11 CHR$(0) + "…" or CHR$(0) + CHR$(133)
F12 CHR$(0) + "†" or CHR$(0) + CHR$(134)
Ins CHR$(0) + "R" or CHR$(0) + CHR$(82)
Del CHR$(0) + "S" or CHR$(0) + CHR$(83)
Home CHR$(0) + "G" or CHR$(0) + CHR$(71)
End CHR$(0) + "O" or CHR$(0) + CHR$(79)
PgUp CHR$(0) + "I" or CHR$(0) + CHR$(73)
PgDn CHR$(0) + "Q" or CHR$(0) + CHR$(81)

Try to make a program that gives the simple or extended ASCII code of any
key or keys combination you press (if it has one).

+--------------+
| Contact Info |
+--------------+
That's all for this tutorial. Hopefully it will help newbies to clear
their knowledge about key detection. If you have questions or comments
you may contact me via email at:
fer2roc@excite.com

+---------+
| Credits |
+---------+
I want to thank Zip, from whom I got some of the information of above.
Also for reviewing the article and of course for hosting my tutorials
on his web site:
http://angelfire.com/co/zippy15

Set Home | Add to Favorites

All Rights Reserved Powered by Free Document Search and Download

Copyright © 2011
This site does not host pdf,doc,ppt,xls,rtf,txt files all document are the property of their respective owners. complaint#downhi.com
TOP