Tasteneingabe an Spiel senden
-
Hallo ich versuche gerade eine Tasteneingabe an ein Spiel zu senden jedoch funktioniert es einfach nicht.
Wenn ich in dem Spiel den Chat öffne dann kann ich sehen das dort ein "a" eingetragen wird.
Wenn ich den Chat geschlossen habe müsste sich meine Spielfigur eingetlich im Kreis drehen ... Tut sich aber nicht !
Maus eingabe lassen sich ohne Probleme an das Spiel senden ( Mause rumbewegen und rum klicken ).
Mit AutoIT kann ich Tasteneingabe an das Spiel senden da funktioniert alles ohne Problem aber wie geht das in C++ ich verstehe nicht wieso das mit meinem code nicht funktioniert.
Gibt es da vielleicht noch eine anderen möglichkeit Eingabe an das Spiel zu senden ?
#include <windows> #include <iostream> using namespace std; int main(int argc, char* argv[]) { Sleep(4000); HWND hwnd; HWND set; hwnd = FindWindow ( "Guild Wars" , 0); if ( hwnd != 0 ) { cout<<"window not found"<<endl; system("PAUSE"); } set = SetFocus( hwnd ); if ( set == 0 ) { cout<<"set focus error"<<endl; } while ( !GetAsyncKeyState (VK_ESCAPE) ) { Sleep(1000); INPUT data; data.type = INPUT_KEYBOARD; data.ki.wVk = 0x41; data.ki.dwFlags = KEYEVENTF_EXTENDEDKEY ; SendInput (1 , &data, sizeof(data)); data.ki.dwFlags = KEYEVENTF_KEYUP; SendInput (1 , &data, sizeof(data)); } return 0; }
-
-
Du verwendest bereits SendInput(), das ist richtig.
Allerdings muß die Ziel-Applikation auch den Fokus (Eingabefokus) haben.Das kannst Du mit AttatchThreadInput() realisieren,
siehe auch "Die Unsitte Tastatureingaben mit WM_KEYDOWN Nachrichten zu simulieren" von Martin Richter:
http://blog.m-ri.de/index.php/2007/12/27/die-unsitte-tastatureingaben-mit-wm_keydown-nachrichten-zu-simulieren/HTH,
MartinNachtrag: Mir ist eben aufgefallen, daß Du vor Aufruf von SendInput() nicht alle Members der Struktur definiert hast!
Hier ein Beispiel aus meinem Code:INPUT s_input; s_input.type = INPUT_KEYBOARD; s_input.ki.wVk = VK_RETURN; s_input.ki.wScan = 28; s_input.ki.dwFlags = 0; s_input.ki.time = 0; s_input.ki.dwExtraInfo = 0; SendInput( 1, &s_input, sizeof( INPUT ) ); //Tastendruck "ENTER" simulieren.
-
@Mmacher ty jetzt funktioniert es.
Aber was genau ist:
data.ki.wScan = 28;
wScan = 28;
Wofür steht der hardware scan code 28 ?
Sobald ich einen anderen Wert an 28 dort eingebe kann ich nichts mehr an das Spiel senden.
Zu diesen hardware scan code Sachen konnte ich leider nichts finden.
-
Weiss keiner was das mit dem hardware scan code auf sich hat ?
-
Nur wenn Du für ki.dwFlags den Flag KEYEVENTF_SCANCODE setzt, dann wird der Inhalt von ki.wScan anstelle von ki.wVk ausgewertet.
db* schrieb:
Wofür steht der hardware scan code 28 ?
Ups, ehrlich gesagt, darauf weiß ich spontan keine Antwort darauf.
Hatte diesen Wert vor Jahren mal aus einem Forumbeitrag übernommen...
Ich weiß, ich hätte das überprüfen sollen, bevor ichs in meinen Sourcen einbaueSoviel ichs weiß, kannst Du für ki.wScan alternativ den Rückgabewert von der Funktion MapVirtualKey() mit uMapType=MAPVK_VK_TO_VSC verwenden.
Diese Funktion generiert aus den Virtual-Key-Code-Konstanten VK_xxx eben diese Hardware-Scan-Codes.Im Moment habe ich es nicht passend zur Hand, um diese Aussage hinreichend genau zu überprüfen.
Vielleicht kannst Du da ein wenig experimentieren und ggf. die Ergebnisse hier posten?HTH,
Martin[Nachtrag:]
db* schrieb:
Sobald ich einen anderen Wert an 28 dort eingebe kann ich nichts mehr an das Spiel senden.
Hmmm, laut MSDN-Doku müßte der Inhalt von ki.wScan eigentlich egal sein, wenn ki.dwFlags immer 0 ist.
Bist Du Dir da sicher, was Du da beobachtet hast?
-
Hier geht es doch um den Austausch von Informationen zwischen einzelnen gleichzeitig laufenden Prozessen. Dafür kann man mit reinem C und WinApi SendMessage einsetzen oder wenn das nicht reicht InterProcessCommunication (IPC) einsetzen. Wo ist das Problem?
-
berniebutt schrieb:
Hier geht es doch um den Austausch von Informationen zwischen einzelnen gleichzeitig laufenden Prozessen. Dafür kann man mit reinem C und WinApi SendMessage einsetzen oder wenn das nicht reicht InterProcessCommunication (IPC) einsetzen. Wo ist das Problem?
Im Grunde genommen hast Du schon recht mit Deiner Aussage.
Das gilt aber NICHT für Benutzereingaben wie Maus und Tastatur!
Wenn Du meinem Link "Die Unsitte Tastatureingaben mit WM_KEYDOWN Nachrichten zu simulieren" oben folgst dann verstehst Du warum hier SendInput() die eindeutig bessere Wahl ist.Martin
-
Info zum Thema "Scancode 28":
Von Microsoft unter "Archive: Key Support, Keyboard Scan Codes, and Windows":
http://msdn.microsoft.com/de-de/windows/hardware/gg463372Dort gibt es ein Dokument "Keyboard Scan Code Specification":
http://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/scancode.docAuf Seite 17 ist für Key "Enter" unter "scan 1 make" der Wert "1C" (dezimal 28) eingetragen.
HTH,
Martin
-
Den Scancode kann man auch mit MapVirtualKey abfragen, also im Falle von VK_RETURN
unsigned scancode = MapVirtualKey(VK_RETURN, 0);
Edit: Sorry Mmacher, ich habe erst jetzt gesehen, dass du besagte Funktion bereits genannt hast.
-
Hallo,
ich hab ein Problem was ich auch nach längerdem rum experimentieren nicht lösen konnte.Wenn im Spiel eine bestimmte Farbe erscheint dann wird die Taste 1 gedrückt, wenn die Farbe danach nochmal erscheint passiert jedoch gar nichts die SendInput Funktion scheint gar nicht ausgelöst zu werden.
Wenn ich dann jedoch selbst einmal die 1 auf meiner Tastatur drück und die Farbe erneut im Spiel erscheint dann wird mein Tastendruck ausgelöst.
Weiss wer woran das liegen kann ? Mir fällt da nichts zu ein.
#include <windows> #include <iostream> using namespace std; int main(int argc, char* argv[]) { bool terminate = false; COLORREF ref; Sleep(3000); UINT key; HWND hwnd; HWND foc; DWORD getThreadID; DWORD getThreadProcessID; bool Attach; hwnd = FindWindow (0,"Guild Wars"); if ( hwnd == 0 ) { cout<<"FindWindow error code:"<<GetLastError(); } HDC hdc = GetDC(0); getThreadID = GetCurrentThreadId(); getThreadProcessID = GetWindowThreadProcessId(hwnd,0); Attach = AttachThreadInput( getThreadID , getThreadProcessID , true ); if ( Attach == 0) { cout<<"AttachThreadInput error code: "<<GetLastError()<<endl; system("PAUSE"); } while ( terminate == false) { ref = GetPixel( hdc, 424, 93 ); if (ref == 0xDAE7A1) { key = MapVirtualKey( 0x31,0 ); INPUT data; data.type = INPUT_KEYBOARD; data.ki.wVk = 0x31; data.ki.wScan = key; data.ki.dwFlags = 0; data.ki.time =0; data.ki.dwExtraInfo = 0; SendInput (1 , &data, sizeof(data)); } if (GetAsyncKeyState(VK_ESCAPE) ==-32767) { AttachThreadInput( getThreadID , getThreadProcessID , false ); terminate = true; } } return 0; }
-
Tasten sind mechanische Elemente mit zwei zuständen: gedrückt und nicht gedrückt.
Wenn sie gedrückt sind, kann man sie nicht noch mal drücken!
-
Also müsste ich die Taste welche gedrückt wurde wieder loslassen?
In der MSDN habe ich zu SendInput folgendes noch gelesen:
http://msdn.microsoft.com/en-us/library/ms646310(v=vs.85).aspxThis function does not reset the keyboard's current state. Any keys that are already pressed when the function is called might interfere with the events that this function generates. To avoid this problem, check the keyboard's state with the GetAsyncKeyState function and correct as necessary.
This function does not reset the keyboard's current state <-- Oder muss ich noch den Status ändern?
-
Es ist ganz einfach: Wenn Du eine Taste drückst, musst Du sie auch wieder loslassen.... es braucht also immer min. 2 (in Worten: ZWEI) Events um einen Tastendruck zu simulieren...
-
Also müsste es so aussehen ?
#include <windows> #include <iostream> using namespace std; int main(int argc, char* argv[]) { bool terminate = false; COLORREF ref; Sleep(3000); UINT key; HWND hwnd; HWND foc; DWORD getThreadID; DWORD getThreadProcessID; bool Attach; hwnd = FindWindow (0,"Guild Wars"); if ( hwnd == 0 ) { cout<<"FindWindow error code:"<<GetLastError(); } HDC hdc = GetDC(0); getThreadID = GetCurrentThreadId(); getThreadProcessID = GetWindowThreadProcessId(hwnd,0); Attach = AttachThreadInput( getThreadID , getThreadProcessID , true ); if ( Attach == 0) { cout<<"AttachThreadInput error code: "<<GetLastError()<<endl; system("PAUSE"); } while ( terminate == false) { ref = GetPixel( hdc, 424, 93 ); if (ref == 0xDAE7A1) { key = MapVirtualKey( 0x31,0 ); INPUT data; data.type = INPUT_KEYBOARD; data.ki.wVk = 0x31; data.ki.wScan = key; data.ki.dwFlags = 0; data.ki.time =0; data.ki.dwExtraInfo = 0; SendInput (1 , &data, sizeof(data)); // Taste drücken SendInput (1 , &data, sizeof(data)); // Taste loslassen } if (GetAsyncKeyState(VK_ESCAPE) ==-32767) { AttachThreadInput( getThreadID , getThreadProcessID , false ); terminate = true; } } return 0; }
-
WO lässt Du denn da die Taste los?
Hast Du schon mal einen Blick ind ie Doku geworfen und die Millionen Beispiele im Internet angeschaut?
-
Jochen Kalmbach schrieb:
...und die Millionen Beispiele im Internet angeschaut?
Gut, ich muss mich korrigieren, Google kennt nur 313000 Treffer für SendInput...
-
Kleiner Tipp: Stichwort KEYEVENTF_KEYUP
HTH,
Martin
-
Hier sind wir im Forum WinApi unterwegs. Da gibt es noch die Möglichkeit, alle Maus- und Tastatureingaben vor der vorgesehenen Verarbeitung mit Subclassing selbst umzubiegen und anderes zu veranlassen.
-
Hallo berniebutt,
so wie es der Fragesteller formuliert hat, wird es mit dem Subclassing kaum funktionieren. Da er die Tasten an einen anderen Prozeß senden muß.db* schrieb:
Hallo ich versuche gerade eine Tasteneingabe an ein Spiel zu senden jedoch funktioniert es einfach nicht.
Oder hast Du in Verbindung mit DLL-Injektion gemeint?
Ok, da muß ich passen, mit DLL-Injektion kenne ich mich nicht so gut aus.HTH,
Martin