; > 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.
;

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

        GET     !IKHG.Source.Chars.Latin1

TAB     *       9
LF      *       10
FF      *       12
CR      *       13

OsbyteSetCountry * &46
OsbyteSetAlphKey * &47
OsbyteFindOsbyteVars * &A6
OsbyteTABch     * &DB
OsbyteKeyBase   * &EE
OsbyteKeyOpt    * &FE

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_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
Country_DvorakLH  * 78
Country_DvorakRH  * 79

Alphabet_Bfont  * 100
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_Cyrillic2 * 120

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

        GBLL    BleedinDaveBell
BleedinDaveBell SETL    {TRUE}

        [ BleedinDaveBell
Alphabet_Default * Alphabet_Latin1
        |
Alphabet_Default * Alphabet_Bfont
        ]

        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

        MACRO
        BodgeKeyHandler $cond
        MEND

        MACRO
$label  DoTopBit        $No
$label  ROUT
        ADRL    R3, TopBitSetTable$No-((K$No.TopBitSet-SpecialList$No):SHL:4)
        B       DoTopBitCommon
        MEND

        MACRO
        DoAccent $No, $AName
PendingAltCode$No
        ADR     R6, KeyReturn
        STRB    R3, [R6, #1]
PendingAltSpecial$No
        ADRL    R4, AccentTable_$AName
        B       PendingAltSpecialCommon
        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
K1NotFitted     * &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
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

KVPendingAltSpecial  * &20 ; offset from structure to new entry
KVPadNumTran         * &24 ; offset from structure to new entry for keypad numerics
KVPadCurTran         * &28 ; offset from structure to new entry for keypad non-numerics
KVSize               * &2C ; size of key structure header

; Module workspace allocation

        ^ 0, R12

NewKeyStructWP  # KVSize        ; key structure header, must be first thing
OldKeyHandler   # 4
CurrentKeyboard # 4     ; current keyboard setting
CurrentKeyAlphabet # 4  ; alphabet for current keyboard
OsbyteVars      # 4
AltDigitValue   # 4

A1Key_WorkspaceSize * :INDEX: @

        ^ :INDEX: CurrentKeyboard, R0

R0CurrentKeyboard # 4
R0CurrentKeyAlphabet # 4
R0OsbyteVars    # 4
R0AltDigitValue # 4     ; value of ALT+digits so far

; User key workspace allocation

        ^ 0, R12

ShiftCount      # 1
CtrlCount       # 1
AltCount        # 1
MyMouseButtons  # 1     ; bit0=R, bit1=C, bit2=L
KeyReturn       # 2     ; length byte (1), value byte
KeyNULReturn    # 3     ; length byte (2), NUL, value byte
NowtReturn      * KeyNULReturn +1 ; zero length list

; **************** 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"
        =       TAB
        =       "0.41 (07 Aug 1998)"
 [ 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
;

A1Key_Service ROUT
        TEQ     r1, #Service_Reset
        TEQNE   r1, #Service_KeyHandler
        TEQNE   r1, #Service_International
        MOVNES  pc, lr

        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_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

        Push    R1
        MOV     r3, r1
        MOV     r1, #Service_International
        MOV     r2, #Inter_CNoToANo
        MOV     r4, #Alphabet_Default
        SWI     XOS_ServiceCall
        STR     r4, CurrentKeyAlphabet  ; alphabet associated with this kb
        Pull    R1

        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

        SUB     r1, r0, r12             ; offset from workspace to structure
        MOV     r2, #KVSize-4
10
        LDR     r3, [r0, r2]
        TEQ     r2, #&04                ; is it KeyTranSize ?
        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

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

        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

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

; 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, 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)
        MOV     R7, #0                  ; 0 pending ALT
        MOV     PC, R14

ProcessKShift ROUT
        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

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

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

        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     R0, R0AltDigitValue     ; load digits
        TST     R7, #KBAlt_SelectKeyboard ; selecting keyboard (CTRL-ALT-F12)?
        ADREQ   R6, KeyNULReturn        ; no, then return NUL char
        STREQB  R0, [R6, #2]
        BEQ     %FT05

        ADR     R1, IDDTable
03
        LDMIA   R1!, {R2, R3}           ; load IDD number, country number
        CMP     R2, #-1                 ; end of table ?
        BEQ     %FT05                   ; then not recognised, so do nothing
        TEQ     R2, R0                  ; 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
        &         1, Country_USA

        &      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
        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
        LDR     R1, R0OsbyteVars
        LDRB    R1, [R1, #OsbyteTABch]          ; TAB key code
        TST     R1, #&80                        ; top bit set ?
        BEQ     ReturnOneCharAlt                ; no, don't shift or ctrl it
        TST     R5, #KBStat_ShiftEngaged
        EORNE   R1, R1, #&10                    ; modify for shift
        TST     R5, #KBStat_CtrlEngaged
        EORNE   R1, R1, #&20                    ; modify for ctrl
ReturnOneCharAlt
        ADR     R6, KeyReturn                   ; pass pointer back to MOS
        STRB    R1, [R6, #1]                    ; having poked byte in
ReturnCharAlt
        TST     R5, #KBStat_PendingAlt          ; if no pending alt
        TSTNE   R7, #KBAlt_AccentMask           ; or its not an accent
        MOVEQ   PC, R14                         ; then return this
        LDR     R1, [R0, #KVPendingAltSpecial]  ; else call the special entry
        ADD     PC, R0, R1

ProcessKNum ROUT
        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
        TEQ     R1, #2                          ; is it first press ?
        EOREQ   R5, R5, #KBStat_ScrollLock      ; yes, then toggle scroll lock
        MOV     PC, R14                         ; (don't auto-repeat)

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

ProcessK1Pad ROUT
        LDR     R3, [R0, #KVPadNumTran]
        ADD     R3, R3, R0
;        ADRL    R3, PadK1NumTran-(SpecialList1Pad-SpecialList1) ; on
        TST     R7, #KBAlt_AltDown
        BNE     AltKeyPad

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

        LDR     R1, R0OsbyteVars
        LDR     R2, [R0, #KVPadCurTran]
        ADD     R2, R2, R0
;        ADRL    R2, PadK1CurTran-(SpecialList1Pad-SpecialList1) ; off
        TST     R5, #KBStat_NoNumLock           ; test num lock
        MOVNE   R3, R2                          ; numlock off -> use R2
        LDRB    R0, [R3, R4]                    ; get table entry
        TEQ     R0, #&FF                        ; dummy key ?
        MOVEQ   PC, R14                         ; then exit

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

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

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

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

AltKeyPad ROUT
        LDRB    R3, [R3, R4]                    ; get value from PadK1NumTran
        SUB     R3, R3, #"0"
        CMP     R3, #10                         ; if not in range 0-9
        BICCS   R7, R7, #(KBAlt_DigitsPresent :OR: KBAlt_SelectKeyboard)
                                                ; then get rid of digs + select
        ORRCC   R7, R7, #KBAlt_DigitsPresent    ; else indicate we have digits
        MOVCS   R2, #0                          ; if no digits
        STRCS   R2, R0AltDigitValue             ; then zero digits
        MOVCS   PC, R14                         ; and exit

        LDR     R2, R0AltDigitValue
        MOV     R1, #10
        MLA     R3, R2, R1, R3                  ; digits = digits*10+new digit
        STR     R3, R0AltDigitValue
        MOV     PC, R14

ReturnNULCharAlt
        ADR     R6, KeyNULReturn                ; store char
        STRB    R1, [R6, #2]
        B       ReturnCharAlt

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

DoTopBitCommon ROUT
        TST     R5, #KBStat_ShiftEngaged
        ADDNE   R3, R3, #2
        TST     R5, #KBStat_CtrlEngaged
        ADDNE   R3, R3, #4
        TST     R7, #KBAlt_AltDown
        ADDNE   R3, R3, #8
        LDRB    R1, [R3, R4, LSL #4]!
        LDRB    R6, [R3, #1]

; 0 => non-alpha, 1 => alpha, 2 => dead accent, 3 => nowt

        MOVS    R6, R6, LSL #31         ; put bit 1 into C, bit 0 into N
        BCS     %FT20
        BPL     ReturnOneOrNULAlt       ; not alpha, so skip

        TST     R5, #KBStat_ShiftEnable
        EORNE   R3, R3, #2
        TSTEQ   R5, #KBStat_NoCapsLock
        ORREQ   R3, R3, #2
        LDRB    R1, [R3]
ReturnOneOrNULAlt
        CMP     R1, #0                  ; if zero (C=1 if equal)
        CMPNE   R1, #&80                ; or if >= &80
        BCS     ReturnNULCharAlt        ; then return NUL char
        B       ReturnOneCharAlt

; come here for dead accent (N=0) or for nowt (N=1)

20
        ADR     R6, NowtReturn          ; point to zero length list
        BICPL   R7, R7, #KBAlt_AccentMask ; if accent, then clear accents
        ORRPL   R7, R7, R1              ; put in new accent
        ORRPL   R5, R5, #KBStat_PendingAlt ; and indicate it
        MOV     PC, R14

; **************************************************************************
;
;       PendingAltCode1 - Process Alt+Char or Accent+Char
;
; in:   R0 -> key structure
;       R2 = internal key number for char
;       R3 = character which would be returned if not an ALT, if not special
;       R4 -> accent table for this keyboard's alphabet
;       R5 = keyboard status
;       R6 -> list that would be returned if not an ALT
;       R7 = pending alt type
;
; out:  R6 -> returned key list
;

PendingAltSpecialCommon ROUT
        TST     R7, #KBAlt_AccentMask   ; is it due to dead accent ?
        BEQ     AlternateChar           ; no, then must be Alt down

; called because of accented char

        AND     R2, R7, #KBAlt_AccentMask ; get just the accent
        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

        LDRB    R2, [R6]                ; load length of current returned list
        LDRB    R2, [R6, R2]            ; R2 = unaccented character
10
        LDRB    R3, [R4], #2            ; R3 = source char
        TEQ     R3, #0                  ; zero => end of list
        MOVEQ   PC, R14                 ; so return char unmodified
        TEQ     R3, R2                  ; if not the char we want
        BNE     %BT10                   ; then loop

        LDRB    R0, [R4, #-1]           ; else load translated char
ReturnOneOrNUL
        CMP     R0, #0                  ; if 0 then return 0 0 (C=1)
        CMPNE   R0, #&80                ; elif -ve return 0 char
        BCS     ReturnNULChar
        B       ReturnOneChar           ; else return 0 char


AlternateChar ROUT
        MOV     R2, R2, LSL #2                  ; multiply index by 4

        TST     R5, #KBStat_CtrlEngaged
        ADDNE   R2, R2, #2

        TST     R5, #KBStat_ShiftEngaged
        ADDNE   R2, R2, #1

        TEQ     R2, #(K1Function1 :SHL: 2) +2   ; is it CTRL-ALT-F1 ?
        BEQ     SelectUKKeyboard                ; then select UK keyboard
        TEQ     R2, #(K1Function2 :SHL: 2) +2   ; is it CTRL-ALT-F2 ?
        BEQ     SelectConfiguredKeyboard        ; then select configured kb
        TEQ     R2, #(K1Function12 :SHL: 2) +2  ; is it CTRL-ALT-F12
        ORREQ   R7, R7, #KBAlt_SelectKeyboard   ; then set IDD selection flag

        B       ReturnNowt                      ; if not one of these
                                                ; then return nowt, since all
                                                ; real ALTs are special

SelectConfiguredKeyboard ROUT
        MOV     R1, #&80                        ; select default keyboard
        B       SelectKeyboard
SelectUKKeyboard
        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
        MOV     R0, #OsbyteSetAlphKey
        SWI     XOS_Byte
        Pull    R14

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

        OutputAccentTable_Latin1

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

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, &FF, &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
        =       K1RightMouse, K1CentreMouse, K1LeftMouse, K1Break
ShiftingKeyListEnd
        ALIGN

        END