Virtuelle Konsolenterminalsequenzen

Virtuelle Terminalsequenzen sind Steuerzeichenfolgen, die beim Schreiben in den Ausgabestream die Cursorbewegung, die Konsolenfarbe und andere Vorgänge steuern können. Sequenzen können im Eingabestream auch als Antwort auf eine Ausgabestream-Abfrageinformationssequenz oder als Codierung von Benutzereingaben empfangen werden, wenn der entsprechende Modus eingestellt ist.

Mit den Funktionen GetConsoleMode und SetConsoleMode können Sie dieses Verhalten konfigurieren. Am Ende dieses Dokuments finden Sie ein Beispiel für die vorgeschlagene Methode zur Aktivierung des Verhaltens virtueller Terminals.

Das Verhalten der folgenden Sequenzen basiert auf den VT100- und abgeleiteten Terminalemulatortechnologien, insbesondere dem xterm-Terminalemulator. Weitere Informationen zu Terminalsequenzen finden Sie unter http://vt100.net und unter http://invisible-island.net/xterm/ctlseqs/ctlseqs.html.

Ausgabesequenzen

Die folgenden Terminalsequenzen werden beim Schreiben in den Ausgabestream vom Konsolenhost abgefangen, wenn das Flag ENABLE_VIRTUAL_TERMINAL_PROCESSING auf dem Bildschirmpufferhandle mit der Funktion SetConsoleMode festgelegt wurde. Beachten Sie, dass das Flag DISABLE_NEWLINE_AUTO_RETURN auch bei der Emulation des Cursorpositionierungs- und Bildlaufverhaltens anderer Terminalemulatoren in Bezug auf Zeichen nützlich sein kann, die in die letzte Spalte einer beliebigen Zeile geschrieben werden.

Einfache Cursorpositionierung

In allen folgenden Beschreibungen ist ESC immer der hexadezimale Wert 0x1B. In Terminalsequenzen dürfen keine Leerzeichen enthalten sein. Einzelne Terminalsequenzen können an beliebiger Zeichen- oder Byteposition über mehrere sequenzielle Aufrufe von WriteFile oder WriteConsole aufgeteilt werden, es empfiehlt sich jedoch, die gesamte Sequenz in einen Aufruf einzuschließen. Ein Beispiel dafür, wie diese Sequenzen in der Praxis verwendet werden, finden Sie im Beispiel am Ende dieses Themas.

Die folgende Tabelle beschreibt einfache Escapesequenzen mit einem einzigen Aktionsbefehl direkt nach dem ESC-Zeichen. Diese Sequenzen haben keine Parameter und werden sofort wirksam.

Alle Befehle in dieser Tabelle entsprechen im Allgemeinen dem Aufruf der Konsolen-API SetConsoleCursorPosition zum Platzieren des Cursors.

Die Cursorbewegung wird durch den aktuellen Viewport im Puffer begrenzt. Es erfolgt kein Bildlauf (falls verfügbar).

Sequenz Kurzform Verhalten
ESC M RI Umgekehrter Index: Führt den Umkehrvorgang von \n aus, bewegt den Cursor eine Zeile nach oben, behält die horizontale Position bei, scrollt im Puffer, falls erforderlich*
ESC 7 DECSC Cursorposition im Arbeitsspeicher speichern**
ESC 8 DECSR Cursorposition aus dem Arbeitsspeicher wiederherstellen**

Hinweis

* Wenn Bildlaufränder festgelegt sind, scrollt RI innerhalb der Ränder nur den Inhalt und lässt den Viewport unverändert. (Siehe Bildlaufränder)

**Es wird kein Wert im Arbeitsspeicher gespeichert, bis der Befehl zum Speichern verwendet wird. Die einzige Möglichkeit, auf den gespeicherten Wert zuzugreifen, ist der Befehl zum Wiederherstellen.

Cursorposition

Die folgenden Tabellen umfassen Sequenzen vom Typ „Einführungszeichen für Steuerungssequenz“ (CSI). Alle CSI-Sequenzen beginnen mit ESC (0x1B), gefolgt von [ (linke eckige Klammer, 0x5b) und können Parameter variabler Länge enthalten, um für jeden Vorgang weitere Informationen anzugeben. Dies wird durch das kompakte <n> dargestellt. Die Tabellen unten sind nach Funktionalität gruppiert, wobei Hinweise unter den einzelnen Tabellen die Funktionsweise der Gruppe erläutern.

Für alle Parameter gelten die folgenden Regeln, sofern nichts anderes angegeben ist:

  • <n> stellt den Abstand der Verschiebung dar und ist ein optionaler Parameter.
  • Wenn <n> ausgelassen wird oder „0“ (null) ist, wird es wie „1“ behandelt.
  • <n> darf nicht größer als 32.767 (maximaler kurzer Wert) sein.
  • <n> darf nicht negativ sein.

Alle Befehle in diesem Abschnitt entsprechen im Allgemeinen dem Aufruf der Konsolen-API SetConsoleCursorPosition.

Die Cursorbewegung wird durch den aktuellen Viewport im Puffer begrenzt. Es erfolgt kein Bildlauf (falls verfügbar).

Sequenz Code Beschreibung Verhalten
ESC [ <n> A CUU Cursor nach oben Cursor wird um <n> nach oben bewegt.
ESC [ <n> B CUD Cursor nach unten Cursor wird um <n> nach unten bewegt.
ESC [ <n> C CUF Cursor vorwärts Cursor wird um <n> vorwärts (nach rechts) bewegt.
ESC [ <n> D CUB Cursor zurück Cursor wird um <n> zurück (nach links) bewegt.
ESC [ <n> E CNL Cursor nächste Zeile Cursor wird von der aktuellen Position aus <n> Zeilen nach unten bewegt.
ESC [ <n> F CPL Cursor vorherige Zeile Cursor wird von der aktuellen Position aus <n> Zeilen nach oben bewegt.
ESC [ <n> G CHA Cursor horizontal absolut Cursor wird horizontal in der aktuellen Zeile zur <n>-ten Position bewegt.
ESC [ <n> d VPA Vertikale Zeile Position absolut Cursor wird vertikal in der aktuellen Spalte zur <n>-ten Position bewegt
ESC [ <y> ; <x> H CUP Cursorposition *Cursor wird zu <x>; <y>-Koordinate innerhalb des Viewports bewegt, wobei <x> die Spalte der Zeile <y> ist
ESC [ <y> ; <x> f HVP Horizontale vertikale Position *Cursor wird zu <x>; <y>-Koordinate innerhalb des Viewports bewegt, wobei <x> die Spalte der Zeile <y> ist
ESC [ s ANSISYSSC Cursor speichern – Ansi.sys-Emulation **Ohne Parameter; führt einen Vorgang zum Speichern des Cursors aus, z. B. DECSC
ESC [ u ANSISYSRC Cursor wiederherstellen – Ansi.sys-Emulation **Ohne Parameter; führt einen Vorgang zum Wiederherstellen des Cursors aus, z. B. DECRC

Hinweis

*Parameter <x> und <y> weisen die gleichen Begrenzungen wie <n> oben auf. Wenn <x> und <y> weggelassen werden, werden sie auf „1;1“ festgelegt.

**Die historische Dokumentation von ANSI.sys ist unter https://msdn.microsoft.com/library/cc722862.aspx zu finden und wurde zur Hilfe/Kompatibilität implementiert.

Cursorsichtbarkeit

Die folgenden Befehle steuern die Sichtbarkeit des Cursors und seinen blinkenden Zustand. Die DECTCEM-Sequenzen entsprechen in der Regel dem Aufruf der Konsolen-API SetConsoleCursorInfo zum Aktivieren/Deaktivieren der Cursorsichtbarkeit.

Sequenz Code Beschreibung Verhalten
ESC [ ? 12 Stunden ATT160 Blinken des Textcursors aktivieren Cursor blinkt.
ESC [ ? 12 l ATT160 Blinken des Textcursors deaktivieren Cursor blinkt nicht mehr.
ESC [ ? 25 h DECTCEM Anzeigen-Modus des Textcursors aktivieren Cursor wird angezeigt.
ESC [ ? 25 l DECTCEM Ausblenden-Modus des Textcursors aktivieren Cursor wird ausgeblendet.

Tipp

Aktivierungssequenzen enden mit dem Kleinbuchstaben h, und Deaktivierungssequenzen enden mit dem Kleinbuchstaben l.

Cursorform

Mit den folgenden Befehlen können Sie die Cursorform anpassen.

Sequenz Code Beschreibung Verhalten
ESC [ 0 SP q DECSCUSR Benutzerform Vom Benutzer konfiguriertes Standardcursorform
ESC [ 1 SP q DECSCUSR Blinkender Block Blinkende Blockcursorform
ESC [ 2 SP q DECSCUSR Beständiger Block Beständige Blockkursorform
ESC [ 3 SP q DECSCUSR Blinkende Unterstreichung Blinkende Unterstreichungscursorform
ESC [ 4 SP q DECSCUSR Beständige Unterstreichung Beständige Unterstreichungscursorform
ESC [ 5 SP q DECSCUSR Blinkender Balken Blinkende Balkencursorform
ESC [ 6 SP q DECSCUSR Beständiger Balken Beständige Balkencursorform

Hinweis

SP ist ein Literalzeichen (0x20) in der Zwischenposition und folgt q (0x71) an der letzten Position.

Viewportpositionierung

Alle Befehle in diesem Abschnitt entsprechen im Allgemeinen dem Aufruf der Konsolen-API ScrollConsoleScreenBuffer zum Verschieben des Inhalts des Konsolenpuffers.

Vorsicht Die Befehlsnamen sind irreführend. Bildlauf (bzw. Scrollen) bezieht sich darauf, in welche Richtung sich der Text während des Vorgangs bewegt, nicht darauf, in welche Richtung sich der Viewport zu bewegen scheint.

Sequenz Code Beschreibung Verhalten
ESC [ <n> S SU Nach oben scrollen Text wird um <n> nach oben gescrollt. Auch als „Nach unten schwenken“ bezeichnet; der Bildschirm wird von unten her mit neuen Zeilen gefüllt.
ESC [ <n> T SD Nach unten scrollen Text wird um <n> nach unten gescrollt. Auch als „Nach oben schwenken“ bezeichnet; der Bildschirm wird von oben her mit neuen Zeilen gefüllt.

Der Text wird beginnend mit der Zeile, in der sich der Cursor befindet, verschoben. Wenn sich der Cursor in der mittleren Zeile des Viewports befindet, verschiebt der „Nach oben scrollen“ die untere Hälfte des Viewports und fügt unten leere Zeilen ein. „Nach unten scrollen“ verschiebt die obere Hälfte der Zeilen des Viewports, und fügt oben neue Zeilen ein.

Wichtig zu beachten ist zudem, dass „Nach oben scrollen“ und „Nach unten scrollen“ auch durch die Bildlaufränder betroffen sind. Die Aktionen „Nach oben scrollen“ und „Nach unten scrollen“ wirken sich nicht auf Zeilen außerhalb der Bildlaufränder aus.

Der Standardwert für <n> ist „1“, und der Wert kann optional weggelassen werden.

Textänderung

Alle Befehle in diesem Abschnitt entsprechen im Allgemeinen dem Aufruf der Konsolen-APIs FillConsoleOutputCharacter, FillConsoleOutputAttribute und ScrollConsoleScreenBuffer zum Ändern des Textpufferinhalts.

Sequenz Code Beschreibung Verhalten
ESC [ <n> @ ICH Zeichen einfügen Fügt <n> Leerzeichen an der aktuellen Cursorposition ein und verschiebt den gesamten vorhandenen Text nach rechts. Text, der den Bildschirm rechts verlässt, wird entfernt.
ESC [ <n> P DCH Zeichen löschen Löscht <n> Zeichen an der aktuellen Cursorposition und schiebt vom rechten Bildschirmrand aus Leerzeichen hinein.
ESC [ <n> X ECH Zeichen überschreiben Überschreibt <n> Zeichen von der aktuellen Cursorposition mit einem Leerzeichen.
ESC [ <n> L IL Zeile einfügen Fügt an der Cursorposition <n> Zeilen in den Puffer ein. Die Zeile, in der sich der Cursor befindet, und die darunter liegenden Zeilen werden nach unten verschoben.
ESC [ <n> M DL Zeile löschen Löscht <n> Zeilen aus dem Puffer, beginnend mit der Zeile, in der sich der Cursor befindet.

Hinweis

Bei IL und DL sind nur die Zeilen innerhalb der Bildlaufränder (siehe „Bildlaufränder“) betroffen. Sind keine Ränder festgelegt, sind die Rahmen des Standardrands der aktuelle Viewport. Werden Zeilen unter die Ränder verschoben, werden Sie verworfen. Werden Zeilen gelöscht, werden am unteren Rand leere Zeilen eingefügt; Zeilen außerhalb des Viewports sind davon nie betroffen.

Der Standardwert für <n> ist „0“, wenn kein Wert festgelegt wird.

Für die folgenden Befehle hat der Parameter <n> 3 gültige Werte:

  • 0 löscht von der aktuellen Cursorposition (einschließlich) bis zum Ende der Zeile/Anzeige.
  • 1 löscht vom Anfang der Zeile/Anzeige bis zur aktuellen Cursorposition (einschließlich).
  • 2 löscht die gesamte Zeile/Anzeige.
Sequenz Code Beschreibung Verhalten
ESC [ <n> J ED In Anzeige überschreiben Ersetzt den gesamten durch <n> angegebenen Text im aktuellen Viewport/Bildschirm durch Leerzeichen.
ESC [ <n> K EL In Zeile überschreiben Ersetzt den gesamten Text in der Zeile mit dem durch <n> angegebenen Cursor durch Leerzeichen.

Textformatierung

Alle Befehle in diesem Abschnitt entsprechen im Allgemeinen dem Aufruf der Konsolen-API SetConsoleTextAttribute zum Anpassen der Formatierung aller zukünftigen Schreibvorgänge im Textpuffer der Konsolenausgabe.

Dieser Befehl ist insofern speziell, als dass die Position <n> unten zwischen 0 und 16 durch Semikolons getrennte Parameter annehmen kann.

Werden keine Parameter angegeben, wird der Befehl so behandelt, als ob als einziges der 0-Parameter angegeben wäre.

Sequenz Code Beschreibung Verhalten
ESC [ <n> m SGR Grafikwiedergabe festlegen Legt das Format des Bildschirms und des Texts wie durch <n> angegeben fest.

Die folgende Tabelle mit Werten kann in <n> verwendet werden, um verschiedene Formatierungsmodi darzustellen.

Formatierungsmodi werden von links nach rechts angewendet. Wenn Sie konkurrierende Formatierungsoptionen anwenden, führt dies dazu, dass jeweils die Option Vorrang hat, die am weitesten rechts angegeben ist.

Für Optionen, die Farben angeben, werden die Farben entsprechend der Definition in der Konsolenfarbtabelle verwendet, die mithilfe der SetConsoleScreenBufferInfoEx-API geändert werden kann. Wenn die Tabelle so geändert wird, dass die „blaue“ Position in der Tabelle einen RGB-Rotton anzeigt, dann werden alle Aufrufe von Foreground Blue diesen Rotton anzeigen, bis sie anderweitig geändert werden.

Wert Beschreibung Verhalten
0 Standard Setzt alle Attribute auf den Standardzustand vor der Änderung zurück.
1 Intensiv/leuchtend Wendet das Flag für Helligkeit/Intensität auf Vordergrundfarbe an.
22 Nicht intensiv/leuchtend Entfernt das Flag für Helligkeit/Intensität von der Vordergrundfarbe.
4 Unterstrich Fügt eine Unterstreichung hinzu.
24 Keine Unterstreichung Entfernt die Unterstreichung.
7 Negativ Tauscht Vordergrund- und Hintergrundfarbe.
27 Positiv (kein Negativ) Setzt Vordergrund-/Hintergrundfarbe wieder auf normal zurück.
30 Vordergrund Schwarz Wendet Schwarz (nicht intensiv/leuchtend) auf den Vordergrund an.
31 Vordergrund Rot Wendet Rot (nicht intensiv/leuchtend) auf den Vordergrund an.
32 Vordergrund Grün Wendet Grün (nicht intensiv/leuchtend) auf den Vordergrund an.
33 Vordergrund Gelb Wendet Gelb (nicht intensiv/leuchtend) auf den Vordergrund an.
34 Vordergrund Blau Wendet Blau (nicht intensiv/leuchtend) auf den Vordergrund an.
35 Vordergrund Magenta Wendet Magenta (nicht intensiv/leuchtend) auf den Vordergrund an.
36 Vordergrund Cyan Wendet Cyan (nicht intensiv/leuchtend) auf den Vordergrund an.
37 Vordergrund Weiß Wendet Weiß (nicht intensiv/leuchtend) auf den Vordergrund an.
38 Vordergrund Erweitert Wendet den erweiterten Farbwert auf den Vordergrund an (weitere Informationen finden Sie unten).
39 Vordergrund Standard Wendet nur den Vordergrund-Teil der Standardwerte an (siehe 0).
40 Hintergrund Schwarz Wendet Schwarz (nicht intensiv/leuchtend) auf den Hintergrund an.
41 Hintergrund Rot Wendet Rot (nicht intensiv/leuchtend) auf den Hintergrund an.
42 Hintergrund Grün Wendet Grün (nicht intensiv/leuchtend) auf den Hintergrund an.
43 Hintergrund Gelb Wendet Gelb (nicht intensiv/leuchtend) auf den Hintergrund an.
44 Hintergrund Blau Wendet (nicht intensiv/leuchtend) auf den Hintergrund an.
45 Hintergrund Magenta Wendet Magenta (nicht intensiv/leuchtend) auf den Hintergrund an.
46 Hintergrund Cyan Wendet Cyan (nicht intensiv/leuchtend) auf den Hintergrund an.
47 Hintergrund Weiß Wendet Weiß (nicht intensiv/leuchtend) auf den Hintergrund an.
48 Hintergrund Erweitert Wendet den erweiterten Farbwert auf den Hintergrund an (weitere Informationen finden Sie unten).
49 Hintergrund Standard Wendet nur den Hintergrund-Teil der Standardwerte an (siehe 0).
90 Vordergrund leuchtend Schwarz Wendet ein intensives/leuchtendes Schwarz auf den Vordergrund an.
91 Vordergrund leuchtend Rot Wendet ein intensives/leuchtendes Rot auf den Vordergrund an.
92 Vordergrund leuchtend Grün Wendet ein intensives/leuchtendes Grün auf den Vordergrund an.
93 Vordergrund leuchtend Gelb Wendet ein intensives/leuchtendes Gelb auf den Vordergrund an.
94 Vordergrund leuchtend Blau Wendet ein intensives/leuchtendes Blau auf den Vordergrund an.
95 Vordergrund leuchtend Magenta Wendet ein intensives/leuchtendes Magenta auf den Vordergrund an.
96 Vordergrund leuchtend Cyan Wendet ein intensives/leuchtendes Cyan auf den Vordergrund an.
97 Vordergrund leuchtend Weiß Wendet ein intensives/leuchtendes Weiß auf den Vordergrund an.
100 Hintergrund leuchtend Schwarz Wendet ein intensives/leuchtendes Schwarz auf den Hintergrund an.
101 Hintergrund leuchtend Rot Wendet ein intensives/leuchtendes Rot auf den Hintergrund an.
102 Hintergrund leuchtend Grün Wendet ein intensives/leuchtendes Grün auf den Hintergrund an.
103 Hintergrund leuchtend Gelb Wendet ein intensives/leuchtendes Gelb auf den Hintergrund an.
104 Hintergrund leuchtend Blau Wendet ein intensives/leuchtendes Blau auf den Hintergrund an.
105 Hintergrund leuchtend Magenta Wendet ein intensives/leuchtendes Magenta auf den Hintergrund an.
106 Hintergrund leuchtend Cyan Wendet ein intensives/leuchtendes Cyan auf den Hintergrund an.
107 Hintergrund leuchtend Weiß Wendet ein intensives/leuchtendes Weiß auf den Hintergrund an.

Erweiterte Farben

Einige virtuelle Terminalemulatoren unterstützen eine Farbpalette mit mehr als den von der Windows-Konsole bereitgestellten 16 Farben. Für diese erweiterten Farben wählt die Windows-Konsole die nächstmögliche passende Farbe aus der vorhandenen 16er-Farbtabelle zur Anzeige aus. Im Gegensatz zu den oben genannten typischen SGR-Werten verwenden die erweiterten Werte zusätzliche Parameter nach dem Anfangsindikator gemäß der nachstehenden Tabelle.

SGR-Untersequenz Beschreibung
38 ; 2 ; <r> ; <g> ; <b> Legt die Vordergrundfarbe auf den in den Parametern <r>, <g>, <b> angegebenen RGB-Wert fest*
48 ; 2 ; <r> ; <g> ; <b> Legt die Hintergrundfarbe auf den in den Parametern <r>, <g>, <b> angegebenen RGB-Wert fest*
38 ; 5 ; <s> Legt die Vordergrundfarbe auf den <s>-Index in der 88er- oder 256er-Farbtabelle fest*
48 ; 5 ; <s> Legt die Hintergrundfarbe auf den <s>-Index in der 88er- oder 256er-Farbtabelle fest*

*Die 88er- und 256er-Farbpaletten, die intern zum Vergleich verwaltet werden, basieren auf dem xterm-Terminalemulator. Die Vergleichs-/Rundungstabellen können zurzeit nicht geändert werden.

Bildschirmfarben

Der folgende Befehl ermöglicht es der Anwendung, die Werte der Bildschirmfarbpalette auf einen beliebigen RGB-Wert festzulegen.

Die RGB-Werte sollten hexadezimal Werte zwischen 0 und ff sein und durch den Schrägstrich getrennt werden (z. B. rgb:1/24/86).

Beachten Sie, dass es sich bei dieser Sequenz um eine „Betriebssystembefehls“-Sequenz (OSC), und nicht, wie bei vielen der anderen aufgelisteten Sequenzen, um eine CSI-Sequenz handelt, und dass sie als solche mit „\x1b]“ und nicht mit „\x1b[“. beginnt. Als OSC-Sequenzen werden sie mit einem Zeichenfolgenabschlusszeichen beendet, das als <ST> dargestellt und mit ESC \ (0x1B 0x5C) übertragen wird. BEL (0x7) kann stattdessen als Abschlusszeichen verwendet werden, aber die längere Form ist vorzuziehen.

Sequenz Beschreibung Verhalten
ESC ] 4 ; <i> ; rgb : <r> / <g> / <b><ST> Bildschirmfarben ändern Legt den Bildschirmfarbpaletten-Index <i> auf die in <r>, <g>, <b> angegebenen RGB-Werte fest.

Modusänderungen

Hierbei handelt es sich um Sequenzen, die die Eingabemodi steuern. Es gibt zwei unterschiedliche Sätze von Eingabemodi: den Pfeiltasten- und den Zehnertastaturtasten-Modus. Der Pfeiltastenmodus steuert die Sequenzen, die von den Pfeiltasten und den Tasten POS1 und ENDE ausgegeben werden, während der Zehnertastaturtasten-Modus in erster Linie die von den Tasten auf der numerischen Tastatur ausgegebene Sequenzen sowie die Funktionstasten steuert.

Jeder dieser Modi ist eine einfache boolesche Einstellung – der Pfeiltastenmodus ist entweder auf „Normal“ (Standard) oder „Anwendung“ und der Zehnertastaturtasten-Modus entweder auf „Numerisch“ (Standard) oder „Anwendung“ festgelegt.

Weitere Informationen zu den in diesen Modi ausgegebenen Sequenzen finden Sie in den Abschnitten „Pfeiltasten“ und „Numerische Tastatur und Funktionstasten“.

Sequenz Code Beschreibung Verhalten
ESC = DECKPAM Aktiviert den Modus „Anwendung“ für die Zehnertastatur. Über Zehnertastaturtasten werden Sequenzen im Modus „Anwendung“ ausgegeben.
ESC > DECKPNM Aktiviert den Modus „Numerisch“ für die Zehnertastatur. Über Zehnertastaturtasten werden Sequenzen im Modus „Numerisch“ ausgegeben.
ESC [ ? 1 Stunde DECCKM Aktiviert den Modus „Anwendung“ für die Pfeiltasten. Über Zehnertastaturtasten werden Sequenzen im Modus „Anwendung“ ausgegeben.
ESC [ ? 1 l DECCKM Deaktiviert den Modus „Anwendung“ für Pfeiltasten (Modus „Normal“ verwenden). Über Zehnertastaturtasten werden Sequenzen im Modus „Numerisch“ ausgegeben.

Abfragestatus

Alle Befehle in diesem Abschnitt entsprechen im Allgemeinen dem Aufruf der Get*-Konsolen-APIs zum Abrufen von Statusinformationen über den aktuellen Zustand des Konsolenpuffers.

Hinweis

Diese Abfragen geben ihre Antworten unmittelbar nach ihrer Erkennung im Ausgabestream in den Konsoleneingabestream ab, während ENABLE_VIRTUAL_TERMINAL_PROCESSING festgelegt ist. Das Flag ENABLE_VIRTUAL_TERMINAL_INPUT gilt nicht für Abfragebefehle, da davon ausgegangen wird, dass die Anwendung, die eine Abfrage erstellt, immer die Antwort erhalten soll.

Sequenz Code Beschreibung Verhalten
ESC [ 6 n DECXCPR Cursorposition melden Geben Sie die Cursorposition wie folgt aus: ESC [ <r> ; <c> R Wobei <r> = Cursorzeile und <c> = Cursorspalte
ESC [ 0 c DA Geräteattribute Meldet die Terminalidentität. Gibt „\x1b[?1;0c“ aus, was „VT101 ohne Optionen“ bedeutet.

Tabstopps

Während die Windows-Konsole traditionell erwartet, dass Tabstopps immer acht Zeichen breit sind, können *nix-Anwendungen, die bestimmte Sequenzen verwenden, die Position der Tabstopps innerhalb der Konsolenfenster ändern, um die Cursorbewegung durch die Anwendung zu optimieren.

Die folgenden Sequenzen ermöglichen es einer Anwendung, die Positionen der Tabstopps innerhalb des Konsolenfensters festzulegen, sie zu entfernen und zwischen ihnen zu navigieren.

Sequenz Code Beschreibung Verhalten
ESC H HTS Horizontalen Tabstopp festlegen Legt einen Tabstopp in der aktuellen Spalte fest, in der sich der Cursor befindet.
ESC [ <n> I CHT Tabulator Cursor horizontal (vorwärts) Bewegt den Cursor zur nächsten Spalte (in derselben Zeile) mit einem Tabstopp. Wenn keine weiteren Tabstopps vorhanden sind, wird der Cursor in die letzte Spalte der Zeile bewegt. Befindet sich der Cursor in der letzten Spalte, wird er zur ersten Spalte der nächsten Zeile bewegt.
ESC [ <n> Z CBT Tabulator Cursor rückwärts Bewegt den Cursor zur vorherigen Spalte (in derselben Zeile) mit einem Tabstopp. Wenn keine weiteren Tabstopps vorhanden sind, wird der Cursor in die erste Spalte bewegt. Befindet sich der Cursor in der ersten Spalte, wird der Cursor nicht bewegt.
ESC [ 0 g TBC Tabstopp löschen (aktuelle Spalte) Löscht den Tabstopp in der aktuellen Spalte, sofern vorhanden. Andernfalls geschieht nichts.
ESC [ 3 g TBC Tabstopp löschen (alle Spalten) Löscht alle momentan festgelegten Tabstopps.
  • Sowohl für CHT als auch für CBT ist <n> ein optionaler Parameter (Standardwert = 1), der angibt, wie oft der Cursor in der angegebenen Richtung vorwärts bewegt werden soll.
  • Wenn keine Tabstopps über HTS festgelegt sind, werden die erste und die letzte Spalte des Fensters von CHT und CBT als die einzigen beiden Tabstopps behandelt.
  • Wird ein Tabstopp mit HTS gesetzt, bewirkt dies zudem, dass die Konsole bei der Ausgabe eines TAB-Zeichens (0x09, '\t') auf die gleiche Weise wie bei CHT zum nächsten Tabulatorstopp navigiert.

Zeichensatz festlegen

Mit den folgenden Sequenzen können Programme die Zuordnung des aktiven Zeichensatzes ändern. Dadurch kann ein Programm 7-Bit-ASCII-Zeichen ausgeben, diese auf dem Terminalbildschirm selbst aber als andere Glyphen anzeigen lassen. Gegenwärtig sind die einzigen zwei unterstützten Zeichensätze ASCII (Standard) und der DEC Special Graphics-Zeichensatz. Unter http://vt100.net/docs/vt220-rm/table2-4.html finden Sie eine Auflistung aller Zeichen, die durch den DEC Special Graphics-Zeichensatz dargestellt werden.

Sequenz Beschreibung Verhalten
ESC ( 0 Zeichensatz festlegen – DEC Line Drawing Aktiviert den Modus „DEC Line Drawing“.
ESC ( B Zeichensatz festlegen – US ASCII Aktiviert den ASCII-Modus (Standard).

Der Modus „DEC Line Drawing“ wird insbesondere zum Zeichnen von Rahmen in Konsolenanwendungen verwendet. In der folgenden Tabelle ist dargestellt, welche ASCII-Zeichen welchen Linienzeichnungszeichen zugeordnet sind.

Hex ASCII DEC Line Drawing
0x6a j
0x6b k
0x6c l
0x6d m
0x6e n
0x71 q
0x74 t
0x75 n
0x76 v
0x77 a
0x78 x

Bildlaufränder

Mit den folgenden Sequenzen können Programme den „Bildlaufbereich“ des Bildschirms konfigurieren, der von Bildlaufvorgängen betroffen ist. Hierbei handelt es sich um eine Teilmenge der Zeilen, die angepasst werden, wenn der Bildschirm ansonsten gescrollt würde, z. B. auf einem '\n' oder RI. Diese Ränder wirken sich auch auf die Zeilen aus, die durch „Zeile einfügen“ (IL) und „Zeile löschen“ (DL), „Nach oben scrollen“ (SU) und „Nach unten scrollen“ (SD) geändert werden.

Die Bildlaufränder können besonders nützlich sein, wenn ein Teil des Bildschirms nicht gescrollt werden soll, wenn der Rest des Bildschirms gefüllt wird, wie z. B. eine Titelleiste am oberen Rand oder eine Statusleiste am unteren Rand Ihrer Anwendung.

Für DECSTBM gibt es zwei optionale Parameter, <t> und <b>, mit denen die Zeilen angegeben werden, die die oberen und unteren Zeilen des Bildlaufbereichs (einschließlich) darstellen. Wenn die Parameter weggelassen werden, ist <t> standardmäßig auf 1 und <b> auf die aktuelle Viewporthöhe voreingestellt.

Bildlaufränder gelten pro Puffer, daher ist zu beachten, dass der alternative Puffer und der Hauptpuffer getrennte Einstellungen für die Bildlaufränder aufweisen (damit eine Vollbildanwendung im alternativen Puffer die Ränder des Hauptpuffers nicht beeinträchtigen kann).

Sequenz Code Beschreibung Verhalten
ESC [ <t> ; <b> r DECSTBM Bildlaufbereich festlegen Legt die VT-Bildlaufränder des Viewports fest.

Fenstertitel

Mit den folgenden Befehlen kann die Anwendung den Titel des Konsolenfensters auf den angegebenen Parameter <string> festlegen. Die Zeichenfolge muss weniger als 255 Zeichen umfassen, um akzeptiert zu werden. Dies entspricht dem Aufrufen von „SetConsoleTitle“ mit der angegebenen Zeichenfolge.

Beachten Sie, dass es sich bei diesen Sequenzen um „Betriebssystembefehls“-Sequenzen (OSC), und nicht, wie bei vielen der anderen aufgelisteten Sequenzen, um CSI-Sequenzen handelt, und dass sie als solche mit „\x1b]“ und nicht mit „\x1b[“ beginnen. Als OSC-Sequenzen werden sie mit einem Zeichenfolgenabschlusszeichen beendet, das als <ST> dargestellt und mit ESC \ (0x1B 0x5C) übertragen wird. BEL (0x7) kann stattdessen als Abschlusszeichen verwendet werden, aber die längere Form ist vorzuziehen.

Sequenz Beschreibung Verhalten
ESC ] 0 ; <Zeichenfolge><ST> Window_Title Legt den Titel des Konsolenfensters auf <Zeichenfolge> fest.
ESC ] 2 ; <Zeichenfolge><ST> Window_Title Legt den Titel des Konsolenfensters auf <Zeichenfolge> fest.

Das abschließende Zeichen hier ist das Glocken-Zeichen, „\x07“.

Alternativer Bildschirmpuffer

*Anwendungen vom Nix-Typ verwenden oft einen alternativen Bildschirmpuffer, um den gesamten Inhalt des Puffers ändern zu können, ohne die Anwendung, von der sie gestartet wurden, zu beeinträchtigen. Der alternative Puffer beschreibt genau die Abmessungen des Fensters ohne Scrollbackbereich.

Beispiel für dieses Verhalten: Angenommen, „vim“ wird von „bash“ gestartet. „Vim“ verwendet den gesamten Bildschirm, um die Datei zu bearbeiten, kehrt dann zu „bash“ zurück und lässt dabei den Originalpuffer unverändert.

Sequenz Beschreibung Verhalten
ESC [ ? 1 0 4 9 h Alternativen Bildschirmpuffer verwenden Wechselt zu einem neuen alternativen Bildschirmpuffer.
ESC [ ? 1 0 4 9 l Hauptbildschirmpuffer verwenden Wechselt zum Hauptpuffer.

Fensterbreite

Mit den folgenden Sequenzen kann die Breite des Konsolenfensters gesteuert werden. Sie entsprechen in etwa dem Aufruf der Konsolen-API „SetConsoleScreenBufferInfoEx“ zum Festlegen der Fensterbreite.

Sequenz Code Beschreibung Verhalten
ESC [ ? 3 h DECCOLM Anzahl der Spalten auf 132 festlegen Legt die Konsolenbreite auf 132 Spalten fest.
ESC [ ? 3 l DECCOLM Anzahl der Spalten auf 80 festlegen Legt die Konsolenbreite auf 80 Spalten fest.

Vorläufiges Zurücksetzen

Die folgende Sequenz kann verwendet werden, um bestimmte Eigenschaften auf ihre Standardwerte zurückzusetzen. Die folgenden Eigenschaften werden auf die folgenden Standardwerte zurückgesetzt (außerdem sind die Sequenzen aufgelistet, die diese Eigenschaften steuern):

  • Cursorsichtbarkeit: sichtbar (DECTEM)
  • Numerische Tastatur: Numerischer Modus (DECNKM)
  • Pfeiltasten-Modus: Normaler Modus (DECCKM)
  • Obere und untere Ränder: Top=1, Bottom=Konsolenhöhe (DECSTBM)
  • Zeichensatz: US ASCII
  • Grafikwiedergabe: Standard/Aus (SGR)
  • Cursorzustand speichern: Startposition (0,0) (DECSC)
Sequenz Code Beschreibung Verhalten
ESC [ ! p DECSTR Vorläufiges Zurücksetzen Setzt bestimmte Terminaleinstellungen auf ihre Standardeinstellungen zurück.

Eingabesequenzen

Die folgenden Terminalsequenzen werden vom Konsolenhost im Eingabestream ausgegeben, wenn das Flag ENABLE_VIRTUAL_TERMINAL_INPUT auf dem Eingabepufferhandle mit dem Flag „SetConsoleMode“ festgelegt wurde.

Es gibt zwei interne Modi, die steuern, welche Sequenzen für bestimmte Eingabetasten ausgegeben werden, den Pfeiltasten-Modus und den Zehnertastaturtasten-Modus. Diese werden im Abschnitt „Modusänderungen“ beschrieben.

Schlüssel Normaler Modus Anwendungsmodus
NACH-OBEN-TASTE ESC [ A ESC O A
NACH-UNTEN-TASTE ESC [ B ESC O B
NACH-RECHTS-TASTE ESC [ C ESC O C
NACH-LINKS-TASTE ESC [ D ESC O D
Startseite ESC [ H ESC O H
ENDE ESC [ F ESC O F

Außerdem gilt Folgendes: Wenn die STRG-Taste mit einer dieser Tasten gedrückt wird, werden unabhängig vom Pfeiltasten-Modus stattdessen die folgenden Sequenzen ausgegeben:

Schlüssel Beliebiger Modus
STRG+NACH-OBEN-TASTE ESC [ 1 ; 5 A
STRG+NACH-UNTEN-TASTE ESC [ 1 ; 5 B
ALT+NACH-RECHTS-TASTE ESC [ 1 ; 5 C
ALT+NACH-LINKS-TASTE ESC [ 1 ; 5 D

Numerische Tastatur und Funktionstasten

Schlüssel Sequenz
Rückschritt 0x7f (DEL)
Anhalten 0x1a (SUB)
Escape 0x1b (ESC)
EINF ESC [ 2 ~
Löschen ESC [ 3 ~
Seite nach oben ESC [ 5 ~
Seite nach unten ESC [ 6 ~
F1 ESC O P
F2 ESC O Q
F3 ESC O R
F4 ESC O S
F5 ESC [ 1 5 ~
F6 ESC [ 1 7 ~
F7 ESC [ 1 8 ~
F8 ESC [ 1 9 ~
F9 ESC [ 2 0 ~
F10 ESC [ 2 1 ~
F11 ESC [ 2 3 ~
F12 ESC [ 2 4 ~

Modifizierer

Alt wird behandelt, indem der Sequenz ein Escapezeichen vorangestellt wird: ESC <c>, wobei <c> das vom Betriebssystem übergebene Zeichen ist. ALT+STRG wird auf die gleiche Weise behandelt, außer dass das Betriebssystem die Taste <c> vorab auf das entsprechende Steuerzeichen umgeschaltet hat, das an die Anwendung umgeleitet wird.

STRG wird im allgemeinen genau so weitergeleitet, wie vom System empfangen. Dabei handelt es sich in der Regel um ein einzelnes Zeichen, das in den reservierten Speicherbereich (0x0-0x1F) des Steuerzeichens umgeschaltet wird. Beispielsweise wird STRG+@ (0x40) zu NUL (0x00), STRG+[ (0x5b) wird ESC (0x1b) usw. Einige Strg-Tastenkombinationen werden speziell gemäß der folgenden Tabelle behandelt:

Schlüssel Sequenz
STRG+LEERTASTE 0x00 (NUL)
STRG+NACH-OBEN-TASTE ESC [ 1 ; 5 A
STRG+NACH-UNTEN-TASTE ESC [ 1 ; 5 B
ALT+NACH-RECHTS-TASTE ESC [ 1 ; 5 C
ALT+NACH-LINKS-TASTE ESC [ 1 ; 5 D

Hinweis

Links STRG+Rechts ALT wird wie ALTGR behandelt. Werden beide zusammen festgestellt, werden sie entfernt, und der Unicodewert des vom System dargestellten Zeichens wird in das Ziel übergeben. Das System übersetzt ALTGR-Werte entsprechend den aktuellen Systemeingabeeinstellungen vor.

Beispiele

Beispiel für SGR-Terminalsequenzen

Der folgende Code enthält mehrere Beispiele für die Textformatierung.

#include <stdio.h>
#include <wchar.h>
#include <windows.h>

int main()
{
    // Set output mode to handle virtual terminal sequences
    HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
    if (hOut == INVALID_HANDLE_VALUE)
    {
        return GetLastError();
    }

    DWORD dwMode = 0;
    if (!GetConsoleMode(hOut, &dwMode))
    {
        return GetLastError();
    }

    dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
    if (!SetConsoleMode(hOut, dwMode))
    {
        return GetLastError();
    }

    // Try some Set Graphics Rendition (SGR) terminal escape sequences
    wprintf(L"\x1b[31mThis text has a red foreground using SGR.31.\r\n");
    wprintf(L"\x1b[1mThis text has a bright (bold) red foreground using SGR.1 to affect the previous color setting.\r\n");
    wprintf(L"\x1b[mThis text has returned to default colors using SGR.0 implicitly.\r\n");
    wprintf(L"\x1b[34;46mThis text shows the foreground and background change at the same time.\r\n");
    wprintf(L"\x1b[0mThis text has returned to default colors using SGR.0 explicitly.\r\n");
    wprintf(L"\x1b[31;32;33;34;35;36;101;102;103;104;105;106;107mThis text attempts to apply many colors in the same command. Note the colors are applied from left to right so only the right-most option of foreground cyan (SGR.36) and background bright white (SGR.107) is effective.\r\n");
    wprintf(L"\x1b[39mThis text has restored the foreground color only.\r\n");
    wprintf(L"\x1b[49mThis text has restored the background color only.\r\n");

    return 0;
}

Hinweis

In Im vorhergehenden Beispiel ist die Zeichenfolge „\x1b[31m“ die Implementierung von ESC [ <n> m, wobei <n> gleich „31“ ist.

Die folgende Grafik zeigt die Ausgabe des vorherigen Codebeispiels.

output of the console using the sgr command

Beispiel für das Aktivieren der virtuellen Terminalverarbeitung

Der folgende Code enthält ein Beispiel für die empfohlene Vorgehensweise zum Aktivieren der virtuellen Terminalverarbeitung für eine Anwendung. Das Beispiel soll Folgendes veranschaulichen:

  1. Der bestehende Modus sollte immer über „GetConsoleMode“ abgerufen und analysiert werden, bevor der Modus mit „SetConsoleMode“ festgelegt wird.

  2. Die Überprüfung, ob „SetConsoleMode“ 0 und „GetLastError“ ERROR_INVALID_PARAMETER zurückgibt, ist der aktuelle Bestimmungsmechanismus bei der Ausführung auf einem System mit einer Vorgängerversion. Eine Anwendung, die ERROR_INVALID_PARAMETER mit einem der neueren Konsolenmodusflags im Bitfeld empfängt, sollte das Verhalten ordnungsgemäß herabstufen und den Vorgang wiederholen.

#include <stdio.h>
#include <wchar.h>
#include <windows.h>

int main()
{
    // Set output mode to handle virtual terminal sequences
    HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
    if (hOut == INVALID_HANDLE_VALUE)
    {
        return false;
    }
    HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE);
    if (hIn == INVALID_HANDLE_VALUE)
    {
        return false;
    }

    DWORD dwOriginalOutMode = 0;
    DWORD dwOriginalInMode = 0;
    if (!GetConsoleMode(hOut, &dwOriginalOutMode))
    {
        return false;
    }
    if (!GetConsoleMode(hIn, &dwOriginalInMode))
    {
        return false;
    }

    DWORD dwRequestedOutModes = ENABLE_VIRTUAL_TERMINAL_PROCESSING | DISABLE_NEWLINE_AUTO_RETURN;
    DWORD dwRequestedInModes = ENABLE_VIRTUAL_TERMINAL_INPUT;

    DWORD dwOutMode = dwOriginalOutMode | dwRequestedOutModes;
    if (!SetConsoleMode(hOut, dwOutMode))
    {
        // we failed to set both modes, try to step down mode gracefully.
        dwRequestedOutModes = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
        dwOutMode = dwOriginalOutMode | dwRequestedOutModes;
        if (!SetConsoleMode(hOut, dwOutMode))
        {
            // Failed to set any VT mode, can't do anything here.
            return -1;
        }
    }

    DWORD dwInMode = dwOriginalInMode | dwRequestedInModes;
    if (!SetConsoleMode(hIn, dwInMode))
    {
        // Failed to set VT input mode, can't do anything here.
        return -1;
    }

    return 0;
}

Beispiel für ausgewählte Anniversary Update-Features

Im Folgenden sehen Sie ein robusteres Beispiel für Code, der eine Vielzahl von Escapesequenzen verwendet, um den Puffer zu bearbeiten, wobei der Schwerpunkt auf den Features liegt, die im Anniversary Update für Windows 10 hinzugefügt wurden.

In diesem Beispiel wird der alternative Bildschirmpuffer verwendet, es werden Tabstopps bearbeitet und Bildlaufränder festgelegt und der Zeichensatz wird geändert.

// System headers
#include <windows.h>

// Standard library C-style
#include <wchar.h>
#include <stdlib.h>
#include <stdio.h>

#define ESC "\x1b"
#define CSI "\x1b["

bool EnableVTMode()
{
    // Set output mode to handle virtual terminal sequences
    HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
    if (hOut == INVALID_HANDLE_VALUE)
    {
        return false;
    }

    DWORD dwMode = 0;
    if (!GetConsoleMode(hOut, &dwMode))
    {
        return false;
    }

    dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
    if (!SetConsoleMode(hOut, dwMode))
    {
        return false;
    }
    return true;
}

void PrintVerticalBorder()
{
    printf(ESC "(0"); // Enter Line drawing mode
    printf(CSI "104;93m"); // bright yellow on bright blue
    printf("x"); // in line drawing mode, \x78 -> \u2502 "Vertical Bar"
    printf(CSI "0m"); // restore color
    printf(ESC "(B"); // exit line drawing mode
}

void PrintHorizontalBorder(COORD const Size, bool fIsTop)
{
    printf(ESC "(0"); // Enter Line drawing mode
    printf(CSI "104;93m"); // Make the border bright yellow on bright blue
    printf(fIsTop ? "l" : "m"); // print left corner 

    for (int i = 1; i < Size.X - 1; i++)
        printf("q"); // in line drawing mode, \x71 -> \u2500 "HORIZONTAL SCAN LINE-5"

    printf(fIsTop ? "k" : "j"); // print right corner
    printf(CSI "0m");
    printf(ESC "(B"); // exit line drawing mode
}

void PrintStatusLine(const char* const pszMessage, COORD const Size)
{
    printf(CSI "%d;1H", Size.Y);
    printf(CSI "K"); // clear the line
    printf(pszMessage);
}

int __cdecl wmain(int argc, WCHAR* argv[])
{
    argc; // unused
    argv; // unused
    //First, enable VT mode
    bool fSuccess = EnableVTMode();
    if (!fSuccess)
    {
        printf("Unable to enter VT processing mode. Quitting.\n");
        return -1;
    }
    HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
    if (hOut == INVALID_HANDLE_VALUE)
    {
        printf("Couldn't get the console handle. Quitting.\n");
        return -1;
    }

    CONSOLE_SCREEN_BUFFER_INFO ScreenBufferInfo;
    GetConsoleScreenBufferInfo(hOut, &ScreenBufferInfo);
    COORD Size;
    Size.X = ScreenBufferInfo.srWindow.Right - ScreenBufferInfo.srWindow.Left + 1;
    Size.Y = ScreenBufferInfo.srWindow.Bottom - ScreenBufferInfo.srWindow.Top + 1;

    // Enter the alternate buffer
    printf(CSI "?1049h");

    // Clear screen, tab stops, set, stop at columns 16, 32
    printf(CSI "1;1H");
    printf(CSI "2J"); // Clear screen

    int iNumTabStops = 4; // (0, 20, 40, width)
    printf(CSI "3g"); // clear all tab stops
    printf(CSI "1;20H"); // Move to column 20
    printf(ESC "H"); // set a tab stop

    printf(CSI "1;40H"); // Move to column 40
    printf(ESC "H"); // set a tab stop

    // Set scrolling margins to 3, h-2
    printf(CSI "3;%dr", Size.Y - 2);
    int iNumLines = Size.Y - 4;

    printf(CSI "1;1H");
    printf(CSI "102;30m");
    printf("Windows 10 Anniversary Update - VT Example");
    printf(CSI "0m");

    // Print a top border - Yellow
    printf(CSI "2;1H");
    PrintHorizontalBorder(Size, true);

    // // Print a bottom border
    printf(CSI "%d;1H", Size.Y - 1);
    PrintHorizontalBorder(Size, false);

    wchar_t wch;

    // draw columns
    printf(CSI "3;1H");
    int line = 0;
    for (line = 0; line < iNumLines * iNumTabStops; line++)
    {
        PrintVerticalBorder();
        if (line + 1 != iNumLines * iNumTabStops) // don't advance to next line if this is the last line
            printf("\t"); // advance to next tab stop

    }

    PrintStatusLine("Press any key to see text printed between tab stops.", Size);
    wch = _getwch();

    // Fill columns with output
    printf(CSI "3;1H");
    for (line = 0; line < iNumLines; line++)
    {
        int tab = 0;
        for (tab = 0; tab < iNumTabStops - 1; tab++)
        {
            PrintVerticalBorder();
            printf("line=%d", line);
            printf("\t"); // advance to next tab stop
        }
        PrintVerticalBorder();// print border at right side
        if (line + 1 != iNumLines)
            printf("\t"); // advance to next tab stop, (on the next line)
    }

    PrintStatusLine("Press any key to demonstrate scroll margins", Size);
    wch = _getwch();

    printf(CSI "3;1H");
    for (line = 0; line < iNumLines * 2; line++)
    {
        printf(CSI "K"); // clear the line
        int tab = 0;
        for (tab = 0; tab < iNumTabStops - 1; tab++)
        {
            PrintVerticalBorder();
            printf("line=%d", line);
            printf("\t"); // advance to next tab stop
        }
        PrintVerticalBorder(); // print border at right side
        if (line + 1 != iNumLines * 2)
        {
            printf("\n"); //Advance to next line. If we're at the bottom of the margins, the text will scroll.
            printf("\r"); //return to first col in buffer
        }
    }

    PrintStatusLine("Press any key to exit", Size);
    wch = _getwch();

    // Exit the alternate buffer
    printf(CSI "?1049l");

}