> 技术文档 > C#程序模拟发送控制键CTRL+鼠标CLICK消息

C#程序模拟发送控制键CTRL+鼠标CLICK消息

项目中需要C#程序给浏览器窗口发送CTRL+CLICK消息。网查了若干文章(包括AI写的):单个发送键盘消息(使用win32的SendInput或PostMessage和SendMessage)和鼠标消息(使用win32的PostMessage和SendMessage)均没有问题,但组合发送时多数未能成功。在参考了某篇发送控制键盘消息的文章中发现,键盘抬起消息虚拟键(VK_KEYUP)编码为0x0002,而不是许多网文(包括AI)中的0x0102。编程测试,0x0002是可行的,并且SendInput与PostMessage可以组合发送键盘与鼠标消息。如下是主要的C#代码。

代码1:TWin32类,PostMessage函数及鼠标消息码。

public class TWin32{[DllImport(\"user32.dll\")][return: MarshalAs(UnmanagedType.Bool)]public static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);public const uint WM_LBUTTONDOWN = 0x0201; // 左键按下消息public const uint WM_LBUTTONUP = 0x0202; // 左键释放消息}

代码2:TKeyInput类,SendInput函数及相关结构体和键盘虚拟码。

public class TKeyInput {[StructLayout(LayoutKind.Sequential)]public struct TInput {public int type;public TUnion union;}[StructLayout(LayoutKind.Explicit)]public struct TUnion {[FieldOffset(0)] public TMouse mi;[FieldOffset(0)] public TKeybd ki;[FieldOffset(0)] public THware hi;}[StructLayout(LayoutKind.Sequential)]public struct TMouse {public int dx;public int dy;public int mouseData;public int dwFlags;public int time;public IntPtr dwExtraInfo;}[StructLayout(LayoutKind.Sequential)]public struct TKeybd {public short wVk;public short wScan;public int dwFlags;public int time;public IntPtr dwExtraInfo;}[StructLayout(LayoutKind.Sequential)]public struct THware {public int uMsg;public short wParamL;public short wParamH;}[Flags]public enum TInputType {MOUSE = 0,KEYBOARD = 1,HARDWARE = 2}public const int VK_SHIFT = 0x0010; //虚拟键键常量public const int VK_CONTROL = 0x0011;public const int VK_KEYDOWN = 0x0100; //事件常量public const int VK_KEYUP = 0x0002; //0x0101;[DllImport(\"User32.dll\", EntryPoint = \"SendInput\")]public static extern uint SendInput(uint cInputs, TInput[] pInputs, int cbSize);public static uint DownKey(short key) {TInput[] inputs = new TInput[1];inputs[0] = GetKeyInput(key, VK_KEYDOWN);var result = SendInput((uint)inputs.Length, inputs, Marshal.SizeOf(typeof(TInput)));return result; // 0表示失败}public static uint UpKey(short key) {TInput[] inputs = new TInput[1];inputs[0] = GetKeyInput(key, VK_KEYUP);var result = SendInput((uint)inputs.Length, inputs, Marshal.SizeOf(typeof(TInput)));return result;}private static TInput GetKeyInput(short key, int option) {TInput input = new TInput {type = (int)TInputType.KEYBOARD,union = new TUnion {ki = new TKeybd {wVk = key,dwFlags = option,}}};return input;}}

代码3:发送Key+Mouse组合消息(CTRL+CLICK)的函数。

public void PostDownUpMouseWithCtrlMessage(IntPtr wHandle, int screenX, int screenY) {IntPtr lParam = new IntPtr(screenX + (screenY << 16));TKeyInput.DownKey(TKeyInput.VK_CONTROL);System.Threading.Thread.Sleep(50); // 延后一点点 TWin32.PostMessage(wHandle, TWin32.WM_LBUTTONDOWN, (new IntPtr(0)), lParam);System.Threading.Thread.Sleep(50); // 延后一点点 TWin32.PostMessage(wHandle, TWin32.WM_LBUTTONUP, (new IntPtr(0)), lParam);System.Threading.Thread.Sleep(50); // 延后一点点 TKeyInput.UpKey(TKeyInput.VK_CONTROL);}

其它说明:

  • SendInput发送的消息,将被前台Windows窗口捕获,PostMessage发送的则被指定wHandle句柄的窗口捕获(注意,不能是mini化的窗口),但鼠标消息事件参数的ctrlKey属性总是true(可以用网页程序测试),表明是CTRL+CLICK消息。
  • C#程序模拟的键盘和鼠标消息,其消息事件参数的isTrusted=true,表明消息是“手工”按键或点击鼠标产生的。而js模拟的键盘鼠标消息,其isTrusted=false,且无法更改。一些视频播放网站中,需要手工点击鼠标网页才能激活,ji模拟的鼠标或键盘消息无效。
  • PostMessage和SendInput发送消息的方式,均是将消息送入Windows的消息队列中,因此不能确保发送成功。还有一个Win32的SendMessage函数,发送的消息不是送入队列,因此不能与SendInput组合使用。
  • 技术资料表明,SendInput可以发送硬件设备消息,包括鼠标、键盘、触摸屏、触摸笔等,但笔者编程用SendInput发送鼠标CLICK消息没有成功,待以后完善。