VT100-Terminal-Emulation in Windows WPF oder Silverlight

7

Ich denke darüber nach, eine WPF- oder Silverlight-App zu erstellen, die genau wie ein Terminalfenster funktioniert. Außer, da es in WPF / Silverlight ist, wird es in der Lage sein, das Terminal-Erlebnis mit Effekten, Bildern usw. zu verbessern.

Ich versuche herauszufinden, wie man ein Terminal am besten emuliert. Ich weiß, wie man mit der VT100-Emulation umgeht, was Parsing usw. angeht. Aber wie kann ich es anzeigen? Ich überlegte, eine RichTextBox zu verwenden und die VT100-Escape-Codes im Wesentlichen in RTF zu konvertieren.

Das Problem, das ich damit sehe, ist die Leistung. Das Terminal könnte nur ein paar Zeichen gleichzeitig haben, und um es in die Textbox laden zu können, würde ich ständig TextRanges erstellen und Load () benutzen, um das RTF zu laden. Damit jede Lade- "Sitzung" abgeschlossen ist, müsste sie RTF vollständig beschreiben. Wenn zum Beispiel die aktuelle Farbe Rot ist, würde jede Eingabe in die TextBox die RTF-Codes benötigen, um den Text rot zu machen, oder ich nehme an, die RTB wird sie nicht als rot laden.

Das scheint sehr redundant zu sein - das resultierende RTF-Dokument, das durch die Emulation erstellt wird, wird extrem unordentlich sein. Auch die Bewegung des Caret scheint nicht so zu sein, als ob sie von der RTB ideal gehandhabt würde. Ich brauche etwas Brauchbares, denke ich, aber das macht mir Angst!

Ich hoffe auf gute Ideen oder Hinweise auf bestehende Lösungen. Vielleicht gibt es eine Möglichkeit, ein tatsächliches Terminal- und Overlay-Zeug darüber zu betten. Das einzige, was ich gefunden habe, ist ein altes WinForms-Steuerelement.

UPDATE: Sehen Sie, wie die vorgeschlagene Lösung aufgrund von perf in meiner Antwort unten fehlschlägt. :(
VT100 Terminal-Emulation in Windows WPF oder Silverlight

    
InfinitiesLoop 10.07.2010, 15:36
quelle

4 Antworten

16

Wenn Sie versuchen, dies mit RichTextBox und RTF zu implementieren, stoßen Sie schnell auf viele Einschränkungen und finden, dass Sie viel mehr Zeit mit der Bearbeitung von Differenzen verbringen, als wenn Sie die Funktionalität selbst implementieren würden.

Tatsächlich ist es recht einfach, eine VT100-Terminalemulation mit WPF zu implementieren. Ich weiß, weil ich gerade einen fast vollständigen VT100 Emulator in einer Stunde oder so implementiert habe. Um genau zu sein, habe ich alles hinzugefügt, außer:

  • Tastatureingabe,
  • Alternative Zeichensätze,
  • Ein paar esoterische VT100-Modi, die ich noch nie benutzt habe,

Die interessantesten Teile waren:

  • Die Zeichen mit doppelter Breite / doppelter Höhe, für die ich RenderTransform und RenderTransformOrigin
  • verwendet habe
  • Das Blinken, für das ich eine Animation auf einem gemeinsamen Objekt verwendet habe, so dass alle Zeichen zusammen blinken
  • Die Unterstreichung, für die ich ein Gitter und ein Rechteck verwendet habe, so dass es eher wie ein VT100-Display aussieht
  • Der Cursor und die Auswahl, für die ich ein Flag für die Zellen selbst gesetzt habe und mit DataTriggers die Anzeige
  • ändere
  • Die Verwendung eines eindimensionalen Arrays und eines verschachtelten Arrays, die auf dieselben Objekte verweisen, um Scrollen und Auswählen zu erleichtern

Hier ist der XAML:

%Vor%

Und hier ist der Code:

%Vor%

Beachten Sie, dass Sie das TerminalCell DataTemplate aktualisieren können, wenn Sie das visuelle Styling nicht mögen. Beispielsweise könnte der Cursor ein blinkendes Rechteck anstelle eines festen Rechtecks ​​sein.

Dieser Code hat Spaß gemacht zu schreiben. Hoffentlich wird es dir nützlich sein. Es hat wahrscheinlich einen oder zwei Fehler (oder drei), da ich es nie wirklich ausgeführt habe, aber ich nehme an, dass diese leicht aufgeklärt werden. Ich würde eine Bearbeitung zu dieser Antwort begrüßen, wenn Sie etwas reparieren.

    
Ray Burns 11.07.2010, 16:53
quelle
1

Ich verstehe nicht, warum Sie sich darüber aufregen, dass das RTF sich verzieht. Ja, es wird. Aber es ist nicht Ihre Last, damit umzugehen, ein Microsoft-Programmierer hat das vor einer Weile gemacht, den Code schreiben zu müssen, um gewundenes RTF zu rendern. Es funktioniert gut und ist völlig undurchsichtig für Sie.

Ja, es wird nicht super schnell sein. Aber was zum Teufel, Sie emulieren ein 80x25-Display, das bei 9600 Baud lief. Die Kontrolle komplett zu ersetzen, um es optimal zu machen, macht wenig Sinn und wird ein großes Unterfangen sein.

    
Hans Passant 10.07.2010 16:44
quelle
1

Nun, um meinen Status zu melden, habe ich festgestellt, dass dies mit WPF oder Silverlight nicht wirklich möglich ist .

Das Problem mit dem vorgeschlagenen Ansatz besteht darin, dass es 80 * 24 TextBlocks plus einige andere Elemente mit mehreren Bindungen für Vordergrundfarbe, Hintergrundfarbe usw. gibt. Wenn der Bildschirm scrollen muss, muss jede dieser Bindungen neu bewertet werden, und es ist sehr, sehr langsam. Die Aktualisierung des gesamten Bildschirms dauert einige Sekunden. In meiner App ist das nicht akzeptabel, der Bildschirm wird ständig scrollen.

Ich habe viele verschiedene Dinge ausprobiert, um es zu optimieren. Ich habe versucht, einen Textblock mit jeweils 80 Läufen pro Zeile zu verwenden. Ich habe versucht, die Änderungsbenachrichtigungen zu verarbeiten. Ich habe versucht, es so ein 'Scroll' Ereignis manuell jeden Textblock aktualisiert. Nichts hilft wirklich - der langsame Teil ist das Aktualisieren der Benutzeroberfläche, nicht die Art, wie es gemacht wird.

Eine Sache, die mir geholfen hätte, wäre, einen Mechanismus zu entwickeln, bei dem nicht für jede Zelle ein Textblock oder Lauf vorhanden ist, sondern nur Textblöcke geändert werden, wenn sich der Stil des Textes ändert. So wäre beispielsweise eine Zeichenfolge aus gleichfarbigem Text nur 1 Textblock. Dies wäre jedoch sehr kompliziert und am Ende würde es nur Szenarien helfen, die wenig Stilvariation auf dem Bildschirm haben. Meine App wird viele Farben fliegen (denke ANSI Kunst), so dass es in diesem Fall immer noch langsam wäre.

Eine andere Sache, von der ich dachte, dass sie helfen würde, ist, wenn ich die Textblöcke nicht aktualisiere, sondern sie scrollte, während der Bildschirm gescrollt wird. Textblöcke würden also von oben nach unten verschoben und dann müssten nur die neuen aktualisiert werden. Mit einer beobachtbaren Sammlung habe ich das geschafft. Es hat geholfen, aber es ist immer noch zu langsam!

Ich habe sogar ein benutzerdefiniertes WPF-Steuerelement mit OnRender in Erwägung gezogen. Ich habe einen erstellt, der drawingContext.RenderText auf verschiedene Arten verwendet hat, um zu sehen, wie schnell er sein könnte. Aber selbst das ist zu langsam, um den Bildschirm ständig zu aktualisieren.

Das ist also ... Ich habe dieses Design aufgegeben. Ich schaue stattdessen auf die Verwendung eines tatsächlichen Konsolenfensters wie hier beschrieben:

Keine Ausgabe von einer WPF-Anwendung an die Konsole?

Ich mag das nicht wirklich, da das Fenster vom Hauptfenster getrennt ist, also suche ich nach einer Möglichkeit, das Konsolenfenster in das WPF-Fenster einzubetten, falls das überhaupt möglich ist. Ich werde eine andere SO-Frage dazu stellen und sie hier verlinken, wenn ich das tue.

UPDATE: Die Einbettung des Konsolenfensters ist ebenfalls fehlgeschlagen, da die Titelleiste nicht entfernt werden kann. Ich habe es als benutzerdefiniertes WinForms-Steuerelement auf niedriger Ebene implementiert, und ich hosse das in WPF. Das funktioniert wunderbar und nach einigen Optimierungen ist es sehr, sehr schnell.

    
InfinitiesLoop 19.07.2010 16:33
quelle
1

Die einzige Möglichkeit, Text effektiv anzuzeigen, ist die Verwendung von TextFormatter. Ich habe Telnet-Client für textbasierte RPG-Spiele implementiert und es funktioniert ziemlich gut. Sie können Quellen unter Ссылка

abrufen     
petka 13.10.2011 11:59
quelle

Tags und Links