home *** CD-ROM | disk | FTP | other *** search
- (* ------------------------------------------------------------------------- *)
- (* SENDKEYS.PAS (v1.0) *)
- (* Simulation von Tastatureingaben an aus Batch-Dateien geladene Programme *)
- (* System: MS-DOS Sprache: Turbo Pascal *)
- (* (c) 1987 Karsten Gieselmann & PASCAL International *)
- (* ------------------------------------------------------------------------- *)
- {$C-,I-,K-,R-,U-,V-} (* alle Compiler-Schalter desaktivieren! *)
- PROGRAM SendKeys;
- {$I REGS8088.INC} (* einbinden der Interrupt-Routinen aus PASCAL 6/87 *)
- {$I CRITICAL.INC}
- {$I MAKEINT.INC}
-
- CONST Version : STRING[14] = 'SENDKEYS v1.0';
- MaxKeyLen = 100; (* Maximalzahl zu uebergebender Scan-Codes *)
- DosSeg = $0040; (* Datensegment des Betriebssystems *)
- FirstChar = $001A; (* Offset des ersten abzuholenden Zeichens *)
- BufPtr = $001C; (* - - letzten - - *)
- MinPtr = $001E; (* untere Begrenzung des Tastaturpuffers *)
- MaxPtr = $003C; (* obere - - - *)
- KeyBoardOldInterrupt : IntEntry_ = (Offset:0; Segment:0);
-
- TYPE CmdStr = STRING [127]; (* maximale Laenge der DOS-Parameterzeile *)
- Line = STRING [255];
- Range = 0..MaxKeyLen;
-
- VAR CmdLine : CmdStr ABSOLUTE CSeg:$0080; (* die DOS-Parameterzeile... *)
- CmdLen : BYTE ABSOLUTE CmdLine; (* ...und deren Laenge *)
- KeyPtr : Range; (* naechster Scan-Code *)
- KeyStroke : ARRAY [Range] OF INTEGER; (* vorgegebene Scan-Codes *)
- KeyLen : INTEGER ABSOLUTE KeyStroke; (* Anzahl vorhandener Codes *)
- SENDKEYS_Seg: INTEGER; (* Segment der residenten R. *)
- (* ------------------------------------------------------------------------- *)
- (* Zeichen im DOS-Tastaturpuffer ablegen *)
- PROCEDURE PutScanCodeInKeyboardBuffer (Code : INTEGER);
- BEGIN
- MemW[DosSeg:MemW[DosSeg:BufPtr]] := Code; (* Scan-Code ablegen *)
- MemW[DosSeg:BufPtr] := MemW[DosSeg:BufPtr] + 2; (* Zeiger weiterrechnen *)
- IF MemW[DosSeg:BufPtr] > MaxPtr THEN MemW[DosSeg:BufPtr] := MinPtr
- END;
- (* ------------------------------------------------------------------------- *)
- (* diese Routine wird vor den Tastatur-Interrupt gehaengt *)
- PROCEDURE KeyboardInterrupt;
- {$I BEGININT.INC}
- IF KeyPtr <= KeyLen THEN (* liegen noch Zeichen vor? *)
- IF MemW[DosSeg:BufPtr] = MemW[DosSeg:FirstChar] THEN (* Puffer leer? *)
- BEGIN
- PutScanCodeInKeyboardBuffer (KeyStroke[KeyPtr]);
- KeyPtr := Succ (KeyPtr) (* naechster Scan-Code *)
- END;
- {$I EXITINT.INC} (* weiter mit normalen Int-16h *)
- KeyBoardOldInterrupt);
- {$I ENDINT.INC}
- (* ------------------------------------------------------------------------- *)
- (* prueft nach, ob SENDKEYS bereits installiert ist *)
- FUNCTION ProgramAlreadyExists (VAR Segment : INTEGER) : BOOLEAN;
- CONST Addr : INTEGER = $0000; (* Adresse des Suchstrings *)
- Seg : INTEGER = $0000; (* Segment von SENDKEYS *)
- MinSeg : INTEGER = $0000; (* minimales Suchsegment *)
- MaxSeg : INTEGER = $0000; (* maximales Suchsegment *)
- Len : INTEGER = $0000; (* Laenge des Suchstrings *)
- found : BOOLEAN = TRUE; (* wurde SENDKEYS gefunden? *)
- BEGIN
- Addr := Ofs (Version); (* Offset des Suchstrings *)
- Len := Length (Version); (* Laenge des Suchstrings *)
- MinSeg := $0A00; MaxSeg := Pred (CSeg);
- INLINE (
- $1E/ (* PUSH DS ;Datensegment sichern *)
- $0E/ (* PUSH CS *)
- $1F/ (* POP DS ;Datensegment ist Code *)
- $A1/MinSeg/ (* MOV AX,MinSeg ;minimales Such-Segment *)
- $8B/$1E/Addr/ (* MOV BX,Addr ;Offset des Vers-Strings *)
- $8B/$16/Addr/ (* MOV DX,Addr ;Offset des Suchstrings *)
- $89/$D6/ (* Loop: MOV SI,DX ;Register zum... *)
- $89/$DF/ (* MOV DI,BX ;...Blockvergleich laden *)
- $8B/$0E/Len/ (* MOV CX,Len ;Laenge des Suchstrings *)
- $40/ (* INC AX ;Such-Segment erhoehen...*)
- $8E/$C0/ (* MOV ES,AX ;und nach ES laden *)
- $F3/$A6/ (* REPZ CMPSB ;vergleichen *)
- $74/$0A/ (* JZ found ;Uebereinstimmung? *)
- $3B/$06/MaxSeg/(* CMP AX,MaxSeg ;maximales Such-Segment? *)
- $75/$EB/ (* JNE Loop ;nein: dann weiter *)
- $B0/$00/ (* MOV AL,00 ;sonst nicht gefunden... *)
- $EB/$05/ (* JMP ready ;...und Suche beenden *)
- $A3/Seg/ (* found: MOV Seg,AX ;gefunden: Segm. sichern *)
- $B0/$01/ (* MOV AL,01 ;und "gefunden" melden *)
- $A2/found/ (* ready: MOV found,AL ;"gefunden"-Status laden *)
- $1F); (* POP DS ;Datensegment herstellen *)
- ProgramAlreadyExists := found;
- Segment := Seg;
- END;
- (* ------------------------------------------------------------------------- *)
- (* Zerlegung der DOS-Parameterzeile in einzelne Argumente *)
- PROCEDURE ParseCommandLine (Segment : INTEGER);
- VAR ParamFile : TEXT;
- ParamLine : Line;
-
- PROCEDURE SetKeyStroke (ScanCode :INTEGER);
- (* besetzt die naechste freie Komponente von "KeyStroke" mit "ScanCode";
- es wird ferner darauf geachtet, dass die Anzahl der Codes die durch
- "MaxKeyLen" gegebene Obergrenze nicht ueberschreitet, wenn erforder-
- lich, wird bei "MaxKeyLen" abeschnitten! *)
- VAR Index : Range;
- BEGIN
- Index := MemW[Segment:Ofs(KeyStroke[0])];
- IF Index < MaxKeyLen THEN
- BEGIN
- Index := Succ (Index);
- MemW[Segment:Ofs(KeyStroke[Index])] := ScanCode;
- MemW[Segment:Ofs(KeyStroke[0])] := Index;
- END
- END;
-
- PROCEDURE Error (ErrorMsg : Line);
- (* Meldung eines eventuell aufgetretenen Fehlers *)
- BEGIN
- WriteLn ('Fehler: ',ErrorMsg); Halt;
- END;
-
- PROCEDURE Parse (ParamLine : Line);
- (* filtert aus "ParamLine" die einzelnen Scan-Codes heraus *)
- CONST EoS = #$00; (* Konstante EndOfString *)
- VAR C : CHAR;
- s : Line;
- p : INTEGER;
-
- FUNCTION NextChar :CHAR;
- (* liefert naechstes Zeichen von ParamLine und loescht es gleichzeitig *)
- BEGIN
- IF Length(ParamLine) > 0 THEN (* noch Zeichen da? *)
- BEGIN
- NextChar := ParamLine[1]; (* ja: Zeichen holen... *)
- Delete (ParamLine,1,1) (* ...und aus ParamLine loeschen *)
- END
- ELSE
- NextChar := EoS (* nein: dann Ende *)
- END;
-
- FUNCTION ScannedNumber :INTEGER;
- (* wertet die bei "Paramline" vorn anstehende (Hexa-)Dezimalzahl aus *)
- VAR C : CHAR;
- s : Line;
- i,Result : INTEGER;
- BEGIN
- s := ''; C := NextChar;
- IF C='#' THEN (* explizite Scan-Code-Angabe: muss hexadezimal sein! *)
- C := '$';
- IF C='$' THEN (* Hexadezimalzahl *)
- BEGIN
- s := '$'; C := NextChar;
- WHILE C IN ['0'..'9','A'..'F','a'..'f'] DO BEGIN
- s := s + C; C := NextChar;
- END;
- END
- ELSE (* Dezimalzahl *)
- BEGIN
- WHILE C IN ['0'..'9'] DO BEGIN
- s := s + C; C := NextChar;
- END;
- END;
- ParamLine := C + ParamLine; (* letztes Zeichen retten *)
- Val (s,i,Result);
- IF Result <> 0 THEN Error ('unerlaubtes Zeichen in einer Zahl!');
- ScannedNumber := i
- END;
-
- BEGIN (* Parse *)
- REPEAT
- C := NextChar;
- CASE C OF
- '"': BEGIN
- p := Pos ('"',ParamLine); (* wo ist Ende der Kette? *)
- IF p=0 THEN Error ('String-Ende nicht gefunden!');
- s := Copy (ParamLine,1,Pred(p)); (* Kette herausfiltern *)
- Delete (ParamLine,1,p);
- FOR p:=1 TO Length(s) DO
- SetKeyStroke (Ord(s[p])); (* Scan-Codes ablegen *)
- END;
- '$','#',
- '0'..'9': BEGIN
- ParamLine := C + ParamLine; (* letztes Zeichen retten *)
- SetKeyStroke (ScannedNumber);
- END;
- ';': C := EoS; (* der Rest ist Kommentar! *)
- ' ',EoS: ; (* nichts machen! *)
- ELSE (* irgendetwas stimmt nicht! *)
- Error ('unerlaubtes Zeichen in Zeile!');
- END;
- UNTIL C = EoS;
- END;
-
- BEGIN (* ParseCommandLine *)
- MemW [Segment:Ofs(KeyPtr)] := 1; KeyLen := 0; (* Zeiger wieder an Anfang *)
- IF (ParamStr(1) = '-f') OR (ParamStr(1) = '-F') THEN (* Parameter-Datei *)
- BEGIN
- Assign (ParamFile, ParamStr(2)); ReSet (ParamFile);
- IF IOResult <> 0 THEN Error ('Parameter-Datei existiert nicht!');
- WHILE NOT Eof(ParamFile) AND (KeyLen < MaxKeyLen) DO BEGIN
- ReadLn (ParamFile, ParamLine); Parse (ParamLine);
- END;
- Close (ParamFile)
- END
- ELSE (* Parameter aus DOS-Kommandozeile *)
- BEGIN
- ParamLine := CmdLine; Parse (ParamLine)
- END
- END;
- (* ------------------------------------------------------------------------- *)
- BEGIN
- IF ProgramAlreadyExists (SENDKEYS_Seg) THEN (* SENDKEYS schon geladen *)
- ParseCommandLine (SENDKEYS_Seg + (DSeg - CSeg))
- ELSE (* sonst resident machen *)
- BEGIN
- WriteLn;
- WriteLn('SendKeys v1.0 resident...');
- WriteLn(' (C) 1987 Karsten Gieselmann & PASCAL Int.');
- WriteLn;
- ParseCommandLine (DSeg);
- WITH KeyBoardOldInterrupt DO IntGet (IntKeyboard, Segment, Offset);
- IntSet (IntKeyboard, CSeg, Ofs (KeyboardInterrupt));
- MakeResident;
- END
- END.