Das Grafik-System für CP/M Plus (CPC 6128, Joyce) und CP/M-86 (IBM-Kompatible)

GSX ohne Geheimnisse

Teil 4: Terminal-Funktionen und PC-Spezialitäten

Martin Kotulla
Bisher beschäftigte sich die Serie mit dem eigentlichen GSX-Schwerpunkt: der Grafik. Im letzten Teil wird gezeigt, daß GSX aber auch für reine Textausgabe etwas zu bieten hat. Und die PC-Benutzer werden sich sicherlich über die Anpassungshinweise für Turbo unter CP/M-86 freuen.

GSX wird normalerweise als Erweiterung des Betriebssystems CP/M abgesehen, die die Ausgabe hochauflösender Grafiken möglich macht. Doch GSX kann noch mehr. Es räumt mit dem Mißstand auf, der seit der ersten CP/M-Version besteht und der diesem Betriebssystem viele Sympathien gekostet hat: GSX bietet auch einen Standard für die Ansteuerung des Textbildschirms!

Wie CP/M-Benutzer unerfreulicherweise feststellen mußten, ist es ja bisher so gewesen, daß jeder Hersteller eines CP/M-Computers oder eines Terminals seine eigenen Steuerzeichen für den Bildschirm definiert hat. So löscht der ASCII-Code 26 (Control-Z) bei vielen Terminals den Bildschirm, beim Schneider CPC unter CP/M 2.2 setzt er hingegen ein Fenster auf dem Monitor-Bildschirm. Beim CPC muß man statt dessen das ASCII-Zeichen 12 (Control-L) ausgeben, was wiederum vom CPC 6128 und Joyce desselben Herstellers unter CP/M Plus nicht akzeptiert wird. Kurz gesagt: Das Chaos ist perfekt.

Kompatible Text-Schnittstelle

Abhilfe schaffen das Installationsprogramme wie GINST aus der Turbo-Pascal-Toolbox. Eleganter ist es aber, einen festen Standard zu entwickeln, an den sich die Programmierer halten können.

Mit GSX kann man den Text-Cursor auf dem Bildschirm bewegen, den Bildschirm oder Teile von ihm löschen, mit invers dargestellten Zeichen schreiben, die aktuelle Cursor-Position abfragen und vieles mehr. Diese Funktionen führten aber bisher in GSX eher ein Schattendasein, da Digital Research sie sehr gut versteckt hat. Denn die Programmierer haben ihnen keine neuen GDOS-Funktionsnummern zugewiesen, sondern alle diese Funktionen unter einer übergeordeneten Funktion zusammengefaßt.

Diese Sammelfunktion besitzt die Nummer 5 und nennt sich sinnigerweise 'Escape', um die Verwandschaft mit den oft verwendeten Terminal-Installationen zu symbolisieren. Durch einen Wert im contrl-Feld wird die gewünschte untergeordnete Einzelfunktion spezifiziert.

Umweg über Escape

Schematisch läßt sich dieser Umweg so darstellen: BDOS -> GDOS -> ESCAPE -> Funktion

Der einzige Sinn dieses indirekten Wegs ist es, genügend 'Raum' für Erweiterungen zu haben. Doch zunächst sind nur 19 Funktionen benutzt, der Rest ist reserviert oder frei für eigene Nutzungen.

Die Belegung der Datenfelder bei der Escape-Funktion ist ebenso standardisiert wie bei den anderen GSX-Funktionen.

Wie üblich enthält contrl(1) die Nummer der GDOS-Funktion. Bei 'Escape' ist das also ständig 5. Über den Inhalt von contrl(6) wählt man die gewünschte Funktion aus der Menge aller Escape-Funktionen.

Und entsprechend dem GSX-Standard, den Sie schon von den anderen Funktionen kennen, werden die Feldelemente contrl(4) und contrl(6) dazu benutzt, die Zahl der übergebenen Parameter festzulegen.

In Turbo-Pascal bringt die Programmierung einer Prozedur GsxEscape keine besonderen Schwierigkeiten mit sich. Das Grundmuster kann zum Beispiel so aussehen:

Procedure GscEscape(FnNum:integer);

Begin
  Contrl[1]:=5;
  Contrl[6]:=FnNum;
  Bdos(115,Addr(pblock[1]));
End;

Bislang 19 Funktionen

Die Nummern der Escape-Funktionen liegen im Bereich von 1 bis 19. Hinter diesen Nummern verstecken sich die folgenden Aufgaben:

1 - Bildschirmgröße in Zeilen und Spalten erfragen
2 - Textmodus aus- und Grafikmodus einschalten
3 - Grafikmodus abschalten und in den Textmodus zurückkehren
4 - Text-Cursor eine Zeile nach oben bewegen
5 - Text-Cursor eine Zeile nach unten bewegen
6 - Text-Cursor ein Zeichen nach rechts bewegen
7 - Text-Cursor ein Zeichen nach links bewegen
8 - Text-Cursor in die linke obere Bildschirmecke stellen (HOME)
9 - Von der Position des Text-Cursors bis zum Bildschirmende löschen
10 - Von der Cursor-Position bis zum Zeilenende löschen
11 - Cursor in Zeile und Spalte absolut positionieren
12 - Text an der Stelle des Text-Cursors ausgeben
13 - Inverse Darstellung des Textes einschalten
14 - Inverse Textdarstellung abschalten
15 - Aktuelle Cursor-Position erfragen
16 - Stellung des Joysticks oder der Maus erfragen
17 - Bildschirm-Hardcopy ausdrucken (sofern implementiert)
18 - Grafik-Cursor an einer Stell positionieren
19 - Grafik-Cursor wieder unsichtbar machen

Die meisten dieser Funktionen sind selbsterklärend und benötigen keine weitere Erläuterung. Zu einigen gibt es aber doch etwas zu sagen.

Allgemein gilt, daß contrl(2) stets auf 0 gesetzt werden muß. Diese Regel besitzt nur eine Ausnahme: die Funktion 18 ('Place Graphics Cursor At Location') will unbedingt contrl(2)=2 übergeben bekommen.

Textbildschirm einschalten!

Wie in der letzten c't schon angesprochen, verwenden einige Computer getrennte Darstellungsweisen für den Text- und den Grafikmodus, wie beispielsweise die PC-Kompatiblen. Hingegen arbeiten die Schneider CPCs und Joyce-PCWs grundsätzlich im Grafikmodus und kennen keinen speziellen Textmodus als solchen. Will man aber auf einem PC mit dem Turbo-Befehl WRITE etwas ausgeben (wie die Routine 'ShowCaps' im Teil 2 der Serie), so muß man zuvor auf den Textmodus umschalten. Weitere Anpassungshinweise finden PC-Besitzer am Ende des Artikels.

In Turbo-Pascal kann man die Umschalt-Prozeduren unter Zuhilfenahme der weiter oben abgedruckten Prozedur GsxEscape so eingeben:

Procedur TextMode;
Begin
 Contrl[2]:=0;
  GsxEscape(3);
End;

Procedure GraphMode;
Begin
  Contrl[2]:=0;
  GsxEscape(2);
End;

Die Bildschirmgröße, die Sie über die Escape-Funktion 1 feststellen können, wird für die Zeilen in intout(1) und für die Spalten in intout(2) gemeldet.
Bein den meisten Terminals und Computern werden Sie eine Angabe von 24 * 80 erhalten. Beim Joyce ist diese Angabe aber größer, da dessen Video-Chip mehr Zeilen und Spalten darstellen kann.

Frei beweglicher Cursor

Die Cursor-Bewegungen in alle vier Himmelsrichtungen sind völlig unproblematisch zu verwenden. Hier zwei Beispiele für 'Cursor noch oben' und 'Cursor' nach links':

Procedure CursorUp;
Begin
  Contrl[2]:=0;
  GsxEscape(4);
End;

Procedure CursorLeft;
Begin
  Contrl[2]:=0;
  GsxEscape(7);
End;

Wird versucht, den Cursor über die Grenzen des Bildschirms hinaus zu bewegen, ignoriert GSX diesen Befehl. Es existiert also kein 'Bildumlauf' wie bei den VT-52-Terminals. Das läßt sich ganz einfach demonstrieren:

For i:=1 To 40 Do
Begin
  CursorUp;
  Write('*');
End;

Die letzten Zeichen 'kleben' an der obersten Bildschirmzeile.

Die Funktion 'Home Cursor' stellt den Text-Cursor in die linke obere Ecke des Bildschirms, die Ausgangsposition ist also:

Procedure Home;
Begin
  Contrl[2]:=0;
  GsxEscape(8);
End;

Zwei Funktionen zum Löschen von Teilen des Bildschirms werden unterstützt: Funktion 9 löscht bis zum Ende des Bildschirms, die Funktion 10 hingegen nur bis zum Ende der Textzeile. Der Ausgangspunkt ist stets die aktuelle Cursor-Position:

Procedure DelEndLine;
Begin
  Contrl[2]:=0;
  GsxEscape(9);
End;

Procedure DelEndScreen;
Begin
  Contrl[2]:=0;
  GsxEscape(10);
End;

Wollen Sie den gesamten Bildschirm löschen, ist es das einfachste, mit der HOME-Funktion den Cursor an den Bildschirmanfang zu stellen und dann mit der Escape-Funktion 10 alle Zeichen bis zum Ende des Bildschirms zu löschen.
Zur direkten Positionierung des Text-Cursors kann die Escape-Funktion 11 benutzt werden. Sie übernimmt in den Feldelementen intin(1) und intin(2) die gewünschten Zeilen- und Spaltennummer:

Procedure GotoXY(S,Z:integer);
Begin
  Contrl[2]:=0;
  intin(1):=Z;
  intin(2):=S;
  GsxEscape(11);
End;

Im Gegenzug können Sie bei GSX auch die gerade gültige Cursor-Position erfragen. Dazu dient die Funktion 15, 'Inquire current cursor address'. Sie übernimmt contrl(2)=0 und contrl(6)=15. Von GSX werden dann die Zeile und Spalte in intout(1) und intout(2) übergeben:

Procedure GetCursor(Var S,Z:integer);
Begin
  Contrl[2]:=0;
  GsxEscape(15);
  Z:=intout[1];
  S:=intout[2];
End;

Attribute

Normalerweise wirken alle über die GSX-Funktionen festgelegten Attribut, hier im speziellen die inverse Darstellung, die die Festlegung der Cursor-Position, auf die folgenden Zeichenausgaben über das BDOS und BIOS. Sie können also in Turbo-Pascal die Standardprozeduren WRITE und WRITELN weiterhin verwenden. Das ist aber von Digital Research nirgends exakt festgelegt. Deshalb ist es durchaus denkbar, daß in exotischen GSX-Anpassungen die GSX-Attribute keine Auswirkung auf die normale Bildschirmausgabe haben.

Sollte dies bei Ihnen zutreffen, können Sie alle Bildschirmausgaben über GSX umleiten. Dazu ist die Escape-Funktin 12 gedacht. Sie übernimmt im Datenfeld intin einen zeichenweise abgelegten ASCII-String und in contrl(4) dessen Länge in Bytes. Contrl(2) ist wieder auf Null gesetzt, und in contrl(6) wird die Funktionsnummer 12 kodiert. Ausgehend von der aktuellen Cursor-Position, gibt die Funktion den Text aus.
Da ist es sehr praktisch, daß Turbo-Pascal die Definition neuer Ausgabetreiber erlaubt. Hierzu muß lediglich die Turbo Systemvariable ConOutPtr auf eine neue Prozedur in Pascal oder Maschinensprache umgelenkt werden:

ConoutPtr:=Addr(NeueProzedur);
bzw.
Ofs(neueProzedur)

Zur Hervorhebung bestimmter Textpassagen ist es üblich, diese mit vertauschten Vorder- und Hintergrundfarben darzustellen. Diese inverse Betriebsart kann über die Funktion 13 eingeschaltet und mit der Escape-Funktion 14 wieder abgeschaltet werden. Computer, die ein VT-52-Terminal (zumindest teilweise) emulieren, etwa der CPC 6128, Joyce und IBM PC unter CP/M-86 können dies durch die Ausgabe der Sequenzen >ESC<p und >ESC<q erreichen. GSX hingegen arbeitet völlig systemunabhängig:

Procedure InverseOn;
Begin
  Contrl[2]:=0;
  GsxEscape(13);
End;

Procedure InverseOff;
Begin
  Contrl[2]:=0;
  GsxEscape(14);
End;

Hardcopy

Die übrigen Escape-Funktionen sind von der Hardware sehr abhängig und bei einigen Computern nicht oder nicht vollständig implementiert. So fehlt die Hardcopy-Routine beispielsweise beim CPC 6128 völlig. Auf Computern, die für sie vorbereitet sind, kann auf dem Drucker eine Hardcopy des Bildschirms so erzeugt werden:

Procedure Hardcopy;
Begin
  Contrl[2]:=0;
  GsxEscape(15);
End;

Den Grafik-Cursor können Sie auf dem Bildschirm positionieren und sichtbar machen. Je nach Geschmack des jeweiligen Programmierers des GIOS-Treibers haben die Cursor ein unterschiedliches Aussehen. Bei den Schneider-Computern handelt es sich um ein Fadenkreuz. Zumindest die Aufrufparameter sind aber standardisiert:

Contrl(2)=0
Contrl(6)=18
Funktionsnummer
Ptsin(1) =x
x-Koordinate

Ptsin(2) =y
y-Koordinate

Die beiden Koordinaten für die x- und y-Position müssen im NDC-System zwischen (0,0) und (32767,32767) liegen. Soll der Grafik-Cursor wieder verschwinden, können Sie den Computer die Escape-Funktion 19 aufrufen lassen.

Ein einfaches Beispiel für die Benutzung dieser beiden Funktionen zeigt das folgende Turbo-Pascal-Listing. Es ist auf die GSX-Bibliothek für Turbo-Pascal aus der letzten c't angewiesen und bewegt das Fadenkreuz über den Bildschirm:

Programm EscDemo;
Var i,j:integer;
(*$i GSXTURBO.LIB*)
Procedure GsxEscape(FnNum:integer);
Begin
  Contrl[1]:=5;
  Contrl[6]:=FnNum;
  Bdos(115,Addr(pblock[1]));
End;

Begin
GraphInit;
OpenWorkstation(1,Solid,Pixel,Vertical);
I:=1;
For j:=1 to 300 Do
Begin
  Contrl[2]:=2;
  I:=i+1:
  Ptsin[1]:=j*100;
  Ptsin[2]:=i*100;
  GsxEscape(18);
  Contrl[2]:=0;
  GscEscape(19);
End;
CloseWorkstation;
End.

Damit Sie aus den bisherigen Erläuterungen auch einen praktischen Nutzen ziehen können, finden Sie hier auch eine kleine Include-Bibliothok für Turbo-Pascal. Sie verwirklicht einige wichtige Funktionen und Prozeduren zu Ansteuerung des Bildschirms in einer weitgehend geräteunabhängigen Weise. Gerade unter CP/M mutet es ziemlich ungewöhnlich an, auf zwei völlig unterschiedlichen Computern dieselben Routinen zu Verwaltung der Bildschirmausgabe benutzen zu können, wenn beide nur über GSX verfügen. Die Bibliothek stellt die folgenden Aufrufe zur Verfügung, die teilweise die Turbo-eigenen Treiber ersetzen oder auch völlig neue Funktionen bieten:

– Ermittlung der Bildschirmgröße int Textzeilen und -spalten:

Procedure GetScreenSize(Var Zeilen,Spalten:integer);

Begin
  Contrl[2]:=0;
  GscEscape(1);
  Zeilen:=intout[1];
  Spalten:=intout[2];
End;

– Positionierung des Text-Cursors:

Procedure GotoXY(Spalte, Zeile:integer);

Begin
  Contrl[2]:=0;
  Intin[1]:=Zeile;
  Intin[2]:=Spalte;
  GscEscape(11);
End;

– Löschen des Bildschirms

Procedure ClrScr;

Begin
  Contrl[2]:=0;
  GscEscape(8);
  Contrl[2]:=0;
  GscEscape(9);
End;

– Einschalten der inversen Darstellung:

Procedure LowVideo;

Begin
  Contrl[2]:=0;
  GscEscape(13);
End;

– Abschalten der inversen Darstellung:

Procedur NormVideo;

Begin
  Contrl[2]:=0;
  GscEscape(14);
End;

– Ermittlung der aktuellen Cursor-Position à la IBM:

Function WhereX:integer;

Begin
  Contrl[2]:=15;
  GscEscape(15);
  WhereX:=intout[2];
End;

Function WhereY:integer;

Begin
  Contrl[2]:=15;
  GscEscape(15);
  WhereY:=intout[1];
End;

 

GSX und Turbo-86

Einige Anpassungen sind nötig, um die Beispiel-Programme aus Teil 2 und die hier vorgestellte Programm-Bibliothek unter CP/M-85 und dem zugehörigen Turbo zum Laufen zu kriegen. Wie im ersten Teil beschrieben, arbeitet GSX-86 im Parameterblock mit 4-Byte-Vektoren (Offset und Segment, in dieser Reihefolge). Außerdem ist in CP/M-86 der Aufruf einder BDOS-Funktion etwas umständlicher, da hierfür ein Übergabe-Record bereitgestellt werden muß. Am einfachsten ist eine kleine Prozedur GSX, die den eigentlichen GDOS-Aufruf vornimmt (über Bdos oder, wie hier vorgestellt, über INTR).

Aber auch wenn man diese Spezialitäten berücksichtigt, wird man bei IBM-Kompatiblen, wie beispielsweise dem Schneider PC mit der vorgestellten Prozedur 'Showcaps' nicht allzu glücklich werden, da der Aufruf von OpenWorkstation den Bildschirm auf Grafik umschaltet und die folgenden Write-Befehle zu nur 'schwer zu lesenden' Linienmustern führen. Abhilfe ist möglich, wenn man entweder wie im Artikel beschrieben die GSX-Funktion 'Text' benutzt, oder wenn man vor dem ersten WRITE wieder auf 'Alpha-Modus' umschaltet. Hierfür bietet GSX als Bestandteil der sogenannten ESCAPE-Funktionen eine Umschaltmöglichkeit an.

Schließlich sollte man zum Abschluß der Routinen mit Close-Workstation auf Alpha-Modus zurückschalten, sonst sieht man auch auf Betriebssystem-Ebene wieder nur die wenig aussagekräftigen Linien.

DRI liefert für IBM-Kompatibel zwei Bildschirmtreiber, von denen man einen in der ASSIGN.SYS-Datei aufführen muß:

DDIBMC.SYS: 320 x 200, 4 Farben

DDIBM.SYS: 640 x 200, 2 Farben

Und nicht vergessen, mit Graphics das GSX zu aktivieren...
[3. Teil] [Inhalt]


Ausgehängt von Werner Cirsovius
Eingescanned von Rüdiger Wilcken Juni 2004
© Heise Verlag