Jak programowo generować zdarzenia naciśnięcia klawiszy w języku C #?

107

Jak mogę programowo utworzyć zdarzenie, które symulowałoby naciśnięcie klawisza na klawiaturze?

Dan Vogel
źródło
6
Czy potrzebujesz tylko zdarzenia do odpalenia?
Daniel A. White
Myślę, że musiałbyś wejść w niezarządzany kod, aby zasymulować „prawdziwe” naciśnięcie klawisza.
Jonas B
Tak, po prostu potrzebuję zdarzenia do odpalenia.
Dan Vogel
1
@GONeale: Wow, komentarz sprzed trzech lat. Okej. Tak, istnieją do tego ważne zastosowania; właśnie dlatego API istnieje w pierwszej kolejności. Jest ich jednak niewielu. Z mojego doświadczenia wynika, że ​​wiele osób robi to, ponieważ tak naprawdę nie rozumieją najlepszego sposobu rozwiązania problemu, tj. „Chcę wywołać kod w moim module obsługi zdarzenia kliknięcia przycisku, ale nie tylko po kliknięciu przycisku”. Tak więc dla początkującego wydaje się logiczne, aby symulować kliknięcie przycisku, kiedy to, co naprawdę powinni zrobić, to wziąć ten kod, wrzucić go do funkcji i wywołać go z innego miejsca w kodzie.
Ed S.,
6
@EdS: Pytanie było dość trafne. Mógłbym dodać wiele dodatkowych szczegółów na temat tworzenia klawiatury i nadal uzyskać tę samą odpowiedź. Biorąc pod uwagę, że otrzymałem dokładnie to, czego potrzebowałem, nie wydaje mi się to pytanie „niskiej jakości”.
Dan Vogel

Odpowiedzi:

147

Pytanie jest oznaczone jako WPF, ale dotychczasowe odpowiedzi to specyficzne WinForms i Win32.

Aby to zrobić w WPF, po prostu skonstruuj KeyEventArgs i wywołaj RaiseEvent w miejscu docelowym. Na przykład, aby wysłać zdarzenie klawisza Insert KeyDown do aktualnie aktywnego elementu:

var key = Key.Insert;                    // Key to send
var target = Keyboard.FocusedElement;    // Target element
var routedEvent = Keyboard.KeyDownEvent; // Event to send
     target.RaiseEvent(
  new KeyEventArgs(
    Keyboard.PrimaryDevice,
    PresentationSource.FromVisual(target),
    0,
    key)
  { RoutedEvent=routedEvent }
);

To rozwiązanie nie opiera się na natywnych wywołaniach ani wewnętrznych elementach systemu Windows i powinno być znacznie bardziej niezawodne niż inne. Umożliwia także symulację naciśnięcia klawisza na określonym elemencie.

Należy pamiętać, że ten kod ma zastosowanie tylko do zdarzeń PreviewKeyDown, KeyDown, PreviewKeyUp i KeyUp. Jeśli chcesz wysyłać zdarzenia TextInput, zrób to:

var text = "Hello";
var target = Keyboard.FocusedElement;
var routedEvent = TextCompositionManager.TextInputEvent;

target.RaiseEvent(
  new TextCompositionEventArgs(
    InputManager.Current.PrimaryKeyboardDevice,
    new TextComposition(InputManager.Current, target, text))
  { RoutedEvent = routedEvent }
);

Pamiętaj również, że:

  • Kontrolki oczekują, że będą odbierać zdarzenia Preview, na przykład PreviewKeyDown powinno poprzedzać KeyDown

  • Używanie target.RaiseEvent (...) wysyła zdarzenie bezpośrednio do celu bez meta-przetwarzania, takiego jak akceleratory, skład tekstu i IME. Zwykle tego chcesz. Z drugiej strony, jeśli naprawdę robisz coś, co z jakiegoś powodu symuluje rzeczywiste klawisze klawiatury, możesz zamiast tego użyć InputManager.ProcessInput ().

Ray Burns
źródło
1
Właśnie wypróbowałem twoją sugestię, nie widzę efektu. Dołączyłem obsługę zdarzeń keyDown do skoncentrowanego elementu. Zdarzenie, które wywołałem, zostało odebrane, ale KeyState ma wartość None, ScanCode to 0, a isDown ma wartość false. Zakładam, że otrzymuję te wartości, ponieważ jest to rzeczywisty stan klawiatury. Naciśnięcie klawisza na rzeczywistej klawiaturze, KeyState = Down, isDown = true, a ScanCode ma wartość.
Dan Vogel
25
kiedy wypróbowałem pierwszy kod keydown, pojawił się błąd w „celu”, nie mogę przekonwertować go na wizualny, dlaczego?
kartal
3
Dan, czy wiesz, jak emulować naciśnięcie klawisza z modyfikatorem (ctrl / alt / shift)? W szczególności muszę symulować InputBinding: m_shell.InputBindings.Add (new KeyBinding (m_command, Key.Insert, ModifierKeys.Control | ModifierKeys.Alt));
Shrike
14
O docelowej emisji, poradziłem sobie używając Keyboard.PrimaryDevice.ActiveSourcezobaczyć stackoverflow.com/questions/10820990/...
OscarRyz
4
Ta odpowiedź jest bardzo dobra, ale nie można jej użyć do wysłania klucza z modyfikatorem, jak zauważył @Shrike. (Np Ctrl+C.)
ANeves
27

Aby utworzyć kluczowe zdarzenia bez kontekstu Windows Forms, możemy użyć następującej metody,

[DllImport("user32.dll")]
public static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, uint dwExtraInfo);

przykładowy kod podano poniżej:

const int VK_UP = 0x26; //up key
const int VK_DOWN = 0x28;  //down key
const int VK_LEFT = 0x25;
const int VK_RIGHT = 0x27;
const uint KEYEVENTF_KEYUP = 0x0002;
const uint KEYEVENTF_EXTENDEDKEY = 0x0001;
int press()
{
    //Press the key
    keybd_event((byte)VK_UP, 0, KEYEVENTF_EXTENDEDKEY | 0, 0);
    return 0;
}

Lista kluczy wirtualnych jest zdefiniowana tutaj .

Aby uzyskać pełny obraz, użyj poniższego linku, http://tksinghal.blogspot.in/2011/04/how-to-press-and-hold-keyboard-key.html

Rajesh
źródło
Odpowiednie, jeśli twoje okno będzie na górze. To częściowo rozwiązało moją sytuację, dzięki!
Sergey
Jako dodatek do odpowiedzi Rajesha, jeśli chcesz to zrobić na platformie mobilnej, musisz zaimportować
plik
21

Nie używałem tego, ale SendKeys może robić, co chcesz.

Użyj SendKeys, aby wysłać naciśnięcia klawiszy i kombinacje naciśnięć klawiszy do aktywnej aplikacji. Nie można utworzyć wystąpienia tej klasy. Aby wysłać naciśnięcie klawisza do klasy i natychmiast kontynuować pracę programu, użyj funkcji Wyślij. Aby poczekać na jakiekolwiek procesy uruchomione przez naciśnięcie klawisza, użyj SendWait.

System.Windows.Forms.SendKeys.Send("A");
System.Windows.Forms.SendKeys.Send("{ENTER}");

Firma Microsoft ma tutaj więcej przykładów użycia .

Michael Petrotta
źródło
3
Próbowałem użyć SendKeys.Send i otrzymałem ten InvalidOperationException: „SendKeys nie może działać wewnątrz tej aplikacji, ponieważ aplikacja nie obsługuje wiadomości systemu Windows. Zmień aplikację na obsługę wiadomości lub użyj metody SendKeys.SendWait”. Używanie SendKey.SendWait nie ma żadnego efektu.
Dan Vogel
Upewnij się, że nie wysyłasz do siebie kluczowego wydarzenia. Przełącz fokus na właściwy proces przed wysłaniem zdarzenia. Drugi powiązany artykuł zawiera pomoc w tej sprawie.
Michael Petrotta
11

Z łatwością! (ponieważ ktoś inny wykonał już za nas pracę ...)

Po spędzeniu dużo czasu na próbowaniu tego z sugerowanymi odpowiedziami natknąłem się na ten projekt Codeplex Symulator wprowadzania systemu Windows, który uprościł symulację naciśnięcia klawisza:

  1. Zainstaluj pakiet, można to zrobić lub z menedżera pakietów NuGet lub z konsoli menedżera pakietów, takich jak:

    Zainstaluj pakiet InputSimulator

  2. Użyj tych 2 wierszy kodu:

    inputSimulator = new InputSimulator() inputSimulator.Keyboard.KeyDown(VirtualKeyCode.RETURN)

I to wszystko!

-------EDYTOWAĆ--------

Strona projektu w Codeplex jest oflagowana z jakiegoś powodu, to jest link do galerii NuGet.

Ravid Goldenberg
źródło
Działa to bardzo dobrze, jednak nie udało mi się znaleźć tego, jak to działa z kombinacją klawiszy,
user1234433222
Kiedy mówisz kombinację klawiszy, masz na myśli CTRL-C?
Ravid Goldenberg
tak, a nawet gdybyś chciał, aby aplikacja konsoli działała na pełnym ekranie, np. Alt-Enter, wiem, że możesz użyć F11, aby przejść do pełnego ekranu, ale byłoby miło zobaczyć, czy Alt-Enter zadziała :)
user1234433222
1
Cóż, możesz to zrobić, chociaż nie próbowałem tego, po prostu użyj inputSimulator.Keyboard.ModifiedKeyStroke (VirtualKeyCode.CONTROL, VirtualKeyCode.VK_C);
Ravid Goldenberg