Comment puis-je générer par programme des événements de pression de touche en C #?

107

Comment puis-je créer par programme un événement qui simulerait une touche appuyée sur le clavier?

Dan Vogel
la source
6
Avez-vous juste besoin que l'événement se déclenche?
Daniel A. White
Je pense que vous devrez entrer dans du code non managé pour simuler une pression de touche «réelle».
Jonas B
Oui, j'ai juste besoin que l'événement se déclenche.
Dan Vogel
1
@GONeale: Wow, un commentaire de trois ans. Alors ok. Oui, il existe des utilisations valables pour cela, c'est pourquoi l'API existe en premier lieu. Ils sont cependant peu nombreux et espacés. D'après mon expérience, beaucoup de gens font cela parce qu'ils ne comprennent pas vraiment la meilleure façon de résoudre un problème, c'est-à-dire «Je veux appeler le code dans mon gestionnaire d'événements de clic de bouton, mais pas seulement lorsqu'un bouton est cliqué». Donc, pour un débutant, il semble logique de simuler un clic sur un bouton, alors que ce qu'ils devraient vraiment faire est de prendre ce code, de le lancer dans une fonction et de l'appeler ailleurs dans le code.
Ed S.
6
@EdS: La question était assez pertinente. J'aurais pu ajouter beaucoup de détails sur la création d'un clavier et obtenir toujours la même réponse. Étant donné que j'ai exactement ce dont j'avais besoin, cela ne me semble pas être une question de «mauvaise qualité».
Dan Vogel

Réponses:

147

La question est étiquetée WPF mais les réponses à ce jour sont spécifiques à WinForms et Win32.

Pour ce faire dans WPF, créez simplement un KeyEventArgs et appelez RaiseEvent sur la cible. Par exemple, pour envoyer un événement Insert key KeyDown à l'élément actuellement sélectionné:

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 }
);

Cette solution ne repose pas sur des appels natifs ni sur des composants internes de Windows et devrait être beaucoup plus fiable que les autres. Il vous permet également de simuler une pression de touche sur un élément spécifique.

Notez que ce code s'applique uniquement aux événements PreviewKeyDown, KeyDown, PreviewKeyUp et KeyUp. Si vous souhaitez envoyer des événements TextInput, vous le ferez à la place:

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 }
);

Notez également que:

  • Les contrôles s'attendent à recevoir des événements d'aperçu, par exemple, PreviewKeyDown doit précéder KeyDown

  • L'utilisation de target.RaiseEvent (...) envoie l'événement directement à la cible sans méta-traitement tel que les accélérateurs, la composition de texte et l'IME. C'est normalement ce que vous voulez. D'un autre côté, si vous faites vraiment quoi simuler des touches de clavier réelles pour une raison quelconque, vous utiliserez plutôt InputManager.ProcessInput ().

Ray Burns
la source
1
J'ai juste essayé votre suggestion, je ne vois aucun effet. J'ai attaché un gestionnaire d'événements keyDown à l'élément focalisé. L'événement que j'ai déclenché est reçu, mais le KeyState est None, le ScanCode est 0 et isDown est false. Je suppose que j'obtiens ces valeurs car c'est l'état réel du clavier. En appuyant sur une touche du clavier réel, KeyState = Down, isDown = true et ScanCode a une valeur.
Dan Vogel
25
quand j'ai essayé le premier code de keydown, j'ai eu une erreur dans "cible" je ne peux pas le convertir en visuel pourquoi?
kartal
3
Dan, savez-vous comment émuler la pression d'une touche avec un modificateur (ctrl / alt / shift)? En particulier, je dois simuler InputBinding: m_shell.InputBindings.Add (new KeyBinding (m_command, Key.Insert, ModifierKeys.Control | ModifierKeys.Alt));
Shrike
14
À propos du problème de la cible , je l'ai Keyboard.PrimaryDevice.ActiveSource
résolu
4
Cette réponse est très bonne, mais elle ne peut pas être utilisée pour envoyer une clé avec un modificateur, comme l'a noté @Shrike. (Par exemple Ctrl+C)
ANeves le
27

Pour produire des événements clés sans contexte Windows Forms, nous pouvons utiliser la méthode suivante,

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

un exemple de code est donné ci-dessous:

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;
}

La liste des clés virtuelles est définie ici .

Pour obtenir une image complète, veuillez utiliser le lien ci-dessous, http://tksinghal.blogspot.in/2011/04/how-to-press-and-hold-keyboard-key.html

Rajesh
la source
Convient, si votre fenêtre sera au-dessus. Cela a partiellement résolu ma situation, merci!
Sergey
Un ajout à la réponse de Rajesh, si vous voulez le faire dans la plate-forme mobile, vous devez importer "coredll.ddl"
user1123236
21

Je ne l'ai pas utilisé, mais SendKeys peut faire ce que vous voulez.

Utilisez SendKeys pour envoyer des frappes et des combinaisons de touches à l'application active. Cette classe ne peut pas être instanciée. Pour envoyer une frappe à une classe et poursuivre immédiatement le déroulement de votre programme, utilisez Envoyer. Pour attendre les processus démarrés par la frappe, utilisez SendWait.

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

Microsoft a d'autres exemples d'utilisation ici .

Michael Petrotta
la source
3
J'ai essayé d'utiliser SendKeys.Send et j'obtiens cette InvalidOperationException: "SendKeys ne peut pas s'exécuter dans cette application car l'application ne gère pas les messages Windows. Modifiez l'application pour gérer les messages ou utilisez la méthode SendKeys.SendWait." L'utilisation de SendKey.SendWait n'a aucun effet.
Dan Vogel
Assurez-vous de ne pas vous envoyer l'événement clé. Basculez sur le processus approprié avant d'envoyer l'événement. Le deuxième article lié a une certaine aide à ce sujet.
Michael Petrotta
11

Facilement! (parce que quelqu'un d'autre a déjà fait le travail pour nous ...)

Après avoir passé beaucoup de temps à essayer cela avec les réponses suggérées, je suis tombé sur ce projet codeplex Windows Input Simulator qui simplifiait la simulation d'une pression sur une touche:

  1. Installez le package, peut être fait ou à partir du gestionnaire de packages NuGet ou de la console du gestionnaire de packages comme:

    Install-Package InputSimulator

  2. Utilisez ces 2 lignes de code:

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

Et c'est tout!

-------ÉDITER--------

La page du projet sur CodePlex est marqué pour une raison quelconque, c'est le lien vers la galerie NuGet.

Ravid Goldenberg
la source
Cela fonctionne très bien, mais je n'ai pas été en mesure de trouver comment faire fonctionner cela avec une combinaison de touches,
user1234433222
Quand vous dites combinaison de touches, voulez-vous dire CTRL-C?
Ravid Goldenberg
oui ou même si vous vouliez qu'une application console passe en plein écran, par exemple Alt-Entrée, je sais que vous pouvez utiliser F11 pour entrer en plein écran mais ce serait bien de voir si Alt-Entrée fonctionnerait :)
user1234433222
1
Eh bien, vous pouvez le faire, même si je ne l'ai pas essayé, utilisez simplement inputSimulator.Keyboard.ModifiedKeyStroke (VirtualKeyCode.CONTROL, VirtualKeyCode.VK_C);
Ravid Goldenberg