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

发布于:2025-07-26 ⋅ 阅读:(17) ⋅ 点赞:(0)

项目中需要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消息没有成功,待以后完善。

网站公告

今日签到

点亮在社区的每一天
去签到