Maussteuerung funktioniert nicht in Grafikmodus, warum?

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Antworten
thosch
Beiträge: 324
Registriert: Mo 10. Jul 2017, 20:32

Maussteuerung funktioniert nicht in Grafikmodus, warum?

Beitrag von thosch »

Hallo,

ich habe den folgenden Quelltext, der im Textmodus einwandfrei die Maus erkennt und die gedrückte Maustaste ausgibt.

Im Grafikmodus (mit Unit Graph eingestellt) tut sich nichts. Warum?

Ich erhalte zwar eine (unleserliche) Ausgabe von der Pepeat/until Schleife, kann jedoch keine Schrift lesen und wenn ich die rechte Maustaste klicke, beendet sich das Programm NICHT. Also wird die Maus im Grafikmodus nicht erkannt.

Woran liegt das. Werden im Grafikmodus andere Ports verwendet? Wenn ja, welche?

Hier erst mal mein Code, der wie geagt im Textmodus korrekt arbeitet:

Code: Alles auswählen

 
{
Programm Maustest:
 
- funktioniert im Textmodus aber nicht in Grafikmodus
 
}
program gMouse;
 
{$mode objfpc}{$H+}
 
uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes, SysUtils, CustApp, Graph, Mouse
  { you can add units after this };
 
type
 
  { TMouseApplication }
 
  TMouseApplication = class(TCustomApplication)
  private
    fromMouse: TMouseEvent;
  protected
    procedure DoRun; override;
  public
    constructor Create(TheOwner: TComponent); override;
    destructor Destroy; override;
    procedure Run;
    procedure WriteHelp; virtual;
  end;
 
var
  InConsoleMode: Boolean = true;
 
function MouseActionStr(Action: word): String;
begin
  case Action of
   MouseActionDown : Result := 'MouseActionDown';
   MouseActionMove : Result := 'MouseActionMove';
   MouseActionUp   : Result := 'MouseActionUp';
  end;
end;
 
function MouseButtonsStr(Button: word): String;
begin
  case Button of
   MouseLeftButton: Result := 'MouseLeftButton';
   MouseMiddleButton: Result := 'MouseMiddleButton';
   MouseRightButton: Result := 'MouseRightButton';
  end;
end;
 
procedure gWriteLn(str1: String);
begin
  Graph.MoveTo(GetX, GetY);
  OutText(str1);
  Graph.MoveTo(1, GetY+1);
end;
 
procedure gPrintLn(str1,str2: String);
begin
  Graph.MoveTo(GetX, GetY);
  OutText(str1);
  Graph.MoveTo(GetX + TextWidth('A'), GetY);
  OutText(str2);
  Graph.MoveTo(1, GetY+1);
end;
 
{ TMouseApplication }
 
procedure TMouseApplication.DoRun;
var
  ErrorMsg: String;
begin
  // quick check parameters
  ErrorMsg:=CheckOptions('h', 'help');
  if ErrorMsg<>'' then begin
    ShowException(Exception.Create(ErrorMsg));
    Terminate;
    Exit;
  end;
 
  // parse parameters
  if HasOption('h', 'help') then begin
    WriteHelp;
    Terminate;
    Exit;
  end;
 
  { add your program here }
 
  // stop program loop
  Terminate;
end;
 
constructor TMouseApplication.Create(TheOwner: TComponent);
var gd,gm: smallint;
begin
  inherited Create(TheOwner);
  StopOnException:=True;
  DetectGraph(gd,gm);
  InitGraph(gd,gm,'');
  if GraphResult = grOk then InConsoleMode := false else
  begin
    Writeln('Konnte keinen passenden Grafikmodus finden');
    Halt(GraphResult);
  end;
  InitMouse;
//ShowMouse; //keine Verhaltensänderung
end;
 
destructor TMouseApplication.Destroy;
begin
// HideMouse;   
  DoneMouse;
  inherited Destroy;
end;
 
procedure TMouseApplication.Run;
begin
  //DoRun;
  repeat
    if PollMouseEvent(fromMouse) then GetMouseEvent(fromMouse);
    gwriteln(MouseButtonsStr(fromMouse.buttons));
    gPrintln('Mouse-Action -> ',MouseActionStr(fromMouse.Action));
  until fromMouse.buttons = MouseRightButton;
 
  gwriteln(MouseButtonsStr(fromMouse.buttons));
  gwriteln('Zurück mit Enter ...');
  //Readln;
  Terminate;
end;
 
procedure TMouseApplication.WriteHelp;
begin
  { add your help code here }
  gPrintLn('Usage: ', ExeName + ' -h');
end;
 
var
  Application: TMouseApplication;
begin
  Application:=TMouseApplication.Create(nil);
  Application.Title:='My Mouse Application';
  Application.Run;
  Application.Free;
end.
 


Nun möchte ich die Maus aber auch im Grafikmodus erkennen und nutzen. Und den Grund wissen, warum das da nicht mehr klappt. In Windows funktioniert es schließlich auch. Der Quellcode ist für Windows überesetzt. Der Mauszeiger wird im Grafikfenster immer angezeigt, egal, ob ich ShowMouse im Code habe oder nicht, aber das Programm reagiert nicht auf meine Maustasten, was ich durch Klick auf die rechte Maustaste festgestellt habe, da die Textmodeversion bei Rechtsklick terminiert, die Grafikversion jedoch nicht.

WO liegt die Ursache?

Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Maussteuerung funktioniert nicht in Grafikmodus, warum?

Beitrag von Warf »

Schau mal hier: Link
The unit is provided for compatibility only: It is recommended to use more modern graphical systems. The graph unit will allow to recompile old programs. They will work to some extent, but if the application has heavy graphical needs, it's recommended to use another set of graphical routines, suited to the platform the program should work on.ä


Langer rede kurzer Sinn, benutz nicht die Graph Unit.

Was spricht denn gegen die LCL? Die wird aktiv weiter entwickelt, ist OOP, und unterstützt bereits vollständiges Event handling (u.a. Maus Erkennung)

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

Re: Maussteuerung funktioniert nicht in Grafikmodus, warum?

Beitrag von Mathias »

Zuerst sollt man wissen, auf welcher Plattform das ganz laufen soll.
Vieleicht will der TE für DOS entwickeln.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

thosch
Beiträge: 324
Registriert: Mo 10. Jul 2017, 20:32

Re: Maussteuerung funktioniert nicht in Grafikmodus, warum?

Beitrag von thosch »

Warf hat geschrieben:Schau mal hier: Link
The unit is provided for compatibility only: It is recommended to use more modern graphical systems. The graph unit will allow to recompile old programs. They will work to some extent, but if the application has heavy graphical needs, it's recommended to use another set of graphical routines, suited to the platform the program should work on.ä


Langer rede kurzer Sinn, benutz nicht die Graph Unit.

Was spricht denn gegen die LCL? Die wird aktiv weiter entwickelt, ist OOP, und unterstützt bereits vollständiges Event handling (u.a. Maus Erkennung)


Und dieses Event-Handling will ich nachbauen um dessen Funktionsweise besser zu verstehen. Kann ja sein, dass da die Graph Unit nicht ganz kompatibel zu Windows ist, aber das muss ja irgendeinen Grund haben. Und den möchte ich herausfinden.

Eigene Recherche hat nämlich ergeben, dass Windows die Zuordnung der Ports zum Zugriff auf die Maus verändert. Wenn das hier die Ursache ist, verwendet also Windows für den Mauszugriff einen anderen Port als unter DOS. Nur welchen?

Wie ordne ich da den richtigen Port zu? Ich guck inzwischen schon mal in meinen Quelltext meiner Maus Unit.

Ich könnte ja ebenso einfach Winmouse verwenden, aber wnn schon plattformübergreifend, dann bitte auch ohne wesentliche Änderungen im Quelltext. Im Zweifelsfall muss ich dann eben die Unit Mouse anpassen.

Bloß warum funktioniert dann der Mauszugriff auf der Konsole, nicht jedoch im Grafikmodus? Ich habe beide Versionen (Textmode wie Grafikmode für Windows übersetzt und unter Windows 10 gestartet, wo es standardmäßig keinen DOS Unterbau mehr gibt. Also läuft auch die Textkonsole unter lupenreinem Windows!

Warum also wird da die Maus im Textmodus erkannt, im Grafikmodus jedoch nicht?

Ich will das Eventhandling nachbauen um es besser zu verstehen. Zum Windows API gibt es keinen Quelltext. Nur zur LCL, die aber auf das Windows API aufsetzt.

Ein Grund mehr, zuerst mal bei der Graph Unit zu bleiben um meine Fragen zu beantworten und die Hintergründe zu verstehen. Wie soll ich sonst komplexere Programme schreiben können?

Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Maussteuerung funktioniert nicht in Grafikmodus, warum?

Beitrag von Warf »

Ich glaube du hast da nicht ganz verstanden wie Moderne Windows Systeme funktionieren. Das input management ist praktisch fundamental anders als in DOS

Windows ist komplett event basiert, das heißt egal ob Konsole oder GUI Anwendung, dein Programm bekommt eine Message Queue, und alle Events werden da reingeschrieben. Sieh mal hier: Link und hier: Link.

Unlike MS-DOS-based applications, Windows-based applications are event-driven. They do not make explicit function calls (such as C run-time library calls) to obtain input. Instead, they wait for the system to pass input to them.


Windows ist also im Gegensatz zu DOS nicht darauf ausgelegt das dein Programm Pollen soll, das muss man nur noch für bestimmte Bibliotheken vor allem in der Spielentwicklung machen (Direct Input, SDL, etc.).
Wenn du also verstehen willst wie Windows Programme mit der Maus umgehen, solltest du eventuell es so machen wie Windows eigentlich designed ist und nicht versuchen DOS Programme für windows zu schreiben ;)

Und tatsächlich ist die LCL recht nah an die Windows API angelehnt (dank Delphi Kompatibilität), bedeutet das die LCL Operationen praktisch 1-1 einer WinAPI operation entsprechen. Wenn du also verstehen willst wie Windows Events managed, schau dir am besten mal an wie die LCL das macht. Strukturell sind die ähnlich aufgebaut.

PS: hast du dir mal die Doc der Mouse Unit durchgelesen? Link
It is intended to be used only in text-based screens, for instance in conjunction with the keyboard and video unit. No support for graphical screens is implemented, and there are (currently) no plans to implement this.

thosch
Beiträge: 324
Registriert: Mo 10. Jul 2017, 20:32

Re: Maussteuerung funktioniert nicht in Grafikmodus, warum?

Beitrag von thosch »

Warf hat geschrieben:Ich glaube du hast da nicht ganz verstanden wie Moderne Windows Systeme funktionieren. Das input management ist praktisch fundamental anders als in DOS

Windows ist komplett event basiert, das heißt egal ob Konsole oder GUI Anwendung, dein Programm bekommt eine Message Queue, und alle Events werden da reingeschrieben. Sieh mal hier: Link und hier: Link.

Unlike MS-DOS-based applications, Windows-based applications are event-driven. They do not make explicit function calls (such as C run-time library calls) to obtain input. Instead, they wait for the system to pass input to them.


Windows ist also im Gegensatz zu DOS nicht darauf ausgelegt das dein Programm Pollen soll, das muss man nur noch für bestimmte Bibliotheken vor allem in der Spielentwicklung machen (Direct Input, SDL, etc.).
Wenn du also verstehen willst wie Windows Programme mit der Maus umgehen, solltest du eventuell es so machen wie Windows eigentlich designed ist und nicht versuchen DOS Programme für windows zu schreiben ;)

Und tatsächlich ist die LCL recht nah an die Windows API angelehnt (dank Delphi Kompatibilität), bedeutet das die LCL Operationen praktisch 1-1 einer WinAPI operation entsprechen. Wenn du also verstehen willst wie Windows Events managed, schau dir am besten mal an wie die LCL das macht. Strukturell sind die ähnlich aufgebaut.

PS: hast du dir mal die Doc der Mouse Unit durchgelesen? Link
It is intended to be used only in text-based screens, for instance in conjunction with the keyboard and video unit. No support for graphical screens is implemented, and there are (currently) no plans to implement this.



Dann wird die Verwirrung komplett, denn warum funktioniert die Maus dann auf der Windows Konsole?

Und warum dann auf besagter Windows Konsole, aber nicht mit der Unit Graph im Grafikmodus?

Das würde ich schon gerne verstehen!

Warum wurde in der Unit Mouse das Polling anstatt des Mausinterruptes gewählt?

Und wie setzt Windows die Mausereignisse um, dort kommt die Mausinfo doch auch letztlich von der Hardware, nur die Windows Software verteilt diese Signale anders als DOS oder vielleicht auch Linux.

Letztlich aber läuft das doch alles auf ein und derselben Hardware! Da muss es doch irgendwo Gemeinsamkeiten geben? Da doch jedes Betriebssystem das auf Rechnern der X86 Familie läüft, auf demselben Prozessor, mit denselben Controllern, mit demselben BIOS oder UEFI, .... läuft.

Habe mir die Erklärung im ersten Link zum Konsolen-Puffer durchgelesen. Wenn ich nun aber mit der Graph Unit den Grafikmodus einschalte und das Ganz dann für Windows übersetze, wo ist da der Unterschied im Mauszugriff? Tastatur noch nicht getestet. Kann also die Windows Konsole keinen Grafikmodus? Warum aber komme ich dann in den Grafikmodus und dann noch im Konsolenfenster. Ich brauche weitere Erklärungen, der Link über die Windows Konsole erklärt noch nicht alles. Aber ich werde in der verlinkten Referenz mal stöbern.

Gibt es denn irgendwo Beispielprogramme?

Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Maussteuerung funktioniert nicht in Grafikmodus, warum?

Beitrag von Warf »

Ich bin selbst absolut kein WinAPI Profi, aber ich versuche es mal so weit zu erklären wie ich es verstanden habe.

Windows unterscheidet Strikt zwischen Konsolen (Text Modus) Anwendungen und GUI Anwendungen. Damit du eine GUI Anwendung hast musst du beim start des programmes STDIN und STDOUT (eventuell auch STDERR da bin ich mir aber nicht sicher) schließen. Das verhindert auch das das kleine konsolenfenster aufpopt (wird automatisch vom Fpc gemacht wenn in deinem Programm {$apptype gui} steht) Wenn du eine Konsolenanwendung hast, STDIN also nicht geschlossen ist, hast du zugriff auf den Konsolen Puffer über den du sowas wie Maus und Keyboard events abfangen kannst (siehe meinen link von oben). Wenn du STDIn schließt wird dieser auch geschlossen. Ich denke mal deshalb funktioniert die Mouse unit auch nicht weil die wohl intern diesen Buffer verwendet (da sie nicht für GUI Anwendungen designed ist braucht sie nix anderes).
Wenn du eine GUI Anwendung hast, bekommst du von Windows eine Message Queue zugewiesen über die so genannte Window-Messages versandt werden. Die sind dann so Informationen wie MouseDown at XXX, KeyDown at Control XX, Button XYZ wurde geklickt, etc. Also nicht nur raw messages, sondern diese Messages implementieren bereits die Logik der Controls. Grundsätzlich funktionieren die Message Queue und der Konsolenbuffer allerdings gleich, wenn der User etwas macht wird es dort reingeschrieben und dein Programm kann es dann jederzeit auslesen.

Der Unterschied zu polling ist, das du bei polling immer den aktuellen Status abfragst statt events. Das hat ein paar vor und einige Nachteile gegenüber Events. Einer der Vorteile warum es bei Spielen eingesetzt wird ist das es in echtzeit ist. Wenn du den Mausstatus abfragst bekommst du den aktuellen mausstatus, während das event kann jederzeit hinzugefügt werden, unabhängig vom Auslesepunkt. Daher kannst du nicht wissen wann tatsächlich geklickt wurde. Ein Nachteil ist aber, wenn die Abarbeitung des Pollings zu lange dauert kannst du events verpassen, während mit der Queue Windows im Hintergrund alle events auffängt und die zur späteren Abarbeitung queued. Daher wird es für gewöhnlich nicht für GUI Anwendungen verwendet, da du keine events missen möchtest (z.B. button 1 wird geklickt, macht eine Berechnung über mehrere Sekunden, dann wird bevor die fertig ist button 2 geklickt, durch polling wär der zweite klick verloren, durch die event queue wird der danach einfach abgearbeitet).

Ums also zusammenzufassen ist der unterschied zwischen events und polling das bei events windows im Hintergrund für dich polling betreibt und dir einen Buffer zur verfügung stellt in dem alle events dann reingeschrieben werden. (Was tatsächlich auch deutlich performanter ist da du damit keine kontextwechsel mehr hast. Beim polling muss für den Hardware zugriff auf Kernel ebene gearbeitet werden und der Wechsel zwischen Userebene wo dein Programm läuft und Kernel ebene ist recht langsam)

Windows ist von Grund auf nicht dazu gebaut Konsolenanwendungen und GUI Anwendungen zu kombinieren. Am besten schreibst du eine konsolenanwendung die eine GUI Anwendung aufrufen kann oder umgekehrt.

Zu der Sache mit der Mouse Unit:
It is intended to be used only in text-based screens, for instance in conjunction with the keyboard and video unit. No support for graphical screens is implemented, and there are (currently) no plans to implement this.

Wenn du eine Konsolenanwendung schreibst läuft diese in einem so genannten Terminal Emulator, der der Anwendung vormacht das es ein text based screen wäre, auch wenn du eigentlich ja im grafischen modus von windows bist.

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

Re: Maussteuerung funktioniert nicht in Grafikmodus, warum?

Beitrag von Mathias »

Und warum dann auf besagter Windows Konsole, aber nicht mit der Unit Graph im Grafikmodus?
Die Unit Graph ist nur zur Kompatibilität zu Turbo-Pascal vorhanden und dies auch nur für die Grafikausgabe. Nebst der Maus funktioniert dort bei mir nicht mal die Tastatur.

Und die Unit Mouse ist so viel ich weis nur für die Console. Die Unit Mouse wird auch in FreeVision verwendet.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Antworten