如何在C#中以编程方式生成按键事件?


107

如何以编程方式创建一个事件,该事件将模拟键盘上的按下键?


6
您只需要触发事件吗?
丹尼尔·怀特

我认为您必须进入非托管代码才能模拟“真实”按键。
乔纳斯·B

是的,我只需要触发该事件即可。
丹·沃格尔

1
@GONeale:哇,三岁了。那好吧。是的,对此有有效的用途,这就是API首先存在的原因。但是它们之间很少。以我的经验,很多人这样做是因为他们并不真正了解解决问题的最佳方法,即“我想在我的按钮单击事件处理程序中调用代码,而不仅仅是在单击按钮时调用”。因此,对于初学者而言,模拟按钮单击似乎是合乎逻辑的,而当他们真正应该做的是获取该代码,将其放入函数中并从代码中的其他位置调用时。
Ed S.

6
@EdS:问题很明确。我本可以为创建键盘添加很多多余的细节,但仍然得到相同的答案。考虑到我确实得到了所需的东西,对我来说这似乎不是一个“质量较差”的问题。
Dan Vogel

Answers:


147

该问题被标记为WPF,但到目前为止的答案是特定的WinForms和Win32。

要在WPF中执行此操作,只需构造一个KeyEventArgs并在目标上调用RaiseEvent。例如,要将Insert key KeyDown事件发送到当前关注的元素:

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

该解决方案不依赖于本地调用或Windows内部,应该比其他解决方案更可靠。它还允许您模拟特定元素上的按键。

请注意,此代码仅适用于PreviewKeyDown,KeyDown,PreviewKeyUp和KeyUp事件。如果要发送TextInput事件,则可以这样做:

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

另请注意:

  • 控件希望接收预览事件,例如PreviewKeyDown应该在KeyDown之前

  • 使用target.RaiseEvent(...)将事件直接发送到目标,而无需诸如加速器,文本合成和IME之类的元处理。这通常是您想要的。另一方面,如果出于某种原因确实执行了模拟实际键盘键的操作,则应改用InputManager.ProcessInput()。


1
我只是尝试了您的建议,没有效果。我已经将keyDown事件处理程序附加到了focused元素上。收到我提出的事件,但KeyState为None,ScanCode为0,isDown为false。我假设我正在获取这些值,因为这是键盘的实际状态。在实际键盘上击中一个键,KeyState = Down,isDown = true,并且ScanCode有一个值。
Dan Vogel,

25
当我尝试keydown的第一个代码时,我在“目标”中遇到错误,无法将其转换为视觉原因吗?
kartal

3
丹,您知道如何模仿带有修饰符(Ctrl / Alt / Shift)的按键吗?我特别需要模拟InputBinding:m_shell.InputBindings.Add(new KeyBinding(m_command,Key.Insert,ModifierKeys.Control | ModifierKeys.Alt));
伯劳鸟

14
关于目标的问题,我的工作了用Keyboard.PrimaryDevice.ActiveSourcestackoverflow.com/questions/10820990/...
OscarRyz

4
这个答案非常好,但是不能用作发送带有修饰符的键,如@Shrike所指出的。(例如Ctrl+C
ANeves,2015年

27

要在没有Windows Forms Context的情况下产生关键事件,我们可以使用以下方法,

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

示例代码如下:

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

虚拟键列表在此处定义。

要获取完整图片,请使用以下链接, http://tksinghal.blogspot.in/2011/04/how-to-press-and-hold-keyboard-key.html


如果您的窗口位于顶部,则合适。它部分解决了我的情况,谢谢!
谢尔盖

Rajesh答案的补充,如果要在移动平台上执行此操作,则必须导入“ coredll.ddl”
user1123236 2013年

21

我没有用过,但是SendKeys可以做您想要的。

使用SendKeys将击键和击键组合发送到活动应用程序。此类无法实例化。要将按键发送给班级并立即继续执行程序流程,请使用“发送”。要等待按键启动的任何进程,请使用SendWait。

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

Microsoft 在此处提供了更多用法示例。


3
我尝试使用SendKeys.Send并得到此InvalidOperationException:“ SendKeys无法在此应用程序内运行,因为该应用程序未处理Windows消息。要么更改应用程序以处理消息,要么使用SendKeys.SendWait方法。” 使用SendKey.SendWait无效。
Dan Vogel,

确保您没有将关键事件发送给自己。发送事件之前,将焦点切换到适当的过程。第二篇链接文章对此有所帮助。
2009年

11

容易!(因为其他人已经为我们完成了工作...)

在花了很多时间尝试使用建议的答案后,我遇到了这个Codeplex项目Windows Input Simulator,它使模拟按键非常简单:

  1. 可以通过NuGet程序包管理器或程序包管理器控制台安装程序包,例如:

    安装包InputSimulator

  2. 使用以下两行代码:

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

就是这样!

- - - -编辑 - - - -

由于某种原因,codeplex上的项目页面被标记,是指向NuGet画廊的链接。


效果很好,但是我一直无法找到如何通过按键组合来实现此功能的方法
user1234433222

当您说组合键时,您是说像CTRL-C一样?
拉维德·戈登伯格

是的,即使您希望控制台应用程序进入全屏模式(例如Alt-Enter),我也知道您可以使用F11进入全屏模式,但是很高兴看到Alt-Enter是否可以工作:)
user1234433222

1
好吧,尽管我还没有尝试过,但是您可以这样做,只需要使用inputSimulator.Keyboard.ModifiedKeyStroke(VirtualKeyCode.CONTROL,VirtualKeyCode.VK_C);
拉维德·戈登伯格

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.