IN    -
OUT   ExtraKeys
TYPE  Module

DEFINE MODULE
  Name     : ExtraKeys
  Version  : 1.07
  Date     : 24 Jun 1995
  Author   : Justin Fletcher
  Help     : Extra keys
  Init     : initialise
  Final    : finalise
  Commands
    Name   : ExtraKeys
    Help   : ...
     ExtraKeys provides some extra control key presses for snazzyness!|M
       Use : Alt-Q for our address!|M
             Alt-D for the current date|M
             Alt-T for the current time|M
             Alt-. for 
             Alt-' for double quotes (curly)|M
             Alt-"" for single quotes (curly)|M
     The use of the quotes in reverse order is because the author uses the
     double quote variety more frequently than the single quotes. The date
     and time codes will give fixed length results without shift, and the
     more usual written results if shift is held.
  End Commands
END MODULE

{ The code contained here in is totally trustworthy, not!
  No, seriously, it should work very well and I have as yet had no
  problems with it.

  DISCLAIMER
  ==========
  The author accepts no responsibility for this modules activities, and does
  not guarentee its suitablity for any specific purpose. The module may not
  be copied without this source code file.

  MAKING THIS CODE
  ================
  This code requires the !JFPatch pre-assembler to make the code. This is a
  simple text-to-basic assembler which takes a text assembler file, makes a
  basic program from it to assemble, assembles it and returns any errors.
  Currently, it is under development and requires a lot of work before it
  will be released in any form. As such, this file is mostly useless, but
  must be distributed with the resultant module.

  ALTERATIONS
  ===========
  The only alterations the author will allow are to the address on Alt-Q.
  This module may be altered, either at the end of the program, or physically
  in the module. If altering directly, the last byte must be 2 and any
  snazzy characters, ie top bit set, must be preceeded by a 0 byte.

Contact
-------
Any comments, queries, donations or bug reports can be sent to :

Fidonet NetMail :  Justin Fletcher at Arcade (0181 655 4412) [2:254/27]
E-Mail : Gerph@arcade.demon.co.uk

Snail Mail :
    Justin Fletcher
    Galadriel
    17b Cromwell Road,
    Weeting,
    Brandon,
    Suffolk.
    IP27 0QT

}

.initialise
    STMFD   (sp)!,{link}
    BL      doclaim
    LDMFD   (sp)!,{pc}

.doclaim
    STMFD   (sp)!,{r0-r2,link}
    MOV     r2,#0                 ; r12 will be 0 on entry to routines
    MOV     r0,#&10               ; vector &10 - key press/release
    ADR     r1,keypvector%        ; to be processed at keypvector%
    BL      claimvector%
    MOV     r0,#&14               ; vector &14 - insert vector
    ADR     r1,insvector%         ; to be processed at keypvector%
    BL      claimvector%
    MOV     r0,#&0E
    MOV     r1,#&0B
    SWI     "XOS_Byte"            ; enable keypress vector
    MOV     r0,#0
    STRB    r0,doingnow
    LDMFD   (sp)!,{r0-r2,pc}^

.finalise
    STMFD   (sp)!,{r0-r2,link}
    MOV     r0,#&0D
    MOV     r1,#&0B
    SWI     "XOS_Byte"            ; disable keypress vector
    MOV     r2,#0
    MOV     r0,#&10               ; keypress vector
    ADR     r1,keypvector%
    BL      releasevector%
    MOV     r0,#&14               ; insert vector
    ADR     r1,insvector%
    BL      releasevector%
    LDMFD   (sp)!,{r0-r2,pc}^

.claimvector%
    STMFD   (sp)!,{r2,link}
    BL      releasevector%
    MOV     r2,#0
    SWI     "XOS_Claim"
    LDMFD   (sp)!,{r2,pc}^

.releasevector%
    STMFD   (sp)!,{r0-r2,link}
.retryrelease%
    LDMFD   r13,{r0,r1}
    MOV     r2,#0
    SWI     "XOS_Release"
    BVC     retryrelease%
    CMP     pc,#0
    LDMFD   (sp)!,{r0-r2,pc}^

.keypvector%
    CMP    r0,#&0B                  ; is this a keypress ?
    MOVNE  pc,link                  ; if not exit
    STMFD  (sp)!,{r0-r2,r4,r5,link} ; stack regs
    BL     setkeypressed
    BL     setshiftflag
    CMP    r5,#0           ; did we process a key ?
    CMPNE  r1,#0           ; was this a key release ?
    BEQ    exitvector      ; if so exit
    LDRB   r0,laltkey      ; what is state of left alt key ?
    CMP    r0,#0           ; if not pressed
    LDREQB r0,raltkey      ; what is state of right alt key ?
    CMPEQ  r0,#0           ; if not pressed (ie both not pressed
    BEQ    exitvector      ; then exit
:
    LDRB   r0,openquote    ; what is state of open quote ?
    CMP    r0,#1           ; if pressed
    BEQ    wasopenquote    ; jump to wasopenquote
    LDRB   r0,address      ; what is state of address ?
    CMP    r0,#1           ; if pressed
    BEQ    wasaddress      ; jump to wasaddress
    LDRB   r0,date         ; what is state of date ?
    CMP    r0,#1           ; if pressed
    BEQ    wasdate         ; jump to wasdate
    LDRB   r0,time         ; what is state of time ?
    CMP    r0,#1           ; if pressed
    BEQ    wastime         ; jump to wastime
    LDRB   r0,dot          ; what is state of dot ?
    CMP    r0,#1           ; if pressed
    BEQ    wasdot          ; jump to wasdot
.exitvector
    LDMFD  (sp)!,{r0-r2,r4,r5,pc}^  ; and exit
:
.setkeypressed
;    MOV    r5,#&7000
;    STR    r2,[r5]        ; for testing the numbers
    MOV    r5,#0
    CMP    r2,#&60         ; is this right alt ?
    STREQB r1,raltkey      ; if so then set its state
    MOVEQ  r5,#1           ; Set the "we've processed a key" flag
    CMP    r2,#&5E         ; how about left alt ?
    STREQB r1,laltkey      ; set its state if so
    MOVEQ  r5,#1           ; Set the "we've processed a key" flag
    CMP    r2,#88          ; what about right shift
    STREQB r1,rshift       ; store state ...
    MOVEQ  r5,#1           ; Set the "we've processed a key" flag
    CMP    r2,#76          ; and left shift
    STREQB r1,lshift       ; and its state.
    MOVEQ  r5,#1           ; Set the "we've processed a key" flag
    CMP    r2,#70          ; is this '" ?
    STREQB r1,openquote    ; set open quote if so
    MOVEQ  r5,#1           ; Set the "we've processed a key" flag
    CMP    r2,#39          ; is this Q ?
    STREQB r1,address      ; set address if so
    MOVEQ  r5,#1           ; Set the "we've processed a key" flag
    CMP    r2,#62          ; is this D ?
    STREQB r1,date         ; set date if so
    MOVEQ  r5,#1           ; Set the "we've processed a key" flag
    CMP    r2,#43          ; is this T ?
    STREQB r1,time         ; set time if so
    MOVEQ  r5,#1           ; Set the "we've processed a key" flag
    CMP    r2,#86          ; is this full stop ?
    STREQB r1,dot          ; set time if so
    MOVEQ  r5,#1           ; Set the "we've processed a key" flag
    MOV    pc,link
:
.setshiftflag
    LDRB   r0,lshift
    CMP    r0,#0
    LDREQB r0,rshift
    CMPEQ  r0,#0
    MOVEQ  r4,#0         ; r4=0 if no shift
    MOVNE  r4,#1         ; r4=1 if either shift
    MOV    pc,link

.wasopenquote
    ADD    r5,r4,#1            ; r5=1 for no shift, 2 for a shift
    LDRB   r2,lastqstate
    EOR    r2,r2,r5            ; invert the state of the quotes
    STRB   r2,lastqstate       ; and store it again
    AND    r2,r2,r5            ; leave just the interesting bit
    MOV    r2,r2,LSR r4        ; and move it down
    ADD    r2,r2,#148          ; add its offset to quote
    SUB    r2,r2,r4,LSL #2     ; subtact the shift so that we get
    ADR    r1,insertcode
    B      setupjump
.wasaddress
    ADR    r1,addresscode
    B      setupjump
.wasdate
    MOV    r2,#0          ; a date
    STRB   r4,shiftstate
    ADR    r1,datecode
    B      setupjump

.wastime
    MOV    r2,#1          ; a time
    STRB   r4,shiftstate
    ADR    r1,datecode
    B      setupjump
:
.wasdot
    CMP    r4,#1          ; was shift pressed ?
    BEQ    exitvector     ; if so then exit - ie allow 
    ADR    r1,dotcode
    B      setupjump
:
; Code to insert things into buffer
.insertcode
    STMFD  (sp)!,{r0-r9,link}
    MOV    r0,#4
    STRB   r0,ignorekeys
    MOV    r0,#153
    MOV    r1,#0
    MOV    r2,#0
    SWI    "XOS_Byte"
    MOV    r0,#153
    MOV    r1,#0
    MOV    r2,r12
    SWI    "XOS_Byte"
:
    MOV    r0,#0
    STRB   r0,doingnow         ; no longer doing
    LDMFD  (sp)!,{r0-r9,pc}^
:
; Insert ... into buffer
.dotcode
    STMFD  (sp)!,{r0-r9,link}
    MOV    r0,#4
    STRB   r0,ignorekeys
    MOV    r0,#153
    MOV    r1,#0
    MOV    r2,#0
    SWI    "XOS_Byte"
    MOV    r0,#153
    MOV    r1,#0
    MOV    r2,#ASC("")
    SWI    "XOS_Byte"
:
    MOV    r0,#0
    STRB   r0,doingnow         ; no longer doing
    LDMFD  (sp)!,{r0-r9,pc}^

:
; Code to insert the address into buffer
.addresscode
    STMFD  (sp)!,{r0-r9,link}
    MOV    r4,#2               ; 2 for end of text
    ADR    r6,addressstr
    BL     insertstring
    MOV    r0,#0
    STRB   r0,doingnow         ; no longer doing
    LDMFD  (sp)!,{r0-r9,pc}^
:
; Code to insert the date into buffer
.datecode
    STMFD  (sp)!,{r0-r9,link}
    ADR    r1,dateblock         ; block to read time into
    MOV    r0,#3                ; code 3 - read time in cs
    STR    r0,[r1]
    MOV    r0,#14               ; code to read time
    SWI    "OS_Word"            ; read time
    CMP    r12,#1               ; was this a time ?
    BEQ    maskfortime
; for dates
    LDRB   r3,shiftstate
    CMP    r3,#1                ; was shift pressed
    ADREQ  r3,datelong          ; yes, long date encoding
    LADRNE r3,dateshort         ; no, short date encoding
    B      processstring
.maskfortime
    LDRB   r3,shiftstate
    CMP    r3,#1                ; was shift pressed
    LADREQ r3,timelong          ; yes, long time encoding
    LADRNE r3,timeshort         ; no, short time encoding
.processstring
    ADR    r1,datestr           ; buffer for string
    ADR    r0,dateblock         ; r0->date in cs
    MOV    r2,#256              ; length of buffer
    SWI    "OS_ConvertDateAndTime"
    MOV    r4,#0                ; 0 for end of string
    ADR    r6,datestr
    BL     insertstring
    SUB    r5,r5,#2             ; r5=length-2
    SUB    r5,r5,r0
    STRB   r5,ignorekeys        ; store at number to ignore
    MOV    r0,#0
    STRB   r0,doingnow          ; no longer doing
    LDMFD  (sp)!,{r0-r9,pc}^

.insertstring
; > r6->string
;   r4=exit code
; < r5->last byte
    STMFD  (sp)!,{r0-r4,link}
    MOV    r5,#0
.insstrloop
    LDRB   r2,[r6,r5]
    CMP    r2,r4              ; is it r4 ? (exit code)
    BEQ    xinsertstring
    MOV    r0,#153
    MOV    r1,#0
    SWI    "XOS_Byte"
    ADD    r5,r5,#1
    B      insstrloop
.xinsertstring
    LDMFD  (sp)!,{r0-r4,pc}^
:
; set up call back code
.setupjump
    MOV     r5,pc
    BIC     r4,r5,#1
    TEQP    r4,#1                  ; set ? flag
    MOVNV   r0,r0
    LDRB    r0,doingnow
    TEQ     r0,#0
    BNE     alreadydoing
    MOV     r0,r1                  ; r0=address
    MOV     r1,r2
    STMFD   (sp)!,{link}
    SWI     "XOS_AddCallBack"
    LDMFD   (sp)!,{link}
    MOVVC   r0,#1
    STRVCB  r0,doingnow            ; set doing
.alreadydoing
    TEQP    r5,#0                  ; Restore state
    MOVNV   r0,r0
    LDMFD   (sp)!,{r0-r2,r4,r5,pc}
:
.insvector%
    STMFD   (sp)!,{r1-r7,link}
    LDRB    r7,ignorekeys
    CMP     r7,#0
    BEQ     xinsvector
    SUB     r7,r7,#1
    STRB    r7,ignorekeys   ; decrement and store counter
    LDRB    r7,last
    CMP     r7,#0
    CMPNE   r0,#ASC("^")
    BNE     xinsvector
    ADR     r7,swapfrom     ; swap ascii code table
    MOV     r5,#0           ; start at beginning
.insvloop
    LDRB    r4,[r7,r5]      ; get the code
    CMP     r4,#0           ; is code =0
    BEQ     xinsvector      ; if no more then exit
    CMP     r0,r4           ; compare
    BEQ     insdoswap       ; if the same then jump to doswap
    ADD     r5,r5,#1
    B       insvloop
.insdoswap
    ADR     r6,swapto       ; addr of codes to swap to
    LDR     r0,[r6,r5]
    CMP     r0,#0
.xinsvector
    STRB    r0,last
    LDMFD   (sp)!,{r1-r7,pc}
:

; Variables
.dateblock :EQUD 0:EQUD 0   ; time in cs
.datelong  :EQUS "%ZDY%ST %MO %CE%YR"+CHR$0
.dateshort :EQUS "%DY %M3 %CE%YR"+CHR$0
.timelong  :EQUS "%Z12:%MI %pm"+CHR$0
.timeshort :EQUS "%24:%MI.%SE"+CHR$0
    ALIGN
.datestr
    RES    256

.doingnow  :EQUB 0
.laltkey   :EQUB 0
.raltkey   :EQUB 0
.lshift    :EQUB 0
.rshift    :EQUB 0
.openquote :EQUB 0
.address   :EQUB 0
.date      :EQUB 0
.time      :EQUB 0
.dot       :EQUB 0
.lastqstate:EQUB 3
.ignorekeys:EQUB 0
.shiftstate:EQUB 0
    ALIGN
.swapfrom  :EQUS "^ʅ"
            EQUS ""
            EQUB 0
    ALIGN
.swapto    :EQUS " weyuioaWEYUIOAAa "
            EQUS CHR$0+CHR$0
            EQUB 0
.last      :EQUB 0
    ALIGN
.addressstr:EQUS "Eddington 9/5"+CHR$13
           :EQUS "University of Essex,"+CHR$13
           :EQUS "Wivenhoe Park,"+CHR$13
           :EQUS "Colchester,"+CHR$13
           :EQUS "Essex."+CHR$13
           :EQUS "CO4 3SQ"+CHR$13
           :EQUB 2
# POST
# RUN <CODE>
