我在这个SendInput片段中做错了什么?

时间:2013-12-29 10:04:42

标签: c# pinvoke sendinput

尝试一些WinAPI的东西。我有一个C#控制台应用,它使用SendInput来模拟某些键盘键的keydownkeyup事件。虽然它不起作用,也许我正在做一些愚蠢的事情,关键是没有发送,不知道我错过了什么 - (试图发送一个“W”,睡5秒,打开一些文本编辑器看到神奇地在那里写信:)

static void Main(string[] args)
{

        INPUT input = new INPUT();
        input.type = (int)InputType.INPUT_KEYBOARD;
        input.U.ki.wScan = 0;
        input.U.ki.time = 0;
        input.U.ki.dwExtraInfo = UIntPtr.Zero;
        input.U.ki.wVk = VirtualKeyShort.KEY_W;

        System.Threading.Thread.Sleep(5000);

        input.U.ki.dwFlags = KEYEVENTF.KEYDOWN;
        NativeCalls.SendInput(1, new INPUT[] { input }, INPUT.Size);

        input.U.ki.dwFlags = KEYEVENTF.KEYUP;
        NativeCalls.SendInput(1, new INPUT[] { input }, INPUT.Size);

        return;
}

解释

public static class NativeCalls
{
    [DllImport("user32.dll")]
    public static extern uint SendInput(
    uint nInputs, [MarshalAs(UnmanagedType.LPArray), In] INPUT[] pInputs, int cbSize);
}

[StructLayout(LayoutKind.Sequential)]
public struct INPUT
{
    internal uint type;
    internal InputUnion U;
    internal static int Size
    {
        get { return Marshal.SizeOf(typeof(INPUT)); }
    }
}

[StructLayout(LayoutKind.Explicit)]
internal struct InputUnion
{
    [FieldOffset(0)]
    internal KEYBDINPUT ki;
}

[StructLayout(LayoutKind.Sequential)]
internal struct KEYBDINPUT
{
    internal VirtualKeyShort wVk;
    internal ScanCodeShort wScan;
    internal KEYEVENTF dwFlags;
    internal int time;
    internal UIntPtr dwExtraInfo;
}

[Flags]
internal enum KEYEVENTF : uint
{
    KEYDOWN = 0x0000,
    EXTENDEDKEY = 0x0001,
    KEYUP = 0x0002,
    SCANCODE = 0x0008,
    UNICODE = 0x0004
}

internal enum InputType { INPUT_MOUSE = 0, INPUT_KEYBOARD = 1, INPUT_HARDWARE = 2 }

internal enum VirtualKeyShort : short
{
    // keys
    KEY_W = 0x57,
    // more keys
}

我做错了什么?为什么关键不被发送?

谢谢:)

1 个答案:

答案 0 :(得分:2)

您的工会声明不完整。因此,Marshal.SizeOf(typeof(INPUT))返回的值不正确。您至少需要定义MOUSEINPUT联合的INPUT部分,因为它具有最大的大小。 pinvoke.net声明就足够了。

我希望SendInput在检查返回值时会告诉您问题。我希望SendInput返回false,然后调用GetLastError会产生ERROR_INVALID_PARAMETER。当然,您不应该直接致电GetLastError。使用SetLastError = trueMarshal.GetLastWin32Error()。您只需在调用Win32 API函数时执行准确的错误检查。

[DllImport("user32.dll", SetLastError=true)]
...

声明的这一部分在pinvoke.net上是错误的,他们省略了SetLastError

您正以笨拙的方式使用SendInput。存在SendInput函数,以便您可以在队列中放置多个输入消息,而不会让其他消息交错。在与现已弃用的SendInputkeybd_event函数相关的mouse_event讨论时,该文档明确了这一点。通过长度为2的数组后调用SendInput