Qt中模拟鼠标消息并与系统鼠标消息进行区分

功能使用场景:

开发一个教学系统,包含了教师端、学生端,并且教师端支持示教功能。此时,学生端的鼠标、键盘不响应系统事件,但需要响应教师端发过来的鼠标移动、按下消息。

因为共享页面相同,为了提高局域网实时效率,采用UDP通讯方式,使用共享鼠标的方式最快(目前我没有找到比这个更快的了,如果有,小伙伴可以评论区告诉我哟,我也学习下)

在实现功能时,主要实现方式:使用钩子函数,处理系统发送的鼠标以及键盘消息。

那么禁用掉教师端的鼠标键盘消息后,如何在教师端响应按下消息时,也让学生端响应呢?

此时,就需要模拟鼠标按下消息,并且需要区分哪些消息是模拟的,哪些是PC机自己发送的。这是本文的重点!

模拟鼠标左键消息

项目中采用了WIN32的方式,可以应用到Qt框架中(我觉得比Qt的MouseEvent方式更简单)

cpp 复制代码
int nPointX = 100;
int nPointY = 100;
mouse_event(MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_LEFTDOWN, nPointX, nPointY, 0, 200);
mouse_event(MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_LEFTUP, nPointX, nPointY, 0, 200);

注意:大家有没有发现使用mouse_event的最后一个参数,不是0而是一个具体的值,那么,在这里这个值有什么用呢?

回答:"200"这个值就是用来区分系统的鼠标消息与自定义消息的。当使用钩子函数禁用鼠标左键消息时,只需要屏蔽由鼠标发送的消息,而不需要屏蔽模拟鼠标消息,这样保证了在示教过程中任何点击事件都是由教师端控制的。

钩子函数应用

1:禁用键盘消息

cpp 复制代码
HHOOK hook_hwnd_mouse = NULL;
HMODULE g_moduleMouse;

LRESULT CALLBACK KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
	KBDLLHOOKSTRUCT* pkbhs = (KBDLLHOOKSTRUCT*)lParam;
	if (nCode == HC_ACTION)
	{
		if (wParam == WM_KEYDOWN || wParam == WM_KEYUP)
		{
			//qDebug() << QStringLiteral("当前是键盘消息!");
			return TRUE;
		}
	}
	return CallNextHookEx(NULL, nCode, wParam, lParam);
}

在开启教师端示教功能时,开启对钩子函数的应用,关闭时解除钩子函数

cpp 复制代码
//开启钩子函数
hook_hwnd_key = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookProc, g_moduleKeyboard, 0);
//取消钩子函数
UnhookWindowsHookEx(hook_hwnd_key);

使用这种方式可以禁用所有的键盘消息。

2:禁用鼠标移动消息

cpp 复制代码
HHOOK hook_hwnd_mouse = NULL;
HMODULE g_moduleMouse;

//鼠标事件
LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
	if (nCode == HC_ACTION)
	{
		switch (wParam)
		{
		case WM_MOUSEWHEEL: // 忽略鼠标滚轮输入,禁用滑动
		case WM_MOUSEMOVE:
			return TRUE; // 拦截消息,不再传递
		}
	}
	return CallNextHookEx(NULL, nCode, wParam, lParam);
}

控制钩子函数的开启与释放,代码如下:

cpp 复制代码
//开启钩子函数
hook_hwnd_mouse = SetWindowsHookEx(WH_MOUSE_LL, MouseHookProc, g_moduleMouse, 0);
//关闭钩子函数
UnhookWindowsHookEx(hook_hwnd_mouse);

3:禁用特定鼠标左键消息

在第二个功能的基础上,钩子函数需要捕获鼠标左键按下、弹起的消息

cpp 复制代码
//鼠标事件
LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
	if (nCode == HC_ACTION)
	{
		switch (wParam)
		{
		case WM_MOUSEWHEEL: // 忽略鼠标滚轮输入,禁用滑动
		case WM_MOUSEMOVE:
			return TRUE; // 拦截消息,不再传递
		case WM_LBUTTONDOWN:
		case WM_LBUTTONUP:
		{
			MOUSEHOOKSTRUCT* pMouseHookStruct = reinterpret_cast<MOUSEHOOKSTRUCT*>(lParam);
			if (dwExtraInfo == 0)
			{
				return TRUE; //屏蔽鼠标的消息
			}
		}
		break;
		}
	}
	return CallNextHookEx(NULL, nCode, wParam, lParam);
}

注:dwExtraInfo由鼠标按下传过来的参数值是0,mouse_event模拟的消息中,dwExtraInfo是200。由此,就能区分出需要屏幕哪些按键消息了。

好了,到这里就结束啦,代码简单,难的是查询函数功能,希望对小伙伴们有用哟!

我是糯诺诺米团,一名C++程序媛~

相关推荐
hold?fish:palm8 分钟前
7 接雨水
开发语言·c++·leetcode
郝学胜-神的一滴1 小时前
中级OpenGL教程 022:探秘三维世界的血脉传承——物体父子关系与矩阵递归奥义
c++·线性代数·unity·矩阵·游戏引擎·unreal engine·opengl
ch0sen1pm2 小时前
刚学完 CAS 原子操作,我花了一晚上写了三个无锁队列
c++
qeen872 小时前
【C++】vector的模拟实现详解(二)
c++·学习·算法·迭代器·stl
熬夜苦读学习2 小时前
QT_信号和槽
开发语言·qt
j7~2 小时前
【C++】C++ 继承全解析:从基本语法到菱形继承的底层原理
开发语言·c++·继承·组合·虚继承·#暑假·七月创作之星博客挑战赛
数行拙笔2 小时前
C++客户端---String类型
开发语言·c++·bootstrap
草莓熊Lotso3 小时前
【Linux网络】深入理解Linux IO多路复用:从本质到select服务器实战
linux·运维·服务器·c语言·网络·数据库·c++
Quz3 小时前
QML 文字入场动画:逐字弹出、逐字飞入、3D 飞入
qt·3d·动画·qml
selfsongs14 小时前
指针、内存管理、现代 C++ 特性
c++