Laden...

Tastaturbefehl an anderes Programm senden

Letzter Beitrag vor 17 Jahren 20 Posts 14.026 Views
Tastaturbefehl an anderes Programm senden

Hallo, das Problem sieht so aus: Ich habe ein Spiel (Ultrastar), das mit Tastatur gesteuert werden kann (auch die Bildschirmtastatur von Windows funktioniert!). Ich will es mit Fernbedienung steuern. Habe dafür Girder eingestellt und programmiert, funktioniert einwandfrei. Ultrastar hat aber kein Handle für die simulierten Tastaturbefehle die Girder schickt. Dafür wollte ich ein kleines Programm schreiben das wie folgt funktionieren sollte:

Girder schickt seine Befehle an das Programm (was im Hintergrund mitläuft) und dieses leitet sie (wie die Bildschirmtastatur) an Ultrastar weiter. DIe Kommunikation zwischen Girder und dem Programm funktioniert wunderbar. An Ultrastar wollte ich die Befehle einfach per SendKeys weiterleiten, das Programm sendet auch, aber das nimmt Ultrastar nicht an. Die Funktion sieht für eine Taste beispielsweise so aus:

private void Form1_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
		{
			if(e.KeyCode == Keys.Left) 
				SendKeys.Send("{Left}");
		}

Also theoretisch müsste das so richtig sein, aber wie gesagt, Ultrastar nimmt es nich an. Weiß jemand irgend ne andere Methode wie ich die Tastaturbefehle an Ultrastar senden könnte?! Kann man rausbekommen wie die Bildschirmtastatur von Windows das macht, da funktioniert es ja, also muss es ja irgendwie gehen 😉

Danke schonmal für Hilfe!

Hallo,

du musst das Programm, an das die Tasten gesendet werden sollen, erst in den Vordergrund holen. Ansonsten sendest du die Tasten an deine eigene Anwendung.

Dazu kannst du die API Funktion SetActiveWindow verwenden. Nachdem du die Taste gesendet hast, brauchst du nur deine Anwendung wieder zu aktivieren.

Also die Anwendung an die gesendet werden soll ist schon das aktive Fenster. Im Prinziep läuft Girder und mein Programm im Hintergrund. Girder sendet bei Tastendruck der Fernbedienung automatisch an mein Programm und das müsste die Taste ja dann per SendKey an das aktive Fenster (Ultrastar) senden. Scheint aber so auch nicht zu klappen.

Gäbe es vielleicht noch ne Möglichkeit über SendMessage?! Habe sowas schon gelesen aber weiß nicht genau wie ich das einsetzen müsste, bzw welche Parameter ich wie übergeben müsste.

benutze lieber keybd_event, SendMessage oder PostMessage (API)
Bei SendMessage und PostMessage kann z.B. das konkrete Handle angegeben werden, für das Fenster an die die emulierte Benutzeraktion gesendet werden soll.

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

Danke erstmal für die Antworten, wenn ich das richtig verstanden habe sendet PostMessage also direkt an ne Windowsanwendung. Aber wie genau kann ich sagen was gesendet werden soll? Also so in etwa müsste ja der code aussehen oder:

int Handle = FindWindow("UltraStar",null);

PostMessage(Handle,(int)Msg.WM_COMMAND,0,0);

An stelle der 1. Null die hinter WM_COMMAND kommt muss ich glaub ich den Code für die Nachricht/ Taste schreiben, stimmt das? Wenn ja wo bekomm ich den Code her?

Das steht in der Platform SDK (Api Doku) z.B. Download unter

Platform SDK (Windows 2003)

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

Öhm, finde ich diese Doku auch irgendwo einzeln? Bzw nach was muss ich da überhaupt suchen 🤔

kann auch nicht schaden:

http://www.pinvoke.net/

Sorry, aber ich werde aus dem ganzen Zeug nich schlau... PostMessage ist ja so aufgebaut:

static extern bool PostMessage(HandleRef hWnd, uint Msg, IntPtr wParam,
   IntPtr lParam);

Also der erste Papameter is das Handle zum Fenster das angesprochen werden soll, der 2. gibt an was bzw. wie gesendet werden soll. Und was ist mit den letzten beiden, wofür sind die? Ich find einfach nix dazu :-\ Was muss ich denn machen um einfach einen simulierten Tastendruck mit Postmessage zu senden?!

Keiner ne Idee?

wenn die ersten beiden Parameter schon reichen, um einen Tastendruck zu senden, reicht für die letzten beiden vielleicht:
IntPtr.Zero;
schon mal probiert ?

Ich würd es mal so versuchen:


const int WM_KEYDOWN = 0x100;
const int WM_KEYUP = 0x101;
const int VK_LEFT = 0x25;

[DllImport("user32")]
static extern bool PostMessage(IntPtr hWnd, int msg, uint wParam, uint lParam);

PostMessage(hWnd, WM_KEYDOWN, VK_LEFT, 0);
PostMessage(hWnd, WM_KEYUP, VK_LEFT, 0xC0000000);

Mit SendKeys hab ich auch grad Probleme...

Wenn ich das so mache dann bekomm ich beim compilieren diese Fehlermeldung: "Der Typ oder Namespace 'DllImport' konnte nicht gefunden werden." Muss ich da noch nen anderen Namespace angeben oder wie?

Und wo bekomm ich nun genau die Werte für die Konstanten her? Und was bedeutet das "0xC0000000" als letzter Parameter in Postmessage?

bezüglich NameSpace:
solche sachen stehen auch in der doku:
"System.Runtime.InteropServices"

bezüglich Konstantenwerte:
http://www.pinvoke.net/default.aspx/Constants/WM.html

Original von matzze2000
Der Typ oder Namespace 'DllImport' konnte nicht gefunden werden.

Du solltest Visual Studio 2005 verwenden. Da kannst du einfach den Cursor auf einen Klassennamen setzen, und wenn er noch nicht türkis eingefärbt (= erkannter Klassenname) ist, erscheint so ein kleines "SmartTag", in dem du entweder den vollständigen Namespace oder eine passende using-Anweisung einfügen lassen kannst. VS2005 findet so alle Klassennamen von allein, du musst dir gar nicht mehr um die entsprechenden Namespaces Gedanken machen.

Und wo bekomm ich nun genau die Werte für die Konstanten her?

Die hab ich doch mit definiert.

Und was bedeutet das "0xC0000000" als letzter Parameter in Postmessage?

Das ist der Parameterwert für die WM_KEYUP-Nachricht, der aussagt, dass die Taste einmal gedrückt wurde und jetzt losgelassen wird. Genauere Infos findest du in der MSDN unter WM_KEYUP.

Original von LonelyPixel

Und wo bekomm ich nun genau die Werte für die Konstanten her?

Die hab ich doch mit definiert.

Ja, aber ich brauche für das Programm dann noch andere Tasten als die Links-taste. Deswegen wollte ich wissen obs irgendwo ne Tabelle oder sowas gibt wo zu jeder Taste der Code steht. Ansonsten schonmal danke für die tollen und hilfreichen Antworten =) 👍

ich hab den entsprechenden Link vorher schon gepostet:
http://www.pinvoke.net/default.aspx/Constants/WM.html

Achso, okay. Die VK_*-Konstanten sind in der MSDN beschrieben. Einfach mal im Index (ungefiltert) nach VK_ suchen, dann auf irgendeinen der Einträge klicken. Bei den Namen steht auch der nummerische Wert dabei. Ansonsten: Alle Konstanten findet man wie immer in den *.h-Dateien im Verzeichnis C:\Programme\Microsoft Visual Studio 8\VC\PlatformSDK\Include. Alle Dateien nach dem gewünschten Namen zu durchsuchen bringt meist den gewünschten Erfolg. So mach ich das meistens, da weiß man auch sicher, dass es stimmt.

Also ich hab jetzt folgenden Code der sich auch so ohne Probleme compilieren lässt:

private void Form1_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
		{
			if(e.KeyCode == Keys.Left) 
			{
				const int WM_KEYDOWN = 0x100;
				const int WM_KEYUP = 0x101;
				const int VK_LEFT = 0x25;
				System.IntPtr Handle = FindWindow("UltraStar",null);

				PostMessage(Handle, WM_KEYDOWN, VK_LEFT, 0);
				PostMessage(Handle, WM_KEYUP, VK_LEFT, 0xC0000000);
				label1.Text = "gesendet!";
			}
		}

Allerdings zeigt UltraStar keinerlei Reaktion wenn ich das Programm ausführ und die Links-Taste drücke. Hat jemand ne Idee woran das liegen könnte bzw wie ich am besten rausfinde, ob mein Handle überhaupt das UltraStar Fenster "findet"?

Welchen Wert hat denn dein "Handle"? (Nicht verwechseln mit Form.Handle.) Wenn es IntPtr(0) ist, hat FindWindow das Fenster nicht gefunden.

Kennst du das Programm Spy, das früher bei Visual C++ immer dabei war? Weiß grad nicht, ob es beim aktuellen Visual Studio noch dabei ist. Damit kannst du jedenfalls alle Fenster im System hierarchisch auflisten lassen, die Handles und tausend weitere Eigenschaften anzeigen lassen und ein Fenster/Control aus der Baumansicht auch auf dem Bildschirm blinken lassen, damit du weißt, ob du das richtige gefunden hast. Man kann auch mit der Maus ein Fenster auf dem Bildschirm auswählen, das einem dann in der Baumansicht ausgewählt wird. So kannst du das richtige Fenster finden. Deine Funktion kannst du so ja erstmal mit dem Texteditor ausprobieren, da funktioniert die ganz bestimmt.