Ich bastle gerade eine Konsolenanwendung bei der man Texte via Readln Eingeben kann / soll.
Nun finde ich es total Praktisch, dass man unter Linux wie Windows wenn man in einer Konsole ist, via Pfeil nach Oben und Unten durch die Historie Blättern kann.
Also habe ich mich mal daran versucht und den folgenden Code zusammen gefrickelt (bisher nur unter Windows getestet, soll aber auch mal auf Linux laufen).
Code: Alles auswählen
Program cmath;
Uses
crt;
Var
ReadlnHistory: Array[0..99] Of String; // Todo, Konfigurierbar machen ?
ReadlnHistoryPtr: Integer;
ReadlnHistoryOffsetIndex: Integer;
Procedure HistoryReadln(Out OutPut: String);
Var
Finished: Boolean;
c: Char;
op, p: TPoint;
NextCharIsControlChar: Boolean;
pIndex, i: Integer;
Begin
// Reset des Historie Offset Index
ReadlnHistoryOffsetIndex := 0;
Finished := false;
OutPut := '';
p.X := WhereX;
p.y := Wherey;
op := p;
NextCharIsControlChar := false;
While Not Finished Do Begin
If KeyPressed() Then Begin
c := ReadKey();
(*
* Steuerzeichen werden durch ein vorgestelltes #0 gesendet
* -> NextCharIsControlChar steuert eine Mini State machine um diese zu erkennen
*)
If c = #0 Then Begin
NextCharIsControlChar := true;
End
Else Begin
If NextCharIsControlChar Then Begin
NextCharIsControlChar := false;
Case c Of
//'K': Key Left
//'M': Key Right
'H': Begin // Key Up
pIndex := (ReadlnHistoryPtr - ReadlnHistoryOffsetIndex + length(ReadlnHistory) - 1) Mod length(ReadlnHistory);
If ReadlnHistory[pIndex] <> '' Then Begin
If ReadlnHistoryOffsetIndex < (length(ReadlnHistory) - 1) Then
ReadlnHistoryOffsetIndex := ReadlnHistoryOffsetIndex + 1;
// Löschen des bisher angezeigten Textes
For i := p.x Downto op.x Do Begin
GotoXY(i, op.y);
write(' ');
End;
// Anzeigen des Textes aus der Historie
GotoXY(op.x, op.y);
OutPut := ReadlnHistory[pIndex];
write(OutPut);
p.x := op.x + length(OutPut);
End;
End;
'P': Begin // Key Down
If ReadlnHistoryOffsetIndex > 0 Then Begin
ReadlnHistoryOffsetIndex := ReadlnHistoryOffsetIndex - 1;
pIndex := (ReadlnHistoryPtr - ReadlnHistoryOffsetIndex + length(ReadlnHistory)) Mod length(ReadlnHistory);
// Löschen des bisher angezeigten Textes
For i := p.x Downto op.x Do Begin
GotoXY(i, op.y);
write(' ');
End;
// Anzeigen des Textes aus der Historie
GotoXY(op.x, op.y);
OutPut := ReadlnHistory[pIndex];
write(OutPut);
p.x := op.x + length(OutPut);
End;
End;
End;
End
Else Begin
Case c Of
#1..#7, #10..#12, #14..#31: Begin
// Nichts diese Zeichen Ignorieren wir mal dezent.
End;
#9: Begin // - Tab -> Leerzeichen
p.x := p.x + 1;
OutPut := OutPut + c;
write(' ');
End;
#13: Begin
Finished := true;
write(#13#10);
End;
#8: Begin
If OutPut <> '' Then Begin
// Löschen des letzten Zeichens
p.x := p.x - 1;
GotoXY(p.x, p.y);
write(' ');
delete(OutPut, length(OutPut), 1);
GotoXY(p.x, p.y);
End;
End;
Else Begin
p.x := p.x + 1;
OutPut := OutPut + c;
write(c);
End;
End;
End;
End;
End;
sleep(1);
End;
// Aufnehmen in die Historie
ReadlnHistory[ReadlnHistoryPtr] := OutPut;
ReadlnHistoryPtr := (ReadlnHistoryPtr + 1) Mod Length(ReadlnHistory);
End;
Var
i: integer;
isRunning: Boolean;
UserInput: String;
Begin
writeln('Los gehts');
writeln('Type "exit" to close');
isRunning := true;
For i := 0 To high(ReadlnHistory) Do Begin
ReadlnHistory[i] := '';
End;
While isRunning Do Begin
write('>');
HistoryReadln(UserInput);
If UserInput = 'exit' Then Begin
isRunning := false;
Continue;
End;
writeln('You wrote: ' +UserInput );
End;
writeln('Press return to exit.');
readln();
End.
Daher die Frage
- Gibt es so was schon "out of the Box" ?
oder wenn nicht
- Hat jemand ne Idee wie ich den Glitch bei #8 wieder los werde ?
Übrigens der "Naive" Ansatz Waere ja:
Code: Alles auswählen
#8: Begin
If OutPut <> '' Then Begin
// Löschen des letzten Zeichens
GotoXY(op.X, op.Y);
For i := 1 To length(OutPut) Do Begin
write(' ');
End;
GotoXY(op.X, op.Y);
delete(OutPut, length(OutPut), 1);
write(OutPut);
p.x := p.x - 1;
End;
End;