Dies ist eine Ergänzung zu meinem Blog Eintrag Die Unsitte Windows interne Nachrichten zu versenden.
In einem der Kommentare wurde ich gefragt wie man es nun mit WM_KEY… Nachrichten richtig macht, weil ich auch diese Nachrichten als „intern“ definiert habe. In meinen Augen ist es unzulässig WM_KEY… Nachrichten per PostMessage oder SendMessage zu versenden. Also ist die Frage berechtigt:
Wie macht man es richtig, mit der Simulation von Tastatureingaben für andere Prozesse ❓
Ersteinmal möchte ich erklären, warum das Senden einer WM_KEY… Nachricht nicht funktioniert, oder oft genug nicht richtig funktioniert:
- Alleine wenn das Programm GetKeyState oder GetAsynchKeystate benutzt um zu ermitteln ob gleichzeitig sie Strg- oder die Umschalttaste gedrückt wird, dann funktioniert SendMessage/PostMessage nicht mehr.
- Wenn das fremde Programm Accelerator verwendet, dann wird hier auch durch senden einer WM_KEY… Nachricht der Accelerator oft genug nicht ausgelöst. Die Folge: Der gewünschte Effekt bleibt aus.
- Man bekommt schnell Probleme mit synthetisierten Zeichen, die zwei Tasteneingaben erfordern, z.B. ^ und a, für â.
- Man muss fürchterlich darauf achten, wenn ein Befehl den Fokus wechselt.
- Die Applikation hat nicht den Fokus! Alleine das kann schon Fehlverhalten auslösen, denn normalerweise kann nur eine aktive Applikation mit Fokus Tastatur- und Mauseingaben erhalten.
- WM_SYSKEY… Nachrichten werden nicht korrekt erzeugt.
Wie macht man es nun ❓
Es ist ganz einfach: Man benutzt SendInput ❗
Der Vollständigkeit halber sei hier noch die legacy Funktion keybd_event erwähnt.
SendInput reiht die Eingaben ein in die Eingabequeue für das gesamte Windows System ein und liefert diese an die aktive Applikation aus und an das Fenster, das den aktuellen Eingabefokus hat. Man kann also nicht einfach so auch das Zielfenster angeben, dass die Eingaben erhalten soll. Das merkt man schon daran, dass es kein Fensterhandle gibt, dass man als Ziel angeben könnte für SendInput.
Frage aber nun: Wie gewährleistet man, dass das richtige Programm die Tastaturnachricht bekommt ❓
Auch hier ist die Antwort relativ einfach! Zwei Dinge sind dazu nötig:
- Dass Zielfenster, bzw. den Thread in dem das Zielfenster muss ausgewählt werden, damit er diese Eingaben auch erhalten darf. Das wird durch AttachThreadInput erreicht. Denn wir wollen die Daten ja nicht an unsere Applikation senden. ❗ Bitte hinterher nicht vergessen AttatchThreadInput mit FALSE aufzurufen und den Thread wieder zu detachen.
- Man muss den Fokus korrekt setzten für das Fenster, dass die Eingaben erhalten soll!
Ist der Zielthread jetzt an die Eingabequeue angeschlossen, kann man ohne Probleme SetFocus ausführen (was ohne AttachThreadInput normalerweise auch nicht möglich wäre). - Wird jetzt SendInput ausgeführt, werden alle Nachrichten korrekt erzeugt und auch alle Commands entsprechend der Tastaturfolge ausgelöst. Auch spezielle Umlaute und Unicode Zeichne lassen sich so erzeugen.
Es ist gar nicht so schwer es richtig zu machen.