(*--------------------------------------------------------------------------
    :Program.       Events
    :Contents.      Anzeige von Events
    :Author.        D.-I. Hiter Vinzenz
    :Copyright.     Public Domain
    :Language.      Modula-2
    :Translator.    M2Amiga 3.2 d
    :History.       V 1.0
    :Support.       Handler von 'ShowInputEvents' von AMOK #1
---------------------------------------------------------------------------*)

(******************************************************************************
 *              Programm               |              Author                  *
 *  ---------------------------------  |  ----------------------------------  *
 *  Modul:      Events                 |  Name:       D.-I. Hiter Vinzenz     *
 *  Typ:        Projekt                |  Adresse:    Petri Au 20,            *
 *  Version:    V 1.0                  |              A-8042 Graz             *
 *  Datum:      03.12.1989             |  Telefon:    (0)316/44 83 13         *
 *  Inhalt:     Anzeige von Events     |                                      *
 *  Copyright:  Public Domain          |                                      *
 *                                     |                                      *
 *-------------------------------------+--------------------------------------*
 *        Programmierumgebung          |          Rechnerumgebung             *
 *  ---------------------------------  |  ----------------------------------  *
 *  Sprache:    ETH Modula-2           |  Hardware:   Commodore AMIGA 500     *
 *  System:     M2Amiga c AMSoft       |  Kickstart:  V 1.2                   *
 *  Compiler:   M2C V 3.2d             |  AmigaDos:   V 1.2                   *
 *  Linker:     M2L V 3.2d             |  Workbench:  V 1.3                   *
 *                                     |                                      *
 *----------------------------------------------------------------------------*
 *  Historie: keine                                                           *
 *----------------------------------------------------------------------------*
 *  Imports:  EventWind (Projekt)                                             *
 *----------------------------------------------------------------------------*
 *  Inhalt:                                                                   *
 *  Events vom Inputdevice werden in grafischer Form angezeigt.               *
 *  Dazu wird ein Inputhandler ins Inputdevice eingehängt. Die Priorität      *
 *  kann durch die Tasten 1, 2, 3 geändert werden.                            *
 *----------------------------------------------------------------------------*
 *                                                                            *
 *  Prozeduren:                                                               *
 *  ------------------------------------------------------------------------  *
 *                                                                            *
 ******************************************************************************)
(*.pa*)
MODULE Events;
(*---------------------- Import aus Standardbibliothek -----------------------*)

FROM SYSTEM      IMPORT ADR, ADDRESS, SETREG, REG, SHIFT, LONGSET, CAST;
FROM Arts        IMPORT Assert, TermProcedure;

(*---------------------- Import aus Amigabibliothek --------------------------*)
FROM Dos         IMPORT Delay;
FROM Exec        IMPORT MsgPortPtr, IOStdReq, Interrupt, MemEntry, Forbid,
                        Permit, IOStdReqPtr, OpenDevice, CloseDevice, DoIO,
                        Disable, Enable,
                        Wait, FindTask, AllocSignal, FreeSignal, Signal, TaskPtr;

FROM ExecSupport IMPORT CreatePort, DeletePort, CreateStdIO, DeleteStdIO;
FROM Input       IMPORT inputName, addHandler, remHandler;
FROM InputEvent  IMPORT InputEvent, InputEventPtr, Class, Qualifiers,
                        QualifierSet;

(*---------------------- Import aus eigener Bibliothek -----------------------*)
FROM EventWind   IMPORT EnterInputEvent, SelectPriority;

(*---------------------- globale Definitionen --------------------------------*)

CONST
  QuitKey     = 069;     (* Esc Key down *)
  LowerPriKey =   1;
  IntuiPriKey =   2;
  HigerPriKey =   3;

VAR
   CopyEvent, OutPutEvent: InputEvent;
  InputDevPort: MsgPortPtr;
  InputRequestBlock: IOStdReqPtr;
  HandlerStuff: Interrupt;
  ownTask: TaskPtr;
  inputSignal: LONGINT;

(*.cp----------------------------------------------------------------------*)
(*                                                                         *)
(*                          Input  Handler:                                *)
(*                                                                         *)
(*-------------------------------------------------------------------------*)

(* It's Variables are global (don't know if allocating them scratches      *)
(* A0 or A1. Who knows ? Who's got a M2Amiga-Debugger ??? Or a even        *)
(* a Disassembler, like TDI's ?¿?                                          *)

VAR
  EV: InputEventPtr;
  Result: InputEventPtr;

PROCEDURE MyHandler();
(* That's my Input-Handler it receives 2 values, though in MODULA-2 it     *)
(* looks like a Procedure receiving and returning nothing. Anyway, there's *)
(* a Pointer returned:                                                     *)
(* A0: Pointer to EventChain the Handler should handle with.               *)
(* A1: This points to my MemEntries, i.e. contains HandlerStuff.date       *)
(* D0: Will contain the new Pointer to Eventlist or NIL if none.           *)

(* $S- This avoids checking Stack size. This Procedure gets another Stack  *)
(* than the main Programm !!                                               *)

BEGIN
  EV := ADDRESS(REG(8)); (* this gets InputEventList from A0 *)
    (* A1 is ignored here 'cause there no memory needed *)

  IF EV^.class = timer THEN
  (* this shouldn't be timer, 'cause there are too many TimerEvents (10/s) *)
    Result := NIL;
  ELSE
    Forbid();
  (* no Task switching. Else a half-changed Event could be printed *)
    CopyEvent := EV^;
    Permit();
    Signal (ownTask, LONGSET{inputSignal});
    Result := EV;
  END;
  SETREG(0,EV);
END MyHandler;

(*.cp----------------------------------------------------------------------*)
PROCEDURE CleanUp;
(*-------------------------------------------------------------------------*)

BEGIN
  IF InputRequestBlock # NIL THEN
    WITH InputRequestBlock^ DO
      command := remHandler;
      data := ADR(HandlerStuff);
    END;
    DoIO(InputRequestBlock);
    DeleteStdIO(InputRequestBlock);
  END;
  IF InputDevPort # NIL THEN  DeletePort(InputDevPort); END;
  IF inputSignal # 0 THEN FreeSignal (inputSignal); END;
END CleanUp;

(*.cp----------------------------------------------------------------------*)
PROCEDURE InitInputRequest (priority: INTEGER);
(*-------------------------------------------------------------------------*)

BEGIN
  InputDevPort      := NIL;
  InputRequestBlock := NIL;
  InputDevPort      := CreatePort (NIL,0);
  Assert(InputDevPort#NIL,ADR("CreatePort failed"));
  InputRequestBlock := CreateStdIO(InputDevPort);
  Assert(InputRequestBlock#NIL,ADR("CreateStdIO failed"));
  ownTask := FindTask (NIL);
  inputSignal := AllocSignal (-1);
  Assert (inputSignal # 0, ADR("AllocSignal failed"));
  WITH HandlerStuff DO
    data := NIL;             (* pointer to it's data (I don't have any)  *)
    code := ADR(MyHandler);  (* Thats my Handle-Procedure *)
    node.pri := priority;          (* Priority higher than Intuition's (50) *)
  END;
  OpenDevice(ADR(inputName),0,InputRequestBlock,LONGSET{});
  WITH InputRequestBlock^ DO
    command := addHandler;
    data := ADR(HandlerStuff);
  END;
  DoIO(InputRequestBlock);
END InitInputRequest;

(*.cp*)
TYPE ClassRememberSet     = SET OF Class;

VAR classRememberSet     : ClassRememberSet;
    qualifierRememberSet : QualifierSet;


(*.cp----------------------------------------------------------------------*)
PROCEDURE ProcessInputEvent (VAR inputEvent: InputEvent);
(*-------------------------------------------------------------------------*)

BEGIN
  INCL(classRememberSet,     inputEvent.class);
  qualifierRememberSet := qualifierRememberSet + inputEvent.qualifier;
END ProcessInputEvent;


TYPE SimpleEvents   = (LeftButtonPressed, RightButtonPressed,
                       JoyStickButtonPressed, KeyPressed);
     SimpleEventSet = SET OF SimpleEvents;

(*.cp----------------------------------------------------------------------*)
PROCEDURE SimpleEventOccurs (simpleEventSet: SimpleEventSet): BOOLEAN;
(*-------------------------------------------------------------------------*)
VAR eventFound: BOOLEAN;

BEGIN
  eventFound := FALSE;
  IF LeftButtonPressed IN simpleEventSet THEN
    IF rawmouse IN classRememberSet THEN
      EXCL(classRememberSet, rawmouse);
      IF leftButton IN qualifierRememberSet THEN
        eventFound := TRUE;
        EXCL(qualifierRememberSet, leftButton);
  END; END; END;
END SimpleEventOccurs;


(*.cp----------------------------------------------------------------------*)
(*                                                                         *)
(*           Main Programm (initialization, Printing and CleanUp)          *)
(*                                                                         *)
(*-------------------------------------------------------------------------*)

VAR
  receivedSignals: LONGSET;

  error : CARDINAL;
  oldsecs,oldmicro: LONGCARD;
  oldclass: Class;

BEGIN
  TermProcedure (CleanUp);
  InitInputRequest (50);
  WITH CopyEvent DO
    timeStamp.secs := 0;
    timeStamp.micro:= 0;
    class := null;
    oldsecs := 0;
    oldmicro := 0;
    oldclass := null;
  END;
  LOOP
    receivedSignals := Wait (LONGSET{inputSignal});
    WITH CopyEvent DO
      IF (class = rawkey) THEN
        CASE code OF
        | QuitKey: EXIT;
        | LowerPriKey: CleanUp; InitInputRequest (40); SelectPriority (1);
        | IntuiPriKey: CleanUp; InitInputRequest (50); SelectPriority (2);
        | HigerPriKey: CleanUp; InitInputRequest (60); SelectPriority (3);
        ELSE;
        END;
      END;
      IF (timeStamp.secs#oldsecs) OR (timeStamp.micro#oldmicro) OR
        (class#oldclass) THEN
        Disable(); (* this differs from Libraries&Devices Reference Manual *)
        (* the Handler is an Interrupt and can't be stopped with Forbid !  *)
        OutPutEvent := CopyEvent;
        Enable();
        WITH OutPutEvent DO;

          oldsecs := timeStamp.secs;
          oldmicro := timeStamp.micro;
          oldclass := class;
          EnterInputEvent (OutPutEvent);
        END;
      END; (* IF CopyEvent#old *)
    END;   (* WITH *)
  END;   (* LOOP *)
END Events.



