Wie kann ich Win32-Mausnachrichten in WPF-Mausereignisse konvertieren?

9

Ich habe ein Win32 (OpenGL) -Steuerelement, das ich in unsere WPF-Anwendung einbetten muss. Es muss auf Maus- und Tastaturereignisse reagieren und diese weitergeben.

Ich habe eine von HwndHost abgeleitete Instanz zum Hosten des systemeigenen Fensters erstellt und die WndProc-Funktion in dieser Klasse überschrieben. Um Win32-Nachrichten an WPF zu propagieren, handhabe ich bestimmte Mausnachrichten und ordnet sie WPF-Ereignissen zu. Verwenden Sie dann die statische InputManager-Klasse, um sie zu erhöhen.

Das Problem ist, wenn ich sie handhabe, sind die Mauskoordinaten durcheinander.

Hier ist ein Beispiel des Codes, den ich verwende, um die Ereignisse zu erhöhen:

%Vor%

Wenn meine WPF-Ereignishandler ausgelöst werden und ich versuche, die Mauskoordinaten abzurufen (zB e.GetPosition((IInputElement) sender) ), erhalte ich die falschen Werte (und sie sind immer die gleichen Werte, unabhängig davon, wo das ursprüngliche Ereignis in meinem Steuerelement aufgetreten ist) / p>

Die Werte scheinen mit der Bildschirmposition des WPF-Fensters zu korrelieren, in dem sich die Anwendung befindet, da sie sich ändern, wenn sich die Fensterposition ändert, aber sie entsprechen auch nicht der tatsächlichen Position des Anwendungsfensters.

Ich denke, das kann etwas mit dem internen Status des WPF InputManagers zu tun haben, und der Tatsache, dass das private Feld MouseDevice._inputSource null ist, wenn meine Ereignisse ausgelöst werden, aber meine Experimente mit .net Reflexion haben dort keine Ergebnisse erbracht.

Ich weiß nicht wirklich, was ich noch versuchen soll. Keyboard-Unterstützung funktionierte aus der Box, es ist nur die Maus-Standort-Unterstützung, die ich nicht richtig funktionieren kann.

    
Josh 21.01.2014, 03:35
quelle

3 Antworten

4

Nachdem ich einen weiteren Tag in Reflector verbracht habe, um den fraglichen .net Quellcode zu analysieren, habe ich die Lösung gefunden. Man muss zuerst den WPF-InputManager initialisieren, indem man ein PreviewInputReportEventArgs router-Ereignis auslöst.

Leider sind dieses Ereignis und die Ereignisargumentstrukturen, die für die Erhöhung erforderlich sind, alle mit internal gekennzeichnet, sodass die Reflexion die einzige Möglichkeit ist, dieses Ereignis auszulösen. Für jeden mit dem gleichen Problem ist hier der C # -Code erforderlich:

%Vor%

wo:

  • timestamp ist die Anzahl der Systemticks beim Auftreten des Mausereignisses (normalerweise Environment.TickCount )
  • pointX und pointY sind die Mauskoordinaten relativ zum Clientbereich der obersten Ebene des Anwendungsfensters
  • wheel ist das Mausrad-Delta

Beachten Sie, dass das Ereignis "Vorschau" nur ausgelöst werden muss. Nach dem Auslösen dieses Ereignisses können die Standardmausereignisse ausgelöst werden, und WPF gibt die korrekten Mauspositionskoordinaten zurück, wenn e.GetPosition() aufgerufen wird.

    
Josh 22.01.2014, 07:01
quelle
0

Die Art, wie ich es mache, ist mit einem anderen Ansatz. Ich übertrage transparentes WPF-Fenster auf meinem HwndHost mit AllowsTransparency -Eigenschaft. Ich verknüpfe interessante Ereignisse im Overlay-Fenster und leite sie mit RaiseEvent wie folgt zu meinem Steuerelement:

%Vor%

Sie müssen nur HwndHost und Overlay-Fensterpositionen synchronisieren, was nicht so schwer ist.

    
ghord 30.06.2015 19:14
quelle
-1

Sie können die absolute Position der Maus (in Bildschirmkoordinaten) jederzeit mit einer p / Invoke-Funktion ermitteln:

%Vor%

Von dort sollten Sie in der Lage sein, relative Koordinaten leicht zu berechnen.

    
Nathan M 21.01.2014 05:20
quelle

Tags und Links