首页 文章

使用带C#的SendInput模拟按键事件

提问于
浏览
3

遵循此主题的建议:distinguish between keyboard's Real and Virtual key presses

我'm trying to create a program, that will send keyboard'使用 SendInput() 方法进行按键事件 .

However, the problem is that when I try to simulate a key press event - nothing happens whatsoever. 到目前为止,这是我的代码:

[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事件 .

EDIT: 汉斯,根据你的建议,这里是编辑 - 但不幸的是,它不起作用 .

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

没有错误..也没有输出 .

1 回答

  • 2

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

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

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

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

相关问题