        include "exec/types.i"
        include "exec/lists.i"
        include "devices/inputevent.i"

waiting   equ 0
selregion equ 1
waitext   equ 2
selgfx    equ 3
waitgfx   equ 4
inserting equ 5
pendsnap  equ 6
killbutt  equ 7

noaction  equ 0
snapgfx   equ 1
snaptext  equ 2
snapinit  equ 3
insert    equ 4
cancel    equ 5

LMB       equ IECODE_LBUTTON
LMB_UP    equ IECODE_UP_PREFIX+IECODE_LBUTTON
RMB       equ IECODE_RBUTTON
RMB_UP    equ IECODE_UP_PREFIX+IECODE_RBUTTON
NO_BUTT   equ IECODE_NOBUTTON
LCOM      equ IEQUALIFIER_LCOMMAND
SHIFT     equ IEQUALIFIER_LSHIFT+IEQUALIFIER_RSHIFT


        XDEF    _myhandler
        XREF    _geta4
        XREF    _LVOSignal
        XREF    _SysBase
        XREF    _MyTask
        XREF    _action
        XREF    _state
        XREF    _modinsert
        XREF    _startsignal
        XREF    _insertsignal
        XREF    _cancelsignal
        XREF    _donesignal
        XREF    _movesignal
        XREF    _clicksignal
        XREF    _timersignal
        XREF    _initsignal
        XREF    _cwsignal
        XREF    _textqual                      ; qualifier for snapping text
        XREF    _gfxqual                       ;    -"-    -"-   -"-    gfx
        XREF    _insertkey
        XREF    _cwkey

        SECTION CODE

_myhandler:

; On entry: a0 : Pointer to event list
;           a1 : Pointer to data

; In loop:  a1 : Pointer to event
;           d0 : scratch

; Result:   d0 : New event list

        movem.l a4,-(sp)

        jsr     _geta4                         ; Get offset base a4

        move.l  a0,a1                          ; a1 = Event list = a0

.nextevent
        cmpa.l  #0,a1                          ; Check for end of list
        beq     .done

        cmp.w   #noaction,_action              ; forced noaction - cancel
        bne     .notcanceled                   ; no, we're in action
        move.w  #waiting,_state                ; no action -> wait state
        bra     .dostate
.notcanceled
        cmp.w   #insert,_action                ; forced insert - cancel
        bne     .dostate                       ; no
        move.w  #inserting,_state              ; set correct state

.dostate
        move.w  _state,d0
        asl.w   #1,d0
        move.w  JumpTable(pc,d0.w),d0
Origin
        jmp     0(pc,d0.w)
JumpTable
        dc.w    .Waiting-Origin-2
        dc.w    .SelRegion-Origin-2
        dc.w    .WaitExt-Origin-2
        dc.w    .SelGfx-Origin-2
        dc.w    .WaitGfx-Origin-2
        dc.w    .Insert-Origin-2
        dc.w    .PendSnap-Origin-2
        dc.w    .CancelTxt-Origin-2

; ********************************************************
; State: Waiting    ~TQ
; Actions     New state             Signal
; TQ          PendSnap              init
; LMB+GQ      SelGfx                init+start
; LCOM+IKEY   Inserting             insert

.Waiting
        cmp.b   #IECLASS_RAWKEY,ie_Class(a1)   ; Is it RAWKEY?
        bne     .wait_RAWMOUSE

        move.w  ie_Qualifier(a1),d0
        and.w   _textqual,d0                   ; TQ?
        bne     .signalinit                    ; Yes -- init

        move.w  ie_Qualifier(a1),d0
        and.w   #LCOM,d0                       ; LCOM?
        beq     .EventHandled                  ; No

        move.w  _cwkey,d0                      ; Control window key
        cmp.w   ie_Code(a1),d0
        beq     .signalcw

        move.w  _insertkey,d0
        beq     .EventHandled                  ; Key = 0 -- disabled

        cmp.w   ie_Code(a1),d0                 ; The insert key?
        bne     .EventHandled                  ; No, pass it on
        bra     .signalinsert                  ; Tell'em to insert

.wait_RAWMOUSE
        cmp.b   #IECLASS_RAWMOUSE,ie_Class(a1) ; Is it RAWMOUSE?
        bne     .EventHandled                  ; Nope, pass it on

        move.w  ie_Qualifier(a1),d0
        and.w   _textqual,d0                   ; TQ?
        bne     .signalinit                    ; Yes

        cmp.w   #LMB,ie_Code(a1)               ; OK, is it SELECTDOWN?
        bne     .EventHandled                  ; Too bad

        move.w  ie_Qualifier(a1),d0
        and.w   _gfxqual,d0                    ; GQ?
        beq     .EventHandled                  ; No, not interested

; Handle event LMB+GQ
        move.b  #IECLASS_NULL,ie_Class(a1)     ; Kill event
        move.w  #snapgfx,_action               ; action snapgfx;
        move.w  #selgfx,_state                 ; state selgfx
        move.l  _initsignal,d0                 ; Signal init and
        or.l    _startsignal,d0                ; start
        bra     SignalTask

.signalinit
        move.w  #pendsnap,_state
        move.w  #snapinit,_action
        move.l  _initsignal,d0                 ; Signal start
        bsr     Signal
        bra     .PendSnap


; *******************************************************
; State: PendSnap   TQ
; Actions     New state           Signal
; ~TQ         Waiting             cancel
; LCOM+IKEY   Inserting           insert
; LMB         SelRegion           start
; RMB         Inserting           insert

.PendSnap
        cmp.b   #IECLASS_RAWKEY,ie_Class(a1)   ; RAWKEY?
        bne     .ps_RAWMOUSE
        move.w  ie_Qualifier(a1),d0
        and.w   _textqual,d0                   ; TQ?
        bne     .ps_IKEY                       ; Still down, continue

;Handle event ~TQ
.ps_TQ
        move.w  #noaction,_action              ; no action
        move.w  #waiting,_state                ; state waiting
        move.l  _cancelsignal,d0               ; snap cancelled
        bra     SignalTask

.ps_IKEY
        move.w  ie_Qualifier(a1),d0
        and.w   #LCOM,d0                       ; LCOM?
        beq     .EventHandled                  ; No

        move.w  _cwkey,d0                      ; Control window key
        cmp.w   ie_Code(a1),d0
        beq     .signalcw

        move.w  _insertkey,d0
        beq     .EventHandled                  ; Key = 0 -- disabled

        cmp.w   ie_Code(a1),d0                 ; The insert key?
        bne     .EventHandled                  ; No, pass it on
        bra     .signalinsert                  ; Tell'em to insert

.ps_RAWMOUSE
        cmp.b   #IECLASS_RAWMOUSE,ie_Class(a1) ; Is it RAWMOUSE?
        bne     .EventHandled                  ; Nope, pass it on

        move.w  ie_Qualifier(a1),d0            ; Might be TQ going up.
        and.w   _textqual,d0                   ; TQ?
        beq     .ps_TQ

        cmp.w   #LMB,ie_Code(a1)               ; OK, is it SELECTDOWN?
        bne     .ps_RMB                        ; Too bad

; Handle event LMB+TQ
        move.b  #IECLASS_NULL,ie_Class(a1)     ; Kill event
        move.w  #snaptext,_action              ; action snaptext
        move.w  #selregion,_state              ; state selregion
        move.l  _startsignal,d0                ; start
        bra     SignalTask

.ps_RMB
        cmp.w   #RMB,ie_Code(a1)               ; MENUDOWN
        bne     .EventHandled

; Handle event RMB+TQ
.signalinsert
        move.b  #IECLASS_NULL,ie_Class(a1)     ; Kill event

        move.w  #0,_modinsert
        move.w  ie_Qualifier(a1),d0
        and.w   #SHIFT,d0                      ; SHIFT?
        beq     .NonModified                   ; No
        move.w  #1,_modinsert
.NonModified
        move.w  #insert,_action
        move.w  #inserting,_state
        move.l  _insertsignal,d0               ; and insert
        bra     SignalTask

.signalcw
        move.b  #IECLASS_NULL,ie_Class(a1)     ; Kill event
        move.w  #noaction,_action
        move.w  #waiting,_state
        move.l  _cancelsignal,d0               ; Exit pending snap
        or.l    _cwsignal,d0                   ; and tell'em to open window
        bra     SignalTask


; *******************************************************
; State: SelRegion  LMB+TQ
; Actions     New state           Signal
; ~TQ         Waiting             cancel
; ~LMB        WaitExt
; MOVE        SelRegion           move
; RMB         SelRegion           click
; ~RMB        SelRegion                      Needs no action
; TIMER       SelRegion           timer

.SelRegion
        cmp.b   #IECLASS_TIMER,ie_Class(a1)    ; Timer event?
        bne     .sr_RAWKEY

;Handle timer event
        move.l  _timersignal,d0
        bra     SignalTask

.sr_RAWKEY
        cmp.b   #IECLASS_RAWKEY,ie_Class(a1)   ; RAWKEY?
        bne     .sr_LMB_UP
        move.b  #IECLASS_NULL,ie_Class(a1)     ; Kill event
        move.w  ie_Qualifier(a1),d0
        and.w   _textqual,d0                   ; TQ?
        bne     .EventHandled                  ; Still down, continue

;Handle event ~TQ
.sr_TQ
        move.w  #cancel,_action                ; no action
        move.w  #killbutt,_state              ; state waiting
        move.l  _cancelsignal,d0               ; snap cancelled
        bra     SignalTask

.sr_LMB_UP
        cmp.b   #IECLASS_RAWMOUSE,ie_Class(a1) ; Is it RAWMOUSE?
        bne     .EventHandled                  ; Nope, pass it on

        move.w  ie_Qualifier(a1),d0            ; Might be TQ going up.
        and.w   _textqual,d0                   ; TQ?
        beq     .sr_TQ

        cmp.w   #LMB_UP,ie_Code(a1)            ; SELECTUP
        bne     .sr_MOVE                       ; no, check for move

; Handle event ~LMB
        move.w  #waitext,_state                ; state waitext
        bra     KillEvent

.sr_MOVE
        cmp.w   #NO_BUTT,ie_Code(a1)           ; MOVE
        bne     .sr_RMB                        ; No, check for RMB
        move.w  ie_Qualifier(a1),d0
        and.w   #IEQUALIFIER_RELATIVEMOUSE,d0  ; RELATIVEMOUSE
        beq     .sr_RMB

; Handle event MOVE
        move.l  _movesignal,d0
        bra     SignalTask

.sr_RMB
        cmp.w   #RMB,ie_Code(a1)               ; MENUDOWN
        bne     .EventHandled                  ; No, not interested

; Handle event RMB
        move.b  #IECLASS_NULL,ie_Class(a1)     ; Kill event
        move.l  _clicksignal,d0
        bra     SignalTask

; ***************************************************
; State WaitExt     TQ
; Actions     New state           Signal
; ~TQ         Waiting             done
; LMB         SelRegion           click
; MOVE        WaitExt                            No action needed.
; RMB         Inserting           done & insert
; TIMER       WaitExt             timer

.WaitExt
        cmp.b   #IECLASS_TIMER,ie_Class(a1)    ; Timer event?
        bne     .we_RAWKEY

;Handle timer event
        move.l  _timersignal,d0
        bra     SignalTask

.we_RAWKEY
        cmp.b   #IECLASS_RAWKEY,ie_Class(a1)   ; RAWKEY?
        bne     .we_LMB
        move.b  #IECLASS_NULL,ie_Class(a1)     ; Kill event
        move.w  ie_Qualifier(a1),d0
        and.w   _textqual,d0                   ; TQ?
        bne     .EventHandled                  ; Still down, continue

;Handle event ~TQ
.we_TQ
        move.w  #noaction,_action              ; no action
        move.w  #waiting,_state                ; state waiting
        move.l  _donesignal,d0                 ; snap finished
        bra     SignalTask

.we_LMB
        cmp.b   #IECLASS_RAWMOUSE,ie_Class(a1) ; Is it RAWMOUSE?
        bne     .EventHandled                  ; Nope, pass it on

        move.w  ie_Qualifier(a1),d0            ; Might be TQ going up.
        and.w   _textqual,d0                   ; TQ?
        beq     .we_TQ                         ; No.

        cmp.w   #LMB,ie_Code(a1)               ; SELECTDOWN
        bne     .we_RMB                        ; no, check for RMB

; Handle event LMB
        move.b  #IECLASS_NULL,ie_Class(a1)     ; Kill event
        move.w  #selregion,_state              ; state waitext
        move.l  _clicksignal,d0                ; Extend selection
        bra     SignalTask

.we_RMB
        cmp.w   #RMB,ie_Code(a1)               ; MENUDOWN
        bne     .EventHandled                  ; No, not interested

; Handle event RMB
        move.b  #IECLASS_NULL,ie_Class(a1)     ; Kill event
        move.w  #insert,_action
        move.w  #inserting,_state
        move.l  _donesignal,d0
        or.l    _insertsignal,d0
        bra     SignalTask

; *******************************************************
; State: SelGfx     LMB+GQ
; Actions     New state           Signal
; ~GQ         Waiting             cancel
; ~LMB        WaitGfx
; MOVE        SelGfx              move
; TIMER       SelGfx              timer
; RMB         SelGfx                        removed

.SelGfx
        cmp.b   #IECLASS_TIMER,ie_Class(a1)    ; Timer event?
        bne     .sg_RAWKEY

;Handle timer event
        move.l  _timersignal,d0
        bra     SignalTask

.sg_RAWKEY
        cmp.b   #IECLASS_RAWKEY,ie_Class(a1)   ; RAWKEY?
        bne     .sg_LMB_UP
        move.b  #IECLASS_NULL,ie_Class(a1)     ; Kill event
        move.w  ie_Qualifier(a1),d0
        and.w   _gfxqual,d0                    ; GQ?
        bne     .EventHandled                  ; Still down, continue

;Handle event ~GQ
.sg_GQ
        move.w  #cancel,_action                ; cancelling snap
        move.w  #killbutt,_state               ; Kill obsolete button
        move.l  _cancelsignal,d0               ; snap cancelled
        bra     SignalTask

.sg_LMB_UP
        cmp.b   #IECLASS_RAWMOUSE,ie_Class(a1) ; Is it RAWMOUSE?
        bne     .EventHandled                  ; Nope, pass it on

        move.w  ie_Qualifier(a1),d0            ; Might be GQ going up.
        and.w   _gfxqual,d0                    ; GQ?
        beq     .sg_GQ

        cmp.w   #LMB_UP,ie_Code(a1)            ; SELECTUP
        bne     .sg_MOVE                       ; no, check for move

; Handle event ~LMB
        move.w  #waitgfx,_state                ; state waitext
        bra     KillEvent

.sg_MOVE
        cmp.w   #NO_BUTT,ie_Code(a1)           ; MOVE
        bne     .EventHandled                  ; No, check for RMB
        move.w  ie_Qualifier(a1),d0
        and.w   #IEQUALIFIER_RELATIVEMOUSE,d0  ; RELATIVEMOUSE
        beq     .EventHandled

; Handle event MOVE
        move.l  _movesignal,d0
        bra     SignalTask

.sg_RMB
        bra     KillEvent

; ***************************************************
; State WaitGfx     GQ
; Actions     New state           Signal
; ~GQ         Waiting             done
; LMB         SelGfx              click
; MOVE        WaitGfx                            No action needed.
; TIMER       WaitGfx             timer
; RMB         WaitGfx             --             remove event

.WaitGfx
        cmp.b   #IECLASS_TIMER,ie_Class(a1)    ; Timer event?
        bne     .wg_RAWKEY

;Handle timer event
        move.l  _timersignal,d0
        bra     SignalTask

.wg_RAWKEY
        cmp.b   #IECLASS_RAWKEY,ie_Class(a1)   ; RAWKEY?
        bne     .wg_LMB
        move.b  #IECLASS_NULL,ie_Class(a1)     ; Kill event
        move.w  ie_Qualifier(a1),d0
        and.w   _gfxqual,d0                    ; GQ?
        bne     .EventHandled                  ; Still down, continue

;Handle event ~GQ
.wg_GQ
        move.w  #noaction,_action              ; no action
        move.w  #waiting,_state                ; state waiting
        move.l  _donesignal,d0                 ; snap finished
        bra     SignalTask

.wg_LMB
        cmp.b   #IECLASS_RAWMOUSE,ie_Class(a1) ; Is it RAWMOUSE?
        bne     .EventHandled                  ; Nope, pass it on

        move.w  ie_Qualifier(a1),d0            ; Might be GQ going up
        and.w   _gfxqual,d0                    ; GQ?
        beq     .wg_GQ

        cmp.w   #LMB,ie_Code(a1)               ; SELECTDOWN
        bne     .wg_RMB                          ; no -- finished

; Handle event LMB
        move.b  #IECLASS_NULL,ie_Class(a1)     ; Kill event
        move.w  #selgfx,_state                 ; state waitext
        move.l  _clicksignal,d0                ; Extend selection
        bra     SignalTask

.wg_RMB
        cmp.w   #NO_BUTT,ie_Code(a1)           ; Any button?
        beq     .EventHandled                  ; No, moves are ok

        bra     KillEvent


; ***************************************************
; State CancelTxt
; Make sure that the Button Up event that we've got
; hanging around doesn't get through.

.CancelTxt
        cmp.b   #IECLASS_RAWMOUSE,ie_Class(a1) ; Is it RAWMOUSE?
        bne     .EventHandled                  ; Nope, just pass it on

        cmp.w   #LMB_UP,ie_Code(a1)            ; The button?
        bne     .EventHandled                  ; No

        move.w  #noaction,_action
        move.w  #waiting,_state
        bra     KillEvent

; ***************************************************
; State Insert
; Snap actions are removed, the rest are passed along.

.Insert
        cmp.b   #IECLASS_RAWMOUSE,ie_Class(a1) ; Is it RAWMOUSE?
        bne     .EventHandled                  ; Nope, pass it on

        cmp.w   #LMB,ie_Code(a1)               ; Left mouse button
        bne     .insert_TQ                     ; No -- just kill

        move.w  #noaction,_action              ; Cancel paste

.insert_TQ
        move.w  ie_Qualifier(a1),d0
        and.w   _textqual,d0                   ; TQ?
        beq     .EventHandled                  ; no

        cmp.w   #NO_BUTT,ie_Code(a1)           ; Any button?
        beq     .EventHandled                  ; No, moves are ok

KillEvent:
        move.b  #IECLASS_NULL,ie_Class(a1)     ; Kill event
        bra     .EventHandled

SignalTask:
        bsr     Signal

.EventHandled
        move.l  ie_NextEvent(a1),a1             ; Get next event
        bra     .nextevent

.done
        movem.l (sp)+,a4
        move.l  a0,d0
        rts

Signal:
        movem.l a0-a2/a6,-(sp)
        move.l  _MyTask,a1
        move.l  _SysBase,a6                     ;  Get ExecBase for Signal
        jsr     _LVOSignal(a6)
        movem.l (sp)+,a0-a2/a6
        rts

        end
