[gelöst] Rätsel mit keypressed

Für Fragen von Einsteigern und Programmieranfängern...
Antworten
alfware17
Beiträge: 134
Registriert: Di 14. Dez 2010, 23:27

[gelöst] Rätsel mit keypressed

Beitrag von alfware17 »

Hallo liebe Leute,

ich habe ein merkwürdiges Problem mit dem Interrupt 16, welchen ich befrage ob eine Taste gedrückt worden ist oder nicht.

Code: Alles auswählen

FUNCTION KeyPressed0: BOOLEAN;
VAR
  ch:CHAR;
  regs:REGISTERS;
BEGIN
  ch:=CHR(0);
  regs.AH:=$01; INTR($16,regs); (* Prüfen auf Taste *)
  IF (regs.AX<>$00) THEN BEGIN
    regs.AH:=$00; INTR($16,regs);
    ch:=CHR(regs.AL); (* Leeren *)
  END;
  KeyPressed0:=(ch<>CHR(0));
END (* KeyPressed0 *);
Das Ganze compiliere ich mit Turbo-Pascal (ja bitte nicht lachen) und einmal unter Virtualbox Windows XP zeigt es das gewünschte Verhalten
(nämlich nur reagieren, wenn Taste gedrückt wurde) und einmal unter VirtualBox MS-DOS muckt es, nämlich wartet es auf Tastendruck und das will ich ja nun gerade nicht.

Hier mein Hauptprogramm

Code: Alles auswählen

uses stdio;
var i:card;
    c:char;
begin
   repeat
     writeln(i,', ');
     inc(i);
     if keypressed0 then begin i:=0; c:=taste0; end;
   until (i>1000000) or (c=' ');
end.
Und die komplette Unit Stdio im Anhang.

In der Stdio.pas steht natürlich auch, daß ich für modernere Betriebsysteme sprich 32/64 bit die Keyboard Unit von FreePascal benutze und das geht auch.
Nur habe ich damals (im Juli) als ich das für 16bit entwickelt habe, den Fehler gemacht, nicht zu testen, ob es denn auch unter MS-DOS geht und nicht nur unter Windows XP.

Mir ist das unklar, aber was mache ich falsch und welchen Int sollte ich ggf. nehmen?

Hintergrund ist, ich habe versucht, die Unit CRT abzulösen, weil es nach meiner Erinnerung irgendein Umlaute-Problem gab. Natürlich kann ich für den immer selteneren
Fall 16bit die schwer ausgebaute CRT und keypressed auch wieder reinnehmen, aber vielleicht weiß ja von euch jemand Rat. Warum verhält sich das (originale) MS-DOS so komisch,
was habe ich nicht bedacht bei der Umsetzung der Idee mit dem Int 16 (aus dem Internet).

Danke!
Dateianhänge
Stdio.pas
(18.19 KiB) 55-mal heruntergeladen
Zuletzt geändert von alfware17 am Mi 13. Dez 2023, 20:19, insgesamt 1-mal geändert.

alfware17
Beiträge: 134
Registriert: Di 14. Dez 2010, 23:27

Re: Rätsel mit kepressed

Beitrag von alfware17 »

Nachtrag: also an der Virtualbox scheint es eher nicht zu liegen, denn das Programm zeigt das gleiche (falsche) Verhalten auch unter DOSBOX (gerade probiert).

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

Re: Rätsel mit kepressed

Beitrag von Mathias »

Ich habe gerade in meiner TP-Kiste gewühlt und folgendes gefunden.
Vielleicht hilft dir dies weiter.
Dies sollte auch auf Pentium und höher laufen, es gab da mal ein BUG in der uses Crt.

Code: Alles auswählen

function KeyPressed : Boolean; assembler;
asm
        push    ds              { DS auf Stack sichern }
        mov     ds, Seg0040
        mov     si, 1ah         { Tastaturbufferanfang in SI laden  (1Ah) }
        lodsb
        mov     bl, al          { Anfangspos von AL in BL }
        inc     si              { Tastaturbufferende in SI laden    (1Ch) }
        lodsb
        mov     bh, al          { Endepos von AL in BH }
        xor     ax, ax          { AX auf False }
        cmp     bl, bh          { Positionen vergleichen }
        jz      @Ende           { wenn <> Zeichen in Tastaturbuffer }
        Inc     ax              { AX auf True }
@Ende:  pop     ds              { DS von Stack holen }
end;

Const
  Merker : Byte = 0;

function ReadKey : Char;
var
  _ah, _al : Byte;
begin
  if Merker = 0 then begin
    asm
      mov ah, 00
      int 16h
      mov _al, al
      mov _ah, ah
    end;
    if _al = 0 then begin
      ReadKey := #0;
      Merker := _ah;
    end else ReadKey := chr(_al);
  end else begin
    ReadKey := chr(Merker);
    Merker := 0;
  end;
end;
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

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

Re: Rätsel mit kepressed

Beitrag von Mathias »

Da noch die ganze Unit, welche auch eine ultaschnelle Textausgabe hatte.
Dateianhänge
NEWCRT.PAS
(11.12 KiB) 60-mal heruntergeladen
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

alfware17
Beiträge: 134
Registriert: Di 14. Dez 2010, 23:27

Re: Rätsel mit kepressed

Beitrag von alfware17 »

@Mathias, danke für die superschnelle Antwort.

Deine Lösung funktioniert im Testprogramm 1-A und ich werde die Unit mit deiner Erlaubnis in meiner Stdio aufrufen für den 16bit-Zweig

In einem alten Forenbeitrag fand ich auch das:
viewtopic.php?t=11899

Die Unit von Siro, 04.12.2018 - so ganz habe ich nicht verstanden, warum die buggy sein soll, die beiden mich interessierenden Funktionen taten es soweit ich sehe auch aber ich müßte die Unit dann wohl kürzen.

Dann lieber deine Lösung. Und Dankeschön!

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

Re: [gelöst] Rätsel mit kepressed

Beitrag von Mathias »

Du kannst die Unit verwenden.

Die unit crt hat Mühe mit zu schnellen CPUs.
Aber in der dosbox sollte sie trozdem laufen, da ein 8088 emuliert wird.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

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

Re: [gelöst] Rätsel mit kepressed

Beitrag von Mathias »

Es gibt noch einen Batch für die original uses Crt:

Code: Alles auswählen

In Turbo.tpl und tpp.tpl

F7 D0 F7 D2 B9 37 00

durch

F7 D0 F7 D2 B9 A0 00

ersetzen.
Dateianhänge
Borland-Pascal 7.0 Cheat.zip
(28.31 KiB) 53-mal heruntergeladen
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

alfware17
Beiträge: 134
Registriert: Di 14. Dez 2010, 23:27

Re: [gelöst] Rätsel mit kepressed

Beitrag von alfware17 »

Danke für das Zip, Mathias - aber was genau meinst du mit Batch? Was wird da gelöst? Ich erinnere mich irgendwo gelesen zu haben, die CRT hätte einen Bug, der runtime 200 verursacht - aber das hat mit meinem eigentlichen Problem/Grund weshalb ich sie abgelöst habe, nichts zu tun oder? Ich wollte endlich auch "echte Umlaute" nicht dieses ae und ue, wobei mir schon klar ist, daß für den Fall irgendein Mensch auf der Welt wird mal mein 16bit-Programm in die Finger bekommen, der dann wahrscheinlich eh in Russland oder Korea sitzt und ganz andere Möglichkeiten/Probleme hat....

ABER, nun habe ich noch mal nachgegoogelt nach meinem Problem aus der Threaderöffnung und muß sagen, shame on me - ich habe damals nicht genau genug gelesen und es zwei Jahre nicht gemerkt (der Code lief spannenderweise in Win XP auch mit der Int $16 Abfrage so wie oben, erst das native DOS machte mich auf den Fehler aufmerksam).
Ich hatte das Workaround mit dem AX irgendwie hingebastelt und als es mal alle gefühlten Tests erfüllte, einfach behalten.... Nur war es nicht gut

HIer nun die m.E. korrekte Version (Keypressed1)
:

Code: Alles auswählen

(* Nutzen der Unit NewCrt *)
FUNCTION Taste0:CHAR;
BEGIN
  Taste0:=ReadKey;
END (* Taste0 *);

FUNCTION KeyPressed0: BOOLEAN;
BEGIN
  KeyPressed0:=KeyPressed;
END (* KeyPressed0 *);

(* Nutzen nur INT $16 *)
FUNCTION Taste1:CHAR;
VAR
  ch:CHAR;
  regs:REGISTERS;
BEGIN
  regs.AH:=$00; INTR($16,regs);
  ch:=CHR(regs.AL); Taste1:=ch;
END (* Taste1 *);

FUNCTION KeyPressed1: BOOLEAN;
VAR
  ZF:BOOLEAN;
  regs:REGISTERS;
BEGIN
  regs.AH:=$01; INTR($16,regs); 
  ZF:=(regs.FLAGS AND $0040 = $0040); KeyPressed1:=NOT ZF;
END (* KeyPressed1 *);
Ich lasse mal beide Varianten in meiner Unit (deine Taste0 und Keypressed0 über die NewCrt und meine jetzt als Taste1 und Keypressed1).

Die Frage, die sich mir stellt - dein Assembler ist natürlich viel besser und auch umfassender, mich interessiert ja in dem Fall Taste0 und Keypressed0 wirklich nur "Taste" oder "nicht Taste" und nicht konkret welche. Aber, warum wird es immer mit ASM umgesetzt, bin ich auf der Pascal-Ebene mit dem Int $16 zu simple und wahrscheinlich dann irgendwo zu langsam? Anders als simuliert in DOSBOX oder Virtualbox werden meine 16-bit Programme wohl kaum mehr laufen und in der 32/64-bit Welt habe ich dann ja die Keyboard Unit.
Frag mich nur, bin ich der einzige der auf die Idee kommt, das so mit den REGISTERS und INTR direkt in Pascal zu machen und wie genau schlechter ist das?

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

Re: [gelöst] Rätsel mit kepressed

Beitrag von Mathias »

aber was genau meinst du mit Batch? Was wird da gelöst?
Damit kann man die Unit Crt, oder die fertige EXE patchen.
Dann sollten Programme, welche die Unit Crt verwenden auch auf schnellen PCs laufen.
Die TURBO.TPL im Anhang ist schon gepatcht. Du muss einfacht die alte TURBO.TPL in deinem TP-Ordner austauschen.
Aber, warum wird es immer mit ASM umgesetzt, bin ich auf der Pascal-Ebene mit dem Int $16 zu simple und wahrscheinlich dann irgendwo zu langsam?
Für die Keyboard-Abfrag sollte es mit Registers und Intr auch klappen, da dies keine Zeitkritische Sache ist.
Meine ASM-Version habe ich dazumal auch mal irgendwo abgeguckt.

Für grafisches machte ASM durchwegs Sinn, du musste mal alles rauskitzeln.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

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

Re: [gelöst] Rätsel mit keypressed

Beitrag von Mathias »

Auf den Original-Disketten von BP70 findet man auch die Sourcen von Readkey und KeyPressed.
Diese sind auch voll in Assembler geschrieben.

Aus Copyright Gründen stelle ich die Sourcen nicht rein.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Antworten