1

只是尝试一些 WinAPI 的东西。我有一个 C# 控制台应用程序,用于SendInput模拟某个键盘键的 akeydownkeyup事件。但它不起作用,也许我在做一些愚蠢的事情,没有发送密钥,不确定我错过了什么 - (尝试发送“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
}

我究竟做错了什么?为什么没有发送密钥?

谢谢 :)

4

1 回答 1

2

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

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

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

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

您正在SendInput以笨拙的方式使用。该SendInput函数的存在使您可以将多个输入消息放入队列中,而不会被其他消息交错。SendInput该文档在讨论与现已弃用的keybd_event功能mouse_event有关时清楚地说明了这一点。SendInput传递一个长度为 2 的数组时调用一次。

于 2013-12-29T10:21:46.330 回答