我试图在 Windows 7 环境中模拟用户点击和鼠标移动,特别是在 Mozilla Firefox 中。我从各种教程、论坛帖子和 MSDN 文档中共同提出的解决方案适用于 99% 的 Windows 应用程序,但不适用于 Firefox 8.0。
根据我的初步研究,在 Windows 中模拟键盘和鼠标输入的最准确(低级)方法是使用 User32.dll Windows 库中的SendInput 函数。为了测试这一点,我编写了一个简短的 C# 程序来循环并调用 SendInput,它每 5 秒创建一次编程鼠标单击,无论鼠标光标在屏幕上的哪个位置。
运行后,该程序几乎可以完美模拟我将焦点切换到的每个应用程序窗口的鼠标单击,甚至包括 Windows 界面本身(开始按钮、任务栏、Windows 资源管理器等),但是当我带上光标时不会发生编程鼠标单击进入 Mozilla Firefox 窗口。
为了更好地了解幕后发生的事情,我启动了 Microsoft Spy++ 并开始检查哪些消息实际上被传递到了 Firefox 窗口的消息队列。果然,Firefox 窗口不会收到任何消息,即使我的光标在它有焦点时会位于它的正上方。当我手动单击鼠标时,Firefox Spy++ 侦听器会发疯并显示我在观察其他应用程序对我的仿真程序的正确响应时看到的完整“nHittest:HTCLIENT wMouseMsg:WM_LBUTTONDOWN”。
谁能解释一下 Mozilla Firefox 是如何/为什么是唯一一个根本不从 SendInput 函数接收任何消息的应用程序之一,或许还有关于如何克服这个问题的建议?
源代码 (为清楚起见删除了导入/外部引用):
static void Main(string[] args)
{
for (; ; )
{
System.Threading.Thread.Sleep(5000);
INPUT[] inp = new INPUT[2];
inp[0].type = INPUT_MOUSE;
inp[0].mi = createMouseInput(0, 0, 0, 0, MOUSEEVENTF_LEFTDOWN);
inp[1].type = INPUT_MOUSE;
inp[1].mi = createMouseInput(0, 0, 0, 0, MOUSEEVENTF_LEFTUP);
SendInput((uint)inp.Length, inp, Marshal.SizeOf(inp[0].GetType()));
}
}
private static MOUSEINPUT createMouseInput(int x, int y, uint data, uint t, uint flag)
{
MOUSEINPUT mi = new MOUSEINPUT();
mi.dx = x;
mi.dy = y;
mi.mouseData = data;
mi.time = t;
mi.dwFlags = flag;
return mi;
}
[StructLayout(LayoutKind.Sequential)]
struct MOUSEINPUT
{
public int dx;
public int dy;
public uint mouseData;
public uint dwFlags;
public uint time;
public IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Explicit)]
private struct INPUT
{
[FieldOffset(0)]
public int type;
[FieldOffset(sizeof(int))] //[FieldOffset(8)] for x64
public MOUSEINPUT mi;
[FieldOffset(sizeof(int))] //[FieldOffset(8)] for x64
public KEYBDINPUT ki;
[FieldOffset(sizeof(int))] //[FieldOffset(8)] for x64
public HARDWAREINPUT hi;
}