如何正确使用 SendInput() 在 C# 中模拟鼠标输入

Posted

技术标签:

【中文标题】如何正确使用 SendInput() 在 C# 中模拟鼠标输入【英文标题】:How to use SendInput() properly to simulate mouse input in C# 【发布时间】:2020-11-07 18:30:51 【问题描述】:

我试图在 C# .NET 中使用 user32 dll 中的 SendInput() 模拟(全局)鼠标点击。 我已经尝试过使用 SendInput() 进行键盘输入,并且效果很好。但由于某些原因,它不适用于鼠标输入。

这是我的代码,

为简单起见,我没有给出 KEYBDINPUT 和 HARDWAREINPUT (struct) 的定义。因为 MOUSEINPUT 仅在此处相关。

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

    //main calling method
    public static void CLICK()
    
        INPUT []i = new INPUT[1];

        i[0].type = 0;
        i[0].U.mi.time = 0;
        i[0].U.mi.dwFlags = MOUSEEVENTF.LEFTDOWN | MOUSEEVENTF.ABSOLUTE;
        i[0].U.mi.dwExtraInfo = UIntPtr.Zero;
        i[0].U.mi.dx = 1;
        i[0].U.mi.dy = 1;

        SendInput(1, i, INPUT.Size);
    

    [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 MOUSEINPUT mi;
        [FieldOffset(0)]
        internal KEYBDINPUT ki;
        [FieldOffset(0)]
        internal HARDWAREINPUT hi;
    

    [StructLayout(LayoutKind.Sequential)]
    internal struct MOUSEINPUT
    
        internal long dx;
        internal long dy;
        internal int mouseData;
        internal MOUSEEVENTF dwFlags;
        internal uint time;
        internal UIntPtr dwExtraInfo;
    

    [Flags]
    internal enum MOUSEEVENTF : uint
    
        ABSOLUTE = 0x8000,
        HWHEEL = 0x01000,
        MOVE = 0x0001,
        MOVE_NOCOALESCE = 0x2000,
        LEFTDOWN = 0x0002,
        LEFTUP = 0x0004,
        RIGHTDOWN = 0x0008,
        RIGHTUP = 0x0010,
        MIDDLEDOWN = 0x0020,
        MIDDLEUP = 0x0040,
        VIRTUALDESK = 0x4000,
        WHEEL = 0x0800,
        XDOWN = 0x0080,
        XUP = 0x0100
    

另外,我为 x,y 尝试了不同的点。以及其他 dwFlags(例如 LEFTUP、MOVE..),但到目前为止没有任何效果。

【问题讨论】:

“到目前为止没有任何效果” 不是问题陈述。见How to Ask。 【参考方案1】:

对于internal long dx;dy,我有int 输入我的struct MOUSEINPUT

根据MOUSEINPUT documentationdxdyLONG

但是 C++ 中的 LONG“至少”是 32 位,而 C# 中的 long 是 64 位。因此它匹配 C#int。 (details)

[StructLayout(LayoutKind.Sequential)]
internal struct MOUSEINPUT

    internal int dx;
    internal int dy;
    internal int mouseData;
    internal MOUSEEVENTF dwFlags;
    internal uint time;
    internal UIntPtr dwExtraInfo;

【讨论】:

这有效,但您知道为什么 MOUSEINPUT.time / KEYBDINPUT.time 不起作用吗?根据documentation,MOUSEINPUT.time 用于事件的时间戳。我认为这是在处理每个输入之前的时间延迟。还是还有别的意思? @FahimMahbub 我没有测试过。我知道对于键盘,当我发送批量输入时它具有嵌入式延迟,例如通过单个 SendInput 调用修改了击键。也许这个延迟时间是相对的,并且仅当您在INPUT[] 数组中发送多个输入项时才有效。 @aepot 您不能使用time 字段来导致实际延迟。这不是它的本意。您需要在 SendInput 调用之间设置实际延迟 @RemyLebeau 感谢您的指正。这是一个猜测,我没有尝试。 When you synthesize input with SendInput, you are also synthesizing the timestamp.

以上是关于如何正确使用 SendInput() 在 C# 中模拟鼠标输入的主要内容,如果未能解决你的问题,请参考以下文章

如果打开任务管理器,来自 user32.dll 的 SendInput 函数将不起作用

INPUT / vector数组不适用于SendInput

如何在 AutoHotkey 中的 SendInput 命令之间添加延迟?

时间:2019-04-10 标签:c++win32SendInput()

我想通过 SendInput API 发送一些密钥

在 Node-FFI 中使用 SendInput