home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ARM Club 3
/
TheARMClub_PDCD3.iso
/
hensa
/
keyboard
/
a228_1
/
!KeyChange
/
KeyCodes
< prev
next >
Wrap
Text File
|
1992-02-08
|
14KB
|
233 lines
The Keycode Story
=================
or
How to get more from your keyboard
==================================
The PRM isn't very forthcoming about the way the keyboard is handled, so
this file attempts to explain how things work, as well as giving the
rationale for the way the KeyChange module works. The information was
gleaned from VERY careful reading of the "Character Input" section of the
PRM (among others), plus quite a lot of experimentation, but I don't
guarantee that it's all exactly right. The main problems are that the PRM
fails to distinguish between things done by the keyboard handler and by
OS_ReadC (which are logically quite distinct), and fails to make very clear
what codes are inserted into the keyboard buffer in different conditions.
All page references are to the 1st edition (issue 1) PRM.
To begin with, it's very important to understand the difference between
five concepts:
1) Function keys - these are the physical red (or grey) keys along the top
of the keyboard, the Print and Insert keys (F0 and F13 in disguise), and
the cursor, Page Up/Down, copy and tab keys (if you set them up
appropriately).
2) Function key strings (or expansions) - these are the strings assigned to
the variables Key$0 to Key$15 with *Key or whatever, that get used when
you hit a function key outside the desktop. These aren't usually used in
the desktop environment.
3) Function key (buffer) codes - these are the codes inserted into the
keyboard buffer when you hit a function key. They are in the range
&80-&FF.
4) Top-bit-set characters - these are also in the range &80-&FF, but are
just treated as normal characters. They are distinguished from function
key codes in the buffer by being preceded by a zero (ASCII NUL), as
described below.
5) Codes returned by OSReadC - these are what your program will normally
see. Normal and top-bit-set characters are just returned as they stand,
but function key codes can be treated in different ways - discarded,
translated into a function key string, returned as a NUL followed by the
code (allowing them to be distinguished from top-bit-set characters),
or returned as a top-bit-set character (although not necessarily the one
with the same code!).
Confused? You will be ...
Things start with a keyboard interrupt whenever you press or release a
key. This can be trapped as event 11 (see p. 122), which gives you a
hardware keycode which is different for every key on the keyboard, and tells
you if the key went down or up. It also gives you a keyboard driver ID, but
no information is given about it, so this isn't very helpful. This means
that the KeyChange module may not work with non-UK keyboards, although there
is a gap for an extra code between left-Shift and "Z", so maybe all is OK.
(Do Acorn make any other keyboards, anyway?) It may also help to know that
the row and column legends on the table are the wrong way around, i.e. the
numbers along the top are the high byte and the ones down the side are the
low byte.
Unfortunately, the event is purely informational, so you can't alter the
keycode at this stage. The BBC micro had a Key Vector which did let you
change the code, but this seems to be the only vector that didn't make it
from the beeb. The PRM does say that you can replace the keyboard handler
completely, but "[i]t is outside the scope of this manual to discuss this
procedure in depth" (p. 468). How can anything be outside the scope of the
PRM?
Anyway, the keyboard handler translates the hardware code into a buffer
code, except for shifting and locking keys, and escape and break if enabled.
Escape is a story in itself; see the table on p. 472. The shift and lock
keys just change an internal flag, which (sometimes) modifies the code
produced by the other keys. You can change the code produced by the tab key
with OS_Byte 219, and (to a very limited extent) those produced by the
keypad with OS_Bytes 238 and 254. Apart from this, the code that enters the
keyboard buffer is that given in the table on p. 520, EXCEPT that ASCII NUL
(Ctrl-@) is entered as two NUL characters in a row. Incidentally, note that
the Page Up/Down keys are effectively just shifted versions of the up/down
cursor keys.
Furthermore, if you have the InternationalKeyboard module enabled, it
allows you to use the Alt keys as shifting keys with various normal keys to
get top-bit-set characters, and to type ASCII codes on the keypad. These
codes are entered into the keyboard buffer as TWO characters, a NUL followed
by the top-bit-set character. Alt with keys that don't give a top-bit-set
character don't give a buffer code at all. If you *Unplug or *RMKill the
InternationalKeyboard module, Alt keys make no difference to the keycode
generated by other keys, and top-bit-set characters can't be typed (as far
as I know). [By this I mean that you can't put them in the buffer; as
described below, OS_ReadC can return function key codes as top-bit-set
characters. You could also put them in by hand with OS_Byte 138.] The fact
that these characters are entered with a preceding NUL means that you can
distinguish top-bit-set characters from function key codes, a vitally
important fact!
Once the code is emitted by the keyboard handler you can start
manipulating it, by grabbing either the buffer insert or buffer remove
vector. KeyChange uses buffer insert, as it needs to know about shifting
keys; codes can be removed from the buffer a long time after they're
inserted, so you might have taken your finger off the shift key by then! The
two vectors are otherwise more-or-less equivalent, as nothing happens to the
codes in between. The main thing to remember is that any code preceded by a
NUL has to be passed unchanged, assuming you only want to mess around with
function key codes. Incidentally, if you pull characters out of the buffer
directly with OS_Byte 145 you'll see the nulls, but OS_ReadC and everything
that calls it deals with translated codes.
The buffer insertion code is called in IRQ mode, and another thing that
the PRM fails to make clear is whether you can call the OS_Bytes which check
the keyboard status (e.g. OS_Byte 121 or 202) in this case. The description
says "interrupt status is not altered", which looks OK, but also says
"re-entrancy not defined". What exactly is the difference between
"undefined" re-entrancy and non-re-entrancy? I suspect that it is OK to call
them, but just to be safe KeyChange traps the key up/down event referred to
earlier, and keeps its own record of the state of keys in which it's
interested. [The more I use the PRM, the more I feel that Acorn have skimped
on defining the entry and exit conditions for SWIs etc.; at first sight it
all looks clear, but the closer you look the less certain it all gets. As a
good example, I believe it to be true that the data block used in Wimp SWIs
remains unchanged except where values are explicitly returned, but I'm
pretty sure it does't say so anywhere. End of whinge.]
Most programs that use the keyboard get characters with OS_ReadC, or with
something like OS_ReadLine that calls it. This passes all normal codes
(below &80) and all top-bit-set characters without interpretation, except
for removing any leading NUL. This includes all control codes;
interpretation of Return, Ctrl-U and Delete is done by OS_ReadLine, and
other codes normally only have an effect once they're echoed to OS_WriteC.
(In the Wimp environment all codes are just passed to tasks to deal with as
they wish).
The cursor and copy keys give buffer codes as shown in the table on page
520. Depending on the mode selected by OS_Byte 4 they either trigger cursor
editing, return top-bit-set characters (not the same ones as their buffer
codes), or get treated as standard function key codes. These are interpreted
according to the setting of OS_Bytes 221-228; they can be discarded,
expanded, returned as a NUL followed by the code (which is the opposite of
how they're stored in the buffer!), or returned as top-bit-set characters.
Note that any codes above &7F in function key strings are returned as
top-bit-set characters, and not interpreted as function key codes.
The Wimp adds yet another twist to all this. It programs the cursor and
copy keys to be treated as normal function keys, and the tab key to give
code &8A (modified appropriately by Shift and Ctrl), which you can't
otherwise get from the keyboard. Note that this isn't the same as F10 due to
the strange way the codes are set out; F0-F9 are &80-&89, but F10-F13 are
&CA-&CD (F13 is the Insert key). Following this interpretation, F14 and F15
don't really exist. However, this doesn't mean that you can't access the
function key strings for F14 and F15, as only the low nibble of the code is
used to determine the string used. Outside the desktop, if you program the
cursor keys to act as function keys with OS_Byte 4 you can get at the F14
and F15 strings with the up and down cursor keys, just as you can get the
F11 and F12 strings with the left and right cursor keys. (Simple, isn't it?)
Anyway, the Wimp also uses OS_Bytes 221-228 to make all function key codes
be returned preceded by a NUL. It then internally translates this to the 32
bit value passed on the Key_Pressed wimp event, which adds &100 to the code
for function keys. Thus the upshot is that wimp tasks see all codes between
&20 and &FF as normal characters, with control codes between &00 and &1F as
usual, and function key values between &180 and &18F, giving you a possible
160 codes to use as hot keys etc. The only fly in the ointment is that,
although the wimp will happily translate any function key code, you can't
actually type 48 of them. I'm typing this with Deskedit, which uses all but
6 of the available function key combinations (i.e. the ones you get with the
red keys), most control codes, and some extras of its own that it must get
by reading the keyboard directly. Thus if you want to use a hot-key
application, you're pretty restricted in your choices. Enter KeyChange!
An initial look at the keyboard shows that the options are fairly limited,
as most of the keys are in use already; the only realistic candidates for
additional uses are the Alt keys, the right-hand Ctrl key, Num Lock and
perhaps Scroll Lock (which doesn't appear to do anything in the desktop). To
get extra "function key" codes you really need a shifting key, although I
suppose you could use Scroll Lock if you ignored the LED and didn't use it
outside the desktop.
The most obvious candidates are the Alt keys, as they probably aren't used
much by most people; unfortunately, with the InternationalKeyboard module
active they don't generate buffer codes at all with most keys, and if you
*Unplug it you can't type top-bit set characters. Thus I decided to use Alt
with a fallback to the right-hand Ctrl for people who want to type
top-bit-set characters.
The next step was to see which codes you can already get, and look for the
best way of generating the rest. Looking at the tables on p. 520 and p. 1198
shows that under the Wimp, with the tab, cursor and copy keys producing
codes rather than effects, you can get all of the codes between &80 and &BF
inclusive, plus &CA-&CD, &DA-&DD, &EA-&ED and &FA-&FD. Thus you need to
generate four extra codes from function keys F0-F9, plus the non-existent
F14 and F15. You can do this with one shifting key, as long as you don't
mind having to hit four keys to get some of the codes! With two shifting
keys you could get all codes with no more than three keys pressed, but this
clashed with my desire to have an option to use the right Ctrl, and would
also mean that you'd have to remember which codes went with which Alt key.
Anyway, you get up to another 36 codes with a maximum of three keys pressed
at once, so this should be fairly acceptable.
A further problem was that the mythical F14 and F15 are shifted versions
of the up and down cursor keys. Ctrl-cursor is a standard way of moving
around text in !Edit etc., and I always use the right-hand Ctrl key for this
as it's obviously convenient; however, I almost never use the right-hand
Ctrl with the function keys (possibly related to being right-handed). Thus I
decided that when using the right-hand Ctrl key only F0-F9 would change, so
you lose 8 possible codes but don't make so many mistakes! The Alt key still
gives the full range, as you wouldn't normally use Alt with the cursor keys
(note that this makes Alt-left cursor duplicate F12).
Having sorted all this out, I turned to the keypad. My original idea was
to use the Num Lock-off state for function keys, as there can't be many
people who use this mode (or even know it exists). However, a look at the
table on p. 528 shows that a) the codes it generates are bizarre, and b) the
"5" key doesn't generate a code at all, which makes things difficult for a
program that works by trapping buffer insertions. I therefore settled on the
rather odd method of using the Num Lock-on state, and toggling between
different modes with Num Lock plus Ctrl or Shift. I really don't think Acorn
thought about what they were doing with the keypad! About the only useful
thing is that there are 16 keys, plus Num Lock and Enter, which is just
right.
Since you don't normally use Ctrl with the keypad it's OK to use it as a
shifting key for all of the function keys. Thus in either Alt or right-Ctrl
mode you can generate all 128 codes, although pressing Ctrl-Ctrl-Shift-#
does require you to have more than the standard number of hands!
So, there's the rationale; I think I've done about the best that's
possible, but things would have been a lot better if Acorn had provided
extra shifting keys (as on the Mac, for example), if it had standardised the
use of hot keys more, and if the keypad were easier to control.