如何正确使用 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
documentationdx
和dy
是LONG
。
但是 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 函数将不起作用
如何在 AutoHotkey 中的 SendInput 命令之间添加延迟?