home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_disks / 200-299 / ff253.lzh / KeyMac / KeyMac.mod < prev    next >
Text File  |  1989-10-19  |  10KB  |  358 lines

  1. (*---------------------------------------------------------------------------
  2.  :Program.    KeyMac
  3.  :Author.     Fridtjof Björn Siebert
  4.  :Address.    Nobileweg 67, D-7-Stgt-40
  5.  :Shortcut.   [fbs]
  6.  :Version.    0.1
  7.  :Date.       17-May-89
  8.  :Copyright.  PD
  9.  :Language.   MODULA-II
  10.  :Translator. M2Amiga v3.2d
  11.  :History.    This is based on RecordInput [fbs] of AMOK#3.
  12.  :Usage.      KeyMac [MacKey [saAc] [PlayKey [saAc]]
  13.  :Contents.   Program to create Keyboard macros. You can specify a
  14.  :Contents.   Macro Key (default alt+HELP). To create a macro just press this
  15.  :Contents.   key and start typing your macro. Then press the macro key again
  16.  :Contents.   to finish your macro. Now you can play the macro by pressing
  17.  :Contents.   the Play Key (default HELP).
  18. ---------------------------------------------------------------------------*)
  19.  
  20. MODULE KeyMac;
  21.  
  22. FROM SYSTEM      IMPORT ADR, ADDRESS, LONGSET;
  23. FROM Arts        IMPORT Assert, TermProcedure, Terminate;
  24. FROM Arguments   IMPORT NumArgs, GetArg;
  25. FROM Exec        IMPORT MsgPortPtr, Interrupt, Forbid, Permit, IOStdReqPtr,
  26.                         OpenDevice, CloseDevice, DoIO, IORequest, FindPort,
  27.                         DevicePtr,IOFlagSet, WaitPort, GetMsg, ReplyMsg,
  28.                         MessagePtr, Wait, FindTask, AllocSignal, NodeType,
  29.                         FreeSignal, Signal, TaskPtr, Message, PutMsg;
  30. FROM ExecSupport IMPORT CreatePort, DeletePort, CreateStdIO, DeleteStdIO;
  31. FROM Input       IMPORT inputName, addHandler, remHandler, writeEvent;
  32. FROM InputEvent  IMPORT InputEventPtr, Class, QualifierSet;
  33. FROM Intuition   IMPORT DisplayBeep;
  34. IMPORT InputEvent;
  35.  
  36. (*-------------------------  Variablen:  ----------------------------------*)
  37.  
  38. CONST
  39.   oom   = "Out of Memory!";
  40.   usage = "KeyMac [Mac [saAc] [Play [saAc]]";
  41.   PortName  = "KeyMac.Port";
  42.   ReplyName = "KeyMac.ReplyPort";
  43.   err = MAX(CARDINAL);
  44.   MaxRecords = 100;
  45.   CopyRight = "© 1989 by Fridtjof Siebert / AMOK";
  46.  
  47. TYPE
  48.   KeyQualis = (shift,alt,ctrl,amiga);
  49.   KeyQualiSet = SET OF KeyQualis;
  50.  
  51. VAR
  52.   InputDevPort: MsgPortPtr;
  53.   InputRequestBlock: IOStdReqPtr;
  54.   HandlerStuff: Interrupt;
  55.   HandlerActive,InputOpen: BOOLEAN;
  56.   PuffEvent,SendEvent: InputEvent.InputEvent;
  57.   count: INTEGER;
  58.   MacKey, PlayKey: CARDINAL;
  59.   MacQual, PlayQual: KeyQualiSet;
  60.   MySig: INTEGER;
  61.   SigSet: LONGSET;
  62.   Me: TaskPtr;
  63.   Argument: ARRAY[0..79] OF CHAR;
  64.   State: (wait,waitrel,record,recordrel,play);
  65.   Records: ARRAY[0..MaxRecords-1] OF RECORD key: CARDINAL; qual: QualifierSet END;
  66.   TraceEv: InputEventPtr;
  67.   Size: INTEGER;
  68.   l: INTEGER;
  69.   args: INTEGER;
  70.   MyMsg: Message;
  71.   QuitMessage: MessagePtr;
  72.   MyPort, OldPort: MsgPortPtr;
  73.  
  74. (*---------------------  Check Qualifier:  --------------------------------*)
  75.  
  76. PROCEDURE CheckQuali(Quali: QualifierSet; Qual: KeyQualiSet): BOOLEAN;
  77. (* this checks the specified Keys in Qual (SHIFT,ALT,CTRL,AMIGA) whether   *)
  78. (* they are in Quali (left or right is unimportent) or not.                *)
  79.  
  80. BEGIN
  81.  RETURN ((shift IN Qual) = ((InputEvent.lShift   IN Quali) OR (InputEvent.rShift   IN Quali)))
  82.     AND ((alt   IN Qual) = ((InputEvent.lAlt     IN Quali) OR (InputEvent.rAlt     IN Quali)))
  83.     AND ((amiga IN Qual) = ((InputEvent.lCommand IN Quali) OR (InputEvent.rCommand IN Quali)))
  84.     AND ((ctrl  IN Qual) =  (InputEvent.control  IN Quali));
  85. END CheckQuali;
  86.  
  87. (*--------------------  Initialize Input.device:  -------------------------*)
  88.  
  89. PROCEDURE OpenInput();
  90.  
  91. BEGIN
  92.   InputDevPort := CreatePort(NIL,0);
  93.   Assert(InputDevPort#NIL,ADR(oom));
  94.   InputRequestBlock := CreateStdIO(InputDevPort);
  95.   Assert(InputRequestBlock#NIL,ADR(oom));
  96.   WITH HandlerStuff DO
  97.     data := NIL;
  98.     node.pri := 51;
  99.   END;
  100.   OpenDevice(ADR(inputName),0,InputRequestBlock,LONGSET{});
  101.   Assert(InputRequestBlock^.error=0,ADR("Can't open InputDevice!"));
  102.   InputOpen := TRUE;
  103. END OpenInput;
  104.  
  105. (*---------------------  Close Input-Device:  -----------------------------*)
  106.  
  107. PROCEDURE CloseInput();
  108.  
  109. BEGIN
  110.   IF InputOpen THEN CloseDevice(InputRequestBlock) END;
  111.   IF InputDevPort#NIL THEN DeletePort(InputDevPort) END;
  112.   IF InputRequestBlock#NIL THEN DeleteStdIO(InputRequestBlock) END;
  113. END CloseInput;
  114.  
  115. (*---------------------------  AddHandler:  -------------------------------*)
  116.  
  117. PROCEDURE AddHandler(Handler: ADDRESS);
  118.  
  119. BEGIN
  120.   HandlerStuff.code := Handler;
  121.   WITH InputRequestBlock^ DO
  122.     command := addHandler;
  123.     data := ADR(HandlerStuff);
  124.   END;
  125.   DoIO(InputRequestBlock);
  126. END AddHandler;
  127.  
  128. (*---------------------------  RemHandler:  -------------------------------*)
  129.  
  130. PROCEDURE RemHandler();
  131.  
  132. BEGIN
  133.   WITH InputRequestBlock^ DO
  134.     command := remHandler;
  135.     data := ADR(HandlerStuff);
  136.   END;
  137.   DoIO(InputRequestBlock);
  138. END RemHandler;
  139.  
  140. (*------------------------  Write InputEvent:  ----------------------------*)
  141.  
  142. PROCEDURE WriteEvent(Event: InputEventPtr);
  143.  
  144. BEGIN
  145.   WITH InputRequestBlock^ DO
  146.     command := writeEvent;
  147.     flags := IOFlagSet{};
  148.     length := SIZE(InputEvent.InputEvent);
  149.     data := Event;
  150.   END;
  151.   DoIO(InputRequestBlock);
  152. END WriteEvent;
  153.  
  154. (*------------------------  InputHandler:  --------------------------------*)
  155.  
  156. PROCEDURE RecordHandler(Ev{8}: InputEventPtr): InputEventPtr; (* $S- *)
  157.  
  158. BEGIN
  159.   TraceEv := Ev;
  160.   WHILE TraceEv#NIL DO
  161.     WITH TraceEv^ DO
  162.       IF class=rawkey THEN
  163.         IF (code=MacKey)  AND CheckQuali(qualifier,MacQual) OR
  164.            (code=PlayKey) AND CheckQuali(qualifier,PlayQual) THEN
  165.           class := null
  166.         END;
  167.         CASE State OF
  168.         waitrel:
  169.           IF (code=MacKey+80H) THEN
  170.             State := wait; class := null;
  171.           END |
  172.         wait:
  173.           IF (code=MacKey) AND CheckQuali(qualifier,MacQual) THEN
  174.             State := recordrel;
  175.           ELSIF (code=PlayKey) AND CheckQuali(qualifier,PlayQual) THEN
  176.             State := play;
  177.             PuffEvent := TraceEv^;
  178.             Signal(Me,SigSet);
  179.           END |
  180.         recordrel:
  181.           IF (code=MacKey+80H) AND CheckQuali(qualifier,MacQual) THEN
  182.             State := record; Size := 0; class := null;
  183.             Signal(Me,SigSet);
  184.           END |
  185.         record:
  186.           Signal(Me,SigSet);
  187.           IF (code=MacKey) AND CheckQuali(qualifier,MacQual) THEN
  188.             State := waitrel;
  189.             Signal(Me,SigSet);
  190.           ELSIF Size<MaxRecords THEN
  191.             Records[Size].key := code;
  192.             Records[Size].qual := qualifier;
  193.             INC(Size);
  194.           END |
  195.         play:
  196.           IF (code=PlayKey) AND CheckQuali(qualifier,PlayQual) THEN
  197.             PuffEvent := TraceEv^;
  198.             Signal(Me,SigSet);
  199.           ELSIF (code=PlayKey+80H) THEN
  200.             class := null;
  201.             State := wait;
  202.           END |
  203.         END;
  204.       END;
  205.     END;
  206.     TraceEv := TraceEv^.nextEvent;
  207.   END;
  208.   RETURN Ev;
  209. END RecordHandler; (* $S+ *)
  210.  
  211. (*-------------------------------------------------------------------------*)
  212.  
  213. PROCEDURE GetQuali(VAR q: KeyQualiSet);
  214. VAR i: INTEGER;
  215. BEGIN
  216.   i := 0; q := KeyQualiSet{};
  217.   LOOP
  218.     CASE Argument[i] OF
  219.     0C: EXIT |
  220.     "s": INCL(q,shift) |
  221.     "a": INCL(q,alt)   |
  222.     "A": INCL(q,amiga) |
  223.     "c": INCL(q,ctrl)  |
  224.     ELSE Assert(FALSE,ADR(usage)) END;
  225.     INC(i);
  226.   END;
  227. END GetQuali;
  228.  
  229. PROCEDURE StrToCard(s: ARRAY OF CHAR): CARDINAL;
  230.  
  231. VAR i,j: CARDINAL;
  232.  
  233. BEGIN
  234.   i := 0; j := 0;
  235.   LOOP
  236.     CASE s[j] OF
  237.     0C: RETURN i |
  238.     "0".."9": i := 10*i+CARDINAL(s[j])-CARDINAL("0") |
  239.     ELSE RETURN err END;
  240.     INC(j);
  241.   END;
  242. END StrToCard;
  243.  
  244. (*-------------------------  TermProcedure:  ------------------------------*)
  245.  
  246. PROCEDURE CleanUp();
  247.  
  248. BEGIN
  249.   IF HandlerActive THEN RemHandler() END;
  250.   CloseInput();
  251.   IF MySig#-1      THEN FreeSignal(MySig) END;
  252.   IF MyPort#NIL THEN
  253.     Forbid();
  254.       IF QuitMessage=NIL THEN QuitMessage := GetMsg(MyPort) END;
  255.       WHILE QuitMessage#NIL DO
  256.         ReplyMsg(QuitMessage);
  257.         QuitMessage := GetMsg(MyPort);
  258.       END;
  259.       DeletePort(MyPort);
  260.     Permit();
  261.   END;
  262. END CleanUp;
  263.  
  264. (*------------------------  Intialisation:  -------------------------------*)
  265.  
  266. BEGIN
  267.  
  268.   HandlerActive := FALSE; InputOpen := FALSE; MySig := -1; Size := 0;
  269.   InputDevPort  := NIL; InputRequestBlock := NIL; State := wait; MyPort := NIL;
  270.   TermProcedure(CleanUp);
  271.  
  272.   MacKey := 5FH; MacQual := KeyQualiSet{alt};
  273.   PlayKey:= 5FH; PlayQual:= KeyQualiSet{};
  274.  
  275. (*------  Have we already been started?  ------*)
  276.  
  277.   OldPort := FindPort(ADR(PortName));
  278.   IF OldPort#NIL THEN
  279.     MyPort := CreatePort(ADR(ReplyName),0);
  280.     Assert(MyPort#NIL,ADR(oom));
  281.     MyMsg.node.type := message;
  282.     MyMsg.replyPort := MyPort;
  283.     PutMsg(OldPort,ADR(MyMsg));
  284.     WaitPort(MyPort);
  285.     DeletePort(MyPort);
  286.     MyPort := NIL;
  287.     Terminate(0);
  288.   END;
  289.   MyPort := CreatePort(ADR(PortName),0);
  290.   Assert(MyPort#NIL,ADR(oom));
  291.  
  292. (*------  Open everything we need:  ------*)
  293.  
  294.   OpenInput();
  295.   AddHandler(ADR(RecordHandler));
  296.   HandlerActive := TRUE;
  297.  
  298.   Me := FindTask(NIL);
  299.   MySig := AllocSignal(-1);
  300.   Assert(MySig#-1,ADR("No more Signals!"));
  301.   SigSet := LONGSET{MySig};
  302.  
  303. (*------  Arguments:  ------*)
  304.  
  305.   count := 1;
  306.   args := NumArgs();
  307.   IF 0<args THEN
  308.     GetArg(1,Argument,l);
  309.     MacKey := StrToCard(Argument);
  310.     Assert(MacKey#err,ADR(usage));
  311.     MacQual := KeyQualiSet{};
  312.     INC(count);
  313.     IF 1<args THEN
  314.       GetArg(2,Argument,l);
  315.       IF StrToCard(Argument)=err THEN
  316.         GetQuali(MacQual);
  317.         INC(count);
  318.       END;
  319.       IF count<=args THEN
  320.         GetArg(count,Argument,l);
  321.         PlayKey := StrToCard(Argument);
  322.         Assert(PlayKey#err,ADR(usage));
  323.         PlayQual := KeyQualiSet{};
  324.         INC(count);
  325.         IF count<=args THEN
  326.           GetArg(count,Argument,l);
  327.           GetQuali(PlayQual);
  328.         END;
  329.       END;
  330.     END;
  331.   END;
  332.  
  333. (*------  Main Loop:  ------*)
  334.  
  335.   LOOP
  336.     IF MyPort^.sigBit IN Wait(LONGSET{MyPort^.sigBit,MySig}) THEN
  337.       EXIT
  338.     ELSE
  339.       CASE State OF
  340.       play,wait:
  341.         count := 0;
  342.         Forbid(); SendEvent := PuffEvent; Permit();
  343.         SendEvent.class     := rawkey;
  344.         SendEvent.nextEvent := NIL;
  345.         WHILE count<Size DO
  346.           SendEvent.code      := Records[count].key;
  347.           SendEvent.qualifier := Records[count].qual;
  348.           WriteEvent(ADR(SendEvent));
  349.           INC(count);
  350.         END |
  351.       record,waitrel:
  352.         DisplayBeep(NIL) |
  353.       ELSE END;
  354.     END;
  355.   END;
  356.  
  357. END KeyMac.
  358.