Größe eines Konsolenfensters ermitteln (Linux)

jrx
Beiträge: 46
Registriert: Fr 14. Mai 2010, 13:23
OS, Lazarus, FPC: Lazarus 1.8.0 r56594 FPC 3.0.4 i386-win32-win32/win64
Wohnort: Erlangen

Größe eines Konsolenfensters ermitteln (Linux)

Beitrag von jrx »

Guten Tag,
ich betreibe einige Raspi headless. Zugriff ist über SSH, da wird auch mein Programm gestartet.

Mit Initialisierung der Unit CRT steht dann auch die Größen des Bildschirmes in der Variable CRT.WindMax zur Ferfügung.
Diese Variable ist dann Basis für die Errechnung bestimmter Ausgaben innerhalb meines Programmes (GotoXY...Write).
Es funktioniert alles, wie es soll - bis ich die Größe des Konsolenfenster mit z.B. putty verändere.

Kann ich denn überhaupt mit CRT oder einem anderen Unit die Größe des aktuellen Bildschirmes/Konsolenfensters dynamisch abfragen?
Es soll so funktionieren wie bspw. beim Midnight-Commander.

Danke.
jrx

Warf
Beiträge: 1491
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: MacOS | Win 10 | Linux
CPU-Target: x86_64
Wohnort: Aachen

Re: Größe eines Konsolenfensters ermitteln (Linux)

Beitrag von Warf »

Kannst dir ja mal diese lib von mir anschauen: https://github.com/Warfley/LazTermUtils

Du musst die lib dann statt crt benutzen (sonst funktioniert die wahrscheinlich nicht). D.h. CRT darf nirgendwo mehr in den uses liegen (das macht sehr unanständige dinge zu den IO filedescriptoren bei der initialization)
Sollte aber alles können was die CRT kann (und mehr).

jrx
Beiträge: 46
Registriert: Fr 14. Mai 2010, 13:23
OS, Lazarus, FPC: Lazarus 1.8.0 r56594 FPC 3.0.4 i386-win32-win32/win64
Wohnort: Erlangen

Re: Größe eines Konsolenfensters ermitteln (Linux)

Beitrag von jrx »

Vielen Dank,

ich bin kurz durch die Quellen gestöbert.
Da sind ja einige Sachen drin, die ich sicher gut gebrauchen kann.
Vielen Dank !

Gibt es auch eine Dokumentation?
Zumindest eine Liste der Funktionen/proceduren, Variablen und Konstanten nebst kurzer Beschreibung.
Sorry, dass ich frage :roll: . Das ist ja alles noch ziemlich frisch auf dem Github.

Warf
Beiträge: 1491
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: MacOS | Win 10 | Linux
CPU-Target: x86_64
Wohnort: Aachen

Re: Größe eines Konsolenfensters ermitteln (Linux)

Beitrag von Warf »

Nö, zum doc schreiben war ich zu faul :D

Gibt einige Beispiele:
ColorTest: Zeigt wie man Farben verwendet, den cursor bewegt sowie die fenstergröße ermittelt (und ist ein benchmark für wie schnell deine konsole reagiert), sowie output buffering damit nicht jeder char einzeln ausgegeben wird
NonBlockingReadTest: Updated kontinuierlich die Konsole und checkt regelmäßig ob escape gedrückt wurde, wartet aber nicht darauf das was gemacht wird sondern falls nix gedrückt wurde updated einfach weiter
ReadKeyExample: Zeigt wie man key downs ausliest inklusiver kombinationen wie Strg + Key oder Alt + Key, etc. (Ohne das dabei das was man eintippt von der konsole geechoed wird, wie das normalerweise bei Read oder Readln ist)
TextMod ist ein beispiel für die ausgabemodifikationen (farbe, unterstrichen, etc.) sowie ein benchmark was deine konsole alles unterstützt (z.b. fraktur wird von den meisten konsolen nicht unterstützt).

Ansonsten, relevant sind die Terminal Streams (Input, Output und Error), wobei die Relevanten funktionen für den Output streams (Error und Output) sind:

Code: Alles auswählen

    function WindowSize: TTerminalSize; inline;
    function IsATTY: Boolean; inline;

    function isOpen: Boolean; inline;
    procedure Close; inline;

    procedure ModifyOutput(const AModifier: TTerminalModifier); inline;
    procedure ResetModifiers; inline;

    procedure Clear(ClearMode: TClearMode = cmTotalScreen; Flush: Boolean = False); inline;
    procedure ClearLine(ClearMode: TLineClearMode = lcmTotalLine; Flush: Boolean = False); inline;
    procedure CursorStartOfLine(Flush: Boolean = False); inline;
    procedure CursorMove(X: Integer; Y: Integer; Flush: Boolean = False); inline;
    procedure CursorGoto(X: Integer; Y: Integer; Flush: Boolean = False); inline;
    procedure CursorGotoX(X: Integer; Flush: Boolean = False); inline;
    procedure CursorGotoY(Y: Integer; Flush: Boolean = False); inline;
    procedure Bell; inline;
    procedure HideCursor; inline;
    procedure ShowCursor; inline;

    procedure FlushControls; inline;
    procedure FlushBuffer; inline;
und für den Input stream:

Code: Alles auswählen

    function IsATTY: Boolean; inline;
    property DirectRead: Boolean read FDirectRead write SetDirectRead;
Außerdem bieten die streams noch einige Read und Write funktionen (Readln, writeln, etc.) zur verfügung die du statt den normalen Readln und writeln funktionen benutzen solltest, da die lib so gebaut ist das sie versucht die normalen Readln und Writeln funktionen möglichst in ruhe zu lassen.

Vor allem gibt es ein paar besonderheiten, wenn DirectRead true ist, wird beim einlesen newline durch #13 (keycode für enter) ersetzt, weshalb ReadLn womöglich nicht funktioniert. Terminal.Input.Readln ist aber so gebaut das es damit klar kommt.
Eine andere besonderheit ist das unter Linux (das teil funktioniert auch unter windows) im direct read modus bei einem writeln der cursor nicht an den anfang der zeile wandert, man muss also CR+LF statt nur LF benutzen (also bei WriteLn müsste man WriteLn(Line, #13); schreiben statt WriteLn(Line)), während sich Terminal.Output.WriteLn darum selbst kümmert.

Du kannst natürlich trozdem (system) readln und writeln benutzen, auf sowas muss man halt nur achten, dann geht das auch. Ich empfehle nur es nicht zu machen, das spart dir viele kopfschmerzen die ich bereits hatte

Mathias
Beiträge: 5084
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunc)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Größe eines Konsolenfensters ermitteln (Linux)

Beitrag von Mathias »

Größe eines Konsolenfensters ermitteln (Linux)
Irgendwo muss dies in den fpc-sourcen vorhanden sein.
Man beachte die fpc-ide, welche in FreeVision läuft.
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot

PascalDragon
Beiträge: 87
Registriert: Mi 3. Jun 2020, 07:18
OS, Lazarus, FPC: L 2.0.8, FPC Trunk, OS Win/Linux
CPU-Target: Aarch64 bis Z80 ;)
Wohnort: München

Re: Größe eines Konsolenfensters ermitteln (Linux)

Beitrag von PascalDragon »

Die IDE, beziehungsweise FreeVision nutzt allerdings die Video Unit, nicht die Crt Unit. Erstere ist mehr für „Vollbild”-Anwendungen gedacht.

Edit: BBCodes gefixt.
Zuletzt geändert von PascalDragon am Di 18. Aug 2020, 13:27, insgesamt 1-mal geändert.
FPC Compiler Entwickler

jrx
Beiträge: 46
Registriert: Fr 14. Mai 2010, 13:23
OS, Lazarus, FPC: Lazarus 1.8.0 r56594 FPC 3.0.4 i386-win32-win32/win64
Wohnort: Erlangen

Re: Größe eines Konsolenfensters ermitteln (Linux)

Beitrag von jrx »

Den Gedanken hatte ich auch schon, aber tp-ide ermittelt nicht wirklich die aktuelle Fenstergröße der Konsole.
Da wird einfach von links nach rechts geschrieben und am Rand abgeschnitten.

jrx
Beiträge: 46
Registriert: Fr 14. Mai 2010, 13:23
OS, Lazarus, FPC: Lazarus 1.8.0 r56594 FPC 3.0.4 i386-win32-win32/win64
Wohnort: Erlangen

Re: Größe eines Konsolenfensters ermitteln (Linux)

Beitrag von jrx »

Warf hat geschrieben:
Mo 17. Aug 2020, 23:23
Kannst dir ja mal diese lib von mir anschauen: https://github.com/Warfley/LazTermUtils
Ich habe mir das heruntergeladen und das *.lpk geöffnet.
Nun habe ich ein example auf meinem Raspi kompiliert. Leider bricht das ab mit der Fehlermeldung

Code: Alles auswählen

Nachrichten, Warnungen: 1
Warning: other unit files search path (aka unit path) of "ReadkeyExample" contains "/home/pi/pascal/Steampi3/LazTermUtils-master/src", which belongs to package "TermUtils"
Projekt kompilieren, Ziel: /home/pi/pascal/Steampi3/LazTermUtils-master/bin/arm-linux/ReadkeyExample: Exit code 1, Fehler: 2, Warnungen: 2, Hinweise: 6
terminalmodifier.pas(149,28) Warning: Function result does not seem to be set
terminalmodifier.pas(156,27) Warning: Function result does not seem to be set
terminalmodifier.pas(99,29) Hint: Parameter "AReset" not used
terminalmodifier.pas(100,29) Hint: Parameter "AReset" not used
terminalmodifier.pas(102,29) Hint: Parameter "AInvert" not used
terminalmodifier.pas(103,29) Hint: Parameter "AInvert" not used
terminalmodifier.pas(501,76) Error: Incompatible type for arg no. 1: Got "{Array Of Const/Constant Open} Array of TTerminalModifier", expected "TModifiers"
terminalmodifier.pas(494,10) Hint: Found declaration: ModifyString(TModifiers;const AnsiString):AnsiString;
terminalmodifier.pas(508,54) Error: Incompatible type for arg no. 1: Got "{Array Of Const/Constant Open} Array of TTerminalModifier", expected "TModifiers"
terminalmodifier.pas(494,10) Hint: Found declaration: ModifyString(TModifiers;const AnsiString):AnsiString;
 
Beim Klicken auf die Errorzeile springen wir hierher:

Code: Alles auswählen

function ColorText(const AString: string; const Foreground: TTextColor): string;
begin
  Result := ModifyString([TTerminalModifier.ForegroundModifier(Foreground)], AString);
end;

function ColorText(const AString: string; const Foreground: TTextColor;
  const Background: TTextColor): string;
begin
  Result := ModifyString([TTerminalModifier.ForegroundModifier(Foreground),
    TTerminalModifier.BackgroundModifier(Background)], AString);
end;   
Vielleicht habe ich ja was übersehen oder falsch gemacht.
jrx

Warf
Beiträge: 1491
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: MacOS | Win 10 | Linux
CPU-Target: x86_64
Wohnort: Aachen

Re: Größe eines Konsolenfensters ermitteln (Linux)

Beitrag von Warf »

Was für eine FPC version benutzt du denn? Es kann sein das du 3.2 benötigst an dieser stelle, da ich dort einen dynamischen Array via [...] initialisiere. Kann sein das das erst mit 3.2 kam.

Ansonsten, als fix dafür:

Code: Alles auswählen

function CreateModifierArray(Modifiers: Array of TTerminalModifier): TModifiers; inline;
var
  i: SizeInt;
begin
  SetLength(Result, Length(Modifiers));
  for i:=Low(Modifiers) to High(Modifiers) do
    Result[i] := Modifiers[i];
end;
Und ersetzt dann die [...] durch CreateModifierArray([...]);

Das gesagt, wenn du eine ältere FPC version benutzt kann es sein das es dir noch wo anders um die ohren fliegt

Mathias
Beiträge: 5084
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunc)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Größe eines Konsolenfensters ermitteln (Linux)

Beitrag von Mathias »

jrx hat geschrieben:
Di 18. Aug 2020, 11:43
Den Gedanken hatte ich auch schon, aber tp-ide ermittelt nicht wirklich die aktuelle Fenstergröße der Konsole.
Da wird einfach von links nach rechts geschrieben und am Rand abgeschnitten.
Muss es aber, und dies sogar sehr komfortabel.
Da muss sogar etwas Interruptgesteuertes sein, ansonsten würde die IDE sich nicht automatisch anpassen, wen man zur Laufzeit die Terminal-Grösse ändert.
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot

Warf
Beiträge: 1491
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: MacOS | Win 10 | Linux
CPU-Target: x86_64
Wohnort: Aachen

Re: Größe eines Konsolenfensters ermitteln (Linux)

Beitrag von Warf »

Mathias hat geschrieben:
Di 18. Aug 2020, 15:22
Da muss sogar etwas Interruptgesteuertes sein, ansonsten würde die IDE sich nicht automatisch anpassen, wen man zur Laufzeit die Terminal-Grösse ändert.
Kann man auch polling mäßig realisieren. Mit meiner lib z.b. würde ich das so machen:

Code: Alles auswählen

While not Terminated do // global variable oder was auch immer
begin
  // für nen resize checken
  windowSize := Terminal.Output.GetWindowSize;
  if (windowSize.X <> oldWindowSize.y) or (windowSize.y <> oldWindowSize.y) then
  begin
    HandleResize(oldWindowSize, windowSize);
    oldWindowSize := windowSize;
  end;
  // key downs checken, ohne das dabei was geprinted wird
  Terminal.Input.DirectRead := true;
  try
    if Terminal.Input.ReadKeyNonBlocking(k) then
      HandleKeyDown(k);
  finally
    Terminal.Input.DirectRead := true;
  end;
  // Fenster zeichnen, wenn man große sachen zeichnet cursor hiden sonst flackerts
  Terminal.Output.HideCursor;
  try
    // buffering aktivieren um performanter zu schreiben
    Terminal.Output.BufferSize := SizeInt.MaxValue;
    try
      RedrawWindow(Terminal.Output, windowSize);
    finally
      Terminal.Output.FlushBuffer;
      Terminal.Output.BufferSize := 0;
    end;
  finally
    Terminal.Output.ShowCursor;
  end;
end;
Den rest kann man dann mehr oder weniger eventgesteuert wie in der LCL bauen.

Damit kann ich bei nem full screen terminal (auf nem 1080p bildschirm mit font size 12) problemlos 60-70 fps erreichen. Damit könnte man sogar spiele (mit miserabeler auflösung) programmieren.


Diese Lib ist übrigens nicht mein erster Versuch in diese Richtug, sondern ich hab bereits schon mal eine lib geschrieben genau für solche full screen terminal Applications, allerdings hab ich mich da extrem in Kompatibilitätsprobleme zwischen Windows und *Nix (xterm) verrannt, weshalb mir kein besseres wort für diesen Code als clusterfuck einfällt.

Link: https://github.com/Warfley/LazTextForms

Die neue lib benutzt ausschließlich xterm kompatible escape sequences, was mittlerweile sogar mit windows kompatibel ist, ist aber konzeptionell sehr an das ursprungsprojekt von mir angelehnt.

Während ich zwar der meinung bin das man den alten code von mir nur verwenden sollte wenn man wirklich sehr mutig ist, hat der code aber sogar zu nem gewissen grad funktioniert, eine beispiel TUI anwendung kann man z.b. hier finden: https://github.com/Warfley/PokeTeamBuilder

jrx
Beiträge: 46
Registriert: Fr 14. Mai 2010, 13:23
OS, Lazarus, FPC: Lazarus 1.8.0 r56594 FPC 3.0.4 i386-win32-win32/win64
Wohnort: Erlangen

Re: Größe eines Konsolenfensters ermitteln (Linux)

Beitrag von jrx »

Unit Video ist mein Schlüssel zum Glück.
Hier der "Brachial Code" zum ausprobieren.
Strg-C beendet dieses Machwerk. :twisted:

Code: Alles auswählen

program project1;

uses
  video,sysutils;

begin
  InitVideo;
  repeat
    Writeln('VideobufSize: ',VideoBufSize);
    SetCursorPos(ScreenWidth-10,ScreenHeight-1);
    Write('Rechts u.');
    sleep(300);
    DoneVideo;
    InitVideo;
  until False;
end.       
Das geht sicher noch ordentlicher. :shock:

Mathias
Beiträge: 5084
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunc)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Größe eines Konsolenfensters ermitteln (Linux)

Beitrag von Mathias »

Und sogar Plattfomübergreifend.
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot

Benutzeravatar
six1
Beiträge: 219
Registriert: Do 1. Jul 2010, 19:01

Re: Größe eines Konsolenfensters ermitteln (Linux)

Beitrag von six1 »

Wobei ich den Ansatz von Warf sehr ordentlich finde, nachzuschauen, ob sich etwas geändert hat und erst dann zu reagieren :D
Gruß, Michael

Mathias
Beiträge: 5084
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunc)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Größe eines Konsolenfensters ermitteln (Linux)

Beitrag von Mathias »

Ich habe mal ein bisschen rumprobiert, da bleibt tatsächlich die Ausgabe immer gleich, wen ich das Termin-Fenster zu Laufzeit in der Grösse verändere.

Code: Alles auswählen

uses Crt;
begin
  repeat
    WriteLn(WindMaxX, '    ', WindMaxY);
  until KeyPressed;
end.
Für Linux-User gibt es noch eine Möglichkeit mit der Unit ncurses.
Der Vorteil dabei, es muss keine externe Package für Lazarus installiert werden.
Einziger Wermutstropfen, folgende Packet muss installiert werden:

Code: Alles auswählen

 sudo apt install libncurses-dev 
Aber das werden die meisten Linuxler sowieso schon installiert haben.

Code: Alles auswählen

uses ncurses;
var
  x, y: integer;
begin
  initscr;
  repeat
    refresh;
    getmaxyx(stdscr, y, x);
    mvprintw(4, 5, 'X: %d, Y: %d', y, x);
  until False; 
end.  
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot

Antworten