home *** CD-ROM | disk | FTP | other *** search
/ Amiga ISO Collection / AmigaUtilCD2.iso / Programming / Pascal / MAXONPASCAL3.DMS / in.adf / DEMOS-OS1.3 / InputHandler.p < prev    next >
Encoding:
Text File  |  1994-07-23  |  7.5 KB  |  198 lines

  1. Program InputHandlerDemo;
  2.  
  3. {
  4.  Dieses Programm ist etwas für Spezialisten und demonstriert, daß man
  5.  sogar so systemnahe Dinge wie Input-Event-Handler in Pascal schreiben
  6.  kann.
  7.  
  8.  Der vom Programm installierte Input-Handler "vertauscht" einige
  9.  Tasten mit ihren jeweiligen Nachbarn, läßt bei anderen Tasten den
  10.  Bildschirm häßlich aufblitzen und sperrt wieder andere Tasten ganz.
  11.  Als einzige nützliche Funktion ermöglicht der Handler es, mit der
  12.  Help-Taste das gerade aktive Fenster nach vorn zu holen.
  13.  
  14.  Währenddessen versetzt sich das Programm selbst in den Waiting State
  15.  (verbraucht also keine Rechenzeit), bis es vom Handler ein Signal
  16.  erhält (das jener beim Empfang der Tastenkombination "Shift links -
  17.  Shift rechts - Escape" sendet). Dann entfernt es den Handler wieder.
  18.  
  19.  Alternativ wäre vorstellbar, daß der Handler dem Hauptprogramm
  20.  nicht nur ein Signal, sondern bei bestimmten Events eine Message
  21.  an einen Messageport schickt. Dann kann man ein Utility schreiben,
  22.  daß bei gewissen Tastenkombinationen bestimmten Operationen
  23.  ausführt, und zwar unabhängig davon, welches Window beim Drücken
  24.  dieser Tasten gerade aktiv ist...
  25.  
  26.  Ein Handler sollte übrigens möglichst keine Pascal-Prozeduren oder
  27.  -Funktionen benutzen, denn das Laufzeitsystem von Kickpascal ist
  28.  nicht als "Shared Library" ausgelegt, d. h. es kann wegen gewissen
  29.  internen statischen Datenstrukturen nicht von zwei parallel laufenden
  30.  Prozessen - z. B. einem Task und einem Input-Handler - gleichzeitig
  31.  benutzt werden. Ein Beispiel: Wenn man mit "Write" eine Zahl ausgibt,
  32.  verwendet die entsprechende Funktion der Laufzeitbibliothek einen
  33.  bestimmten Pufferspeicher, um die Zahl in eine Zeichenfolge zu
  34.  wandeln. Wenn nun das Hauptprogramm vom Handler unterbrochen wird,
  35.  während es gerade eine Zahl ausgibt, und der Handler ebenfalls eine
  36.  Zahl schreiben will, gibt es ein Chaos. Solche Konflikte dürften
  37.  zwar in der Regel nicht zu einem Guru führen, aber die Programme
  38.  werden dadurch instabil.
  39. }
  40.  
  41. { MaxonPascal3-Anpassung / Test:  Falk Zühlsdorff (PackMAN) 1994 }
  42.  
  43. Uses ExecIO,Intuition;
  44.  
  45. {$opt b-;
  46.   incl "exec/interrupts.h",
  47.        "devices/input.h",
  48.        "devices/inputevent.h",
  49.        "intuition/intuitionbase.h" }
  50.  
  51. Type CodeTyp = Array[1..15] of Word;
  52.  
  53. Var port        : p_MsgPort;    { Port zur Kommunikation mit dem Device }
  54.     ioreq       : ^IOStdReq;   { Hier reicht Standard-Struktur }
  55.     inter       : Interrupt;    { Interrupt-Struktur zum Handler }
  56.     err         : BYTE;         { Fehlernummern der Device-Operationen }
  57.     ThisTask    : p_Task;       { Zeiger auf diesen Task }
  58.     Sig, SigBit : Long;         { Signalnummern }
  59.     _paslibbase : Byte; IMPORT; { Pascal-interne Adresse }
  60.     InterfaceCode : Codetyp;    { Speicher für kurze Assembler-Routine }
  61.  
  62.  
  63. {$opt b-,s- : Handler darf Stack nicht prüfen, da er sonst fälschlich
  64.   einen Stacküberlauf feststellen und aussteigen würde - GURU! }
  65.  
  66. Function Handler (data: Ptr; event: p_InputEvent) : p_InputEvent;
  67.  
  68.   { Diese Funktion wird (mit Umweg über den Assembler-Teil) bei jedem
  69.     Input-Event aufgerufen. Als Parameter erhält sie einen Zeiger auf
  70.     eine Liste von Input-Event-Strukturen und eine Kopie des Zeigers
  71.     "is_Data" der Interrupt-Struktur (wird hier nicht benötigt). Die
  72.     Funktion muß als Ergebnis einen Zeiger auf eine (evtl. veränderte)
  73.     Liste zurückgeben.
  74.     Beachten Sie, daß Kickpascal Parameter auf dem Stack in genau
  75.     umgekehrter Reihenfolge als C erwartet. Deshalb ist "data" hier
  76.     der erste Parameter und kann ersatzlos gestrichen werden. }
  77.  
  78.   Const Qual = IEQUALIFIER_LSHIFT or IEQUALIFIER_RSHIFT;
  79.         { Qualifier für Abbruch-Taste }
  80.  
  81.   Var e2    : p_InputEvent;
  82.       err   : Boolean;
  83.       ibase : p_IntuitionBase;
  84.  
  85.   Begin
  86.     e2 := event;
  87.     ibase:=IntuitionBase;
  88.     While e2 <> Nil Do
  89.       { Liste durchlaufen }
  90.       Begin
  91.  
  92.         If (e2^.ie_Class and IECLASS_RAWKEY) <> 0 Then
  93.           Case e2^.ie_Code and $7f of
  94.             $00..$3F : e2^.ie_Code := e2^.ie_Code xor 1;
  95.                        { Tasten vertauschen }
  96.             $40..$44 : DisplayBeep(Ibase^.FirstScreen);
  97.                        { Screen blitzen lassen }
  98.             $45      : If (e2^.ie_Qualifier and Qual) = Qual Then
  99.                          { Ende-Signal abschicken: }
  100.                          Signal(ThisTask, 1 shl SigBit);
  101.             $46..$5E : e2^.ie_Class := IECLASS_NULL;
  102.                        { Tasten-Ereignis unterdrücken }
  103. {            $5F      : err := WindowToFront (Ibase^.ActiveWindow);}
  104.                        { Window nach vorn holen }
  105.           Otherwise ;
  106.           End;
  107.  
  108.         e2 := e2^.ie_NextEvent          { nächstes Element der Liste }
  109.       End;
  110.  
  111.     Handler := event;            { Zeiger auf alte Liste zurückgeben }
  112.  
  113.   End;
  114.  
  115. {$opt s0}
  116.  
  117.  
  118.  
  119. Begin { Hauptprogramm }
  120.  
  121.   { Zunächst wird hier auf eine etwas eigenwillige Methode
  122.     Maschinencode eingebunden: }
  123.  
  124.   InterfaceCode :=
  125.     CodeTyp($48E7, $7F00,                    { MOVEM.L d1-d7,-(a7) }
  126.             $48E7, $00FE,                    { MOVEM.L a0-a6,-(a7) }
  127.             $4BF9, Addr(_paslibbase) shr 16,
  128.                    Addr(_paslibbase)and$FFFF,{ LEA _paslibbase,a5  }
  129.             $4EB9, Addr(Handler) shr 16,
  130.                    Addr(Handler) and $FFFF,  { JSR Handler         }
  131.             $4CDF, $7F00,                    { MOVEM.L (a7)+,a0-a6 }
  132.             $4CDF, $00FE,                    { MOVEM.L (a7)+,a1-a7 }
  133.             $4E75                            { RTS                 }
  134.            );
  135.   { Die Assembler-Routine macht folgendes:
  136.     Alle Register werden sicherheitshalber auf den Stack gerettet,
  137.     denn Kickpascal-Prozeduren tun dies nicht(!) selbst. Dies
  138.     geschieht in zwei MOVEM-Zeilen, um zu erreichen, daß die Register
  139.     a0 und a1 zuunterst auf dem Stack liegen und somit vom in Pascal
  140.     geschriebenen eigentlichen Handler als Parameter übernommen werden
  141.     (a0 zeigt auf die Event-Liste, a1 auf die hier nicht benötigten
  142.     Daten). Kickpascal-Code benötigt in a5 einen Zeiger auf die
  143.     "Paslibbase" (Anfangsadresse des Global Vector und Basis der
  144.     Laufzeitbibliothek). Die Adresse kann vom Linker importiert
  145.     werden und wird mit einer LEA-Anweisung ins Adressregister 5
  146.     geschrieben.
  147.     Dann wird per JSR in die Prozedur "Handler" eingesprungen.
  148.     Zum Schluß werden die Register rekonstruiert, außer d0, das den
  149.     Rückgabewert der Function enthält. }
  150.  
  151.   { Input-Device öffnen: }
  152.   port:=CreatePort("Input-Device-Port",0);
  153.   ioreq := CreateStdIO (port);
  154.   Open_Device ('input.device', 0, ioreq, 0);
  155.   Writeln('Device geöffnet.');
  156.  
  157.   { Alles für die Kommunikation zwischen Handler und Hauptprogramm
  158.     vorbereiten: }
  159.   ThisTask := FindTask (Nil);
  160.   SigBit := AllocSignal (-1);
  161.   If SigBit < 0 Then Error ('Kein freies Signal!');
  162.  
  163.   { Interrupt-Struktur initialisieren: }
  164.   With inter, is_node Do
  165.     Begin
  166.       is_Code := ^InterfaceCode;
  167.       is_Data := Nil;
  168.       ln_Name := 'Input-Handler in Kickpascal';
  169.       ln_Pri  := 51  { Intuition hat die Priorität 50. Wir erhalten
  170.                        also die Events, noch bevor Intuition sie zu
  171.                        sehen bekommt. }
  172.     End;
  173.  
  174.   { Jetzt wird's spannend: }
  175.   ioreq^.io_Data := ^inter;
  176.   ioreq^.io_Command := IND_ADDHANDLER;
  177.   err:=DoIO(PTR(ioreq));
  178.   Writeln ('Handler hinzugefügt - Tastatur vermurkst.');
  179.   Writeln ('Programm kann mit Shift-Shift-Esc abgebrochen werden.');
  180.  
  181.   { Warten, bis der Event-Handler sich meldet: }
  182.   sig := Wait (1 shl SigBit);
  183.  
  184.   { System wieder aufräumen: }
  185.   ioreq^.io_Data := ^inter;
  186.   ioreq^.io_Command := IND_REMHANDLER;
  187.   err := DoIO (PTR(ioreq));
  188.   writeln('Handler entfernt.');
  189.  
  190.   FreeSignal (SigBit);
  191.  
  192.   Close_Device (ioreq);
  193.   DeleteStdIO (ioreq);
  194.   DeletePort (port)
  195.  
  196. End.
  197.  
  198.