C# WPF Tastendruck simulieren und an ein Programm weiterleiten

OP #3793912
Hallo zusammen,

Ich möchte mit C# WPF eine Benutzeroberfläche programmieren, mit der auf 
ein Programm einer CNC-Steuerung zugegriffen werden kann.

- Die Benutzeroberfläche hat das Ziel, die Bedienung der CNC-Maschine 
auf das Nötigste zu reduzieren. Die Oberfläche muss mit WPF erstellt 
werden, Windows Forms kommt aufgrund von Vorgaben nicht in Frage.

- Das Programm, welches die CNC-Maschine steuert, läuft unter einem 
normalen Windows-Rechner. Die Befehle, die das Programm ausführen soll, 
können mit den Funktionstasten F2 bis F9 durchgeführt werden.

- Beim Start der Oberfläche wird das CNC-Steuerprogramm unsichtbar mit 
geöffnet. Die Oberfläche besteht aus Buttons mit der Aufschrift 
"Referenzfahrt durchführen", "Parkposition anfahren", "Job starten", 
etc.

- Bei einem Klick auf einen dieser Buttons soll der Druck auf eine 
Funktionstaste (F2 bis F9, je nach gedrückten Button) simuliert und an 
das CNC-Programm weitergeleitet werden.

Das Problem dabei ist, das ich zum einen nicht weiß, wie ich den Druck 
auf eine Taste unter WPF simulieren kann (ich habe nur was gefunden, wie 
das unter Windows Forms geht) und zum anderen habe ich keine Idee, wie 
ich dann diesen Tastendruck an das CNC-Programm senden kann.

Ich hoffe Ihr könnt mir helfen oder zumindest Tipps geben, in welche 
Richtung ich arbeiten sollte. Danke
Gast #3793915
Daniel M. schrieb:
> Das Problem dabei ist, das ich zum einen nicht weiß, wie ich den Druck
> auf eine Taste unter WPF simulieren kann (ich habe nur was gefunden, wie
> das unter Windows Forms geht) und zum anderen habe ich keine Idee, wie
> ich dann diesen Tastendruck an das CNC-Programm senden kann.

das hat auch nicht mit Windows Form oder WPF zu tun.

Unter Windows werden Tastatureingaben per Event an ein Programm 
gesteuert. Du musst also nur die ProcessID von dem anderen Programm 
ermitteln und dann kannst du dort einen Event hin schicken.
OP #3793927
Peter II schrieb:
> Daniel M. schrieb:
>> Das Problem dabei ist, das ich zum einen nicht weiß, wie ich den Druck
>> auf eine Taste unter WPF simulieren kann (ich habe nur was gefunden, wie
>> das unter Windows Forms geht) und zum anderen habe ich keine Idee, wie
>> ich dann diesen Tastendruck an das CNC-Programm senden kann.
>
> das hat auch nicht mit Windows Form oder WPF zu tun.
>
> Unter Windows werden Tastatureingaben per Event an ein Programm
> gesteuert. Du musst also nur die ProcessID von dem anderen Programm
> ermitteln und dann kannst du dort einen Event hin schicken.

Vielen Dank für die Antwort. Ist die Prozess ID dynamisch, d.h. bei 
jedem Start des Programms anders, oder ist sie immer gleich?
Gast #3794408
Daniel M. schrieb:
> Ist die Prozess ID dynamisch, d.h. bei
> jedem Start des Programms anders, oder ist sie immer gleich?

Dynamisch. Die Frage hättest Du Dir mit Hilfe des Taskmanagers (oder 
Konsole & tasklist) aber auch leicht selbst beantworten können.
OP #3795289
adamzwerg schrieb:
> Daniel M. schrieb:
>> Ist die Prozess ID dynamisch, d.h. bei
>> jedem Start des Programms anders, oder ist sie immer gleich?
>
> Dynamisch. Die Frage hättest Du Dir mit Hilfe des Taskmanagers (oder
> Konsole & tasklist) aber auch leicht selbst beantworten können.

Ja, das ist mir im Nachhinein auch aufgefallen. Sorry für die unnötige 
Frage. Habe mittlerweile auch mit der Funktion: 
"System.Diagnostics.Process.GetProcessesByName(Prozessname)[0].Id"
die PID in meinem Programm einholen können.

jo schrieb:
> Windows + Echtzeitmaschinensteuerung = bäh.
>
> Gruß Jonas

Das mag eine Ansicht von dir sein, die ich auch respektiere. Allerdings 
sind das Parameter, die ich nicht ändern kann und mit denen ich ein 
vorgegebenes Ziel erreichen muss. Von daher wäre ich über eine 
konstruktivere Antwort dankbar.
OP #3795457
Ich habe es jetzt geschafft mit folgenden Code einen Tastendruck zu 
simulieren:
1
/// <summary>
2
/// Interaktionslogik für MainWindow.xaml
3
/// </summary>
4
public partial class MainWindow : Window
5
{
6
  // Konstruktor für das Fenster
7
  public MainWindow()
8
  {
9
    InitializeComponent();
10
  }
11
  // Eventhandler für das Event "Taste nach unten gedrückt"
12
  private void OnKeyDownHandler(object sender, KeyEventArgs e)
13
  {
14
    // Wenn die gedrückte (simulierte) Taste die F5-Taste ist...
15
    if (e.Key == Key.F5)
16
    {
17
      //... Infotext in der Textbox "textBox1" ausgeben
18
      textBox1.Text = "F5-Tastendruck wurde simuliert";
19
    }
20
  }
21
  // Eventhandler für das Event "button1 wurde geklickt"
22
  private void button1_Click(object sender, RoutedEventArgs e)
23
  {
24
    KeyEventArgs args = new   KeyEventArgs(Keyboard.PrimaryDevice,
25

26
    Keyboard.PrimaryDevice.ActiveSource, 0, Key.F5);
27

28
    args.RoutedEvent = Keyboard.KeyDownEvent;
29

30
    InputManager.Current.ProcessInput(args);
31
  }    
32
}

Auch kann ich die Process-ID, an welches Programm der Tastendruck 
gesendet werden soll, mittels der im vorigen Beitrag genannten Funktion 
ermitteln.

Jetzt stehe ich allerdings vor dem Problem, wie ich diesen Tastendruck 
an das Programm weiterleiten kann.
Gast #3795860
Dass das andere Programm versteckt im Hintergrund läuft, könnte ein 
Problem sein. Überhaupt ist das eine ziemlich unsaubere Methode, bei der 
die Details evtl. sogar von der Windows-Version abhängen. Es wäre sehr 
viel besser, wenn das CNC-Programm irgendeine Art von externer Steuerung 
zuließe (über Pipes, Sockets oder wie auch immer).

Tipp: Probiere es erst einmal mit dem oben bereits genannten AutoIt 
(Send, ControlSend). Wenn du damit etwas erreichst, sollte es auch mit 
einem eigenen Programm klappen; wenn nicht, sieht es vermutlich eher 
schlecht aus.
OP #3796147
Ich habe jetzt folgenden Code zum Testen geschrieben, der bis auf einen 
Kleinigkeit auch soweit funktioniert. Der Prozess "Notepad" wird in den 
Vordergrund geholt (dieser wurde zuvor gestartet) und auch wird ein 
F5-Tastendruck simuliert (der entsprechende Handler wird aufgerufen). 
Nur leider wird das Event nicht an den Prozess "Notepad" weitergeleitet. 
Wie kann das sein?

Hier der Code:
1
private void button1_Click(object sender,
2
                           RoutedEventArgs eventhandlerDelegate)
3
{
4
  // F5-Tastendruck simulieren
5
  KeyEventArgs args = new KeyEventArgs(Keyboard.PrimaryDevice, 
6
                                      Keyboard.PrimaryDevice.ActiveSource, 
7
                                      0, 
8
                                      Key.F5);
9
  // Event zuordnen
10
  args.RoutedEvent = Keyboard.KeyDownEvent;
11
  // 
12
  InputManager.Current.ProcessInput(args);
13
  // Prozess  in den Vordergrund holen (als Beispiel Notepad)
14
  SetForegroundWindow(Process.GetProcessesByName("notepad")[0].MainWindowHandle);
15
}
Gast #3796543
Daniel M. schrieb:
> Ich habe jetzt folgenden Code zum Testen geschrieben, der bis auf
> einen Kleinigkeit auch soweit funktioniert.

Der funktioniert eigentlich überhaupt nicht ... Du rufst ProcessInput 
(BTW: das bedeutet nicht "Sende etwas an Prozess xyz") auf und bringst 
dann das Fenster in den Vordergrund. Aber selbst mit dem entsprechenden 
Fenster im Vordergrund klappt es so nicht.

> Wie kann das sein?

Das liegt daran, dass du einen Denkfehler machst:

> Der Prozess "Notepad" wird in den Vordergrund geholt

Nein, das Fenster wird in den Vordergrund geholt.

> Nur leider wird das Event nicht an den Prozess "Notepad" weitergeleitet.

An das Fenster.

Lade mal das hier runter, wenn du willst:
http://inputsimulator.codeplex.com/
bzw. installiere es direkt über die NuGet-Konsole in Visual Studio per
Install-Package InputSimulator

Dann sollte dein Notepad-Test ungefähr so funktionieren 
(Minimalbeispiel, alles in die Fenster-Klasse gepackt):

1
public partial class MainWindow : Window
2
  {
3
    public MainWindow()
4
    {
5
      InitializeComponent();
6
      _keysim = new KeyboardSimulator(new InputSimulator());
7
    }
8

9
    [DllImport("user32.dll")]
10
    static extern bool SetForegroundWindow(IntPtr hWnd);
11

12
    [DllImport("user32.dll")]
13
    private static extern IntPtr GetForegroundWindow();
14

15
    private void OnSend(object sender, RoutedEventArgs e)
16
    {
17
      if(ActivateTargetWindow("notepad"))
18
      {
19
        _keysim.KeyPress(VirtualKeyCode.F5);
20
      }
21
    }
22

23
    private static bool ActivateTargetWindow(string procName)
24
    {
25
      var proc = Process.GetProcessesByName(procName);
26
      if(proc.Length == 0) return false;
27

28
      var windowHandle = proc[0].MainWindowHandle;
29
      SetForegroundWindow(windowHandle);
30

31
      const int maxTries = 10;
32
      const int delay = 20;
33
      int curTry = 0;
34
      bool targetIsForeground;
35
      do
36
      {        
37
        Thread.Sleep(delay);
38
        targetIsForeground = GetForegroundWindow() == windowHandle;
39
        curTry++;
40
      } while(!targetIsForeground && curTry < maxTries);
41
      
42
      return targetIsForeground;
43
    }
44

45
    private readonly KeyboardSimulator _keysim;
46
  }

Dir ist sicher klar, dass dir das - auch wenn es funktioniert - bei 
deinem versteckten Hintergrundfenster kaum weiter hilft. Darum mein 
Hinweis auf AutoIt und ControlSend (zum Testen, ob das Ganze überhaupt 
funktioniert, nicht als Ersatz für dein C#-Programm).
OP #3797528
adamzwerg schrieb:
> Lade mal das hier runter, wenn du willst:
> http://inputsimulator.codeplex.com/
> bzw. installiere es direkt über die NuGet-Konsole in Visual Studio per
> Install-Package InputSimulator

Danke für die Antwort.

Das Programm habe ich jetzt runter geladen. Aber ich verstehe nicht, wie 
ich das benutzen kann. Ich finde nirgends ein Menüpunkt mit Namen 
"Install-Package" im Visual Studio.

Wie kann ich das Programm nutzen?
Gast #3797537
Na das gibst du in der Console ein:

"Install-Package InputSimulator"

dann wird es installiert. Eventuell musst du dann noch die passenden 
Usings in deinem Program einbauen.

Gruß Jonas
Gast #3798424
Du kannst auch rechte Maustaste auf dein Projekt im "Solution Explorer" 
und dann "Manage NuGet Packages" und dort nach InputSimulator suchen.
(Die nuget-Konsole kann ansonsten via "Tools" > "NuGet-Package Manager" 
> "Package Manager Console" eingeblendet werden)
Gast #3798526
>Ich habe aber keine Consolenanwendung...

Eh, du hast eher kein Plan. Ich rede von einer Console (hier die nuget 
console) die man über Visual-Studio aufrufen um anschließend damit 
komfortabel neue Packete für die Integration in eigene Projekte 
installieren kann.

Gruß Jonas
OP #3798803
bluppdidupp schrieb:
> Du kannst auch rechte Maustaste auf dein Projekt im "Solution Explorer"
> und dann "Manage NuGet Packages" und dort nach InputSimulator suchen.
> (Die nuget-Konsole kann ansonsten via "Tools" > "NuGet-Package Manager"
>> "Package Manager Console" eingeblendet werden)

"Tools" gibt es leider bei meiner Version nicht und auch im 
Solutionexplorer gibt es keinen Eintrag mit "Manage NuGet Packages".
Wie heißt das denn bei der deutschen VS-Version?
OP #3798896
Gustav schrieb:
> Daniel M. schrieb:
>> Wie heißt das denn bei der deutschen VS-Version?
>
> Ganz ehrlich: laß es einfach.
>
> Gärtnern ist doch ein schönes Hobby. Töpfern. Vielleicht auch Minigolf?

Es geht hier ja nicht ums Hobby, sondern um eine Problemstellung 
innerhalb einer Abschlussarbeit. Von daher kein hilfreicher Ratschlag
OP #3798969
Gustav schrieb:
> Du hast recht.
>
> Es gibt doch auch andere schöne Abschlußarbeiten. Im Ausbildungsberuf
> Gärtner, Keramikmeister oder Spitzensportler. :-)

Du scheinst das nicht ganz zu verstehen.
Es geht hier um eine elektrotechnische/ informationstechnische 
Problemstellung.

Und es geht auch nicht um eine Ausbildung sondern ein Studium. Und da 
ich fast fertig bin, kommt ein Wechsel der Fachrichtung auch nicht in 
Frage.
Gast #3800138
Boris P. schrieb:
> Ist auch erst in den neuern Visual Studio Versionen (2013?) enthalten.

Ich meine ab 2012 und auch in Express-Editions.


Daniel M. schrieb:
> "Tools" gibt es leider bei meiner Version nicht und auch im
> Solutionexplorer gibt es keinen Eintrag mit "Manage NuGet Packages".
Tools heisst dort meine ich "Extras", aber der Begriff "NuGet" sollte 
einem an zig Stellen über den Weg laufen, wenn man drauf achtet.
Welches VS-Version ist denn installiert?
OP #3802102
Ich habe das Problem jetzt erfolgreich gelöst:

Mit der Funktion EnumWindos() zuerst sämtliche Prozesse einholen, diese 
dann nach Titel und Klassennamen filtern. Die Klasse "Process" ist dafür 
nicht geeigent, da diese nur die MainHandles zurückgibt und das in 
meinem Fall nicht ausreichend war.

Anschließend das gesuchte Handle des Fensters ermitteln und an dieses 
mit der Funktion PostMessage() einen simulierten Tastendruck senden.

Vielen Dank für die zahlreichen Antworten, auch wenn einer hier nicht 
ganz verstanden hat, worum es eigendlich ging :)

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 12 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.