        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

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

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


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

_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
        cmp.w   #waiting,d0                    ; state waiting?
        beq     .Waiting                       ; goto state waiting

        cmp.w   #selregion,d0                  ; state selregion?
        beq     .SelRegion                     ; goto state selregion

        cmp.w   #waitext,d0                    ; state waitext?
        beq     .WaitExt                       ; goto state waitext

        cmp.w   #selgfx,d0                     ; state selgfx?
        beq     .SelGfx                        ; goto state selgfx

        cmp.w   #waitgfx,d0                    ; state waitgfx?
        beq     .WaitGfx                       ; goto state waitgfx

        cmp.w   #pendsnap,d0
        beq     .PendSnap

        cmp.w   #inserting,d0                  ; state inserting?
        beq     .Insert                        ; don't mess with inserted chars

        bra     .EventHandled                  ; shouldn't happen

; ********************************************************
; State: Waiting
; 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  _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
; Actions     New state           Signal
; ~TQ         Waiting             cancel
; LCOM+IKEY   Inserting           insert
; TQ+LMB      SelRegion           start
; TQ+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
        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  _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

        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  #inserting,_state
        move.w  #insert,_action
        move.l  _insertsignal,d0               ; and insert
        bra     SignalTask


; *******************************************************
; State: SelRegion
; Actions     New state           Signal
; ~TQ         Waiting             cancel
; ~LMB+TQ     WaitExt
; MOVE        SelRegion           move
; RMB+TQ      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.w  ie_Qualifier(a1),d0
        and.w   _textqual,d0                   ; TQ?
        bne     .EventHandled                  ; Still down, continue

;Handle event ~TQ
        move.w  #noaction,_action              ; no action
        move.w  #waiting,_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

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

; Handle event ~LMB
        move.b  #IECLASS_NULL,ie_Class(a1)     ; Kill event
        move.w  #waitext,_state                ; state waitext
        bra     .EventHandled

.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
; 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.w  ie_Qualifier(a1),d0
        and.w   _textqual,d0                   ; TQ?
        bne     .EventHandled                  ; Still down, continue

;Handle event ~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

        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
; Actions     New state           Signal
; ~GQ         Waiting             cancel
; ~LMB+GQ     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.w  ie_Qualifier(a1),d0
        and.w   _gfxqual,d0                    ; TQ?
        bne     .EventHandled                  ; Still down, continue

;Handle event ~GQ
        move.w  #noaction,_action              ; no action
        move.w  #waiting,_state                ; state waiting
        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

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

; Handle event ~LMB
        move.b  #IECLASS_NULL,ie_Class(a1)     ; Kill event
        move.w  #waitgfx,_state                ; state waitext
        bra     .EventHandled

.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
        move.b  #IECLASS_NULL,ie_Class(a1)     ; Kill event
        bra     .EventHandled

; ***************************************************
; State WaitGfx
; 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.w  ie_Qualifier(a1),d0
        and.w   _gfxqual,d0                    ; GQ?
        bne     .EventHandled                  ; Still down, continue

;Handle event ~TQ
        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

        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

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


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

        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
