Como posso gerar eventos de pressionamento de tecla programaticamente em C #?

107

Como posso criar programaticamente um evento que simule uma tecla sendo pressionada no teclado?

Dan Vogel
fonte
6
Você só precisa que o evento seja disparado?
Daniel A. White,
Acho que você teria que entrar no código não gerenciado para simular um pressionamento de tecla 'real'.
Jonas B
Sim, só preciso que o evento seja disparado.
Dan Vogel
1
@GONeale: Uau, um comentário de três anos. OK então. Sim, existem usos válidos para isso; é por isso que a API existe em primeiro lugar. No entanto, eles são poucos e distantes entre si. Na minha experiência, muitas pessoas fazem isso porque não entendem realmente a melhor maneira de resolver um problema, ou seja, "Quero chamar o código em meu manipulador de eventos de clique de botão, mas não apenas quando um botão é clicado". Portanto, para um iniciante, parece lógico simular um clique de botão, quando o que eles realmente deveriam fazer é pegar esse código, jogá-lo em uma função e chamá-lo de outro lugar no código.
Ed S.
6
@EdS: A pergunta foi direta ao ponto. Eu poderia ter acrescentado muitos detalhes em excesso sobre a criação de um teclado e ainda obter a mesma resposta. Considerando que recebi exatamente o que precisava, não me parece uma pergunta de "baixa qualidade".
Dan Vogel

Respostas:

147

A pergunta está marcada como WPF, mas as respostas até agora são WinForms e Win32 específicos.

Para fazer isso no WPF, basta construir um KeyEventArgs e chamar RaiseEvent no destino. Por exemplo, para enviar um evento KeyDown da tecla Insert para o elemento atualmente em foco:

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

Esta solução não depende de chamadas nativas ou internas do Windows e deve ser muito mais confiável do que as outras. Também permite simular um pressionamento de tecla em um elemento específico.

Observe que este código só se aplica a eventos PreviewKeyDown, KeyDown, PreviewKeyUp e KeyUp. Se você quiser enviar eventos TextInput, faça o seguinte:

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

Observe também que:

  • Os controles esperam receber eventos de visualização, por exemplo, PreviewKeyDown deve preceder KeyDown

  • O uso de target.RaiseEvent (...) envia o evento diretamente para o destino sem meta-processamento, como aceleradores, composição de texto e IME. Normalmente é isso que você deseja. Por outro lado, se você realmente fizer o que simular as teclas reais do teclado por algum motivo, deverá usar InputManager.ProcessInput ().

Ray Burns
fonte
1
Acabei de tentar sua sugestão, não vejo efeito. Anexei um manipulador de eventos keyDown ao elemento em foco. O evento que levantei é recebido, mas o KeyState é Nenhum, o ScanCode é 0 e isDown é falso. Presumo que estou obtendo esses valores porque esse é o estado real do teclado. Pressionar uma tecla no teclado real, KeyState = Down, isDown = true e ScanCode tem um valor.
Dan Vogel
24
quando tentei o primeiro código de keydown, obtive erro no "target" não consigo convertê-lo para visual por quê?
kartal de
3
Dan, você sabe como emular o pressionamento de uma tecla com um modificador (ctrl / alt / shift)? Particularmente, preciso simular InputBinding: m_shell.InputBindings.Add (new KeyBinding (m_command, Key.Insert, ModifierKeys.Control | ModifierKeys.Alt));
Shrike de
14
Sobre o problema de destino , resolvi usando Keyboard.PrimaryDevice.ActiveSourcever stackoverflow.com/questions/10820990/…
OscarRyz
4
Essa resposta é muito boa, mas não pode ser usada para enviar uma tecla com um modificador, como observou @Shrike. (Ex Ctrl+C.)
ANeves
28

Para produzir eventos chave sem o contexto do Windows Forms, podemos usar o seguinte método,

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

o código de amostra é fornecido abaixo:

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

A lista de chaves virtuais é definida aqui .

Para obter a imagem completa, use o link abaixo, http://tksinghal.blogspot.in/2011/04/how-to-press-and-hold-keyboard-key.html

Rajesh
fonte
Adequado, se sua janela for para cima. Isso resolveu parcialmente minha situação, obrigado!
Sergey de
Além da resposta de Rajesh, se você quiser fazer isso na plataforma móvel, você deve importar "coredll.ddl"
user1123236
22

Eu não usei, mas SendKeys pode fazer o que você quiser.

Use SendKeys para enviar pressionamentos de tecla e combinações de pressionamento de tecla para o aplicativo ativo. Esta classe não pode ser instanciada. Para enviar um pressionamento de tecla a uma classe e continuar imediatamente com o fluxo do seu programa, use Enviar. Para aguardar qualquer processo iniciado pelo pressionamento de tecla, use SendWait.

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

A Microsoft tem mais alguns exemplos de uso aqui .

Michael Petrotta
fonte
3
Tentei usar SendKeys.Send e recebo esta InvalidOperationException: "SendKeys não pode ser executado dentro deste aplicativo porque o aplicativo não está manipulando mensagens do Windows. Altere o aplicativo para lidar com mensagens ou use o método SendKeys.SendWait." Usar SendKey.SendWait não tem efeito.
Dan Vogel
Certifique-se de não enviar o evento principal para você mesmo. Mude o foco para o processo adequado antes de enviar o evento. O segundo artigo vinculado tem alguma ajuda nisso.
Michael Petrotta
11

Facilmente! (porque outra pessoa já fez o trabalho para nós ...)

Depois de passar muito tempo tentando fazer isso com as respostas sugeridas, me deparei com este projeto codeplex do Windows Input Simulator que simplificou ao máximo a simulação de um pressionamento de tecla:

  1. A instalação do pacote pode ser feita a partir do gerenciador de pacotes NuGet ou do console do gerenciador de pacotes como:

    Install-Package InputSimulator

  2. Use estas 2 linhas de código:

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

E é isso!

-------EDITAR--------

A página do projeto no codeplex está sinalizada por algum motivo, este é o link para a galeria NuGet.

Ravid Goldenberg
fonte
Isso funciona muito bem, mas não consegui descobrir como fazê-lo funcionar com uma combinação de teclas,
user1234433222
Quando você diz combinação de teclas, quer dizer CTRL-C?
Ravid Goldenberg
sim, ou mesmo se você quiser que um aplicativo de console vá para tela inteira, por exemplo, Alt-Enter, sei que você pode usar F11 para entrar em tela inteira, mas seria bom ver se Alt-Enter funcionaria :)
user1234433222
1
Bem, você pode fazer isso, embora eu não tenha tentado, basta usar inputSimulator.Keyboard.ModifiedKeyStroke (VirtualKeyCode.CONTROL, VirtualKeyCode.VK_C);
Ravid Goldenberg de