【问题标题】:simulating key press event using SendInput with C#使用带有 C# 的 SendInput 模拟按键事件
【发布时间】:2012-05-09 15:44:14
【问题描述】:

听从这个帖子的建议:distinguish between keyboard's Real and Virtual key presses

我正在尝试创建一个程序,它将使用 SendInput() 方法发送键盘的按键事件。

但是,问题是当我尝试模拟按键事件时 - 什么都没有发生。到目前为止,这是我的代码:

    [DllImport("user32.dll")]
    static extern UInt32 SendInput(UInt32 nInputs, [MarshalAs(UnmanagedType.LPArray, SizeConst = 1)] INPUT[] pInputs, Int32 cbSize);

    [StructLayout(LayoutKind.Sequential)]
    struct KEYBDINPUT
    {
        public short wScan; public int dwFlags;
        public int time; public IntPtr dwExtraInfo;
    }

    [StructLayout(LayoutKind.Explicit)]
    struct INPUT
    {
        [FieldOffset(0)] public int type;
        [FieldOffset(8)]  public KEYBDINPUT ki; //x64 - 8, x32 - 4
    }

    const int KEYEVENTF_DOWN = 0; //key UP
    const int KEYEVENTF_EXTENDEDKEY = 0x0001;
    const int KEYEVENTF_KEYUP = 0x0002; //key UP
    const int KEYEVENTF_UNICODE = 0x0004;
    const int KEYEVENTF_SCANCODE = 0x0008; // scancode

    public void Send_Key(short Keycode)
    {
        INPUT[] InputData = new INPUT[1];
        InputData[0].type = 1;
        InputData[0].ki.wScan = Keycode;
        InputData[0].ki.dwFlags = KEYEVENTF_KEYUP | KEYEVENTF_SCANCODE;
        InputData[0].ki.time = 0;
        InputData[0].ki.dwExtraInfo = IntPtr.Zero;
        SendInput(1, InputData, Marshal.SizeOf(typeof(INPUT)));
    }

为了破译扫描码,我下载了这个线程中建议的程序:

https://superuser.com/questions/293609/windows-7-tool-to-capture-keyboard-scan-codes

根据这个程序 - 我键盘的“a”键代码是“65”

我的程序应该在文本框文本改变时触发按键事件,所以如果我们输入“q” - 文本应该变为“q”加上send_key()的结果,即“qa”:

    private void textBox2_TextChanged(object sender, EventArgs e)
    {
        Send_Key(0x0065); // nothing happens (0x65 also fails)
    }

我做错了什么?将来我将更改此代码,以便我可以指定按键保持时间(在 DOWN 和 UP 事件之间)。但目前,出于测试目的,我只模拟 keyUP 事件。

编辑:汉斯,根据你的建议,这里是编辑 - 但很遗憾,它不起作用。

 public void Send_Key(short Keycode)
        {
            INPUT[] InputData = new INPUT[1];
            InputData[0].type = 1;
            InputData[0].ki.wScan = Keycode;
            InputData[0].ki.dwFlags = KEYEVENTF_DOWN;
            InputData[0].ki.time = 0;
            InputData[0].ki.dwExtraInfo = IntPtr.Zero;

            uint intReturn = SendInput(1, InputData, Marshal.SizeOf(typeof(INPUT)));

            if (intReturn == 0) //!=1
            {
                throw new Exception("Could not send keyDOWN: " + Keycode);
            }

            INPUT[] InputData2 = new INPUT[1];
            InputData2[0].type = 1;
            InputData2[0].ki.wScan = Keycode;
            InputData2[0].mi.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP | KEYEVENTF_SCANCODE;
            InputData2[0].ki.time = 0;
            InputData2[0].ki.dwExtraInfo = IntPtr.Zero;

            uint intReturn2 = SendInput(1, InputData2, Marshal.SizeOf(typeof(INPUT)));

            if (intReturn2 == 0) //!=1
            {
                throw new Exception("Could not send keyUP: " + Keycode);
            }
        }

没有错误..没有输出。

【问题讨论】:

  • edit2:在尝试打印一封信失败后,当我关闭我的程序时 - 我无法在 Google Chrome 中更改 TABS !!!多次检查这件事-我的程序是原因!奇怪..
  • 我不是 100%,但我不认为你可以像 TextChanged 那样直接“附加” - 我认为你必须为此生成一个线程 - 仍然可能不是全部。无论如何,为什么将其用于“您自己的应用程序”?你用的是win-forms?...
  • 是的,这确实是 winforms。通过完全更改代码(在某个论坛上找到)并从此页面选择正确的扫描代码解决了我的问题:msdn.microsoft.com/en-us/library/aa299374(v=vs.60).aspx 例如要打印“a”,我必须输入“30”或“0x1E”..跨度>

标签: c# simulation keyboard-events sendinput


【解决方案1】:

但现在,出于测试目的,我只模拟 keyUP 事件

我想这没关系,但这不会让 Windows 做任何事情。要生成击键,您必须首先发送 KEYDOWN。 “保持时间”没有任何有用的效果,因此只需将两个 SendInput 调用放在同一个方法中即可。

您应该添加错误检查,winapi 调用不会产生任何异常。如果函数返回 0,则抛出 Win32Exception。并使用 SetLastError = true 修复 [DllImport] 声明。

您可以通过设置 ki.wVk 字段并省略 KEYEVENTF_SCANCODE 标志来避免使用您在 superuser.com 上找到的程序。这样您就可以指定虚拟键而不是扫描码。 .NET Keys enumeration type 为您提供所需的值。像 Keys.A 一样为 A 键生成按键。

【讨论】:

  • 查看编辑:keydown 事件 - 添加,保持时间 - 跳过,SetLastError - 添加,异常 - 添加。关于 ScanCodes - 如果可能的话,我想坚持使用它们..
  • 你没有理由使用虚拟键。使用 Keys 枚举更简单。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-20
  • 2011-02-04
  • 1970-01-01
  • 1970-01-01
  • 2022-11-10
  • 2017-12-13
相关资源
最近更新 更多