*******************************************************************************
*
* KeyMenu.asm  V1.03  02 Mar 1991      
*                                     
*
* Usage:
*   KeyMenu QUIT
*   KeyMenu ?
*   KeyMenu [<options>]
*     Where <options> is one or more of the following:  
*      -i  info about KeyMenu's current configuration
*      -b  toggle Intuition pointer blanking            default=OFF
*      -t  toggle clearing of RMBTRAP flag in windows   default=OFF
*      -q# # = qualifier key(s) to supplement move keys default=Right Shift
*      -p# # = input handler priority in decimal        default=51
*      -a# # = hex keycode of ACTIVATION key            default=Right ALT
*      -e# # = hex keycode of ESCAPE key                default=ESC
*      -s# # = hex keycode of SELECT key                default=Return
*      -l# # = hex keycode of LEFT key                  default=Cursor left
*      -r# # = hex keycode of RIGHT key                 default=Cursor right
*      -u# # = hex keycode of UP key                    default=Cursor up
*      -d# # = hex keycode of DOWN key                  default=Cursor down
*
*
*   This program serves as the user interface to the KeyMenu-Handler. It is 
*   used to install the KeyMenu-Handler, change it's configuration at any time
*   or remove the handler from the system. This program is completely
*   re-entrant (pure).
*
*
* Modification History:
*
*       Date       By                       Modification
*     --------  --------------------    --------------------------------------
*     09/09/89  Ken Lowther             Initial release, V1.01
*
*     09/13/89  Ken Lowther             V1.02 - Added qualifier option to allow
*                                       changing the qualifier key that can be
*                                       used with the movement keys.
*
*     09/30/89  Ken Lowther             V1.02 - This program no longer creates a
*                                       process for the keymenu-handler module.
*
*     03/02/91  Ken Lowther             V1.03 - Re-installed intuition pointer
*                                       blanking option.
*
*******************************************************************************
            nolist
            include "macros.i"
            include "exec/types.i"
            include "exec/strings.i"
            include "exec/nodes.i"
            include "exec/ports.i"
            include "exec/execbase.i"
            include "exec/ables.i"
            include "exec/interrupts.i"
            include "exec/memory.i"
            include "exec/lists.i"
            include "exec/io.i"
            include "devices/input.i"
            include "devices/inputevent.i"
            include "intuition/intuition.i"
            include "libraries/dos.i"
            include "libraries/dosextens.i"
            include "keymenu-handler.i"
            include "keymenu.i"
            list 
            nomlist

kmw         equr    a4                          ; keymenu workarea register
gbl         equr    a5                          ; handler global register

*******************************************************************************
*                                                                             * 
*           Miscellaneous equates                                             *
*                                                                             *
*******************************************************************************
keynamesmax equ     (keynamesend-keynames)/2    ; maximum keycode in keynames
                                                ; table
kmportl     equ     kmportend-kmport            ; port name length
quitwordl   equ     quitwordend-quitword
nomeml      equ     nomemend-nomem

            cseg
            public  main
            near    code
*******************************************************************************
*                                                                             * 
*       main                                                                  *
*                                                                             *
*       This is the main routine of keymenu. It is where execution begins.    *
*       Here we perform the following functions.                              *
*           1) Initialize program                                             *
*           2) parse the runtime command line and report errors if any.       *
*           3) determine what work is to be done and call the appropriate     *
*              routines to do it.                                             *
*           4) perform program cleanup and exit.                              *
*                                                                             *
*       Input Registers:                                                      *
*           a0 - command line address                                         *
*           d0 - command line length                                          *
*                                                                             *
*       Output Registers:                                                     *
*           d0 - amigados return code                                         *
*                                                                             *
*******************************************************************************
main        movem.l mainregs,-(sp)          ; save entry registers
*-----------------------------------------------------------------------------*
*           go initialize, exit if initialization fails                       *
*-----------------------------------------------------------------------------*
            jsr     init                    ; go initialize
            bne     mainexit                ; initialization failed, branch
*-----------------------------------------------------------------------------*
*           parse the runtime command, exit if errors                         *
*-----------------------------------------------------------------------------*
            jsr     parse                   ; go parse the runtime command
            bne     maincleanup             ; parser failed, branch
*-----------------------------------------------------------------------------*
*           determine what is to be done                                      *
*-----------------------------------------------------------------------------*
            lea     kmport(pc),a1           ; point to handler's port name
            Call    FindPort                ; go see if it exists
            tst.l   d0                      ; does port exist ?
            bne     main010                 ; yes, branch
*-----------------------------------------------------------------------------*
*           handler doesn't exist, create it                                  *
*-----------------------------------------------------------------------------*
            jsr     create                  ; go create handler
            beq     maincleanup             ; branch if unable to create it
main010     bset.b  #FLAGB_exists,kmw_flags(kmw) ; indicate port exists
            move.l  d0,gbl                  ; setup handler global register
main015     btst.b  #FLAGB_quit,kmw_flags(kmw) ; was 'quit' specified ?
            beq     main020                 ; no, branch
*-----------------------------------------------------------------------------*
*           quit was specified, stop the handler and exit                     *
*-----------------------------------------------------------------------------*
            jsr     quit                    ; yes, get rid of handler
            bra     maincleanup             ; get out            
main020     btst.b  #FLAGB_exists,kmw_flags(kmw) ; does handler exist ?
            beq     maincleanup             ; no, branch
*-----------------------------------------------------------------------------*
*           process any runtime parameters that may have been given           *
*-----------------------------------------------------------------------------*
            jsr     params                  ; yes, go process any runtime params
*-----------------------------------------------------------------------------*
*           do cleanup and exit.                                              *
*-----------------------------------------------------------------------------*
maincleanup move.l  kmw_dosbase(kmw),a1     ; get dos library base
            Call    CloseLibrary            ; close it
            move.l  kmw,a1                  ; get work area address
            move.l  #kmw_size,d0            ; get size of work area
            Call    FreeMem                 ; go free the work area
mainexit    movem.l (sp)+,mainregs          ; restore registers
            clr.l   d0                      ; set return code for dos
            rts                             ; return to caller
mainregs    reg     d1-d7/a0-a6             ; registers saved by main

*******************************************************************************
*                                                                             * 
*       init                                                                  *
*                                                                             *
*       This routine performs the following initialization tasks:             *
*           1) opens the dos library                                          *
*           2) gets std output file handle                                    *
*           3) allocates and initializes our workarea                         *
*                                                                             *
*       Input Registers:                                                      *
*           a0 - command line address                                         *
*           d0 - command line length                                          *
*                                                                             *
*       Output Registers:                                                     *
*           a4 - workarea address                                             *
*           a6 - exec library base                                            *
*           d0 - return code (0=initialization successful)                    *
*                                                                             *
*******************************************************************************
init        move.l  AbsExecBase,a6          ; setup exec library base
            move.l  a0,a3                   ; save command line address
            move.l  d0,d3                   ; save command line length
*-----------------------------------------------------------------------------*
*           Open DOS Library                                                  *
*-----------------------------------------------------------------------------*
            lea     doslib(pc),a1           ; point to library name
            moveq.l #0,d0                   ; we don't care what version
            Call    OpenLibrary             ; go open the library
            move.l  d0,a5                   ; save library base for use later
            beq     init_err1               ; openlibrary failed - can't tell
                                            ; user - just exit
*-----------------------------------------------------------------------------*
*           Get STD Output File Handle                                        *
*-----------------------------------------------------------------------------*
            Call    Output,a5               ; get file handle for screen
            move.l  d0,a2                   ; save output file handle
            beq     init_err                ; if no handle was returned - branch
*-----------------------------------------------------------------------------*
*           Allocate our workarea                                             *
*-----------------------------------------------------------------------------*
            move.l  #kmw_size,d0            ; set size of area to allocate
            move.l  #MEMF_CLEAR,d1          ; indicate type of memory
            Call    AllocMem                ; go get it
            move.l  d0,kmw                  ; setup our workarea register
            bne     init010                 ; if allocate was successful, branch
            move.l  a2,d1                   ; get file handle
            lea     nomem(pc),a0            ; get error message address
            move.l  a0,d2
            move.l  #nomeml,d3              ; get error message length
            Call    Write,a5                ; write error message
            bra     init_err                ; go cleanup
*-----------------------------------------------------------------------------*
*           Initialize our workarea                                           *
*-----------------------------------------------------------------------------*
init010
            move.l  a5,kmw_dosbase(kmw)     ; save dos base address
            move.l  a2,kmw_filehandle(kmw)  ; save output file handle
            move.l  a3,kmw_cmd(kmw)         ; save runtime command address
            move.w  d3,kmw_cmd_length(kmw)  ; save runtime command length
            move.b  #-1,kmw_AKey(kmw)       ; initialize to null keys
            move.b  #-1,kmw_DKey(kmw)
            move.b  #-1,kmw_SKey(kmw)
            move.b  #-1,kmw_UpKey(kmw)
            move.b  #-1,kmw_DownKey(kmw)
            move.b  #-1,kmw_LeftKey(kmw)
            move.b  #-1,kmw_RightKey(kmw)
            move.b  #handlerpri,kmw_handlerpri(kmw) ; default handler priority
            bra     init_ok                 ; initialized ok - return
*-----------------------------------------------------------------------------*
*           Failed to get Output File Handle                                  *
*-----------------------------------------------------------------------------*
init_err    
            move.l  a5,a1                   ; get dos library base
            Call    CloseLibrary            ; close it
*-----------------------------------------------------------------------------*
*           Couldn't initialize for whatever reason - set return code         *
*-----------------------------------------------------------------------------*
init_err1   moveq.l #1,d0                   ; indicate failure
            bra     initexit                ; get out
*-----------------------------------------------------------------------------*
*           initialized ok - set return code                                  *
*-----------------------------------------------------------------------------*
init_ok     clr.l   d0                      ; indicate success
*-----------------------------------------------------------------------------*
*           Common return point                                               *
*-----------------------------------------------------------------------------*
initexit    rts                             ; return

*******************************************************************************
*                                                                             * 
*       changekey                                                             *
*                                                                             *
*       This routine is called to change a keymenu configuration key from one *
*       value to another and print a message documenting the change.          *
*                                                                             *
*       Input Registers:                                                      *
*           a0 - address of keymenu's global area for the key being changed   *
*           a1 - address of text describing the key being changed             *
*           d0 - new key value to be used (-1 = no change)                    *
*                                                                             *
*       Output Registers:                                                     *
*           none                                                              *
*                                                                             *
*******************************************************************************
changekey   movem.l ckregs,-(sp)            ; save registers
            cmp.b   #-1,d0                  ; was a new value given ?
            beq     changekeyexit           ; no, branch
            clr.l   d1                      ; clear work register
            move.b  (a0),d1                 ; get old value of key
            move.l  d0,d2                   ; get new key value
            asl.w   #1,d2                   ; multiply by 2
            lea     keynames(pc),a3         ; get address of key names table
            lea     keyval(pc),a2           ; get address of key value table
            move.w  d0,-(sp)                ; pass new key value
            move.w  (a3,d2.w),d2            ; get disp of new key name
            pea     (a2,d2.w)               ; pass addr of new key name
            move.l  d1,d2                   ; get old key value
            asl.w   #1,d2                   ; multiply by 2
            move.w  d1,-(sp)                ; pass old key value
            move.w  (a3,d2.w),d2            ; get disp of old key name
            pea     (a2,d2.w)               ; pass address of old key name
            move.l  a1,-(sp)                ; pass text of key being changed
            move.b  d0,(a0)                 ; update keymenu's global area
            lea     changemsg(pc),a0        ; get format string address
            jsr     printf                  ; go print change message
            add.l   #16,sp                  ; adjust stack pointer
changekeyexit
            movem.l (sp)+,ckregs
            rts                             ; return to caller
ckregs      reg     d0-d2/a0-a3
            
*******************************************************************************
*                                                                             * 
*       params                                                                *
*                                                                             *
*       This routine processes any runtime params that may have been given    *
*       to change keymenu's configuration. Also, messages are produced        *
*       indicating any changes that are made.                                 * 
*                                                                             *
*       Input Registers:                                                      *
*           a4 - keymenu workarea address (kmw)                               *
*           a5 - handler global area                                          *
*                                                                             *
*       Output Registers:                                                     *
*           none                                                              *
*                                                                             *
*******************************************************************************
params      clr.l   d0
*-----------------------------------------------------------------------------*
*           Change any of the various keys that keymenu uses.                 *
*-----------------------------------------------------------------------------*
            move.b  kmw_AKey(kmw),d0        ; load parameter
            lea     gb_AKey(gbl),a0         ; point to global area
            lea     akey(pc),a1             ; text for change message
            jsr     changekey               ; go change the key if necessary
            move.b  kmw_DKey(kmw),d0        ; load parameter
            lea     gb_DKey(gbl),a0         ; point to global area
            lea     dkey(pc),a1             ; text for change message
            jsr     changekey               ; go change the key if necessary
            move.b  kmw_SKey(kmw),d0        ; load parameter
            lea     gb_SKey(gbl),a0         ; point to global area
            lea     skey(pc),a1             ; text for change message
            jsr     changekey               ; go change the key if necessary
            move.b  kmw_UpKey(kmw),d0       ; load parameter
            lea     gb_UpKey(gbl),a0        ; point to global area
            lea     upkey(pc),a1            ; text for change message
            jsr     changekey               ; go change the key if necessary
            move.b  kmw_DownKey(kmw),d0     ; load parameter
            lea     gb_DownKey(gbl),a0      ; point to global area
            lea     downkey(pc),a1          ; text for change message
            jsr     changekey               ; go change the key if necessary
            move.b  kmw_LeftKey(kmw),d0     ; load parameter
            lea     gb_LeftKey(gbl),a0      ; point to global area
            lea     leftkey(pc),a1          ; text for change message
            jsr     changekey               ; go change the key if necessary
            move.b  kmw_RightKey(kmw),d0    ; load parameter
            lea     gb_RightKey(gbl),a0     ; point to global area
            lea     rightkey(pc),a1         ; text for change message
            jsr     changekey               ; go change the key if necessary
            btst.b  #FLAGB_trap,kmw_flags(kmw) ; was rmbtrap option specified ?
            beq     params025               ;  ; no, branch
*-----------------------------------------------------------------------------*
*           Change the clear RMBTRAP option                                   *
*-----------------------------------------------------------------------------*
            lea     info4(pc),a0            ; point to message text
            bchg.b  #FLAGB_Clear_rmbtrap,gb_flags(gbl) ; invert the bit
            beq     params010               ; was off, now on, branch
            pea     nowoff(pc)              ; indicate now off
            bra     params020
params010   pea     nowon(pc)               ; indicate now on
params020   jsr     printf                  ; go tell what we did
            addq.l  #4,sp                   ; adjust stack pointer

params025   btst.b  #FLAGB_Qual,kmw_flags(kmw) ; was a qualifier(s) specified ?
            beq     params026                  ; no, branch
*-----------------------------------------------------------------------------*
*           Change qualifier(s)                                               *
*-----------------------------------------------------------------------------*
            move.b  kmw_Qual(kmw),gb_Qual(gbl) ; update global area
            jsr     printqual               ; go print new keys
            
params026   btst.b  #FLAGB_blankp,kmw_flags(kmw) ; was blank pointer option
                                                  ; given ?
            beq     params030                     ; no, branch
*-----------------------------------------------------------------------------*
*           Change the blank intuition pointer option                         *
*-----------------------------------------------------------------------------*
            lea     info5(pc),a0            ; point to message text
            bchg.b  #FLAGB_Blank_pointer,gb_flags(gbl) ; invert the bit
            beq     params027               ; was off, now on, branch
            pea     nowoff(pc)              ; indicate now off
            bra     params028
params027   pea     nowon(pc)               ; indicate now on
params028   jsr     printf                  ; go tell what we did
            addq.l  #4,sp                   ; adjust stack pointer

params030   btst.b  #FLAGB_info,kmw_flags(kmw) ; was info asked for ?
            beq     params110                  ; no, branch
*-----------------------------------------------------------------------------*
*           print info about keymenu's configuration                          *
*-----------------------------------------------------------------------------*
            lea     info1(pc),a0            ; point to message text
            pea     kmport(pc)              ; put portname address on the stack
            jsr     printf                  ; go print it
            addq.w  #4,sp                   ; adjust stack
            move.b  gb_AKey(gbl),d0         ; load key's value
            lea     akey(pc),a1             ; point to text describing the key
            jsr     printkey                ; print info message
            move.b  gb_DKey(gbl),d0
            lea     dkey(pc),a1
            jsr     printkey
            move.b  gb_SKey(gbl),d0
            lea     skey(pc),a1
            jsr     printkey
            move.b  gb_UpKey(gbl),d0
            lea     upkey(pc),a1
            jsr     printkey
            move.b  gb_DownKey(gbl),d0
            lea     downkey(pc),a1
            jsr     printkey
            move.b  gb_RightKey(gbl),d0
            lea     rightkey(pc),a1
            jsr     printkey
            move.b  gb_LeftKey(gbl),d0
            lea     leftkey(pc),a1
            jsr     printkey
            jsr     printqual               ; go print key qualifier(s)
            lea     info5(pc),a0            ; point to message text
            btst.b  #FLAGB_Blank_pointer,gb_flags(gbl) ; blank pointer option on ?
            beq     params070                          ; no, branch
            pea     on(pc)                  ; pass 'on' text to printf
            bra     params080
params070   pea     off(pc)                 ; pass 'off' text to printf
params080   jsr     printf                  ; print the message
            addq.l  #4,sp                   ; adjust the stack pointer
            lea     info4(pc),a0            ; point to message text
            btst.b  #FLAGB_Clear_rmbtrap,gb_flags(gbl) ; is clear rmbtrap on ?
            beq     params090                          ; no, branch
            pea     on(pc)                  ; pass 'on' text to printf
            bra     params100
params090   pea     off(pc)                 ; pass 'off' text to printf
params100   jsr     printf                  ; print the message
            addq.l  #4,sp                   ; adjust the stack pointer
params110
            rts                             ; return to caller

*******************************************************************************
*                                                                             * 
*       printkey                                                              *
*                                                                             *
*       This routine is called to print the configured value of a key         *
*                                                                             *
*       Input Registers:                                                      *
*           a1 - address of text describing the key being changed             *
*           d0 - key value                                                    *
*                                                                             *
*       Output Registers:                                                     *
*           none                                                              *
*                                                                             *
*******************************************************************************
printkey    movem.l pkregs,-(sp)            ; save registers
            clr.l   d1                      ; clear work register
            move.l  d0,d2                   ; get key value
            asl.w   #1,d2                   ; multiply by 2
            lea     keynames(pc),a3         ; get address of key names table
            lea     keyval(pc),a2
            move.w  d0,-(sp)                ; pass key value
            move.w  (a3,d2.w),d2
            pea     (a2,d2.w)
            move.l  a1,-(sp)                ; pass text of key being changed
            lea     info2(pc),a0            ; get format string address
            jsr     printf                  ; go print change message
            add.l   #10,sp                  ; adjust stack pointer
printkeyexit
            movem.l (sp)+,pkregs
            rts                             ; return to caller
pkregs      reg     d0-d2/a0-a3
            
*******************************************************************************
*                                                                             * 
*       printqual                                                             *
*                                                                             *
*       This routine is called to print the configured key qualifier(s)       *
*                                                                             *
*       Input Registers:                                                      *
*           a5 - address of keymenu global area                               *
*                                                                             *
*       Output Registers:                                                     *
*           none                                                              *
*                                                                             *
*******************************************************************************
printqual   movem.l pqregs,-(sp)            ; save registers
            lea     info3(pc),a0            ; get format string address
            jsr     printf                  ; go print the string
            lea     none(pc),a0
            tst.b   gb_Qual(gbl)            ; are there any qualifiers
            beq     pq030                   ; no, branch
            moveq.l #7,d1                   ; set number of bits
pq010       btst.b  d1,gb_Qual(gbl)         ; is qualifier present ?
            beq     pq015                   ; no, branch
            move.l  d1,d2
            asl.w   #1,d2                   ; multiply by 2
            lea     qualnames(pc),a3        ; get address of qualifier names
            lea     keyval(pc),a2
            move.w  (a3,d2.w),d2
            pea     (a2,d2.w)
            lea     info3a(pc),a0           ; get format string address
            jsr     printf                  ; go print key name
            addq.l  #4,sp                   ; adjust stack pointer
pq015       dbra    d1,pq010
pq020       lea     info3end(pc),a0

pq030       jsr     printf                  ; print end of the message
printqualexit
            movem.l (sp)+,pqregs
            rts                             ; return to caller
pqregs      reg     d0-d2/a0-a3
            
*******************************************************************************
*                                                                             * 
*       quit                                                                  *
*                                                                             *
*       This routine stops the input handler and frees all its remaining      *
*       resources in the following manner:                                    *
*           1) signal the handler that we are stopping.                       *
*           2) wait for handler to signal back that it is ready to stop       *
*           3) remove the handlers port and tell the input device to stop     *
*              passing events to the handler.                                 *
*           4) unload the handler's segment                                   *
*                                                                             *
*       Input Registers:                                                      *
*           a4 - keymenu work area (kmw)                                      *
*           a5 - handler global area (gbl)                                    *
*                                                                             *
*       Output Registers:                                                     *
*           none                                                              *
*                                                                             *
*******************************************************************************
quit        btst.b  #FLAGB_exists,kmw_flags(kmw) ; does handler exist ?
            beq     quit020                 ; no, branch
            lea     remove(pc),a0           ; get removing message address
            jsr     printf                  ; go write removing message
*-----------------------------------------------------------------------------*
*           Signal the input handler that we intend to stop                   *
*-----------------------------------------------------------------------------*
            sub.l   a1,a1                   ; setup to find our task
            Call    FindTask                ; go get our task pointer
            move.l  d0,gb_task(gbl)         ; save our task pointer
            moveq.l  #-1,d0                 ; setup to allocate a signal
            Call    AllocSignal             ; go allocate one
            move.b  d0,gb_tasksignum(gbl)   ; save signal number
            move.l  #SIGBREAKF_CTRL_C,d0      ; set signal mask
            move.l  gb_handtask(gbl),a1     ; get task to signal
            Call    Signal                  ; signal the handler task to stop
*-----------------------------------------------------------------------------*
*           Wait for the handler to signal us that it's ok to stop            *
*-----------------------------------------------------------------------------*
            clr.l   d0
            clr.l   d1
            move.b  gb_tasksignum(gbl),d1
            bset.l  d1,d0                   ; create wait mask
            Call    Wait                    ; wait for handler to signal us
            clr.l   d0
            move.b  gb_tasksignum(gbl),d0   ; get allocated signal number
            Call    FreeSignal              ; go free the signal
*-----------------------------------------------------------------------------*
*           remove the handler's port and tell input device to remove us from *
*           the handler list                                                  *
*-----------------------------------------------------------------------------*
            move.l  gbl,a1                  ; get handler's port
            Call    RemPort                 ; remove it from the public eye
            moveq.l #IND_REMHANDLER,d0      ; indicate we want to remove handler
            jsr     tellinputdevice         ; go tell it to the input.device
            bne     quit010                 ; if removed, branch
            lea     handlererr(pc),a0       ; get error message address
            jsr     printf                  ; go tell user
            bra     quit020
*-----------------------------------------------------------------------------*
*           Unload the handler's segment and tell user everything ok.         *
*-----------------------------------------------------------------------------*
quit010     move.l  gb_Segment(gbl),d1      ; get segment address
            Call    UnLoadSeg,kmw_dosbase(kmw) ; get rid of it
            lea     ok(pc),a0               ; get message address
            jsr     printf                  ; write it
*-----------------------------------------------------------------------------*
*           cleanup remaining resources                                       *
*-----------------------------------------------------------------------------*
quit020     jsr     cleanup
            rts                             ; return to caller

*******************************************************************************
*                                                                             * 
*       parse                                                                 *
*                                                                             *
*       This routine parses the command line setting flags and keyvalues in   *
*       our work area indicating what options were given when we were invoked.*
*                                                                             *
*       Input Registers:                                                      *
*           a4 - keymenu work area (kmw)                                      *
*                                                                             *
*       Output Registers:                                                     *
*           d0 - return code (0=parsing successful)                           *
*                                                                             *
*******************************************************************************
parse       movem.l parseregs,-(sp)         ; save registers
            clr.l   d2                      ; clear length register
            move.w  kmw_cmd_length(kmw),d2  ; get runtime command length
            subq.w  #1,d2                   ; reduce by 1 for dbra instr  
            beq     parseexit               ; no command to parse, branch
            move.l  kmw_cmd(kmw),a2         ; get runtime command pointer
*-----------------------------------------------------------------------------*
*           Upshift the entire runtime command                                *
*-----------------------------------------------------------------------------*
parse010    move.b  (a2,d2.w),d0            ; get character
            cmp.b   #'a',d0                 ; within lowercase range ?
            blt     parse012                ; no, branch
            cmp.b   #'z',d0
            bgt     parse012
            and.b   #$5f,d0                 ; upshift the character
parse012    move.b  d0,(a2,d2.w)            ; put it back
            dbra    d2,parse010             ; loop through entire command
            clr.l   d2                      ; clear index register
*-----------------------------------------------------------------------------*
*           Scan runtime command searching for valid option specifiers        *
*-----------------------------------------------------------------------------*
parse015    cmp.b   #'-',(a2,d2.w)          ; option specifier ?
            bne     parse065                ; no, branch
            addq.w  #1,d2                   ; bump index
            cmp.b   #'A',(a2,d2.w)          ; change activation key ?
            bne     parse020                ; no, branch
            lea     kmw_AKey(kmw),a3        ; yes, load result area address
            bra     parsekey                ; go get new keyvalue

parse020    cmp.b   #'E',(a2,d2.w)          ; change escape key ?
            bne     parse025                ; no, branch
            lea     kmw_DKey(kmw),a3        ; yes, load result area address
            bra     parsekey                ; go get new keyvalue

parse025    cmp.b   #'S',(a2,d2.w)          ; change select key ?
            bne     parse030                ; no, branch
            lea     kmw_SKey(kmw),a3        ; yes, load result area address
            bra     parsekey                ; go get new keyvalue

parse030    cmp.b   #'U',(a2,d2.w)          ; change up key ?
            bne     parse035                ; no, branch
            lea     kmw_UpKey(kmw),a3       ; yes, load result area address
            bra     parsekey                ; go get new keyvalue

parse035    cmp.b   #'D',(a2,d2.w)          ; change down key ?
            bne     parse040                ; no, branch
            lea     kmw_DownKey(kmw),a3     ; yes, load result area address
            bra     parsekey                ; go get new keyvalue

parse040    cmp.b   #'L',(a2,d2.w)          ; change left key ?
            bne     parse045                ; no, branch
            lea     kmw_LeftKey(kmw),a3     ; yes, load result area address
            bra     parsekey                ; go get new keyvalue

parse045    cmp.b   #'R',(a2,d2.w)          ; change right key ?
            bne     parse050                ; no, branch
            lea     kmw_RightKey(kmw),a3    ; yes, load result area address
*-----------------------------------------------------------------------------*
*           A keyvalue specifier has been found, check its validity and       *
*           if valid save it for use later. If invalid, issue a message       *
*           and quit.                                                         *
*-----------------------------------------------------------------------------*
parsekey    clr.l   d4                      ; indicate hex numbers
            jsr     parsevalue              ; go parse the value
            bne     parse_keyerror          ; bad value, branch
            cmp.w   #keynamesmax,d0         ; is value within range ?
            bgt     parse_keyerror          ; no, branch
            lea     keynames(pc),a1
            asl.w   #1,d0
            cmp.w   #-1,(a1,d0.w)           ; is this a valid keyvalue ?
            beq     parse_keyerror          ; no, branch
            asr.w   #1,d0
            move.l  d3,d2                   ; adjust index
            move.b  d0,(a3)                 ; save keyvalue
            bra     parse015                ; go check for end of command

parse050    cmp.b   #'T',(a2,d2.w)          ; toggle rmbtrap option ?
            bne     parse054                ; no, branch
            bset.b  #FLAGB_trap,kmw_flags(kmw) ; set indicator
parse052    addq.w  #1,d2                   ; bump index
            bra     parse015                ; loop for next character
            
parse054    cmp.b   #'B',(a2,d2.w)          ; toggle blank pointer option ?
            bne     parse055                ; no, branch
            bset.b  #FLAGB_blankp,kmw_flags(kmw) ; set indicator
            bra     parse052                ; bump index & check next character

parse055    cmp.b   #'I',(a2,d2.w)          ; configuration info wanted ?
            bne     parse057                ; no, branch
            bset.b  #FLAGB_info,kmw_flags(kmw) ; set indicator
            bra     parse052

parse057    cmp.b   #'Q',(a2,d2.w)          ; qualifier key(s) ?
            bne     parse060                ; no, branch
            moveq.l #1,d4                   ; indicate decimal number
            jsr     parsevalue              ; go parse the value
            bne     parse_qualerror         ; bad value, branch
            cmp.w   #255,d0                 ; within range ?
            bgt     parse_qualerror         ; no, branch
            move.b  d0,kmw_Qual(kmw)        ; save qualifier
            bset.b  #FLAGB_Qual,kmw_flags(kmw) ; indicate option specified
            move.l  d3,d2                   ; adjust index
            bra     parse015

parse060    cmp.b   #'P',(a2,d2.w)          ; handler priority option ?
            bne     parse_optionerror       ; no, bad option specified, branch
            moveq.l #1,d4                   ; indicate decimal number
            jsr     parsevalue              ; go parse the value
            bne     parse_prierror          ; bad value, branch
            cmp.w   #255,d0                 ; is it within range ?
            bgt     parse_prierror          ; no, branch
            move.l  d3,d2                   ; adjust index
            move.b  d0,kmw_handlerpri(kmw)  ; save priority
            move.w  d0,-(sp)                ; pass pri value
            lea     primsg(pc),a0           ; get format string address
            jsr     printf                  ; go print change message
            addq.l  #2,sp                   ; adjust stack pointer
            bra     parse015
            
*-----------------------------------------------------------------------------*
*           Print 'HELP' information ?                                        *
*-----------------------------------------------------------------------------*
parse065    cmp.b   #'?',(a2,d2.w)          ; help wanted ?
            bne     parse070                ; no, branch
            lea     help1(pc),a0            ; address of message
            jsr     printf                  ; go write it
            lea     help2(pc),a0            ; address of message
            jsr     printf                  ; go write it
            lea     help3(pc),a0            ; address of message
            jsr     printf                  ; go write it
            lea     help4(pc),a0            ; address of message
            jsr     printf                  ; go write it
            lea     help4a(pc),a0           ; address of message
            jsr     printf                  ; go write it
            lea     help5(pc),a0            ; address of message
            jsr     printf                  ; go write it
            lea     help6(pc),a0            ; address of message
            jsr     printf                  ; go write it
            lea     help6a(pc),a0           ; address of message
            jsr     printf                  ; go write it
            lea     help7(pc),a0            ; address of message
            pea     akey(pc)                ; text describing key
            jsr     printf                  ; go write it
            addq.l  #4,sp                   ; adjust stack pointer
            lea     help8(pc),a0            ; address of message
            pea     dkey(pc)                ; text describing key
            jsr     printf                  ; go write it
            addq.l  #4,sp                   ; adjust stack pointer
            lea     help9(pc),a0            ; address of message
            pea     skey(pc)                ; text describing key
            jsr     printf                  ; go write it
            addq.l  #4,sp                   ; adjust stack pointer
            lea     help10(pc),a0           ; address of message
            pea     leftkey(pc)             ; text describing key
            jsr     printf                  ; go write it
            addq.l  #4,sp                   ; adjust stack pointer
            lea     help11(pc),a0           ; address of message
            pea     rightkey(pc)            ; text describing key
            jsr     printf                  ; go write it
            addq.l  #4,sp                   ; adjust stack pointer
            lea     help12(pc),a0           ; address of message
            pea     upkey(pc)               ; text describing key
            jsr     printf                  ; go write it
            addq.l  #4,sp                   ; adjust stack pointer
            lea     help13(pc),a0           ; address of message
            pea     downkey(pc)             ; text describing key
            jsr     printf                  ; go write it
            addq.l  #4,sp                   ; adjust stack pointer
            bra     parse_error             ; get out
*-----------------------------------------------------------------------------*
*           'QUIT'ting KeyMenu                                                *
*-----------------------------------------------------------------------------*
parse070    lea     quitword(pc),a0
            lea     (a2,d2.w),a1
            move.w  #quitwordl-1,d0
parse072    cmp.b   (a0)+,(a1)+             ; 'QUIT' ?
            bne     parse075                ; no, branch
            dbra    d0,parse072             ; loop control
            bset.b  #FLAGB_quit,kmw_flags(kmw) ; set indicator
            add.w   #quitwordl,d2           ; bump index
            bra     parse015                ; loop for next option
*-----------------------------------------------------------------------------*
*           White space or end of command ?                                   *
*-----------------------------------------------------------------------------*
parse075    cmp.b   #' ',(a2,d2.w)          ; white space ?
            bne     parse080                ; no, branch
            addq.w  #1,d2                   ; yes, bump index
            bra     parse015                ; loop for next character

parse080    cmp.b   #LF,(a2,d2.w)           ; are we at the end of the command ?
            bne     parse_optionerror       ; no, branch
            bra     parseok                 ; yes, branch
*-----------------------------------------------------------------------------*
*           Print 'Invalid key value specified' message                       *
*-----------------------------------------------------------------------------*
parse_keyerror
            jsr     showerror               ; go list the command and show where
                                            ; the error occurred
            lea     keyerror(pc),a0         ; get address of message text
            jsr     printf                  ; go write it
            bra     parse_error             ; take error exit
*-----------------------------------------------------------------------------*
*           Print 'Invalid handler priority specified' message                *
*-----------------------------------------------------------------------------*
parse_prierror
            jsr     showerror               ; go list the command and show where
                                            ; the error occurred
            lea     prierror(pc),a0         ; get address of message text
            jsr     printf                  ; go write it
            bra     parse_error             ; take error exit
*-----------------------------------------------------------------------------*
*           Print 'Invalid qualifier(s) specified' message                    *
*-----------------------------------------------------------------------------*
parse_qualerror
            jsr     showerror               ; go list the command and show where
                                            ; the error occurred
            lea     qualerror(pc),a0        ; get address of message text
            jsr     printf                  ; go write it
            bra     parse_error             ; take error exit
*-----------------------------------------------------------------------------*
*           Print 'Invalid/Unknown option specified' message                  *
*-----------------------------------------------------------------------------*
parse_optionerror
            jsr     showerror               ; go list the command and show where
                                            ; the error occurred
            lea     opterror(pc),a0         ; get address of message text
            jsr     printf                  ; go write it
*-----------------------------------------------------------------------------*
*           Some kind of parsing error occured, set return code               *
*-----------------------------------------------------------------------------*
parse_error moveq.l #1,d0
            bra     parseexit
*-----------------------------------------------------------------------------*
*           parsed ok - set return code                                       *
*-----------------------------------------------------------------------------*
parseok     moveq.l #0,d0
*-----------------------------------------------------------------------------*
*           Common return point                                               *
*-----------------------------------------------------------------------------*
parseexit   movem.l (sp)+,parseregs         ; restore registers
            rts                             ; return to caller
parseregs   reg     d1-d4/a0-a3


*******************************************************************************
*                                                                             * 
*       parsevalue                                                            *
*                                                                             *
*       This routine parses ascii values and converts them to binary.         *
*                                                                             *
*       Input Registers:                                                      *
*           a4 - keymenu work area (kmw)                                      *
*           d2 - displacement into command where option containing value      *
*                starts.                                                      *
*           d4 - 0 = ascii numbers are in hex, 1 = ascii numbers are decimal  *
*                                                                             *
*       Output Registers:                                                     *
*           d0 - binary value                                                 *
*           d4 - 0 = parsed ok, 1 = parse error                               *
*                                                                             *
*******************************************************************************
parsevalue  addq.w  #1,d2                   ; bump index
            move.l  d2,d3                   ; use temporary index
            clr.l   d0                      ; clear accumulator
            clr.l   d1                      ; clear work register
parseval010 move.b  (a2,d3.w),d1
            cmp.b   #'0',d1                 ; within decimal range ?
            blt     parseval015             ; no, branch
            cmp.b   #'9',d1
            bgt     parseval015            
            sub.b   #'0',d1                 ; make binary
            bra     parseval020
parseval015 tst.l   d4                      ; hex number ?
            bne     parseval025             ; no, branch
            cmp.b   #'A',d1                 ; within hex alpha range ?
            blt     parseval025             ; no, branch
            cmp.b   #'F',d1
            bgt     parseval025
            sub.b   #'A'-10,d1              ; make binary
parseval020 tst.l   d4                      ; hex number ?
            beq     parseval023             ; yes, branch
            mulu    #10,d0                  ; multiply accumulator by 10
            bra     parseval024
parseval023
            asl.w   #4,d0                   ; multiply accumulator by 16
parseval024
            add.w   d1,d0                   ; add current digit
            addq.w  #1,d3                   ; bump accumulator
            bra     parseval010             ; loop for next char
parseval025 cmp.b   #' ',d1                 ; end of value ?
            beq     parseval030             ; yes, branch
            cmp.b   #LF,d1                  ; end of command ?
            beq     parseval030             ; yes, branch
            bra     parse_valerror          ; no, error, branch
parseval030 cmp.w   d2,d3                   ; was anything parsed ?
            bne     parse_valok             ; no, branch
parse_valerror
            moveq.l #1,d4                   ; indicate error
            bra     parse_valend            ; go to common return
parse_valok clr.l   d4                      ; indicate value ok
parse_valend
            rts                             ; return to caller

*******************************************************************************
*                                                                             * 
*       showerror                                                             *
*                                                                             *
*       This routine displays the runtime command with a caret symbol         *
*       underneath the portion of the command that caused the parsing error.  *
*                                                                             *
*       Input Registers:                                                      *
*           a4 - keymenu work area (kmw)                                      *
*           d2 - displacement into command where caret symbol should go       *
*                                                                             *
*       Output Registers:                                                     *
*           none                                                              *
*                                                                             *
*******************************************************************************
showerror   movem.l showerrorregs,-(sp)     ; save registers
            move.l  kmw_cmd(kmw),a0         ; message text pointer
            clr.l   d0
            move.w  kmw_cmd_length(kmw),d0  ; message text length
            jsr     putmessage              ; go write the command text
            clr.l   d3                      ; clear counter
            moveq.l #1,d0                   ; set length of text to write
            lea     kmw_buffer(kmw),a0      ; get address of buffer
            move.b  #' ',(a0)               ; put blank in buffer
showerr010  cmp.w   d2,d3                   ; have we reached the displacement ?
            bge     showerr015              ; yes, branch
            jsr     putmessage              ; go write a blank
            addq.w  #1,d3                   ; bump counter
            bra     showerr010              ; loop
showerr015  move.b  #'^',(a0)               ; put ^ in buffer
            jsr     putmessage              ; go write it
            move.b  #LF,(a0)                ; put linefeed in buffer
            jsr     putmessage              ; go write it
            movem.l (sp)+,showerrorregs     ; restore registers
            rts
showerrorregs reg d3

*******************************************************************************
*                                                                             * 
*       printf                                                                *
*                                                                             *
*       This routine is called to print a formatted message substituting data *
*       into the message from parameters (passed on the stack) using 'C'-like *
*       formatting characters. The calling routine is responsible for placing *
*       the datastream parameters on the stack and then adjusting the stack   *
*       after execution of this routine. It is assumed that the parameters    *
*       are located 4 bytes beyond the current stack pointer upon entry to    *
*       this routine.                                                         *
*                                                                             *
*       Input Registers:                                                      *
*           a0 - address of format string                                     *
*           a3 - address of current position in buffer                        *
*           a4 - workarea address                                             *
*                                                                             *
*       Output Registers:                                                     *
*           none.                                                             *
*                                                                             *
*******************************************************************************
printf      lea     4(sp),a1                ; get datastream address
            movem.l printfregs,-(sp)        ; save registers
            lea     putchar(pc),a2          ; point to routine to build buffer
            lea     kmw_buffer(kmw),a3      ; point to buffer
            Call    RawDoFmt                ; go format the buffer
            lea     kmw_buffer(kmw),a0      ; point to buffer
            move.l  a0,a1                   ; save buffer start
            move.l  #kmw_bsize-1,d0         ; get maximum size of buffer
printf010   move.b  (a1),(a1)+              ; scan buffer for end
            dbeq    d0,printf010            ; loop til end
            sub.l   a0,a1                   ; compute size of datastream
            move.l  a1,d0                   ; setup for putmessage
            jsr     putmessage              ; go write the message
            movem.l (sp)+,printfregs        ; restore registers
            rts
printfregs  reg     a2/a3

*******************************************************************************
*                                                                             * 
*       putmessage                                                            *
*                                                                             *
*       This routine writes a message to the standard output device           *
*                                                                             *
*       Input Registers:                                                      *
*           a0 - address of message text to write                             *
*           a4 - keymenu work area (kmw)                                      *
*           d0 - length of message text to write                              *
*                                                                             *
*       Output Registers:                                                     *
*           none                                                              *
*                                                                             *
*******************************************************************************
putmessage  movem.l putmessageregs,-(sp)    ; save registers
            move.l  a0,d2                   ; message text
            move.l  d0,d3                   ; text length
            move.l  kmw_filehandle(kmw),d1  ; output file handle
            Call    Write,kmw_dosbase(kmw)  ; go write the message
            movem.l (sp)+,putmessageregs    ; restore registers
            rts
putmessageregs reg  d0-d3/a0

*******************************************************************************
*                                                                             * 
*       putchar                                                               *
*                                                                             *
*       This routine is called by the 'RawDoFmt' exec function to put each    *
*       character of a formatted datastring into an output buffer. The        *
*       printf routine is used to pass the address of this routine to exec.   *
*                                                                             *
*       Input Registers:                                                      *
*           d0 - character to be put into a buffer                            *
*           a3 - address of current position in buffer                        *
*                                                                             *
*       Output Registers:                                                     *
*           a3 - incremented to next position in buffer                       *
*                                                                             *
*******************************************************************************
putchar     move.b  d0,(a3)+                ; put character into buffer
            rts                             ; return to caller

*******************************************************************************
*                                                                             * 
*       create                                                                *
*                                                                             *
*       This routine loads the keymenu-handler code and adds it as an input   *
*       handler to the input.device, if possible                              *
*                                                                             *
*       Input Registers:                                                      *
*           a4 - workarea address                                             *
*                                                                             *
*       Output Registers:                                                     *
*           d0 - handler global area/null if unable to load/add handler       *
*                                                                             *
*******************************************************************************
create      btst.b  #FLAGB_quit,kmw_flags(kmw) ; was 'quit' specified ?
            bne     create_err              ; yes, keymenu not running, branch
*-----------------------------------------------------------------------------*
*           Allocate handler global area                                      *
*-----------------------------------------------------------------------------*
            move.l  #gb_size,d0             ; set size of area to allocate
            move.l  #MEMF_CLEAR+MEMF_PUBLIC,d1; indicate type of memory
            Call    AllocMem                ; go get it
            move.l  d0,gbl                  ; setup our global area register
            bne     create015               ; if allocate was successful, branch
create010   lea     nomem(pc),a0            ; get error message address
            jsr     printf                  ; go write error message
            bra     create_err              ; go cleanup
*-----------------------------------------------------------------------------*
*           Initialize global area                                            *
*-----------------------------------------------------------------------------*
create015   move.b  #ralt_down,gb_AKey(gbl)
            move.b  #esc_down,gb_DKey(gbl)
            move.b  #return_down,gb_SKey(gbl)
            move.b  #CURSORUP,gb_UpKey(gbl)
            move.b  #CURSORDOWN,gb_DownKey(gbl)
            move.b  #CURSORLEFT,gb_LeftKey(gbl)
            move.b  #CURSORRIGHT,gb_RightKey(gbl)
            move.b  #IEQUALIFIER_RSHIFT,gb_Qual(gbl)
            move.l  gbl,gb_handler+IS_DATA(gbl)
            moveq.l #blank_pointer_size,d0  ; set size of area to allocate
            move.l  #MEMF_CLEAR+MEMF_CHIP,d1 ; indicate type of memory
            Call    AllocMem                ; go get it
            move.l  d0,gb_blank_ptr(gbl)    ; save pointer data address
            bne     create020               ; if allocate was successful, branch
create018   jsr     cleanup                 ; go release everything
            bra     create010
*-----------------------------------------------------------------------------*
*           begin installing keymenu handler                                  *
*-----------------------------------------------------------------------------*
create020   lea     install(pc),a0          ; get install message address
            jsr     printf                  ; go write install message
            move.b  #PA_SIGNAL,gb_Port+MP_FLAGS(gbl) ; setup message port
            move.b  #0,gb_Port+LN_PRI(gbl)
            move.b  #NT_MSGPORT,gb_Port+LN_TYPE(gbl)
            move.l  #kmportl,d0             ; size of port name
            move.l  #MEMF_PUBLIC,d1         ; set type of memory to get
            Call    AllocMem                ; go allocate it
            move.l  d0,gb_Port+LN_NAME(gbl) ; save its address
            beq     create018               ; branch if allocation failed
            move.l  d0,a0                   ; get destination address
            lea     kmport(pc),a1           ; get address of port name
            move.w  #kmportl-1,d1           ; get length of area to move
create030   move.b  (a1,d1.w),(a0,d1.w)     ; copy port name
            dbra    d1,create030            ; loop through port name
            lea     gb_Port+MP_MSGLIST(gbl),a0 ; get address of message list
            NEWLIST a0                      ; initialize it
*-----------------------------------------------------------------------------*
*           Open Intuition Library                                            *
*-----------------------------------------------------------------------------*
            lea     intuitionlib(pc),a1     ; point to library name
            moveq.l #0,d0                   ; we don't care what version
            Call    OpenLibrary             ; go open the library
            move.l  d0,gb_IBase(gbl)        ; save lib base for handler's use
            bne     create040               ; openlibrary successful, branch
            jsr     cleanup                 ; go release everything
            lea     interr(pc),a0           ; get error message address
            jsr     printf                  ; go write error message
            bra     create_err              ; take error exit
*-----------------------------------------------------------------------------*
*           Load 'Keymenu-handler' segment                                    *
*-----------------------------------------------------------------------------*
create040   lea     handlerpath(pc),a0      ; use library path first
            move.l  a0,d1
            Call    LoadSeg,kmw_dosbase(kmw) ; try to load the segment
            move.l  d0,gb_Segment(gbl)      ; save segment pointer
            bne     create050               ; if loaded, branch
            lea     handlername(pc),a0      ; use current directory
            move.l  a0,d1
            Call    LoadSeg,kmw_dosbase(kmw) ; try load again
            move.l  d0,gb_Segment(gbl)      ; save segment pointer
            bne     create050               ; if loaded, branch
            lea     loaderr(pc),a0          ; get format string address
            pea     handlername(pc)         ; setup datastream
            jsr     printf                  ; go print the message
            addq.l  #4,sp                   ; adjust stack pointer
            jsr     cleanup                 ; go release everything
            bra     create_err              ; take error exit
*-----------------------------------------------------------------------------*
*           Add message port so that we can get access later.                 *
*-----------------------------------------------------------------------------*
create050   move.l  gbl,a1                  ; get port address
            Call    AddPort                 ; add the port to the system
            sub.l   a1,a1                   ; setup to find our task
            Call    FindTask                ; go get our task pointer
            move.l  d0,gb_task(gbl)         ; save our task pointer
            moveq.l  #-1,d0                 ; setup to allocate a signal
            Call    AllocSignal             ; go allocate one
            move.b  d0,gb_tasksignum(gbl)   ; save signal number
            move.l  gb_Port+LN_NAME(gbl),d1
            moveq.l #procpri,d2             ; process priority
            move.l  gb_Segment(gbl),d3      ; process code segment
            move.l  #procstack,d4           ; process stack size
            Call    CreateProc,kmw_dosbase(kmw) ; go create the process
            clr.l   d0
            clr.l   d1
            move.b  gb_tasksignum(gbl),d1
            bset.l  d1,d0                   ; create wait mask
            Call    Wait                    ; wait for handler to signal us
*-----------------------------------------------------------------------------*
*           Add handler to input.device                                       *
*-----------------------------------------------------------------------------*
            clr.l   d0
            move.b  gb_tasksignum(gbl),d0   ; get allocated signal number
            Call    FreeSignal              ; go free the signal number
            move.b  #handlerpri,gb_handler+LN_PRI(gbl)
            moveq.l #IND_ADDHANDLER,d0      ; indicate we want to add handler
            jsr     tellinputdevice         ; go tell it to the input.device
            bne     create060               ; if added, branch
            bset.b  #FLAGB_quit,kmw_flags(kmw) ; indicate that we want out
            lea     handlererr(pc),a0       ; get error message address
            jsr     printf                  ; go tell user
            bra     create_ok               ; take normal exit
create060   lea     handlerok(pc),a0        ; get format string address
            pea     kmport(pc)              ; put portname address on stack
            jsr     printf                  ; go print 'ok' message
            addq.l  #4,sp                   ; adjust stack pointer
            
            
create_ok   move.l  gbl,d0                  ; pass back address of global area
            bra     createexit
create_err  move.l  #0,d0                   ; indicate no handler

createexit  rts                             ; return to caller

*******************************************************************************
*                                                                             * 
*       tellinputdevice                                                       *
*                                                                             *
*       This routine is called to open the input.device, send a command to    *
*       it and then close it.                                                 *
*                                                                             *
*       Input Registers:                                                      *
*           d0 - function to be sent to the input.device                      *
*           a4 - keymenu workarea address (kmw)                               *
*           a5 - handler global area                                          *
*                                                                             *
*                                                                             *
*       Output Registers:                                                     *
*           d0 - return code (non-zero=success)                               *
*                                                                             *
*******************************************************************************
tellinputdevice
            movem.l tidregs,-(sp)           ; save registers
            move.l  d0,d3                   ; save function for use later
            moveq.l #-1,d2                  ; default to good return
*-----------------------------------------------------------------------------*
*           Create a port to communicate with the input.device                *
*-----------------------------------------------------------------------------*
            moveq.l  #-1,d0                 ; setup to allocate a signal
            Call    AllocSignal             ; go allocate one
            move.l  d0,d6                   ; save signal number for later use
            move.l  #MP_SIZE,d0             ; size of port
            move.l  #MEMF_PUBLIC+MEMF_CLEAR,d1 ; set type of memory to get
            Call    AllocMem                ; go allocate a message port
            move.l  d0,d4                   ; save its address
            bne     tid010                  ; if allocated ok, branch
            clr.l   d2                      ; set bad return code
            bra     tid070                  ; go free resources 
tid010      move.l  d4,a2
            move.b  #NT_MSGPORT,LN_TYPE(a2) ; initialize the port
            move.b  #PA_SIGNAL,MP_FLAGS(a2)
            move.b  gb_tasksignum(gbl),MP_SIGBIT(a2)
            sub.l   a1,a1
            Call    FindTask                ; go find our task
            move.l  d0,MP_SIGTASK(a2)
            lea     MP_MSGLIST(a2),a0
            NEWLIST a0
*-----------------------------------------------------------------------------*
*           Create a standard IO block                                        *
*-----------------------------------------------------------------------------*
            move.l  #IOSTD_SIZE,d0          ; size of std request
            move.l  #MEMF_CLEAR+MEMF_PUBLIC,d1 ; set type of memory
            Call    AllocMem                ; go allocate it
            move.l  d0,d5                   ; save its address
            bne     tid020                  ; branch if allocated ok
            clr.l   d2                      ; set bad return code
            bra     tid060                  ; go free resources
tid020      move.l  d5,a3
            move.b  #NT_MESSAGE,LN_TYPE(a3)
            move.l  d4,MN_REPLYPORT(a3)
            move.w  #IOSTD_SIZE,MN_LENGTH(a3)
*-----------------------------------------------------------------------------*
*           Open input device                                                 *
*-----------------------------------------------------------------------------*
            lea     inputdevice(pc),a0      ; point to device name
            clr.l   d0                      ; unit 0
            move.l  d5,a1                   ; inputblock
            clr.l   d1                      ; flags
            Call    OpenDevice              ; go open the input device
            tst.l   d0                      ; open ok ?
            beq     tid030                  ; yes, branch
            clr.l   d2                      ; set bad return code
            bra     tid050                  ; go free resources
*-----------------------------------------------------------------------------*
*           Issue request to input device                                     *
*-----------------------------------------------------------------------------*
tid030      move.w  d3,IO_COMMAND(a3)       ; set function in inputblock
            lea     gb_handler(gbl),a0      ; get address of handler data
            move.l  a0,IO_DATA(a3)          ; put it in the inputblock
            move.l  a3,a1
            Call    DoIO                    ; issue the I/O
            tst.l   d0                      ; was I/O successful ?
            beq     tid040                  ; yes, branch
            clr.l   d2                      ; no, set bad return code
*-----------------------------------------------------------------------------*
*           Close the input device                                            *
*-----------------------------------------------------------------------------*
tid040      move.l  d5,a1
            Call    CloseDevice             ; close the input device
*-----------------------------------------------------------------------------*
*           Delete the input block                                            *
*-----------------------------------------------------------------------------*
tid050      move.l  #IOSTD_SIZE,d0          ; get size of standard request
            move.l  d5,a1                   ; get pointer to block
            Call    FreeMem                 ; go deallocate memory
*-----------------------------------------------------------------------------*
*           Delete the input port                                             *
*-----------------------------------------------------------------------------*
tid060      move.l  #MP_SIZE,d0             ; get size of port
            move.l  d4,a1                   ; get pointer to port
            Call    FreeMem                 ; go deallocate the port
*-----------------------------------------------------------------------------*
*           Free the signal associated with the port                          *
*-----------------------------------------------------------------------------*
tid070      clr.l   d0
            move.b  gb_tasksignum(gbl),d0
            Call    FreeSignal              ; go free the signal
*-----------------------------------------------------------------------------*
*           Set return code and exit                                          *
*-----------------------------------------------------------------------------*
            move.l  d2,d0
            movem.l (sp)+,tidregs           ; restore registers
            rts                             ; return to caller
tidregs     reg     a2-a3/d2-d5

*******************************************************************************
*                                                                             * 
*       cleanup                                                               *
*                                                                             *
*       This routine frees resources that have been allocated or acquired     *
*       during execution.                                                     *
*                                                                             *
*       Input Registers:                                                      *
*           a4 - keymenu work area (kmw)                                      *
*           a5 - keymenu handler global area                                  *
*                                                                             *
*       Output Registers:                                                     *
*           none                                                              *
*                                                                             *
*******************************************************************************
cleanup     
*-----------------------------------------------------------------------------*
*           Close Intuition Library                                           *
*-----------------------------------------------------------------------------*
            move.l  gb_IBase(gbl),d0        ; get intuition library base
            beq     cleanup070              ; branch if not open
            move.l  d0,a1
            Call    CloseLibrary            ; close it
*-----------------------------------------------------------------------------*
*           Deallocate port name area                                         *
*-----------------------------------------------------------------------------*
cleanup070  move.l  gb_Port+LN_NAME(gbl),d0 ; get port name area address
            beq     cleanup080              ; branch if no area
            move.l  d0,a1
            move.l  #kmportl,d0             ; get size of area
            Call    FreeMem                 ; go free it
*-----------------------------------------------------------------------------*
*           Deallocate blank pointer chip memory                              *
*-----------------------------------------------------------------------------*
cleanup080  move.l  gb_blank_ptr(gbl),d0    ; get blank pointer area address
            beq     cleanup090              ; branch if no area
            move.l  d0,a1
            move.l  #blank_pointer_size,d0  ; get size of area
            Call    FreeMem                 ; go free it
*-----------------------------------------------------------------------------*
*           Deallocate handler global area                                    *
*-----------------------------------------------------------------------------*
cleanup090  move.l  gbl,a1                  ; get global area address
            move.l  #gb_size,d0             ; get size of work area
            Call    FreeMem                 ; go free it
            rts

*******************************************************************************
*                                                                             * 
*           Miscellaneous constants                                           *
*                                                                             *
*******************************************************************************
doslib      DOSNAME                         ; library names

intuitionlib INTUITIONNAME

inputdevice dc.b    'input.device',0

            portname kmport
kmportend

handlerpath dc.b    'L:'
handlername dc.b    'KeyMenu-Handler',0


install     dc.b    'Installing KeyMenu, ',0
remove      dc.b    'Removing KeyMenu, ',0
nomem       dc.b    'Unable to allocate work area, Aborted',LF,0
nomemend
interr      dc.b    'Unable to open Intuition library',LF,0
loaderr     dc.b    'Unable to find %s',LF,0
handlererr  dc.b    'Handler error',0
handlerok   dc.b    'ok. %s, PUBLIC DOMAIN.',LF,0
ok          dc.b    'ok',LF,0

help1       dc.b    'Usage: KeyMenu '
quitword    dc.b    'QUIT'
quitwordend
            dc.b    LF,0
help2       dc.b    '       KeyMenu [<options>]',LF,0
help3       dc.b    '    Where <options> is one or more of the following:',LF,0
help4       dc.b    "     -i  = info about KeyMenu's current settings",LF,0
help4a      dc.b    '     -b  = toggle Intuition pointer blanking',LF,0
help5       dc.b    '     -q# = key qualifier(s) in decimal',LF,0
help6       dc.b    '     -t  = toggle clear RMBTRAP flag option',LF,0
help6a      dc.b    '     -p# = input handler priority in decimal',LF,0 
help7       dc.b    '     -a# = %s',LF,0
help8       dc.b    '     -e# = %s',LF,0
help9       dc.b    '     -s# = %s',LF,0
help10      dc.b    '     -l# = %s',LF,0
help11      dc.b    '     -r# = %s',LF,0
help12      dc.b    '     -u# = %s',LF,0
help13      dc.b    '     -d# = %s',LF,0

akey        dc.b    'ACTIVATION key',0
dkey        dc.b    'ESCAPE key',0
skey        dc.b    'SELECT key',0
leftkey     dc.b    'LEFT key',0
rightkey    dc.b    'RIGHT key',0
upkey       dc.b    'UP key',0
downkey     dc.b    'DOWN key',0

keyerror    dc.b    'Invalid key value',LF,0
prierror    dc.b    'Invalid handler priority',LF,0
qualerror   dc.b    'Invalid qualifier(s)',LF,0
opterror    dc.b    'Invalid/unknown option',LF,0
changemsg   dc.b    '%s: %s (%x) changed to %s (%x)',LF,0
primsg      dc.b    'Input handler priority is %d',LF,0
nowoff      dc.b    'now '
off         dc.b    'OFF',0
nowon       dc.b    'now '
on          dc.b    'ON',0
info1       dc.b    '%s Configuration:',LF,0
info2       dc.b    '%14s is %s (%x)',LF,0
info3       dc.b    'Key qualifier(s):',0
info3a      dc.b    ' %s ',0
none        dc.b    ' None'
info3end    dc.b    LF,0
info4       dc.b    'Clear RMBTRAP option is %s',LF,0
info5       dc.b    'Blank Intuition Pointer option is %s',LF,0

*******************************************************************************
*                                                                             * 
*           Key Value Table                                                   *
*                                                                             *
*           Contains text descriptions of the various keys supported.         *
*           Entries are variable length null terminated strings. This table   *
*           is indexed by the keynames table. The order of the entries in     *
*           this table is not significant.                                    *
*                                                                             * 
*******************************************************************************
keyval                                      ; this label must be first
key00       dc.b    '`',0
key01       dc.b    '1',0
key02       dc.b    '2',0
key03       dc.b    '3',0
key04       dc.b    '4',0
key05       dc.b    '5',0
key06       dc.b    '6',0
key07       dc.b    '7',0
key08       dc.b    '8',0
key09       dc.b    '9',0
key0a       dc.b    '0',0
key0b       dc.b    '-',0
key0c       dc.b    '=',0
key0d       dc.b    '\',0
key0f       dc.b    'Numeric Pad 0',0
key10       dc.b    'Q',0
key11       dc.b    'W',0
key12       dc.b    'E',0
key13       dc.b    'R',0
key14       dc.b    'T',0
key15       dc.b    'Y',0
key16       dc.b    'U',0
key17       dc.b    'I',0
key18       dc.b    'O',0
key19       dc.b    'P',0
key1a       dc.b    '[',0
key1b       dc.b    ']',0
key1d       dc.b    'Numeric Pad 1',0
key1e       dc.b    'Numeric Pad 2',0
key1f       dc.b    'Numeric Pad 3',0
key20       dc.b    'A',0
key21       dc.b    'S',0
key22       dc.b    'D',0
key23       dc.b    'F',0
key24       dc.b    'G',0
key25       dc.b    'H',0
key26       dc.b    'J',0
key27       dc.b    'K',0
key28       dc.b    'L',0
key29       dc.b    ';',0
key2a       dc.b    "'",0
key2d       dc.b    'Numeric Pad 4',0
key2e       dc.b    'Numeric Pad 5',0
key2f       dc.b    'Numeric Pad 6',0
key31       dc.b    'Z',0
key32       dc.b    'X',0
key33       dc.b    'C',0
key34       dc.b    'V',0
key35       dc.b    'B',0
key36       dc.b    'N',0
key37       dc.b    'M',0
key38       dc.b    ',',0
key39       dc.b    '.',0
key3a       dc.b    '/',0
key3c       dc.b    'Numeric Pad .',0
key3d       dc.b    'Numeric Pad 7',0
key3e       dc.b    'Numeric Pad 8',0
key3f       dc.b    'Numeric Pad 9',0
key40       dc.b    'Space Bar',0
key41       dc.b    'Backspace',0
key42       dc.b    'Tab',0
key43       dc.b    'Numeric Pad Enter',0
key44       dc.b    'Return',0
key45       dc.b    'Escape',0
key46       dc.b    'Delete',0
key4a       dc.b    'Numeric Pad -',0
key4c       dc.b    'Cursor up',0
key4d       dc.b    'Cursor down',0
key4e       dc.b    'Cursor right',0
key4f       dc.b    'Cursor left',0
key50       dc.b    'F1',0
key51       dc.b    'F2',0
key52       dc.b    'F3',0
key53       dc.b    'F4',0
key54       dc.b    'F5',0
key55       dc.b    'F6',0
key56       dc.b    'F7',0
key57       dc.b    'F8',0
key58       dc.b    'F9',0
key59       dc.b    'F10',0
key5f       dc.b    'Help',0
key60       dc.b    'Left Shift',0
key61       dc.b    'Right Shift',0
key62       dc.b    'Caps Lock',0
key63       dc.b    'Control',0
key64       dc.b    'Left Alt',0
key65       dc.b    'Right Alt',0
key66       dc.b    'Left Amiga',0
key67       dc.b    'Right Amiga',0


*******************************************************************************
*                                                                             * 
*           Key Name Table                                                    *
*                                                                             *
*           Ordered by keycode. Each entry consists of a word displacement    *
*           into the keyval table. Entries for unsupported keycodes contain   *
*           a negative displacement.                                          *
*                                                                             *
*                                                                             * 
*******************************************************************************
keynames    dc.w    key00-keyval
            dc.w    key01-keyval
            dc.w    key02-keyval
            dc.w    key03-keyval
            dc.w    key04-keyval
            dc.w    key05-keyval
            dc.w    key06-keyval
            dc.w    key07-keyval
            dc.w    key08-keyval
            dc.w    key09-keyval
            dc.w    key0a-keyval
            dc.w    key0b-keyval
            dc.w    key0c-keyval
            dc.w    key0d-keyval
            dc.w    -1
            dc.w    key0f-keyval
            dc.w    key10-keyval
            dc.w    key11-keyval
            dc.w    key12-keyval
            dc.w    key13-keyval
            dc.w    key14-keyval
            dc.w    key15-keyval
            dc.w    key16-keyval
            dc.w    key17-keyval
            dc.w    key18-keyval
            dc.w    key19-keyval
            dc.w    key1a-keyval
            dc.w    key1b-keyval
            dc.w    -1
            dc.w    key1d-keyval
            dc.w    key1e-keyval
            dc.w    key1f-keyval
            dc.w    key20-keyval
            dc.w    key21-keyval
            dc.w    key22-keyval
            dc.w    key23-keyval
            dc.w    key24-keyval
            dc.w    key25-keyval
            dc.w    key26-keyval
            dc.w    key27-keyval
            dc.w    key28-keyval
            dc.w    key29-keyval
            dc.w    key2a-keyval
            dc.w    -1
            dc.w    -1
            dc.w    key2d-keyval
            dc.w    key2e-keyval
            dc.w    key2f-keyval
            dc.w    -1
            dc.w    key31-keyval
            dc.w    key32-keyval
            dc.w    key33-keyval
            dc.w    key34-keyval
            dc.w    key35-keyval
            dc.w    key36-keyval
            dc.w    key37-keyval
            dc.w    key38-keyval
            dc.w    key39-keyval
            dc.w    key3a-keyval
            dc.w    -1
            dc.w    key3c-keyval
            dc.w    key3d-keyval
            dc.w    key3e-keyval
            dc.w    key3f-keyval
            dc.w    key40-keyval
            dc.w    key41-keyval
            dc.w    key42-keyval
            dc.w    key43-keyval
            dc.w    key44-keyval
            dc.w    key45-keyval
            dc.w    key46-keyval
            dc.w    -1
            dc.w    -1
            dc.w    -1
            dc.w    key4a-keyval
            dc.w    -1
            dc.w    key4c-keyval
            dc.w    key4d-keyval
            dc.w    key4e-keyval
            dc.w    key4f-keyval
            dc.w    key50-keyval
            dc.w    key51-keyval
            dc.w    key52-keyval
            dc.w    key53-keyval
            dc.w    key54-keyval
            dc.w    key55-keyval
            dc.w    key56-keyval
            dc.w    key57-keyval
            dc.w    key58-keyval
            dc.w    key59-keyval
            dc.w    -1
            dc.w    -1
            dc.w    -1
            dc.w    -1
            dc.w    -1
            dc.w    key5f-keyval
qualnames   dc.w    key60-keyval
            dc.w    key61-keyval
            dc.w    key62-keyval
            dc.w    key63-keyval
            dc.w    key64-keyval
            dc.w    key65-keyval
            dc.w    key66-keyval
keynamesend dc.w    key67-keyval

            public  create
            end
