C# - 触发关键事件以进行主动控制

时间:2017-04-07 18:49:09

标签: c#

我发现命令System.Windows.Forms.SendKeys.Send()用于向按键发送密钥。如果打开外部应用程序,如记事本并设置焦点,此功能可以工作,我将看到我的密钥打印在此文本字段中。例如,如果使用按键事件System.Windows.Forms.SendKeys.SendDown("A");,该怎么做呢?

我尝试在Timer中调用此命令System.Windows.Forms.SendKeys.Send(),但运行时错误与非常快速的录音有关。

1 个答案:

答案 0 :(得分:3)

不幸的是,您无法使用SendKeys类。您需要转到较低级别的API。

使用keydown消息调用窗口

在Windows中,键盘事件通过Windows消息泵发送到窗口和控件。使用PostMessage的一段代码可以解决这个问题:

[DllImport("user32.dll")]
static extern bool PostMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);

const uint WM_KEYDOWN = 0x0100;

void SendKeyDownToProcess(string processName, System.Windows.Forms.Keys key)
{
    Process p = Process.GetProcessesByName(processName).FirstOrDefault();
    if (p != null)
    {
        PostMessage(p.MainWindowHandle, WM_KEYDOWN, (int)key, 0);
    }
}

请注意,在收到相应的WM_KEYUP之前,接收这些事件的应用程序可能无法执行任何操作。您可以从here获取其他消息常量。

修改主窗口以外的控件

上面的代码会将一个keydown发送给" MainWindowHandle。"如果您需要将其发送到其他内容(例如主动控件),则需要使用PostMessage以外的句柄调用p.MainWindowHandle。问题是......你如何处理这个问题?

这实际上非常复杂......你需要暂时将你的线程附加到窗口的消息输入并戳它以找出句柄是什么。这仅在当前线程存在于Windows窗体应用程序中并且具有活动消息循环时才有效。

可以找到here的解释,以及此示例:

using System.Runtime.InteropServices;

public partial class FormMain : Form
{
    [DllImport("user32.dll")]
    static extern IntPtr GetForegroundWindow();

    [DllImport("user32.dll")]
    static extern IntPtr GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);

    [DllImport("user32.dll")]
    static extern IntPtr AttachThreadInput(IntPtr idAttach, 
                         IntPtr idAttachTo, bool fAttach);

    [DllImport("user32.dll")]
    static extern IntPtr GetFocus();

    public FormMain()
    {
        InitializeComponent();
    }

    private void timerUpdate_Tick(object sender, EventArgs e)
    {
        labelHandle.Text = "hWnd: " + 
                           FocusedControlInActiveWindow().ToString();
    }

    private IntPtr FocusedControlInActiveWindow()
    {
        IntPtr activeWindowHandle = GetForegroundWindow();

        IntPtr activeWindowThread = 
          GetWindowThreadProcessId(activeWindowHandle, IntPtr.Zero);
        IntPtr thisWindowThread = GetWindowThreadProcessId(this.Handle, IntPtr.Zero);

        AttachThreadInput(activeWindowThread, thisWindowThread, true);
        IntPtr focusedControlHandle = GetFocus();
        AttachThreadInput(activeWindowThread, thisWindowThread, false);

        return focusedControlHandle;
    }
}

好消息 - 如果SendKeys为你工作,那么你可能不需要做所有这些 - SendKeys也会向主窗口句柄发送消息。