2010-09-05 18 views
15

Próbuję symulować polecenia klawiatury dla niestandardowej aplikacji kontrolera gier. Ponieważ będę musiał symulować polecenia w środowisku DirectInput większość zwykłych metod nie działa. Wiem, że używanie haka działa w 100%, ale staram się znaleźć łatwiejszą implementację.Symulowanie klawiatury za pomocą interfejsu SendInput API w aplikacjach DirectInput

Zrobiłem sporo wyszukiwania i okazało się, że przy użyciu API SendInput z Scancodes zamiast wirtualnych kluczy powinno działać, ale wydaje się, że zachowuje się tak, jak klucz jest "sticking". Wysłałem zarówno zdarzenia KEYDOWN, jak i KEYUP, ale kiedy próbuję wysłać wiadomość w środowisku DirectInput, gra zachowuje się tak, jakby klawisz był przytrzymywany.

Na przykład, jeśli zasymuluję naciśnięcie klawisza "W" i przypisuję ten klucz do gracza "Pierwszego człowieka" do akcji "przesuń się do przodu", to po wejściu w grę funkcja poniżej spowoduje, że postać ruszy do przodu . Jednakże, wydając komendę tylko raz, przesunie ona znak do przodu w nieskończoność.

Oto fragment kodu (C#) dla funkcji SendInput Dzwonię:

[DllImport("user32.dll")] 
static extern UInt32 SendInput(UInt32 nInputs, [MarshalAs(UnmanagedType.LPArray, SizeConst = 1)] INPUT[] pInputs, Int32 cbSize); 

public static void Test_KeyDown() 
{ 
    INPUT[] InputData = new INPUT[2]; 
    Key ScanCode = Microsoft.DirectX.DirectInput.Key.W; 

    InputData[0].type = 1; //INPUT_KEYBOARD 
    InputData[0].wScan = (ushort)ScanCode; 
    InputData[0].dwFlags = (uint)SendInputFlags.KEYEVENTF_SCANCODE; 

    InputData[1].type = 1; //INPUT_KEYBOARD 
    InputData[1].wScan = (ushort)ScanCode; 
    InputData[1].dwFlags = (uint)(SendInputFlags.KEYEVENTF_KEYUP | SendInputFlags.KEYEVENTF_UNICODE); 

    // send keydown 
    if (SendInput(2, InputData, Marshal.SizeOf(InputData[1])) == 0) 
    { 
     System.Diagnostics.Debug.WriteLine("SendInput failed with code: " + 
     Marshal.GetLastWin32Error().ToString()); 
    } 
} 

Nie jestem pewien, czy ta metoda jest przegrana, lub jeśli nie jest po prostu coś mi głupio "brakuje. Nienawidzę nadmiernego komplikowania mojego kodu, jeśli nie muszę, używając haków, ale jest to również nowe terytorium dla mnie.

Każda pomoc, którą każdy może dać, jest bardzo ceniona.

Dzięki!

+4

Co to jest "INPUT []"? Czy to miało pochodzić z '" user32.dll "'? –

Odpowiedz

21

Znalazłem rozwiązanie mojego własnego problemu. Pomyślałem, że opublikuję tutaj, aby pomóc każdemu, kto może mieć podobne problemy w przyszłości.

Polecenie keyup nie działało poprawnie, ponieważ tylko przy wysyłaniu kodu skanowania, keyup musi być OR'ed z flagą kodu skanowania (skutecznie włączając obie flagi), aby powiedzieć SendInput() API, że jest to zarówno KEYUP i polecenie SCANCODE.

Na przykład, następujący kod będzie prawidłowo wystawić skanowania kodu klucza-up:

INPUT[] InputData = new INPUT[1]; 

InputData[0].Type = (UInt32)InputType.KEYBOARD; 
//InputData[0].Vk = (ushort)DirectInputKeyScanCode; //Virtual key is ignored when sending scan code 
InputData[0].Scan = (ushort)DirectInputKeyScanCode; 
InputData[0].Flags = (uint)KeyboardFlag.KEYUP | (uint)KeyboardFlag.SCANCODE; 
InputData[0].Time = 0; 
InputData[0].ExtraInfo = IntPtr.Zero; 

// Send Keyup flag "OR"ed with Scancode flag for keyup to work properly 
SendInput(1, InputData, Marshal.SizeOf(typeof(INPUT))) 

Dzięki Hans na odpowiedź. Zrobiłem kilka badań i wysłałem dwie wiadomości z powrotem do siebie, tak jak oryginalny przykład rzeczywiście symuluje "naciśnięcie klawisza", ale jest bardzo szybki. Nie działa to dobrze dla polecenia ruchu, ale byłoby idealne, gdy klawisze akcji mają zostać "dotknięte" i nie przytrzymywane.

Pole klucza wirtualnego jest również ignorowane podczas wysyłania kodu skanowania. Firma MSDN miała do powiedzenia na ten temat:

"Ustaw flagę KEYEVENTF_SCANCODE, aby zdefiniować wejście klawiatury w odniesieniu do kodu skanowania. Jest to użyteczne do symulacji fizycznego naciśnięcia klawisza bez względu na to, która klawiatura jest aktualnie używana. wartość klucza może się zmieniać w zależności od aktualnego układu klawiatury lub innych klawiszy, ale kod skanowania będzie zawsze taki sam. "

http://msdn.microsoft.com/en-us/library/ms646271%28v=VS.85%29.aspx

+3

W twoim rozwiązaniu znalazłeś wzmiankę o DirectInputKeyScanCode, że nie mogę go użyć, mógłbyś mi pomóc? – Fede

+0

Czy możesz opublikować pełne rozwiązanie dotyczące naciśnięcia klawisza w dół i klawisza? Nie jestem pewien, co robię źle i co muszę wymienić w pierwszym wysłanym fragmencie kodu. DZIĘKI! –

3

starałem się symulować klawiatur dla prezentacji w technologii Flash, a także mający ten sam problem. Zrobił to dla aplikacji takich jak Notatnik, ale nie dla flash. Po wielu godzinach szukania w Google w końcu zadziałało:

public static void GenerateKey(int vk, bool bExtended) 
    { 
     INPUT[] inputs = new INPUT[1]; 
     inputs[0].type = INPUT_KEYBOARD; 

     KEYBDINPUT kb = new KEYBDINPUT(); //{0}; 
     // generate down 
     if (bExtended) 
      kb.dwFlags = KEYEVENTF_EXTENDEDKEY; 

     kb.wVk = (ushort)vk; 
     inputs[0].ki = kb; 
     SendInput(1, inputs, System.Runtime.InteropServices.Marshal.SizeOf(inputs[0])); 

     // generate up 
     //ZeroMemory(&kb, sizeof(KEYBDINPUT)); 
     //ZeroMemory(&inputs,sizeof(inputs)); 
     kb.dwFlags = KEYEVENTF_KEYUP; 
     if (bExtended) 
      kb.dwFlags |= KEYEVENTF_EXTENDEDKEY; 

     kb.wVk = (ushort)vk; 
     inputs[0].type = INPUT_KEYBOARD; 
     inputs[0].ki = kb; 
     SendInput(1, inputs, System.Runtime.InteropServices.Marshal.SizeOf(inputs[0])); 
    } 
Powiązane problemy