MODULE NoUmlaut;
(*$ StackChk:=FALSE LargeVars:=FALSE StackParms:=FALSE Volatile:=FALSE *)

(* 19.5.91 Bernd Preusing, AMSoft *)
(* 31.08.92/bp defaultToggle=ralt -capslock ß *)

(* Commodity, die
   ÄÖÜäöüß in Ae,Oe,Ue,ae,oe,ue,ss wandelt,
   Sie kann mittels "TOGGLE=ralt -capslock ß" ein- oder ausgeschaltet werden.

   CX_PRIORITY=0
   TOGGLE=ralt -capslock ß  (schaltet ACTIVE an/aus)
   ACTIVE=YES    (Aktiv beim Start?)
 *)

(* Nur die teile zwischen vvv und ^^^ ändern! *)

FROM SYSTEM	IMPORT	ADR,ADDRESS,CAST,BITSET,LONGSET,TAG;
FROM String	IMPORT	Compare;
FROM ExecSupport IMPORT	CreatePort, DeletePort;
IMPORT
   A:  Arts,
   DD:DosD,
   ED:ExecD,
   EL:ExecL,
   IE:InputEvent,
   CD:CommoditiesD,
   CL:CommoditiesL,
   CS:CommoditiesSupport;

CONST
  ver=ADR("$VER: NoUmlaut 4.2 (31.08.92) © Bernd Preusing\n\r");
  priorityToolType="CX_PRIORITY";
  toggleToolType="TOGGLE"; (* = ralt ß *)
  defaultToggle="ralt -capslock ß";
  activeToolType="ACTIVE"; (* =YES *)

  (* vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv *)
  comName="NoUmlaut";
  comTitle="Umlaut Converter © 1991 Bernd Preusing";
  comDescr="Converts ÄÖÜäöüß to Ae..ss";
  cxDefaultPriority=0;
  toggle=1; (* Kennung toggle-Msg HotKey *)
  (* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ *)

TYPE
  Str255=ARRAY [0..255] OF CHAR;
  Str255Ptr=POINTER TO Str255;

VAR
  (*$ LongAlign:=TRUE *)
  tBuff:ARRAY[1..10] OF LONGINT;
  cxport:ED.MsgPortPtr;
  broker:CD.CxObjPtr; (* Our broker *)
  hotkeybuff:Str255; (* for showing the user the hotkey *)
  mynb:CD.NewBroker;
  cxsignal:SHORTINT;

  Aeie,
  aeie,
  Ueie,
  ueie,
  Oeie,
  oeie,
  szie:IE.InputEventPtr;
  cxGate:CD.CxObjPtr; (* Master für enable,disable *)
  enabled:BOOLEAN;
  myIx:CD.IX;

PROCEDURE setupCustomCx():BOOLEAN;
VAR
  UmlFilter:CD.CxObjPtr;
  s:Str255Ptr;
BEGIN
  (*
     Aufbau broker: (HotKey enabled, disabled den Filter)
     __broker__
     |        |
  HotKey   cxGate, Filter, der alles durchlaesst)
              |   |   |   |   |   |   |
              Ä   Ö   Ü   ä   ö   ü   ß   (* Filter *)
              |   |   |   |   |   |   |
              Ae  Oe  Ue  ae  oe  ue  ss  (* Translators *)
   *)

  (*
     Dies koennte auch durch ArgStrings gesteuert werden, gibt
     aber Probleme mit Case bei Ae,ae z.B.
   *)
  Aeie:=CS.InvertString(ADR("Ae"),NIL);
  aeie:=CS.InvertString(ADR("ae"),NIL);
  Ueie:=CS.InvertString(ADR("Ue"),NIL);
  ueie:=CS.InvertString(ADR("ue"),NIL);
  Oeie:=CS.InvertString(ADR("Oe"),NIL);
  oeie:=CS.InvertString(ADR("oe"),NIL);
  szie:=CS.InvertString(ADR("ss"),NIL);

  CL.AttachCxObj(broker,CS.HotKey(CS.ArgString(ADR(toggleToolType),ADR(defaultToggle)),cxport,toggle));
  cxGate:=CS.CxFilter(NIL);
  myIx.version:=CD.ixVersion;
  myIx.class:=IE.rawkey;
  (* Rest bleibt 0, alle rawkeys durchlassen! *)
  CL.SetFilterIX(cxGate,ADR(myIx));

  CL.AttachCxObj(broker,cxGate);
  UmlFilter:=CS.CxFilter(ADR("-repeat caps ä"));
  CL.AttachCxObj(UmlFilter,CS.CxTranslate(Aeie));
  CL.AttachCxObj(cxGate,UmlFilter);

  UmlFilter:=CS.CxFilter(ADR("-repeat caps ö"));
  CL.AttachCxObj(UmlFilter,CS.CxTranslate(Oeie));
  CL.AttachCxObj(cxGate,UmlFilter);

  UmlFilter:=CS.CxFilter(ADR("-repeat caps ü"));
  CL.AttachCxObj(UmlFilter,CS.CxTranslate(Ueie));
  CL.AttachCxObj(cxGate,UmlFilter);

  UmlFilter:=CS.CxFilter(ADR("-repeat ä"));
  CL.AttachCxObj(UmlFilter,CS.CxTranslate(aeie));
  CL.AttachCxObj(cxGate,UmlFilter);

  UmlFilter:=CS.CxFilter(ADR("-repeat ö"));
  CL.AttachCxObj(UmlFilter,CS.CxTranslate(oeie));
  CL.AttachCxObj(cxGate,UmlFilter);

  UmlFilter:=CS.CxFilter(ADR("-repeat ü"));
  CL.AttachCxObj(UmlFilter,CS.CxTranslate(ueie));
  CL.AttachCxObj(cxGate,UmlFilter);

  UmlFilter:=CS.CxFilter(ADR("-repeat -capslock ß"));
  CL.AttachCxObj(UmlFilter,CS.CxTranslate(szie));
  CL.AttachCxObj(cxGate,UmlFilter);

  s:=CS.ArgString(ADR(activeToolType),ADR("YES"));
  enabled:=Compare(s^,"YES")=0;
  IF CL.ActivateCxObj(cxGate,enabled) THEN END;
  RETURN TRUE; (* Error wird gleich gecheckt! *)
END setupCustomCx;

PROCEDURE shutdownCustomCx();
BEGIN
  (* setup wiueder löschen, soweit nicht durch DelAll getan *)
  IF Aeie#NIL THEN
    CS.FreeIEvents(Aeie);
    Aeie:=NIL;
  END;
  IF aeie#NIL THEN
    CS.FreeIEvents(aeie);
    aeie:=NIL;
  END;
  IF Oeie#NIL THEN
    CS.FreeIEvents(Oeie);
    Oeie:=NIL;
  END;
  IF oeie#NIL THEN
    CS.FreeIEvents(oeie);
    oeie:=NIL;
  END;
  IF Ueie#NIL THEN
    CS.FreeIEvents(Ueie);
    Ueie:=NIL;
  END;
  IF ueie#NIL THEN
    CS.FreeIEvents(ueie);
    ueie:=NIL;
  END;
  IF szie#NIL THEN
    CS.FreeIEvents(szie);
    szie:=NIL;
  END;
END shutdownCustomCx;

PROCEDURE handleCustomCxMsg(id:LONGCARD);
BEGIN
  IF id=toggle THEN (* HotKey *)
    enabled:=~enabled;
    IF CL.ActivateCxObj(cxGate,enabled) THEN END;
  END;
END handleCustomCxMsg;

(* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ *)

PROCEDURE handleCxMsg(msg:ED.MessagePtr);
VAR
  msgid:LONGINT;
  msgtype:LONGCARD;
BEGIN
  msgid:=CL.CxMsgID(CAST(CD.CxMsgPtr,msg));
  msgtype:=CL.CxMsgType(CAST(CD.CxMsgPtr,msg));
  EL.ReplyMsg(msg);
  IF msgtype=CD.cxmIevent THEN
    handleCustomCxMsg(msgid);
  ELSIF msgtype=CD.cxmCommand THEN
    IF msgid=CD.cxcmdDisable THEN
      IF CL.ActivateCxObj(broker,FALSE) THEN END;
    ELSIF msgid=CD.cxcmdEnable THEN
      IF CL.ActivateCxObj(broker,TRUE) THEN END;
    ELSIF (msgid=CD.cxcmdAppear) OR (msgid=CD.cxcmdUnique) THEN
      A.Terminate;
    ELSIF msgid=CD.cxcmdKill THEN
      A.Terminate
    END;
  END; (* else nix? *)
END handleCxMsg;

PROCEDURE shutdownCx();
VAR
  msg:ED.MessagePtr;
BEGIN
  shutdownCustomCx;
  IF cxport#NIL THEN
    CL.DeleteCxObjAll(broker);
    LOOP
      msg:=EL.GetMsg(cxport);
      IF msg=NIL THEN EXIT END;
      EL.ReplyMsg(cxport);
    END;
    DeletePort(cxport);

    cxport:=NIL;
    cxsignal:=-1;
    CAST(ADDRESS,broker):=NIL;
  END;
END shutdownCx;


PROCEDURE setupCx():BOOLEAN;
VAR
  error:LONGCARD;
  coerr:CD.CoErrorSet;
BEGIN
  shutdownCx;
  cxport:=CreatePort(mynb.name,0);
  IF cxport=NIL THEN
    RETURN FALSE
  END;
  cxsignal:=cxport^.sigBit;
  mynb.pri:=CS.ArgInt(ADR(priorityToolType),cxDefaultPriority);
  mynb.port:=cxport;


  broker:=CL.CxBroker(mynb,error);
  IF broker=NIL THEN
    shutdownCx;
    RETURN FALSE
  END;

  IF ~setupCustomCx() THEN
    shutdownCx;
    RETURN FALSE
  END;

  coerr:=CL.CxObjError(broker);
  IF coerr#CD.CoErrorSet{} THEN
    shutdownCx;
    RETURN FALSE
  END;

  IF CL.ActivateCxObj(broker,TRUE) THEN END;
  RETURN TRUE;
END setupCx;

PROCEDURE main();
VAR
  sigrcvd:LONGSET;
  msg:ADDRESS;
BEGIN
  IF ~setupCx() THEN
    A.Terminate;
  END;
  LOOP (* exit by terminate *)
    sigrcvd:=EL.Wait(LONGSET{DD.ctrlE,cxsignal});
    IF DD.ctrlE IN sigrcvd THEN
      A.Terminate
    END;
    LOOP
      IF cxport=NIL THEN EXIT END;
      msg:=EL.GetMsg(cxport);
      IF msg=NIL THEN EXIT END;
      handleCxMsg(msg);
    END;
  END; (* LOOP *)
END main;

PROCEDURE terminate();
BEGIN
  shutdownCx;
END terminate;


BEGIN
  IF A.kickVersion<36 THEN (* braucht 36 *)
    A.Exit(36)
  END;
  mynb.version:=CD.nbVersion;
  mynb.name:=ADR(comName);
  mynb.title:=ADR(comTitle);
  mynb.descr:=ADR(comDescr);
  mynb.unique:=CD.nbuUnique+CD.nbuNotify;
  (* Rest bleibt NIL oder 0 *)
  main;
CLOSE
  terminate;
END NoUmlaut.
