Structure of a key handler:

The handler starts with the following structure:

    +0: Offset to simple translation table
    +4: Number of entries in simple translation table
    +8: Offset to internal key mapping (-ve INKEY) table
   +12: Offset to list of shifting keys
   +16: Offset to list of special keys
   +20: Offset to list of special key code entries
   +24: Offset to initialisation entry point
   +28: Offset to pending Alt code routine
   +32: Optional flags word (present if bit 31 of +4 is set)


KeyBdStatus is a bitfield: Bit 0: KBStat_PendingAlt
                               1: KBStat_ScrollLack
                               2: KBStat_NoNumLock
                               3: KBStat_ShiftEngaged
                               4: KBStat_CapsLock
                               5: KBStat_NoShiftLock
                               6: KBStat_CtrlEngaged
                               7: KBStat_ShiftEnable

This is the byte referenced by OS_Byte 202.

PendingAltType is a byte that is conventionally used to store information
about pending conditions (eg dead accents).


Initialisation entry point
--------------------------

In:  R0->handler
     R1=keyboard ID
     R5=KeyBdStatus
     R7=PendingAltType
     R12->fixed workspace (allocated by kernel) - approx 170 bytes, not aligned

Out: All registers preserved, except R5 and R7 can be updated, R8 corrupted.

This is called once on initialisation of the keyboard driver.


Simple translation table
------------------------
This is a table of bytes. When a key is pressed, the kernel looks up
byte (low-level key number)*4 + (1 if shift enabled) + (2 if ctrl enabled).
If the byte read is FF, or the key number is outside the table, then the key
is decided to be "special" and looked up in the special table. Otherwise the
key is modified by the kernel for caps lock (if it decides it is
alphanumeric), and inserted into the keyboard buffer. Hence bytes 80-FE are
interpreted as function keys. Autorepeat and debounce are handled
automatically in this case.

If the key is outside this list or is special (all four bytes &FF)
and is on the shifting list (see below) the kernel will not autorepeat it and
will not perform rollover. The special code (if any) will be called for both up
and down. This is intended for Shift,Ctrl,Alt,mouse buttons etc.

Internal key mapping
--------------------
This is a table of words. Word N-&80 corresponds to OS_Byte 129 N 255 (ie
internal key number 128-N). Each word is treated as four bytes - each byte
corresponding to a low-level key number that corresponds to this INKEY- number,
or &FF.
For example, the entry for INKEY-1 is &FFFF4C58, meaning that low level
keys &4C and &58 make INKEY-1 return true.

This table is normally constant across all keyboards.

Shifting key list
-----------------
Byte 0: Number of entries (n)
Bytes 1-n: Low level key numbers

This table is a list of modifier keys. Typically this comprises:

   Left Shift, Right Shift, Left Ctrl, Right Ctrl, Left Alt, Right Alt,
   Select, Menu, Adjust

Special key list
----------------
Byte 0: Number of entries (n)
Bytes 1-n: Low level key numbers

This lists the keys that have special handler code. This gets invoked if the
simple table contains FF (see above).

Special key code list
---------------------
Word 0: Offset to handler for first special key (from start of list)
...

This lists the handler routines for each special key.

Calling environment:

In:  R0->handler
     R1=action (shifting key:0,1=up,down;  non-shifting:2=first,3=autorepeat)
     R2=low-level key number
     R3->table of exit points
     R4=special key number (eg 1 for first special key)
     R5=KeyBdStatus
     R6->a zero byte (so left unmodified -> no output)
     R7=PendingAltType
     R12->fixed workspace (allocated by kernel) - approx 170 bytes, not aligned

Out: R0-R4 preserved
     R5 updated
     R6->output (first byte=length, subsequent bytes to insert into buffer)
     R7 updated
     R8 corrupted

Alternative exits can be taken by branching to:

     R3+0:MouseButtonChange

       With R0 = new mouse button state (bits 0,1,2 = Adjust,Menu,Select)

     R3+4:DoBreakKey

       Registers as passed in to the special key handler

Pending Alt Code
----------------
In:  R0->handler
     R1=action (2=first,3=autorepeat)
     R2=low-level key number
     R3=character that would normally be generated (from the simple table)
     R5=KeyBdStatus
     R6->a zero byte (so left unmodified -> no output)
     R7=PendingAltType
     R12->fixed workspace (allocated by kernel) - approx 170 bytes, not aligned

Out: R0-R4 preserved
     R5 updated
     R6->output (first byte=length, subsequent bytes to insert into buffer)
     R7 updated
     R8 corrupted

This code is called if a simple key is pressed while the PendingAlt bit is set, instead
of the character in the simple table being generated.

Flags word
----------

Bit  Meaning
0    Key handler uses wide (16 bit) key numbers

Wide key numbers
----------------

If wide key numbers are in use, the following changes to the key handler format are in effect:

* The simple translation table contains 16 bit entries, not 8 bit. &FF still corresponds to "no mapping"
* The internal key mapping table has 2x16 bit entries per key, not 4x8 bit entries. &FF still corresponds to "no mapping"
* The shifting key list & special key list contain 16 bit entries, not 8 bit. The entry count is also a 16 bit value.
