Probleme mit Grafischen Zeichen in der Windows Console

visualteam
Beiträge: 1
Registriert: Fr 24. Jan 2014, 16:36
OS, Lazarus, FPC: Debian 9 + 10, Win10prof (aktuelles Lazarus 64bit)
CPU-Target: 64 Bit
Wohnort: Franken
Kontaktdaten:

Re: Probleme mit Grafischen Zeichen in der Windows Console

Beitrag von visualteam »

Blocktronic hat geschrieben:...
Insofern sehe ich es als sehr Positiv an, da nun etwas neues entstehen wird.
Vermutlich werde ich dieses Terminal für Windows dann auch als Freeware in die Welt entlassen.

...


Danke - und laß hören/sehen :-)

Gruß VT
________________
:-)

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

Re: Probleme mit Grafischen Zeichen in der Windows Console

Beitrag von Mathias »

Vieleicht hilf dir das weiter, mit diesem Code aus einem Delphi-Programm, konnte ich alle 256-ASCII auf eine Bitmap ausgeben.

Code: Alles auswählen

      with Font do begin
        Charset := OEM_CHARSET;
        Color := 0;
        Height := 0;
        Name := 'Terminal';
        Pitch := fpDefault;
        Size := 24;
        Style := [fsBold, fsItalic, fsUnderline, fsStrikeOut];
        Style := [];
      end;
Dateianhänge
Zwischenablage-1.png
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

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

Re: Probleme mit Grafischen Zeichen in der Windows Console

Beitrag von Mathias »

So bringe ich sogar alle 256 ASCII-Zeichen in die Console, inklusive der Steuerzeichen.

Interessante währe noch, wen man über einen Pointer direkt in die Konsole zugreiffen könnte, so ählich wie unter DOS mit Mem[$B800:0000].

Code: Alles auswählen

program project1;
uses
  Windows;
 
  procedure OutCharXY(x, y: integer; ch: char; col: byte);
  var
    numChars: integer = 1;
    c: coord;
    p: longword = 0;
  begin
    c.X := x;
    c.Y := y;
    FillConsoleOutputAttribute(GetStdHandle(STD_OUTPUT_HANDLE), col,
      numChars, c, p);
    FillConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE), ch,
      numChars, c, p);
  end;
 
 
var
  i: integer;
begin
  for i := 0 to 255 do begin
    OutCharXY(i mod 16 * 2, i div 16, char(i), 7);
  end;
  readln;
end
Dateianhänge
Ascii.png
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Iceman_03
Beiträge: 8
Registriert: Fr 18. Jun 2010, 11:57

Re: Probleme mit Grafischen Zeichen in der Windows Console

Beitrag von Iceman_03 »

Ich hatte das gleiche Probleme, konnte es jetzt jedoch lösen. Vorweg, ich arbeite noch mit FPC 2.6.4.

Das Problem mit der Darstellung der Zeichen in einer Konsolenanwendung liegt an den Windows-Schriftarten. Die Rasterschriftart (Terminal) basiert auf der Codepage 850 und hat damit zum Beispiel als Zeichen 185 ($b9) das "╣" (Doppelte vertikale Linie nach links). Die den beiden anderen Schriftarten die unter Win7 für eine Konsolenanwendung zur Verfügung stehen, "Consolas" und "Lucida Console", haben einen Unicode-Zeichensatz und da ist das Zeichen 185 ein "Ù".

Das Problem liegt, IMHO, in der Procedure WriteStr aus der crt.pp von Free Pascal.

Code: Alles auswählen

procedure WriteStr(const s: string);
var
  WritePos: Coord; { Upper-left cell to write from }
  numWritten : DWord;
  WinAttr : word;
  i: integer;
begin
  WritePos.X:=currX-2;
  WritePos.Y:=currY-1;
 
  WinAttr:=TextAttr;
  for i:=1 to Length(s) do
    begin
      Inc(WritePos.X);
      WriteConsoleOutputCharacter(GetStdhandle(STD_OUTPUT_HANDLE), @s[i], 1, writePos, numWritten);
      WriteConsoleOutputAttribute(GetStdhandle(STD_OUTPUT_HANDLE),@WinAttr, 1, writePos, numWritten);
      Inc(CurrX);
      if CurrX>WindMaxX then
        begin
          CurrX:=WindMinX;
          Inc(CurrY);
          While CurrY>WindMaxY do
            begin
              RemoveLine(1);
              Dec(CurrY);
            end;
          WritePos.X:=currX-2;
          WritePos.Y:=currY-1;
        end;
    end;
end;


Hier wird die Function WriteConsoleOutputCharacter aus der kernel32.dll verwendet. Es wird char für char einzeln an diese Funktion übergeben. Ergo wird unter Consolas oder Lucida Console ein "Ù" ausgegeben.

Eine Konvertierung des AnsiStrings nach UTF-8 bringt auch nichts. Ich konnte das Problem erst beseitigen, indem ich den AnsiString nach UTF-8, AnsiChar(185) -> U+2563 ($e2+$95+$a3), und danach nach WideSting konvertiert habe.
wString := UTF8Decode(CP850toUTF8(aString))

Danach noch schnell die WriteStr aus der CRT.PP umgeschrieben auf WriteConsoleOutputCharacterW und schon werden die Zeichen auch unter Consolas und Lucida Console korrekt ausgegeben. Bei der Schriftart Terminal darf natürlich keine Umwandlung in UTF-8 erfolgen -> wString := WideString(aString). Ergo mache ich vorweg eine Abfrage des gewählten Font über die Kernel32-Funktion GetCurrentConsoleFontEx. Siehe hierzu den Post von Michl weiter oben.

Da es mir auch nicht klar ist, warum die Procedure WriteStr jedes Zeichen einzeln an die Function WriteConsoleOutputCharacterW übergibt, wo diese doch eigentlich dafür gedacht ist auch mehrere Zeichen auf einmal auszugeben, habe ich gleich mal die gesamte Procedure umgeschrieben.

Code: Alles auswählen

procedure WriteStr(const s: WideString);
var WritePos                 : Coord; { Upper-left cell to write from }
    numWritten               : DWord;
    numWrite                 : DWord;
    sLen                     : DWord;
    WinAttr                  : Array [1..255] of word;
    i                        : integer;
begin
  WritePos.X := currX-2;
  WritePos.Y := currY-1;
  FillWord(WinAttr,255,TextAttr);
 
  sLen := Length(s);
  i := 1;
  Repeat
    Inc(WritePos.X);
    numWrite := Min(WindMaxX-CurrX+1,sLen+1-i);
    WriteConsoleOutputCharacterW(GetStdhandle(STD_OUTPUT_HANDLE), @s[i], numWrite, writePos, numWritten);
    WriteConsoleOutputAttribute(GetStdhandle(STD_OUTPUT_HANDLE),@WinAttr, numWrite, writePos, numWritten);
    inc(CurrX,numWrite);
    inc(i,numWrite);
    if CurrX>WindMaxX then
    begin
      CurrX:=WindMinX;
      Inc(CurrY);
      While CurrY>WindMaxY do
      begin
        RemoveLine(1);
        Dec(CurrY);
      end;
      WritePos.X:=currX-2;
      WritePos.Y:=currY-1;
    end;
  Until (i>sLen);
end;


Ich habe es jetzt noch nicht getestet, aber ich gehe davon aus, dass dadurch die Ausgabe im Konsolenfenster auch beschleunigt werden sollte.
Borland Pascal 7.0 | Delphi 5 Enterprise | Delphi XE6 Enterprise | Lazarus 1.2.2 - FPC 2.6.4 Win7

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

Re: Probleme mit Grafischen Zeichen in der Windows Console

Beitrag von Mathias »

Du könntest das mal hier melden:
Vielleicht haben die Entwickler ein Argument, das sie dies so lösen.

http://lists.freepascal.org/cgi-bin/mai ... /fpc-devel
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Michl
Beiträge: 2505
Registriert: Di 19. Jun 2012, 12:54

Re: Probleme mit Grafischen Zeichen in der Windows Console

Beitrag von Michl »

Mathias hat geschrieben:Du könntest das mal hier melden:
Braucht mMn nicht. Mit dem aktuellen Lazarus 1.6 kann man problemlos die verwendete Codepage der Windows Console verändern. Sie kann sogar UTF-8. Z.B.:

Code: Alles auswählen

uses
  ..., setdefaultcodepages;
 
procedure TForm1.Button1Click(Sender: TObject);
begin
  Writeln('Hallo Welt ÄÖÜ');
  WriteLn('Hallo Welt, Hello world, Γειά σου κόσμος, Witaj świecie, Olá mundo und Здравствуйте мир');
end;
Einfach die Unit setdefaultcodepages von hier verwenden (durch den Hack, den Lazarus macht und als DefaultSystemCodepage UTF-8 verwendet, wird mit setdefaultcodepages UTF-8 als ConsoleCodepage genutzt).

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection; 

Antworten