; > adfs::TimsWini.arm.SourceDisc.!IKHG.Source.IntKeyBody

; ************************************************************
; ***    C h a n g e   L i s t  (better late than never!)  ***
; ************************************************************

; Date       Description
; ----       -----------
; 17-Feb-88  Modified Norway/Denmark, Sweden/Finland
; 19-Feb-88  Modified InkeyTran so that INKEY(-95) returns state of new key
;             next to left shift key on international keyboards
; 19-Feb-88  Added code to select configured keyboard on initialisation
; 16-Mar-88  Conditional versioning between 1.20 and 2.00
;            Started modify AltCharTable mechanism
; 13-Apr-88  Fixed pound/backtick problem
; 14-Apr-88  Attempt to fix initialisation problem on A500s
; 28-Apr-88  Changed version string to "Int'l Keyboard"
; 20-Jul-88  Allow kbids from 1-31
; 24-Oct-88  Modify for International Keyboard Handler Generator
; 18-Jul-89  Started to modify to allow Alt+key to give dead accents
; 31-Jul-89  Changed 'Dir', 'Hdr' etc to 'IKHG$Dir', 'IKHG$Hdr' etc
; 18-Oct-89  Corrected entry for shift-2 in TopBitSetTable1
; 02-Feb-90  Added entries to IDD table, and changed Esperanto to 1100
; 22-Nov-91  TMD Changed selection of keyboard structure to use ID rather
;            than current keyboard country number, changed list of headers
; 26-Nov-91  TMD Changed initialisation to set keyboard to current keyboard,
;            rather than default, so that it doesn't override what the
;            Territory manager says.
; 16-Dec-91  OSS Corrected burnt in UK keyboard to match the spec.
;            Added Mexico (and Israel) to IDD table.
; 22-Jan-92  OSS Corrected Perth layout to match Tim Caspell's spec, made
;            ID 3 (PC) use Perth layout, enabled "WwYy" circumflex (Welsh).
; 16-Feb-92  OSS Added Tim's corrected Letters.Latin1, which tells !IKHG
;            how to uppercase y and w circumflex. The module binary is
;            unaffected.
; 04-Mar-92  TMD Removed Arthur120 conditionals.
;            Removed references to non-existent keyboard id 3 (was PC at one stage).
;            Tidied it up a bit.
;            Made it not hang up if no keyboard attached (bug RP-1355).
; 27-Jun-94  Sorted out sources for international build.
;            Added offsets in key structure so that keypad chars can be changed.
; 10-Aug-98  BJGA Added PC-style delete capability and Ursula service call table.
; 18-Aug-98  BJGA Fixed numerous layout bugs
; 31-Aug-98  Internals fully revised to use new UCS layout structures created
;            by keygen. Alphabet adaptive, including UTF-8.
; 02-Sep-98  Hexadecimal keypad selection added. If the first digit is 0,
;            then the number entered is read as hex. (Physical) keypad keys
;            "/", "*", "-", "+", "." and "Enter" stand for digits A-F respectively.
;            Also, logical keys A-F will work.
; 28-Sep-98  BJGA Merged in 10-Sep-98 and 24-Sep-98 changes to Ursula branch
;            viz: updated layout drawfiles; added dialling codes for Wales, Wales2,
;            DvorakUK and DvorakUSA; introduced quoted characters to !IKHG.Source.Chars;
;            layout changes to Belgium, Denmark, France, Germany, Greece, Israel,
;            LatinAm, Russia, Switzerland and Turkey; and Ctrl-Alt-F1/F2 use a callback.
;            Also fixed Japan delete key to be special.
; 26-Aug-99  Software support for "FN" key.
;

        GBLL    PCDel           ; option to have Delete key return &8B (Copy) instead
PCDel   SETL    {TRUE}

        GBLL    Ursula          ; add Ursula service call table
Ursula  SETL    {TRUE}

        GET     Hdr:ListOpts
        GET     Hdr:Macros
        GET     Hdr:System
        GET     Hdr:ModHand
        GET     Hdr:Services
        GET     Hdr:Proc

OsbyteSetCountry * &46
OsbyteSetAlphKey * &47
OsbyteFindOsbyteVars * &A6
OsbyteTABch     * &DB
OsbyteKeyBase   * &EE
OsbyteKeyOpt    * &FE
 [ PCDel
OsbyteReadCmos  * &A1
CmosDelByte     * &C3
CmosDelBit      * 1
 ]

Country_UK      * 1
Country_Master  * 2
Country_Compact * 3
Country_Italy   * 4
Country_Spain   * 5
Country_France  * 6
Country_Germany * 7
Country_Portugal * 8
Country_Esperanto * 9
Country_Greece  * 10
Country_Sweden  * 11
Country_Finland * 12
Country_Denmark * 14
Country_Norway  * 15
Country_Iceland * 16
Country_Canada1 * 17
Country_Canada2 * 18
Country_Canada  * 19
Country_Turkey  * 20
Country_Arabic  * 21
Country_Ireland * 22
Country_HongKong * 23
Country_Russia  * 24
Country_Russia2 * 25
Country_Israel  * 26
Country_Mexico  * 27
Country_LatinAm * 28
Country_Australia * 29
Country_Austria * 30
Country_Belgium * 31
Country_Japan   * 32
Country_MiddleEast * 33
Country_Netherlands * 34
Country_Switzerland * 35
Country_Wales   * 36

Country_USA     * 48
Country_Wales2   * 49

Country_ISO1    * 80
Country_ISO2    * 81
Country_ISO3    * 82
Country_ISO4    * 83
Country_ISO5    * 84
Country_ISO6    * 85
Country_ISO7    * 86
Country_ISO8    * 87
Country_ISO9    * 88

Country_DvorakUK  * 70
Country_DvorakUSA * 71

Alphabet_Latin1 * 101
Alphabet_Latin2 * 102
Alphabet_Latin3 * 103
Alphabet_Latin4 * 104
Alphabet_Cyrillic * 105
Alphabet_Arabic * 106
Alphabet_Greek  * 107
Alphabet_Hebrew * 108
Alphabet_Latin5 * 109
Alphabet_Welsh  * 110
Alphabet_UTF8   * 111
Alphabet_Latin9 * 112
Alphabet_Latin6 * 113

Keyboard_A500   * 0
Keyboard_A1     * 1
Keyboard_Perth  * 2
Keyboard_RCMM   * 3
Keyboard_None   * &FF

        MACRO
        IKT     $A, $B, $C, $D, $E, $F, $G, $H
        IKT2    $A
        IKT2    $B
        IKT2    $C
        IKT2    $D
        IKT2    $E
        IKT2    $F
        IKT2    $G
        IKT2    $H
        MEND

        MACRO
        IKT2    $TE
        LCLA    T
T       SETA    $TE
        [ (T :AND: &FF00) = 0
T       SETA    T :OR: &FF00
        ]
        [ (T :AND: &FF0000) = 0
T       SETA    T :OR: &FF0000
        ]
        [ (T :AND: &FF000000) = 0
T       SETA    T :OR: &FF000000
        ]
        &       T
        MEND

; UK Keyboard keys

K1Escape        * &00
K1Function1     * &01
K1Function2     * &02
K1Function3     * &03
K1Function4     * &04
K1Function5     * &05
K1Function6     * &06
K1Function7     * &07
K1Function8     * &08
K1Function9     * &09
K1Function10    * &0A
K1Function11    * &0B
K1Function12    * &0C
K1Print         * &0D
K1ScrollLock    * &0E
K1Break         * &0F
K1BackTick      * &10
K1Digit1        * &11
K1Digit2        * &12
K1Digit3        * &13
K1Digit4        * &14
K1Digit5        * &15
K1Digit6        * &16
K1Digit7        * &17
K1Digit8        * &18
K1Digit9        * &19
K1Digit0        * &1A
K1Minus         * &1B
K1Equals        * &1C
K1Pound         * &1D
K1BackSpace     * &1E
K1Insert        * &1F
K1Home          * &20
K1PageUp        * &21
K1NumLock       * &22
K1NumPadSlash   * &23
K1NumPadStar    * &24
K1NumPadHash    * &25
K1Tab           * &26
K1LetterQ       * &27
K1LetterW       * &28
K1LetterE       * &29
K1LetterR       * &2A
K1LetterT       * &2B
K1LetterY       * &2C
K1LetterU       * &2D
K1LetterI       * &2E
K1LetterO       * &2F
K1LetterP       * &30
K1OpenSquare    * &31
K1CloseSquare   * &32
K1BackSlash     * &33
K1Delete        * &34
K1Copy          * &35
K1PageDown      * &36
K1NumPad7       * &37
K1NumPad8       * &38
K1NumPad9       * &39
K1NumPadMinus   * &3A
K1CtrlLeft      * &3B
K1LetterA       * &3C
K1LetterS       * &3D
K1LetterD       * &3E
K1LetterF       * &3F
K1LetterG       * &40
K1LetterH       * &41
K1LetterJ       * &42
K1LetterK       * &43
K1LetterL       * &44
K1SemiColon     * &45
K1Tick          * &46
K1Return        * &47
K1NumPad4       * &48
K1NumPad5       * &49
K1NumPad6       * &4A
K1NumPadPlus    * &4B
K1ShiftLeft     * &4C
K1NotFittedLeft * &4D
K1LetterZ       * &4E
K1LetterX       * &4F
K1LetterC       * &50
K1LetterV       * &51
K1LetterB       * &52
K1LetterN       * &53
K1LetterM       * &54
K1Comma         * &55
K1Dot           * &56
K1Slash         * &57
K1ShiftRight    * &58
K1CursorUp      * &59
K1NumPad1       * &5A
K1NumPad2       * &5B
K1NumPad3       * &5C
K1CapsLock      * &5D
K1AltLeft       * &5E
K1Space         * &5F
K1AltRight      * &60
K1CtrlRight     * &61
K1CursorLeft    * &62
K1CursorDown    * &63
K1CursorRight   * &64
K1NumPad0       * &65
K1NumPadDot     * &66
K1NumPadEnter   * &67
K1AcornLeft     * &68
K1AcornRight    * &69
K1Menu          * &6A
K1NoConvert     * &6B
K1Convert       * &6C
K1Kana          * &6D
K1NotFittedRight * &6E
K1FN            * &6F
K1LeftMouse     * &70
K1CentreMouse   * &71
K1RightMouse    * &72

; Bits in pending ALT flag

KBAlt_AccentMask  * 31

KBAlt_AltDown        * (1 :SHL: 5)
KBAlt_DigitsPresent  * (1 :SHL: 6)
KBAlt_SelectKeyboard * (1 :SHL: 7)      ; set after CTRL-ALT-F12

; Kernel-referenced entries
KVKeyTran            * &0
KVKeyTranSize        * &4
KVInkeyTran          * &8
KVShiftingList       * &C
KVSpecialList        * &10
KVSpecialCodeTable   * &14
KVInit               * &18
KVPendingAltCode     * &1C
; Private entries
KVPadNumTran         * &20 ; offset from structure to new entry for keypad numerics
KVPadCurTran         * &24 ; offset from structure to new entry for keypad non-numerics
KVFNTable            * &28
KVUCSTable0          * &2C
KVUCSTable1          * &30
KVSize               * &34 ; size of key structure header

KBStat_NoKanaLock    * KBStat_NoShiftLock  ; we've reassigned this bit

; Module workspace allocation

        ^ 0, R12

NewKeyStructWP  # KVSize        ; key structure header, must be first thing
OldKeyHandler   # 4
CurrentKeyboard # 4     ; current keyboard setting
OsbyteVars      # 4
AltDigitValue   # 4
CurrentAlphabet # 4
AlphabetTable   # 4
FallbackCode    # 4
DeleteChar      # 1
HexDigits       # 1

A1Key_WorkspaceSize * :INDEX: @

        ^ :INDEX: CurrentKeyboard, R0

R0CurrentKeyboard # 4
R0OsbyteVars    # 4
R0AltDigitValue # 4     ; value of ALT+digits so far
R0CurrentAlphabet # 4
R0AlphabetTable # 4
R0FallbackCode  # 4
R0DeleteChar    # 1
R0HexDigits     # 1

; User key workspace allocation

        ^ 0, R12

ShiftCount      # 1
CtrlCount       # 1
AltCount        # 1
AltLeftDown     # 1     ; for layouts where Left-Alt + Shift toggles layers
FNDown          # 1
MyMouseButtons  # 1     ; bit0=R, bit1=C, bit2=L
TempAction      # 1     ; to remember the action in ProcessUCS
KeyReturn       # 2     ; length byte (1), value byte
KeyNULReturn    # 3     ; length byte (2), NUL, value byte
NowtReturn      * KeyNULReturn +1 ; zero length list
KeyUTFReturn    # 13    ; length byte (up to 12), 6 * (NUL, value)
KeyUTFReturnEnd # 0

; Handy macro to do the FN processing. Good for any non-modifier key.
; Corrupts R2 - this relies not only EVERY non-modifier handler not
; using R2, as if we end up calling a different handler, R2 will
; be corrupted.

	GBLA	HandleFNsize

        MACRO
        HandleFN
01      LDRB    R2, FNDown              ; is FN down?
        TEQ     R2, #0                  ; if not, process as normal
        Push    "R14", NE
        BLNE    FindFN
        Pull    "R14", NE
HandleFNsize    SETA    . - %BT01
        MEND

; **************** Module code starts here **********************

        AREA    |!!!Module|,CODE,READONLY

Module_BaseAddr

        DCD     0
        DCD     A1Key_Init    -Module_BaseAddr
        DCD     A1Key_Die     -Module_BaseAddr
        DCD     A1Key_Service -Module_BaseAddr
        DCD     A1Key_Title   -Module_BaseAddr
        DCD     A1Key_HelpStr -Module_BaseAddr
        DCD     A1Key_HC_Table-Module_BaseAddr

A1Key_Title
        =       "InternationalKeyboard", 0

A1Key_HelpStr
        =       "Int'l Keyboard", 9, "$Module_MajorVersion ($Module_Date)"
 [ Module_MinorVersion <> ""
        =       " $Module_MinorVersion"
 ]
 [ Keyboard <> "All"
        =       " $Keyboard"
 ]
        =       0
        ALIGN

; **************************************************************************

A1Key_HC_Table * Module_BaseAddr

; **************************************************************************
;
;       A1Key_Init - Initialisation routine
;

A1Key_Init Entry
        LDR     r2, [r12]               ; have we got workspace yet ?
        TEQ     r2, #0
        BNE     %FT05

        MOV     r0, #ModHandReason_Claim
        MOV     r3, #A1Key_WorkspaceSize
        SWI     XOS_Module
        EXIT    VS

; r2 -> workspace

        STR     r2, [r12]               ; save address in my workspace pointer,
                                        ; so Tutu can free it for me when I die
05
        MOV     wp, r2

        MOV     r0, #OsbyteSetAlphKey
        MOV     r1, #&FF                ; read current keyboard (as determined by Territory Mgr)
        SWI     XOS_Byte
        ORRVC   r1, r1, #128            ; and set current keyboard to that, to cause a kbd reset
        SWIVC   XOS_Byte

        BLVC    SetUpKeyStructureAndHandlerIfUs
        EXIT

; **************************************************************************
;
;       A1Key_Die - Die entry
;

A1Key_Die Entry
        LDR     wp, [r12]
        PHPSEI                          ; disable interrupts round this bit
        Push    r14                     ; (r14 contains previous I_bit status)

        MOV     r0, #0                  ; read current handler address
        SWI     XOS_InstallKeyHandler
        TEQ     r0, r12
        BNE     %FT10                   ; key handler isn't us, so exit

        LDR     r0, OldKeyHandler
        SWI     XOS_InstallKeyHandler

10
        Pull    r14
        PLP                             ; restore old IRQ state
        CLRV
        EXIT

; **************************************************************************
;
;       A1Key_Service - Main entry point for services
;
; in:   R1 = service reason code
;       R2 = parameter
;
; out:  R1 = 0 if we claimed it
;       R2 preserved
;

 [ Ursula
ServiceTable
        DCD     0 ; flags
        DCD     Service2 - Module_BaseAddr
        DCD     Service_Reset         ; &27
        DCD     Service_International ; &43
        DCD     Service_KeyHandler    ; &44
        DCD     0 ; terminator
        DCD     ServiceTable - Module_BaseAddr
A1Key_Service ROUT
        MOV     R0, R0
 |
A1Key_Service ROUT
 ]
        TEQ     r1, #Service_Reset
        TEQNE   r1, #Service_KeyHandler
        TEQNE   r1, #Service_International
        MOVNES  pc, lr
 [ Ursula
Service2
 ]

        Entry   "r1"
        LDR     wp, [r12]                       ; point to workspace
        TEQ     r1, #Service_KeyHandler         ; if Service_KeyHandler
        BEQ     %FT10                           ; then branch

        TEQ     r1, #Service_Reset              ; else if Service_Reset
        TEQNE   r2, #Inter_Keyboard             ; or (the only other option) Service_International
                                                ; with reason code NewKeyboard
        BLEQ    SetUpKeyStructureAndHandlerIfUs ; then call routine
        EXITS

; it's Service_KeyHandler, so claim service if kbid recognised

10
        BL      SetUpKeyStructureAndHandlerIfUs ; call setup routine
        STR     r1, [sp]                        ; r1 on exit = 0 if it was us, else preserved
        EXITS

; **************************************************************************
;
;       SetUpKeyStructureAndHandlerIfUs - If suitable keyboard ID, set up
;       the keyboard structure and claim handler
;
; in:   r12 -> workspace
;       SVC or IRQ mode
;
; out:  r1 = 0 if we now own the handler
;       Otherwise r1 preserved
;

SetUpKeyStructureAndHandlerIfUs Entry "r0,r1"

        MOV     r0, lr
        ORR     r1, r0, #SVC_mode       ; switch into SVC mode so we can issue SWIs
        TEQP    r1, #0
        NOP

        Push    "r0-r4,lr"
        MOV     r0, #1
        SWI     XOS_InstallKeyHandler
        TEQ     r0, #Keyboard_A1
        TEQNE   r0, #Keyboard_Perth
        TEQNE   r0, #Keyboard_RCMM
        TEQNE   r0, #Keyboard_None
        BNE     %FT50

        MOV     r0, #OsbyteFindOsbyteVars
        MOV     r1, #0
        MOV     r2, #&FF
        SWI     XOS_Byte
        ORR     r1, r1, r2, LSL #8
        STR     r1, OsbyteVars          ; set up osbyte vars address

        MOV     r0, #OsbyteSetAlphKey
        MOV     r1, #&FF                ; read keyboard number
        SWI     XOS_Byte
        STR     r1, CurrentKeyboard

        MOV     r0, #-1
        STR     r0, CurrentAlphabet
        STR     r0, FallbackCode

        MOV     r0, r12
        BL      GetAlphabetTable

        ADRL    R0, KeyStructureTable
        MOV     R4, R0
05
        LDMIA   R4!,{R2,R3}             ; load keyboard number, offset pair
        CMP     R2, #-1                 ; if end of table
        TEQNE   R1, R2                  ; or numbers match then drop through
        BNE     %BT05                   ; else try next
        ADD     R0, R0, R3              ; point to found table or default

        TEQP    pc, #SVC_mode + I_bit   ; disable IRQs round this bit
        NOP                             ; needed to get objasm to assemble cleanly

        MOV     r2, #KVSize-4
        SUB     r1, r0, r12             ; offset from workspace to structure
10
        LDR     r3, [r0, r2]
        TEQ     r2, #KVKeyTranSize      ; is it KeyTranSize ?
        TEQNE   r3, #0                  ; or is it 0
        ADDNE   r3, r3, r1              ; if not then relative offset
        STR     r3, [r12, r2]
        SUBS    r2, r2, #4
        BCS     %BT10

; now set up key handler to point to us, if it doesn't already

        MOV     r0, #0
        SWI     XOS_InstallKeyHandler
        TEQ     r0, r12
        STRNE   r0, OldKeyHandler
        MOVNE   r0, r12
        SWINE   XOS_InstallKeyHandler

 [ PCDel
; scan CMOS to determine delete type
        MOV     r0, #OsbyteReadCmos
        MOV     r1, #CmosDelByte
        SWI     XOS_Byte
        TST     r2, #1 :SHL: CmosDelBit
        MOVEQ   r0, #&7F
        MOVNE   r0, #&8B
        STRB    r0, DeleteChar
 ]

        Pull    "r0-r4,lr"
        TEQP    r0, #0                  ; return to original mode and IRQ state

        MOV     r0, #0
        STR     r0, [sp, #4]            ; set stacked r1 to 0, so we claim the service
        EXITS

; the keyboard id is not recognised by us, so put back old handler if it's
; set to us at the moment

50
        MOV     r0, #0
        SWI     XOS_InstallKeyHandler
        TEQ     r0, r12                 ; if it's us
        LDREQ   r0, OldKeyHandler       ; then put back old one
        SWIEQ   XOS_InstallKeyHandler

        Pull    "r0-r4,lr"
        TEQP    r0, #0                  ; return to original mode and IRQ state
        NOP
        EXITS

; **************************************************************************

; Find out what alphabet the system is using
;
; on entry: r0 -> my workspace
; on exit: r3 = CurrentAlphabet = alphabet number
;          r4 = AlphabetTable = alphabet table or 0

GetAlphabetTable ROUT
        Entry   "r0,r1,r12"
        MOV     r12, r0
        MOV     r0, lr          ; switch into SVC mode so we can issue SWIs
        ORR     r1, r0, #SVC_mode
        TEQP    r1, #0
        NOP

        Push    "r0-r2,lr"
        MOV     r0, #OsbyteSetAlphKey
        MOV     r1, #&7F                ; read alphabet number
        SWI     XOS_Byte
        LDR     r3, CurrentAlphabet
        TEQ     r1, r3
        BNE     %FT50
        LDR     r4, AlphabetTable
20
        Pull    "r0-r2,lr"
        TEQP    r0, #0                  ; return to original mode and IRQ state
        NOP
        EXITS

50      MOV     r3, r1
        STR     r3, CurrentAlphabet
        TEQ     r3, #Alphabet_UTF8
        BEQ     %BT20

        MOV     r4, #0
        MOV     r1, #Service_International
        MOV     r2, #Inter_UCSTable
        SWI     XOS_ServiceCall
        STR     r4, AlphabetTable
        B       %BT20


; **************************************************************************

; Now the code to handle it

; Initialise keyboard table handler
;
; in:   R0 -> KeyStruct
;       R1 = keyboard id
;       R5 = KeyBdStatus
;       R7 = PendingAltType
;       R12 -> my workspace
;
; out:  R5 = new KeyBdStatus
;       R7 = new PendingAltType

KeyStructInit ROUT
        MOV     R0, #0                  ; no shift or ctrl keys down
        STRB    R0, ShiftCount
        STRB    R0, CtrlCount
        STRB    R0, AltCount
        STRB    R0, AltLeftDown
        STRB    R0, FNDown
        STRB    R0, MyMouseButtons
        STRB    R0, KeyNULReturn+1      ; NUL for NUL char return
        MOV     R0, #1                  ; string length for single key return
        STRB    R0, KeyReturn+0
        MOV     R0, #2                  ; length for NUL char return
        STRB    R0, KeyNULReturn+0

        BIC     R5, R5, #(KBStat_ShiftEngaged :OR: KBStat_CtrlEngaged :OR: KBStat_PendingAlt)
        ORR     R5, R5, #KBStat_NoKanaLock
        MOV     R7, #0                  ; 0 pending ALT
        MOV     PC, R14

ProcessKShift ROUT
        LDRB    R0, AltLeftDown         ; is Left Alt down (where it switches layers?)
        TEQ     R0, #1
        LDREQB  R0, ShiftCount
        TEQEQ   R0, #0                  ; if so, is Shift going down for the first time?
        TEQEQ   R1, #1
        EOREQ   R5, R5, #KBStat_NoKanaLock ; if so, toggle layers, then proceed as normal

        ADR     R0, ShiftCount
        MOV     R2, #KBStat_ShiftEngaged
ProcessShiftOrCtrl
        TEQ     R1, #0                  ; R1=1 => down, R1=0 => up
        LDRB    R3, [R0]
        ADDNE   R3, R3, #1              ; if down then increment (still NE)
        SUBEQS  R3, R3, #1              ; if up then decrement and setup Z
        STRB    R3, [R0]
        ORRNE   R5, R5, R2              ; one or more shift/ctrl keys down
        BICEQ   R5, R5, R2              ; zero shift/ctrl keys down
        MOV     PC, R14

ProcessKCtrl ROUT
        ADR     R0, CtrlCount
        MOV     R2, #KBStat_CtrlEngaged
        B       ProcessShiftOrCtrl

ProcessKFN ROUT
        STRB    R1, FNDown
        MOV     PC, R14

ProcessKRight ROUT
        MOV     R2, #1
ProcessMouseButton
        TEQ     R1, #0
        LDRB    R0, MyMouseButtons
        ORRNE   R0, R0, R2              ; button going down
        BICEQ   R0, R0, R2              ; button going up
        STRB    R0, MyMouseButtons
        MOV     PC, R3                  ; call his routine and exit

ProcessKCentre ROUT
        MOV     R2, #2
        B       ProcessMouseButton

ProcessKLeft ROUT
        MOV     R2, #4
        B       ProcessMouseButton

ProcessKAltLeft ROUT
        STRB    R1, AltLeftDown                 ; note new state of Left Alt
        TEQ     R1, #0                          ; are we going down?
        TSTNE   R5, #KBStat_ShiftEngaged        ; and is either Shift already down?
        EORNE   R5, R5, #KBStat_NoKanaLock      ; if so, toggle layers
        MOV     PC, R14

ProcessKAlt ROUT
        LDRB    R3, AltCount
        TEQ     R3, #0                  ; if no ALTs down so far, then must be

        STREQ   R3, R0AltDigitValue     ; going down, so zero cumulative digits
        STREQB  R3, R0HexDigits

        TEQ     R1, #0                  ; 0 => up, 1 => down
        ADDNE   R3, R3, #1              ; if down then increment
        SUBEQS  R3, R3, #1              ; if up then decrement and setup Z
        STRB    R3, AltCount
        BNE     %FT10

        TST     R7, #KBAlt_DigitsPresent ; if no digits present
        BEQ     %FT05                   ; then skip

        LDR     R1, R0AltDigitValue     ; load digits
        TST     R7, #KBAlt_SelectKeyboard ; selecting keyboard (CTRL-ALT-F12)?
        BNE     SelectIDDKeyboard

; return either byte, or UCS character

        Push    R14
        BL      GetAlphabetTable
        Pull    R14
        TEQ     R3, #Alphabet_UTF8
        BNE     %FT02

        BIC     R1, R1, #&80000000      ; strip down to 31 bits
        BICS    R7, R7, #(KBAlt_AltDown :OR: KBAlt_DigitsPresent)
        BICEQ   R5, R5, #KBStat_PendingAlt
        B       ReturnUCS

02
        ADR     R6, KeyNULReturn        ; return 0 then byte
        STRB    R1, [R6, #2]
        B       %FT05

SelectIDDKeyboard
        ADR     R0, IDDTable
03
        LDMIA   R0!, {R2, R3}           ; load IDD number, country number
        CMP     R2, #-1                 ; end of table ?
        BEQ     %FT05                   ; then not recognised, so do nothing
        TEQ     R2, R1                  ; found match ?
        BNE     %BT03

        ORR     R1, R3, #&80
        Push    R14
        BL      SelectKeyboard
        Pull    R14

05
        BICS    R7, R7, #(KBAlt_AltDown :OR: KBAlt_DigitsPresent :OR: KBAlt_SelectKeyboard)
        B       %FT15
10
        ORRS    R7, R7, #KBAlt_AltDown
15
        ORRNE   R5, R5, #KBStat_PendingAlt ; if NZ then still need bit set
        BICEQ   R5, R5, #KBStat_PendingAlt ; else clear bit
        MOV     PC, R14

IDDTable
        &        44, Country_UK
        &        39, Country_Italy
        &        34, Country_Spain
        &        33, Country_France
        &        49, Country_Germany
        &       351, Country_Portugal
        &      1100, Country_Esperanto
        &        30, Country_Greece
        &        46, Country_Sweden
        &       358, Country_Finland
        &        45, Country_Denmark
        &        47, Country_Norway
        &       354, Country_Iceland
        &        90, Country_Turkey
        &       353, Country_Ireland
        &       852, Country_HongKong
        &         7, Country_Russia
        &       972, Country_Israel
        &        52, Country_Mexico
        &        61, Country_Australia
        &        43, Country_Austria
        &        32, Country_Belgium
        &        81, Country_Japan
        &        31, Country_Netherlands
        &        41, Country_Switzerland
        &      1222, Country_Wales
        &         1, Country_USA
        &      2222, Country_Wales2

        &      9944, Country_DvorakUK
        &       991, Country_DvorakUSA

        &      1001, Country_ISO1
        &      1002, Country_ISO2
        &      1003, Country_ISO3
        &      1004, Country_ISO4
        &      1005, Country_ISO5
        &      1006, Country_ISO6
        &      1007, Country_ISO7
        &      1008, Country_ISO8
        &      1009, Country_ISO9
        &       -1, -1

ProcessKCaps ROUT
        HandleFN
HandleKCaps
        TEQ     R1, #2                          ; is it first press ?
        MOVNE   PC, R14                         ; don't auto-repeat

        TST     R5, #KBStat_ShiftEngaged        ; if shift down
        BICNE   R5, R5, #KBStat_NoCapsLock      ; then force CAPS on
        ORRNE   R5, R5, #KBStat_ShiftEnable     ; and SHIFT CAPS state
        EOREQ   R5, R5, #KBStat_NoCapsLock      ; else toggle caps lock state
        BICEQ   R5, R5, #KBStat_ShiftEnable     ; and cancel shift enable

        MOV     PC, R14

ProcessKTab ROUT
        HandleFN
HandleKTab
        LDR     R3, R0OsbyteVars
        LDRB    R3, [R3, #OsbyteTABch]          ; TAB key code
        TST     R3, #&80                        ; top bit set ?
        BEQ     ReturnOneCharAlt                ; no, don't shift or ctrl it
        TST     R5, #KBStat_ShiftEngaged
        EORNE   R3, R3, #&10                    ; modify for shift
        TST     R5, #KBStat_CtrlEngaged
        EORNE   R3, R3, #&20                    ; modify for ctrl
ReturnOneCharAlt
        TST     R5, #KBStat_PendingAlt          ; if no pending alt
        TSTNE   R7, #KBAlt_AccentMask           ; or its not an accent
        ADREQ   R6, KeyReturn
        STREQB  R3, [R6, #1]                    ; then return this
        MOVEQ   PC, R14
        LDR     R4, [R0, #KVPendingAltCode]
        ADD     PC, R0, R4                      ; call PendingAltCode, as the Kernel would


ProcessKDelete ROUT
        HandleFN
HandleKDelete
 [ PCDel
        LDRB    R1, R0DeleteChar                ; get configured delete character
 |
        MOV     R1, #&7F
 ]
        B       ReturnOneChar

ProcessKNum ROUT
        HandleFN
HandleKNum
        TEQ     R1, #2                          ; is it first press ?
        EOREQ   R5, R5, #KBStat_NoNumLock       ; yes, then toggle num lock
        MOV     PC, R14                         ; (don't auto-repeat)

ProcessKScroll ROUT
        HandleFN
HandleKScroll
        TEQ     R1, #2                          ; is it first press ?
        EOREQ   R5, R5, #KBStat_ScrollLock      ; yes, then toggle scroll lock
        MOV     PC, R14                         ; (don't auto-repeat)

ProcessKKana ROUT
        HandleFN
HandleKKana
        TEQ     R1, #2                          ; is it first press ?
        EOREQ   R5, R5, #KBStat_NoKanaLock      ; yes, then toggle kana lock
        MOV     PC, R14                         ; (don't auto-repeat)

ProcessKShiftCaps ROUT
        HandleFN
HandleKShiftCaps
        TEQ     R1, #2                          ; is it first press ?
        MOVNE   PC, R14                         ; (don't auto-repeat)
        EOR     R5, R5, #KBStat_NoCapsLock      ; toggle caps lock
        TST     R5, #KBStat_NoCapsLock
        ORREQ   R5, R5, #KBStat_ShiftEnable     ; set shift enable if caps lock on
        BICNE   R5, R5, #KBStat_ShiftEnable
        MOV     PC, R14

ProcessKBreak ROUT
        HandleFN
        ADD     PC, R3, #4                      ; offset for break routine

ProcessK1Pad ROUT
        HandleFN
        TST     R7, #KBAlt_AltDown
        BNE     AltKeyPad

        BICS    R7, R7, #KBAlt_AccentMask       ; cancel accents
        BICEQ   R5, R5, #KBStat_PendingAlt

        TST     R5, #KBStat_NoNumLock           ; test num lock
        LDREQ   R3, [R0, #KVPadNumTran]         ; num lock on
        LDRNE   R3, [R0, #KVPadCurTran]         ; num lock off
        ADD     R3, R3, R0
        LDRB    R1, [R3, R4]                    ; get table entry
        TEQ     R1, #&FF                        ; dummy key ?
        MOVEQ   PC, R14                         ; then exit

        LDR     R6, R0OsbyteVars
        LDRB    R2, [R6, #OsbyteKeyBase]        ; add on numeric key base
        SUB     R1, R1, #"0"
        ADD     R1, R1, R2

        LDRB    R2, [R6, #OsbyteKeyOpt]         ; zero => ctrl/shift modifies
        TEQ     R2, #0
        BNE     %FT10                           ; [don't modify]

        TST     R1, #&80                        ; top bit set ?
        BEQ     %FT10                           ; no, then don't modify

        TST     R5, #KBStat_ShiftEngaged
        EORNE   R1, R1, #&10                    ; modify for shift
        TST     R5, #KBStat_CtrlEngaged
        EORNE   R1, R1, #&20                    ; modify for ctrl
10
ReturnOneChar
        ADR     R6, KeyReturn                   ; pass pointer back to MOS
        STRB    R1, [R6, #1]                    ; having poked byte in
        MOV     PC, R14

AltKeyPad ROUT
        LDR     R3, [R0, #KVPadNumTran]
        LDRB    R1, R0HexDigits                 ; are we doing hex?
        ADD     R3, R3, R0
        TEQ     R1, #0
        BNE     AltKeyPadHex
        LDRB    R3, [R3, R4]                    ; get value from PadK1NumTran
        SUB     R3, R3, #"0"
        CMP     R3, #10                         ; if not in range 0-9
        BICHS   R7, R7, #(KBAlt_DigitsPresent :OR: KBAlt_SelectKeyboard)
                                                ; then get rid of digs + select
        ORRLO   R7, R7, #KBAlt_DigitsPresent    ; else indicate we have digits
        MOVHS   R2, #0                          ; if no digits
        STRHS   R2, R0AltDigitValue             ; then zero digits
        MOVHS   PC, R14                         ; and exit

        LDR     R2, R0AltDigitValue
        MOV     R1, #10
        MLAS    R3, R2, R1, R3                  ; digits = digits*10+new digit
        TSTEQ   R7, #KBAlt_SelectKeyboard
        STREQB  R1, R0HexDigits                 ; 0 pressed first - switch to hex (not IDD)
        STR     R3, R0AltDigitValue
        MOV     PC, R14

AltKeyPadHex
        LDRB    R1, [R3, R4]
        SUB     R1, R1, #"0"                    ; check digits first - they're logical
        CMP     R1, #10
        BLO     GotHex

        ADR     R4, HexPadTable                 ; scan table of physical codes
05      LDRB    R1, [R4], #2
        TEQ     R2, R1
        LDREQB  R1, [R4, #-1]
        BEQ     GotHex
        TEQ     R1, #0
        BNE     %BT05

GotHex
        LDR     R2, R0AltDigitValue
        ADD     R2, R1, R2, LSL #4              ; digits = digits*16+new digit
        STR     R2, R0AltDigitValue
        MOV     PC, R14

HexPadTable
        =       K1NumPadSlash, &A
        =       K1NumPadStar,  &B
        =       K1NumPadHash,  &C
        =       K1NumPadMinus, &C
        =       K1NumPadPlus,  &D
        =       K1NumPadDot,   &E
        =       K1NumPadEnter, &F
        =       0
        ALIGN

ReturnNULChar
        ADR     R6, KeyNULReturn
        STRB    R1, [R6, #2]
        MOV     PC, R14

; **************************************************************************
;
; 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 corrupted
;      R5 updated
;      R6->output (first byte=length, subsequent bytes to insert into buffer)
;      R7 updated

ProcessUCS ROUT
        HandleFN

        TST     R5, #KBStat_NoKanaLock
        LDRNE   R2, [R0, #KVUCSTable0]
        LDREQ   R2, [R0, #KVUCSTable1]
        ADD     R4, R4, R4, LSL #3      ; R4 = key * 9
        ADD     R2, R0, R2
        ADD     R2, R2, R4, LSL #2      ; R2 -> 36-byte entry for key

        TST     R7, #KBAlt_DigitsPresent
        BNE     CheckHexAtoF

; select the correct Shift/Ctrl/Alt variant.
        STRB    R1, TempAction
        MOV     R1, #0
        TST     R5, #KBStat_ShiftEngaged
        ORRNE   R1, R1, #4
        TST     R5, #KBStat_CtrlEngaged
        ORRNE   R1, R1, #8
        TST     R7, #KBAlt_AltDown
        ORRNE   R1, R1, #16

02      TST     R5, #KBStat_NoCapsLock
        BNE     %FT05

; process Caps Lock
        LDR     R4, [R2, #32]           ; get the capital-mapping word
        MOV     R4, R4, LSR R1
        AND     R4, R4, #&F             ; R4=alternate form for this character
        TST     R4, #8                  ; bit 3 of R4 set if only Shift-Caps changes
        BEQ     %FT03

        TST     R5, #KBStat_ShiftEnable
        BEQ     %FT05

        AND     R4, R4, #7
03      MOV     R1, R4, LSL #2

05      LDR     R1, [R2, R1]

06      TST     R1, #&80000000
        BNE     FunnyUCS

ReturnUCSAlt
        ANDS    R2, R7, #KBAlt_AccentMask   ; Check if we've got a pending accent
        MOVEQ   R2, #-1
        STREQ   R2, R0FallbackCode          ; clear "fallback" character
        BEQ     ReturnUCS

; We have to apply a dead accent now.

        ADRL    R4, AccentTable
        LDR     R2, [R4, R2, LSL #2]    ; offset to appropriate accent
        ADD     R4, R4, R2              ; R4 now points to accent list

        BICS    R7, R7, #KBAlt_AccentMask ; no more accents
        BICEQ   R5, R5, #KBStat_PendingAlt ; if no more then zero status bit
07
        LDR     R3, [R4], #8            ; R3 = base character
        CMP     R3, R1
        BHI     ReturnUCS               ; we're not in the list - return char unmodified
        BNE     %BT07                   ; not found it yet

        STR     R1, R0FallbackCode      ; remember unaccented form, in case accented form
                                        ; not available
        LDR     R1, [R4, #-4]           ; R1 = accented form

;       R1 = real UCS code
ReturnUCS
        CMP     R1, #&80
        BLO     ReturnOneOrNUL          ; 00-7F always the same

        Push    R14
        BL      GetAlphabetTable
        Pull    R14

        TEQ     R3, #Alphabet_UTF8
        BNE     ReturnUCSForAlphabet

; Create the UTF-8 sequence
        Push    R5
        ADR     R6, KeyUTFReturnEnd
        MOV     R5, #2
        MOV     R4, #2_00100000
10
        AND     R2, R1, #2_00111111     ; continuation byte
        ORR     R2, R2, #2_10000000
        STRB    R2, [R6, #-1]!
        MOV     R2, #0                  ; don't forget the 0 padding...
        STRB    R2, [R6, #-1]!
        MOV     R1, R1, LSR #6
        CMP     R1, R4
        MOVHS   R4, R4, LSR #1
        ADDHS   R5, R5, #1
        BHS     %BT10

; and the leading byte...
        MOV     R4, #&FF00
        ORR     R2, R1, R4, LSR R5
        STRB    R2, [R6, #-1]!
        MOV     R2, #0                  ; don't forget the 0 padding...
        STRB    R2, [R6, #-1]!
        MOV     R5, R5, LSL #1
        STRB    R5, [R6, #-1]!
        Pull    R5
        MOV     PC, R14

ReturnUCSForAlphabet
        MOVS    R3, R4                  ; alphabet table
        BEQ     ReturnUCSForNoAlphabet

; find which (if any) of codes &80-&FF is what we want
        MOV     R6, #&80

13      LDR     R2, [R3, R6, LSL #2]
        TEQ     R1, R2
        MOVEQ   R1, R6
        BEQ     ReturnNULChar
        ADD     R6, R6, #1
        CMP     R6, #&FF
        BLS     %BT13

; can't find it - do we have a fallback?
15      LDR     R1, R0FallbackCode
        CMP     R1, #-1
        MOVNE   R6, #-1
        STRNE   R6, R0FallbackCode    ; clear fallback, else infinite loop
        BNE     ReturnUCS

; give up - output nothing
        ADR     R6, NowtReturn
        MOV     PC, R14

ReturnUCSForNoAlphabet                  ; Assume pure ISO Latin 1
        CMP     R1, #&FF
        BHI     %BT15
        B       ReturnNULChar

FunnyUCS
        CMN     R1, #1                 ; Check for &FFFFFFFF - nothing
        ADREQ   R6, NowtReturn

        BIC     R1, R1, #&80000000     ; &800000xx - a raw buffer code
        CMP     R1, #&100
        ADRLO   R6, KeyReturn
        STRLOB  R1, [R6, #1]
        MOVLO   PC, R14

; Oooh - it's summat special
        CMP     R1, #&10000
        BLO     %FT40                  ; &8000xxxx - daft
        CMP     R1, #&20000
        BLO     SpecialKey             ; &8001xxxx - special key
        CMP     R1, #&30000
        BLO     DeadKey                ; &8002xxxx - dead key

40      ADRHI   R6, NowtReturn
        MOV     PC, R14

CheckHexAtoF
; We're doing something digitty - if it's hex we need to check for A-F.
; If it's not hex or A-F, we return immediately - it's not sensible to
; be outputting standard Alt symbols while doing a keypad sequence, although
; this is what pre 0.50 versions did.

        LDRB    R4, R0HexDigits         ; are we doing hex?
        TEQ     R4, #0
        MOVEQ   PC, R14
        LDR     R4, [R2, #0]            ; get the base symbol for this key
        BIC     R4, R4, #&20            ; upper case the codes that matter
        CMP     R4, #"A"
        MOVLO   PC, R14
        CMP     R4, #"F"
        MOVHI   PC, R14
        SUB     R1, R4, #"A"-10
        B       GotHex

SpecialKey
        SUB     R4, R1, #&10000
        CMP     R4, #10
        LDRB    R1, TempAction
        ADDLO   PC, PC, R4, LSL #2
        B       %BT40
        B       HandleKScroll
        B       HandleKNum
        B       HandleKTab
        B       HandleKCaps
        B       HandleKKana
        B       HandleKShiftCaps
        B       HandleKDefaultKeyboard
        B       HandleKConfiguredKeyboard
        B       HandleKDialKeyboard
        B       HandleKDelete

DeadKey
        SUB     R1, R1, #&20000
        BIC     R7, R7, #KBAlt_AccentMask  ; clear accents
        ORR     R7, R7, R1                 ; put in new accent
        ORR     R5, R5, #KBStat_PendingAlt ; and indicate it
        MOV     PC, R14

; Silly entry conditions here. Can return normally,
; preserving flags to carry on as normal, can pull PC from the stack
; to ignore the keypress altogether, or can call a new handler
; in the special table.
;
; Note that as in the HandleFN macro we're merrily scrambling R2.
;
FindFN  ROUT
        LDR     R2, [R0, #KVFNTable]    ; if no FN table at all
        TEQ     R2, #0
        MOVEQS  PC,R14

        Push    "R1,R3"
        ADD     R3, R0, R2
        LDRB    R2, [R3], #1            ; R2 = number of FN entries
        TEQ     R2, #0
        BEQ     NoFN
FNLoop  LDRB    R1, [R3], #2            ; R1 = base FN key, advance R3 to next entry
        CMP     R1, R4
        LDREQB  R4, [R3, #-1]           ; if R1 = this key, change R4 to new key
        BEQ     FNContinue
        BHI     NoFN                    ; if R1 > this key, its not there
        SUBS    R2, R2, #1
        BNE     FNLoop
NoFN
        Pull    "R1,R3,PC"              ; no FN entry - output nothing

FNContinue
; Need to call the correct handler...
        LDR     R2, [R0, #KVSpecialCodeTable]
        ADD     R2, R2, R0              ; R2 -> special code table
        SUB     R1, R2, #4              ; 0th entry is for 1st special
        LDR     R1, [R1, R4, LSL #2]    ; R1 = offset to code
        ADD     R2, R1, R2              ; R2 = address of code
	ADD	R2, R2, #HandleFNsize   ; Skip past the FN handling code :)
        Pull    "R1,R3,LR"
        MOV     PC, R2

; **************************************************************************
;
; in:   R0 -> key structure
;       R1 = action (2=first,3=autorepeat)
;       R2 = internal key number for char
;       R3 = character which would be returned if not an ALT
;       R5 = keyboard status
;       R6 -> a zero byte
;       R7 = pending alt type

PendingAltCode ROUT
        TST     R7, #KBAlt_AccentMask   ; is it due to dead accent ?
        MOVEQ   PC, R14                 ; no, then must be Alt down - any real Alts are
                                        ; special - simple keys return nothing.

; called because of accented char

        MOV     R1, R3
        CMP     R1, #&80                ; is it a Basic Latin character?
        BLO     ReturnUCSAlt            ; if so - get ProcessUCS to add the accent

; Boring - it's just a function key. Remove the dead accent and
; output the function key.

        BICS    R7, R7, #KBAlt_AccentMask ; no more accents
        BICEQ   R5, R5, #KBStat_PendingAlt ; if no more then zero status bit

        B       ReturnOneChar

ReturnOneOrNUL
        CMP     R1, #0                  ; if 0 then return 0 0 (C=1)
        CMPNE   R1, #&80                ; elif -ve return 0 char
        BCS     ReturnNULChar
        B       ReturnOneChar           ; else return 0 char

HandleKDialKeyboard
        TST     R7, #KBAlt_AltDown              ; ensure Alt is down...
        ORRNE   R7, R7, #KBAlt_SelectKeyboard   ; set IDD selection flag
        MOV     PC, R14

HandleKConfiguredKeyboard ROUT
        MOV     R1, #&80                        ; select default keyboard
        B       SelectKeyboard
HandleKDefaultKeyboard
        MOV     R1, #&81                        ; select UK keyboard
SelectKeyboard
        MOV     R3, PC
        AND     R3, R3, #3
        EOR     R3, R3, #SVC_mode
        TEQP    R3, PC                          ; select SVC mode
        NOP                                     ; wait for it to happen

        Push    R14
        ADR     R0, CallBack_SelectKeyboard
        SWI     XOS_AddCallBack                 ; R1 already set up
        Pull    R14

        TEQP    R3, PC                          ; reenter previous mode
        NOP                                     ; wait for it to happen
ReturnNowt
        ADR     R6, NowtReturn                  ; return nowt
        MOV     PC, R14

CallBack_SelectKeyboard
        Push    "R0-R2,R14"
        MOV     R0, #OsbyteSetAlphKey
        MOV     R1, R12                         ; R12 used to pass keyboard + &80
        SWI     XOS_Byte
        Pull    "R0-R2,PC"

; **************************************************************************
;
;       Reverse table lookup for INKEY(-ve)
;

; For reference, here is the definitive internal key list. A number of codes
; are for BBC compatibility. For example, code 71 was the "@" key on the
; BBC micro - there was no separate @ key on the Archimedes UK layout,
; so the 2 key (Shift-2 was @) generates this internal code. These compatibility
; codes should not be used by new programs.
;
; Don't forget that these codes are supposed to be for _physical_ keys -
; the code for the key to the left of backspace never changes, no matter
; how it is marked.
;
; Internal code    Key                Low-level codes
; 0                Shift              4C or 58
; 1                Ctrl               3B or 61
; 2                Alt                5E or 60
; 3                Left Shift         4C
; 4                Left Ctrl          3B
; 5                Left Alt           5E
; 6                Right Shift        58
; 7                Right Ctrl         61
; 8                Right Alt          60
; 9                Select             70
; 10               Menu               71
; 11               Adjust             72
; 12               FN                 6F
; 13               (not defined)
; 14               (not defined)
; 15               (not defined)
; 16               Q                  27
; 17               3                  13
; 18               4                  14
; 19               5                  15
; 20               F4                 04
; 21               8                  18
; 22               F7                 07
; 23               -                  1B
; 24               ^                  16 (BBC compatibility - see 52)
; 25               Left Arrow         62
; 26               Keypad 6           4A
; 27               Keypad 7           37
; 28               F11                0B
; 29               F12                0C
; 30               F10                0A
; 31               Scroll Lock        0E
; 32               Print              0D
; 33               W                  28
; 34               E                  29
; 35               T                  2B
; 36               7                  17
; 37               I                  2E
; 38               9                  19
; 39               0                  1A
; 40               _                  1B (BBC compatibility - see 23)
; 41               Down Arrow         63
; 42               Keypad 8           38
; 43               Keypad 9           39
; 44               Break              0F
; 45               `                  10
; 46               Pound              1D (not fitted)
; 47               Backspace          1E
; 48               1                  11
; 49               2                  12
; 50               D                  3E
; 51               R                  2A
; 52               6                  16
; 53               U                  2D
; 54               O                  2F
; 55               P                  30
; 56               [                  31
; 57               Up Arrow           59
; 58               Keypad +           4B
; 59               Keypad -           39
; 60               Keypad Enter       67
; 61               Insert             1F
; 62               Home               20
; 63               Page Up            21
; 64               Caps Lock          5D
; 65               A                  3C
; 66               X                  4F
; 67               F                  3F
; 68               Y                  2C
; 69               J                  42
; 70               K                  43
; 71               @                  12 (BBC compatibility - see 49)
; 72               :                  45
; 73               Enter              47
; 74               Keypad /           23
; 75               Keypad Delete      (not mapped)
; 76               Keypad .           66
; 77               Num Lock           22
; 78               Page Down          36
; 79               '                  46
; 80               Shift Lock         (not mapped)
; 81               S                  3D
; 82               C                  50
; 83               G                  40
; 84               H                  41
; 85               N                  53
; 86               L                  44
; 87               ;                  45 (BBC compatibility - see 72)
; 88               ]                  32
; 89               Delete             34
; 90               Keypad #           25 (not normally fitted)
; 91               Keypad *           24
; 92               Keypad ,           (not mapped)
; 93               =                  1C
; 94               \                  4D
; 95               Not fitted (R)     6E (between / and Shift on Japanese keyboard)
; 96               Tab                26
; 97               Z                  4E
; 98               Space              5F
; 99               V                  51
; 100              B                  52
; 101              M                  54
; 102              ,                  55
; 103              .                  56
; 104              /                  57
; 105              End                35
; 106              Keypad 0           65
; 107              Keypad 1           5A
; 108              Keypad 3           5C
; 109              No Convert         6B
; 110              Convert            6C
; 111              Kana               6D
; 112              Escape             00
; 113              F1                 01
; 114              F2                 02
; 115              F3                 03
; 116              F5                 05
; 117              F6                 06
; 118              F8                 08
; 119              F9                 09
; 120              # (\ on BBC+Arch)  33
; 121              Right Arrow        64
; 122              Keypad 4           48
; 123              Keypad 5           49
; 124              Keypad 2           5B
; 125              Left Acorn         68
; 126              Right Acorn        69
; 127              Menu               6A

InkeyTran
        IKT     &6A, &69, &68, &5B, &49, &48, &64, &33          ; 80-87
        IKT     &09, &08, &06, &05, &03, &02, &01, &00          ; 88-8F
        IKT     &6D, &6C, &6B, &5C, &5A, &65, &35, &57          ; 90-97
        IKT     &56, &55, &54, &52, &51, &5F, &4E, &26          ; 98-9F
        IKT     &6E, &4D, &1C, &FF, &24, &25, &34, &32          ; A0-A7
        IKT     &45, &44, &53, &41, &40, &50, &3D, &FF          ; A8-AF
        IKT     &46, &36, &22, &66, &FF, &23, &47, &45          ; B0-B7
        IKT     &12, &43, &42, &2C, &3F, &4F, &3C, &5D          ; B8-BF
        IKT     &21, &20, &1F, &67, &3A, &4B, &59, &31          ; C0-C7
        IKT     &30, &2F, &2D, &16, &2A, &3E, &12, &11          ; C8-CF
        IKT     &1E, &1D, &10, &0F, &39, &38, &63, &1B          ; D0-D7
        IKT     &1A, &19, &2E, &17, &2B, &29, &28, &0D          ; D8-DF
        IKT     &0E, &0A, &0C, &0B, &37, &4A, &62, &16          ; E0-E7
        IKT     &1B, &07, &18, &04, &15, &14, &13, &27          ; E8-EF
        IKT     &FF, &FF, &FF, &6F, &72, &71, &70, &60          ; F0-F7
        IKT     &61, &58, &5E, &3B, &4C, &5E60, &3B61, &4C58    ; F8-FF

; **************************************************************************

ShiftingKeyList
        =       ShiftingKeyListEnd-ShiftingKeyList-1
        =       K1ShiftLeft, K1ShiftRight, K1CtrlLeft, K1CtrlRight
        =       K1AltLeft, K1AltRight, K1FN
        =       K1RightMouse, K1CentreMouse, K1LeftMouse, K1Break
ShiftingKeyListEnd
        ALIGN

; **************************************************************************
;
; A general purpose special code list used by most UCS keyboard drivers -
; long enough for lots of keys, every one special.
;
SpecialCodeTable
        &       ProcessKShift - SpecialCodeTable
        &       ProcessKShift - SpecialCodeTable
        &       ProcessKCtrl - SpecialCodeTable
        &       ProcessKCtrl - SpecialCodeTable
        &       ProcessKAlt - SpecialCodeTable
        &       ProcessKAlt - SpecialCodeTable
        &       ProcessKFN - SpecialCodeTable
        &       ProcessKLeft - SpecialCodeTable
        &       ProcessKCentre - SpecialCodeTable
        &       ProcessKRight - SpecialCodeTable
        &       ProcessKBreak - SpecialCodeTable
        &       ProcessK1Pad - SpecialCodeTable
        &       ProcessK1Pad - SpecialCodeTable
        &       ProcessK1Pad - SpecialCodeTable
        &       ProcessK1Pad - SpecialCodeTable
        &       ProcessK1Pad - SpecialCodeTable
        &       ProcessK1Pad - SpecialCodeTable
        &       ProcessK1Pad - SpecialCodeTable
        &       ProcessK1Pad - SpecialCodeTable
        &       ProcessK1Pad - SpecialCodeTable
        &       ProcessK1Pad - SpecialCodeTable
        &       ProcessK1Pad - SpecialCodeTable
        &       ProcessK1Pad - SpecialCodeTable
        &       ProcessK1Pad - SpecialCodeTable
        &       ProcessK1Pad - SpecialCodeTable
        &       ProcessK1Pad - SpecialCodeTable
        &       ProcessK1Pad - SpecialCodeTable
        &       ProcessK1Pad - SpecialCodeTable
        &       ProcessKScroll - SpecialCodeTable
        &       ProcessKNum - SpecialCodeTable
        &       ProcessKTab - SpecialCodeTable
        &       ProcessKCaps - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
        &       ProcessUCS - SpecialCodeTable
SpecialCodeTableEnd

; And the default keypad layout.

PadKNumTran
        =       "/*#789-456+1230.",&0D
PadKCurTran
        =       "/*#",&1E,&8F,&9F,"-",&8C,&FF,&8D,"+",&8B,&8E,&9E,&CD,&7F,&0D
        ALIGN

        END