你平时使用的鼠标中藏着一个鲜为人知秘密,它与鼠标名字的起源有关,这回我就给大家揭开这个秘密。请看图:
哈哈,纯粹娱乐一下。不过这回我们确实要探一探鼠标在Windows编程中的秘密。
鼠标估计大家天天都在用,我觉得没有必要再给大家“扫盲”了,如果非要讲点什么的话,那我就提一下关于鼠标操作的常用术语:单击、双击和拖拽,相信大家都很清楚。还是同讲键盘一样,讲鼠标还是从与之相关的消息入手吧。
上一回我们了解到Windows只把键盘消息发送给拥有输入焦点的窗口。而鼠标消息与此不同:只要在某窗口按下鼠标,那么该窗口的窗口过程就会收到鼠标消息,而不管该窗口之前是否活动或者是否拥有输入焦点。
好了,大家了解了一下窗口对于键盘消息与鼠标消息接收的不同之后,我们就来学习一下关于鼠标的22个消息。(好像有点多哦……)
客户区鼠标消息
由上一回我们得知Windows只把键盘消息发送给拥有输入焦点的窗口,而鼠标消息与此不同:只要鼠标跨越窗口或者在某窗口下按下鼠标键,那么窗口过程就会收到鼠标消息,不管该窗口是否活动或者是否拥有输入焦点。
当在窗口的客户区中按下或者释放一个鼠标按键时,窗口过程会接收到下面这些消息:
键
|
按下
|
释放
|
按下(双键)
|
左
|
WM_LBUTTONDOWN
|
WM_LBUTTONUP
|
WM_LBUTTONDBLCLK
|
中
|
WM_MBUTTONDOWN
|
WM_MBUTTONUP
|
WM_MBUTTONDBLCLK
|
右
|
WM_RBUTTONDOWN
|
WM_RBUTTONUP
|
WM_RBUTTONDBLCLK
|
对于三键鼠标,窗口过程才会收到MBUTTON消息(当然现在这种鼠标很不常见了,常见的是两键一轮的鼠标,你会发现鼠标轮除了滚动还可以点击,点击鼠标轮就会产生三键鼠标点击中键的效果,同样会产生MBUTTON的消息)。
仅当定义的窗口类能接收DBLCLK(双击)消息之后,窗口过程才能接受这类消息。既然说到此我们就先来看一下关于鼠标双击的消息。鼠标双击是指在短时间内单击鼠标键两次。要确定为双击,这两次单击必须发生在其相互的物理位置十分接近的状况下,并且发生在指定的时间间隔内。你可以在“控制面板”中改变时间间隔。
一般窗口过程是接收不到双击键的鼠标消息的,如果希望窗口过程能够收到这种消息,那么在调用RegisterClass初始化窗口类结构时,必须在窗口风格中包含CS_DBLCLKS标识符:
wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
如果在窗口风格中未包含CS_DBLCLKS,而用户在短时间内双击了鼠标键,那么窗口过程会接收到下面这些消息:
WM_LBUTTONDOWN
WM_LBUTTONUP
WM_LBUTTONDOWN
WM_LBUTTONUP
如果你的窗口类别风格中包含了CS_DBLCLKS,那么双击鼠标键时窗口过程将收到如下消息:
WM_LBUTTONDOWN
WM_LBUTTONUP
WM_LBUTTONDBLCLK
WM_LBUTTONUP
WM_LBUTTONDBLCLK消息简单地替换了第二个WM_LBUTTONDOWN消息。
双击中的第一次单击操作完成单击的功能,第二次单击操作(WM_LBUTTONDBLCLK消息)则完成第一次按键以外的事情。看一个双击的“慢动作回放”:例如,看看“Windows 资源管理器”中是如何用鼠标来操作文件列表的。第一次单击操作将选中文件,“Windows资源管理器”用反白显示出被选择的文件。第二次单击操作则指示“Windows 资源管理器”打开该文件。
别怪我啰嗦,再举一个单击的例子吧。如果你在非活动窗口的客户区中按下鼠标左键,Windows将把活动窗口改为在其中按下鼠标按键的这个窗口,然后把WM_LBUTTONDOWN消息送到该窗口的窗口过程。当释放鼠标左键时,则Windows再把WM_LBUTTONUP消息送到该窗口的窗口过程。常规情况下,BUTTONUP与BUTTONDOWN消息会成对出现在一个窗口中,但也会有例外。如果鼠标按键在另一个窗口中被释放,则这个窗口的窗口过程只能接收到WM_LBUTTONDOWN消息,而没有相应的WM_LBUTTONUP消息。同理,另一个窗口的窗口过程在未接收到WM_LBUTTONDOWN消息的情况下却先接收到了WM_LBUTTONUP消息。当然这个例子有点“极端”,但确实存在这种情况。
我们再来认识一个鼠标消息WM_MOUSEMOVE。当鼠标移过窗口的客户区,窗口过程就会收到一系列此消息。当然在你把鼠标移过客户区时,Windows并不为鼠标经过的每个可能的像素位置都产生一条WM_MOUSEMOVE消息。你的程序接收到WM_MOUSEMOVE消息的次数依赖于鼠标硬件以及你的窗口过程处理鼠标移动消息的速度。
对于上面这10个消息来说,其lParam值均含有鼠标的位置:低位字为x坐标,高位字为y坐标,这两个坐标是相对于窗口客户区左上角的位置。您可以用LOWORD和HIWORD宏来提取这些值:
x = LOWORD (lParam) ;
y = HIWORD (lParam) ;
wParam的值指示鼠标按键以及Shift和Ctrl键的状态。你可以使用头文件WINUSER.H中定义的与运算来测试wParam。(如果忘了lParam和wParam,就去复习一下第四回中消息结构体的讲解)
MK_LBUTTON
|
按下左键
|
MK_MBUTTON
|
按下中键
|
MK_RBUTTON
|
按下右键
|
MK_SHIFT
|
按下Shift键
|
MK_CONTROL
|
按下Ctrl键
|
MK前缀代表“鼠标按键”。
例如,如果收到了WM_LBUTTONDOWN消息,而且值
wparam &MK_SHIFT
是TRUE(非0),你就知道当左键按下时也按下了Shift键。
再来看一个例子,如果在程序中一种功能的实现依赖于鼠标单击和Shift、Ctrl键的组合,可以使用如下方法:
if (wParam & MK_SHIFT)
{
if (wParam & MK_CONTROL)
{
//按下了Shift和Ctrl键
}
else
{
//只按下了Shift键
}
}
else
{
if (wParam & MK_CONTROL)
{
//只按下了Ctrl键
}
else
{
//Shift和Ctrl键均未按下
}
}
非客户区鼠标消息
在窗口的客户区内移动或按下鼠标按键时,将产生前面讲的10种消息。如果鼠标在窗口的客户区之外但还在窗口内,Windows就给窗口过程发送一条“非客户区”鼠标消息。窗口非客户区包括标题栏、菜单和窗口滚动条。
通常,我们不需要处理非客户区鼠标消息,而是将这些消息传给DefWindowProc,从而使Windows执行系统功能。就这方面来说,非客户区鼠标消息类似于系统键盘消息WM_SYSKEYDOWN、WM_SYSKEYUP和WM_SYSCHAR。
非客户区鼠标消息几乎完全与显示区域鼠标消息相对应。消息中含有字母“NC”以表示是非客户区消息。
如果鼠标在窗口的非客户区中移动,那么窗口过程会接收到WM_NCMOUSEMOVE消息。
鼠标按键会产生如下表所示的消息。
键
|
按下
|
释放
|
按下(双击)
|
左
|
WM_NCLBUTTONDOWN
|
WM_NCLBUTTONUP
|
WM_NCLBUTTONDBLCLK
|
中
|
WM_NCMBUTTONDOWN
|
WM_NCMBUTTONUP
|
WM_NCMBUTTONDBLCLK
|
右
|
WM_NCRBUTTONDOWN
|
WM_NCRBUTTONUP
|
WM_NCRBUTTONDBLCLK
|
对非客户区的10个鼠标消息,wParam和lParam参数与客户区的10个鼠标消息的wParam和lParam参数有一定的差别。
wParam参数指明移动或者按鼠标按键的非客户区位置。它设定为以HT开头的标识符之一(HT表示 “命中测试”)。
lParam参数的低位字为x坐标,高位字为y坐标,但是,它们都是屏幕坐标,而不是像客户区鼠标消息那样指的是客户区坐标。①
命中测试消息
这个消息是WM_NCHITTEST,它代表“非客户区命中测试”。从它的名字来看它应该在“非客户区鼠标消息”中讲才对呀,既然我把它单拿出来,自然是有道理的。它的作用比较“特殊”,而且要讲的内容比较多。
当光标移动或鼠标按下、释放时,Windows系统就会发送此消息,并且此消息优先于其它的客户区和非客户区鼠标消息。这里的“优先于”怎么讲?就是Windows用WM_NCHITTEST消息产生所有其它的鼠标消息,这种由消息引出其它消息的思想在Windows中是很普遍的。(想一想我们在第四回是不是曾经遇到过?)Windows用这个消息来做什么?
“HITTEST”就是“命中测试”的意思,WM_NCHITTEST消息用来获取鼠标当前命中的位置。WM_NCHITTEST的消息响应函数会根据鼠标当前的坐标来判断鼠标命中了窗口的哪个部位,消息响应函数的返回值指出了部位。再补充一点,此消息的lParam 参数含有鼠标位置的x和y屏幕坐标,wParam参数没有用。
为了便于理解,我先描述一下Windows对鼠标键按下的响应流程:
1. 确定鼠标键点击的是哪个窗口。Windows会用表记录当前屏幕上各个窗口的区域坐标,当鼠标驱动程序通知Windows鼠标键按下了,Windows根据鼠标的坐标确定它点击的是哪个窗口。
2. 确定鼠标键点击的是窗口的哪个部位。Windows会向鼠标键点击的窗口发送WM_NCHITTEST消息,来询问鼠标键点击的是窗口的哪个部位。窗口程序通常把这个消息传送给DefWindowProc默认处理,然后Windows用WM_NCHITTEST消息产生与鼠标位置相关的所有其它鼠标消息。具体地说,就是在处理WM_NCHITTEST消息时,从DefWindowProc返回的值将成为其它鼠标消息中的wParam参数。一般来说,WM_NCHITTEST消息是系统来处理的,我们用户一般不用去主动去处理它。
3. 根据鼠标键点击的部位给窗口发送相应的消息。例如:如果WM_NCHITTEST的消息响应函数的返回值是HTCLIENT,表示鼠标点击的是客户区,同时Windows将把屏幕坐标转换为客户区坐标并产生相应的客户区鼠标消息,在这里就是Windows向窗口发送WM_LBUTTONDOWN消息;如果WM_NCHITTEST的消息响应函数的返回值不是HTCLIENT(比如说是HTCAPTION),即鼠标点击的是非客户区,Windows就会向窗口发送wParam等于HTCAPTION的WM_NCLBUTTONDOWN消息。
其返回值有很多,现在简单列举一部分吧,仅供参考。
HTNOWHERE -不在窗口中
HTCLIENT - 客户区
HTCAPTION - 标题
HTSYSMENU - 系统菜单
HTMENU - 菜单
HTHSCROLL - 水平滚动条
HTVSCROLL - 垂直滚动条
HTMINBUTTON - 最小化按钮
HTMAXBUTTON - 最大化按钮
HTLEFT - 左边界
HTRIG - 右边界
HTTOP - 上边界
HTTOPLEFT - 左上角
HTTOPRIG - 右上角
HTBOTTOM - 下边界
HTBOTTOMLEFT - 左下角
HTBOTTOMRIG- 右下角
HTCLOSE- 关闭按钮
再来看个实际例子吧,方便大家理解一下上面的内容。
大家想一下我们如何来屏蔽鼠标键的操作,让其失效?我们上面讲过“Windows用WM_NCHITTEST消息产生所有其它的鼠标消息”,我们可以在窗口过程中加入以下语句:
case WM_NCHITTEST:
return (LRESULT)HTNOWHERE;//由于窗口过程返回值是LRESULT类型的,这里
//行了强制类型转换
我们把第二回的代码模板中“caseWM_CREATE”语段和“case WM_PAINT”语段(行59-68)删掉,加入上面的语段,运行一下。是不是发现鼠标对窗口(包括客户区和非客户区)所有的点击、拖动操作都失效了,因为我们截获了WM_NCHITTEST消息,返回HTNOWHERE ,“欺骗”操作系统这时鼠标“不在”窗口中的,虽然鼠标确实在窗口中。再来讲一个“欺骗”的例子吧。一般我们鼠标单击一个窗口标题栏的时才可拖动窗口移动,如果我们要想实现鼠标只要单击窗口任一个位置就可以拖动窗口的功能,这该怎么办呢?照葫芦画瓢即可:
case WM_NCHITTEST:
return (LRESULT)HTCAPTION;
这样只要你在窗口中任意位置单击鼠标,系统就会由WM_NCHITTEST消息引发wParam 值标志标题栏的WM_NCLBUTTONDOWN消息,这时当前窗口将处于 “拖拽状态”(Windows内部记录了每个窗口的状态信息)。由于标识了“拖拽状态”,则从此刻起到鼠标键放开之前,你的鼠标移动状况完全由Windows跟踪。它根据鼠标的移动,使得窗口作“同步”移动。
注意,这个过程中,窗口不会收到WM_NCMOUSEMOVE消息,因为窗口和鼠标是“同步”移动的,你的鼠标相对于窗口是静止的。
注:但问题同时也出现了, 我想在右击这个窗体客户区的时候弹出一个菜单,当我完成 WM_RBUTTONDOWN 这个消息的时候,发现窗体收不到这个消息, 将WM_NCHITTEST消息的实现去掉就可以了,看了一原因是:
因为你在WM_NCHITTEST中处理了鼠标消息,把它定位成HTCAPTION,也就是鼠标在标题栏上,而标题栏属于非客户区(NC);非客户区的事件消息都是以WM_NC开头的。也就是说,当你的WM_NCHITTEST返回HTCAPTION时,原来可以用WM_LBUTTONDOWN处理的消息,你只能用WM_NCLBUTTONDOWN来处理。
解决方法:同时处理WM_NCHITTEST和WM_NCRBUTTONDOWN,而不处理WM_RBUTTONDOWN。
最后一个鼠标消息
我们平时常用的鼠标轮来移动滚动条,当鼠标轮转动时就会产生WM_MOUSEWHEEL消息。关于这个消息我将在以后和滚动条一起讲。
①对屏幕坐标,显示器左上角的x和y的值为0。当往右移时x的值增加,往下移时y的值增加。
你可以用两个Windows函数将屏幕坐标转换为客户区坐标或者反之:
ScreenToClient (hwnd, &pt) ;
ClientToScreen (hwnd, &pt) ;
这里pt是POINT结构。这两个函数转换了保存在结构中的值,而且没有保留以前的值。注意,如果屏幕坐标点在窗口客户区的上面或者左边,客户区坐标x或y值就是负值。
分享到:
相关推荐
【PHP入门】 PHP(Hypertext Preprocessor)是一种广泛使用的开源服务器端脚本语言,尤其适用于Web开发,能够嵌入HTML中。本篇笔记基于韩顺平老师的讲解,全面覆盖了从基础到精通的PHP知识体系。 1. **HTML基础** HTML,即超文本标记语言,用于创建网页内容。它包括各种标签来定义网页结构,如`<html>`、`<head>`、`<body>`等。HTML与CSS结合使用,可以实现页面样式控制。HTML5作为最新版本,引入了更多增强功能,如离线存储、拖放功能和媒体元素等。运行HTML有两种方式:本地运行(直接通过浏览器打开文件)和远程访问(通过HTTP协议在服务器上运行)。 2. **动态网页技术** 动态网页能够根据用户输入或服务器状态变化实时更新内容。PHP作为动态网页开发的重要技术之一,具有跨平台、安全性高、效率好、成本低、易于学习和丰富的开源社区支持等优点。PHP可以连接多种数据库,如MySQL,并在PHP4、PHP5和PHP6(及后续版本)中逐。内容来源于网络分享,如有侵权请联系我删除。另外如果没有积分的同学需要下载,请私信我。
花生好坏缺陷识别数据集,7262张图片,支持yolov7格式的标注,识别准确率在95.7% 两种标签: Good,Bad 花生好坏缺陷识别数据集,7262张图片,支持yolo,coco json,pasical voc xml格式的标注,识别准确率在95.7% 详情查看地址:https://backend.blog.csdn.net/article/details/144983881
总务科(基建办)2024年工作总结.doc
该项目包含完整的前后端代码、数据库脚本和相关工具,简单部署即可运行。功能完善、界面美观、操作简单,具有很高的实际应用价值,非常适合作为Java毕业设计或Java课程设计使用。 所有项目均经过严格调试,确保可运行!下载后即可快速部署和使用。 1 适用场景: 毕业设计 期末大作业 课程设计 2 项目特点: 代码完整:详细代码注释,适合新手学习和使用 功能强大:涵盖常见的核心功能,满足大部分课程设计需求 部署简单:有基础的人,只需按照教程操作,轻松完成本地或服务器部署 高质量代码:经过严格测试,确保无错误,稳定运行 3 技术栈和工具 前端:HTML + Vue.js 后端框架:Spring Boot 开发环境:IntelliJ IDEA 数据库:MySQL(建议使用 5.7 版本,更稳定) 数据库可视化工具:Navicat 部署环境:Tomcat(推荐 7.x 或 8.x 版本),Maven
广东省高清卫星地图全图
本文聚焦智能聊天机器人于电商客服领域的应用,开篇点明研究背景,剖析电商发展促使客服需求暴增,传统客服乏力,智能机器人应运而生。接着详述电商客服发展脉络、现存痛点,如高峰拥堵、知识滞后、服务同质化等。核心技术涵盖自然语言处理、机器学习、知识图谱,系统采用微服务架构,各模块分工协作。开发流程包括精细调研、多元数据采集、模型选型调优等。创新应用体现于售前精准导购、沉浸式营销,售中订单跟踪、答疑,售后问题处理与回访。经量化指标与用户调研评估成效显著,虽有挑战,但未来借助新技术有望重塑电商服务生态,助力企业与消费者双赢。
该项目包含完整的前后端代码、数据库脚本和相关工具,简单部署即可运行。功能完善、界面美观、操作简单,具有很高的实际应用价值,非常适合作为Java毕业设计或Java课程设计使用。 所有项目均经过严格调试,确保可运行!下载后即可快速部署和使用。 1 适用场景: 毕业设计 期末大作业 课程设计 2 项目特点: 代码完整:详细代码注释,适合新手学习和使用 功能强大:涵盖常见的核心功能,满足大部分课程设计需求 部署简单:有基础的人,只需按照教程操作,轻松完成本地或服务器部署 高质量代码:经过严格测试,确保无错误,稳定运行 3 技术栈和工具 前端:HTML + Vue.js 后端框架:Spring Boot 开发环境:IntelliJ IDEA 数据库:MySQL(建议使用 5.7 版本,更稳定) 数据库可视化工具:Navicat 部署环境:Tomcat(推荐 7.x 或 8.x 版本),Maven
eap2025010741566905-1-1.pdf
双馈风机MATLAB simulink模型 多个模型打包发送
给小孩找的,看着还不错,分享出来~
该项目包含完整的前后端代码、数据库脚本和相关工具,简单部署即可运行。功能完善、界面美观、操作简单,具有很高的实际应用价值,非常适合作为Java毕业设计或Java课程设计使用。 所有项目均经过严格调试,确保可运行!下载后即可快速部署和使用。 1 适用场景: 毕业设计 期末大作业 课程设计 2 项目特点: 代码完整:详细代码注释,适合新手学习和使用 功能强大:涵盖常见的核心功能,满足大部分课程设计需求 部署简单:有基础的人,只需按照教程操作,轻松完成本地或服务器部署 高质量代码:经过严格测试,确保无错误,稳定运行 3 技术栈和工具 前端:HTML + Vue.js 后端框架:Spring Boot 开发环境:IntelliJ IDEA 数据库:MySQL(建议使用 5.7 版本,更稳定) 数据库可视化工具:Navicat 部署环境:Tomcat(推荐 7.x 或 8.x 版本),Maven
bcolz-1.2.1-cp38-cp38-win-amd64.whl.rar
内容概要:本文详尽阐述了自动驾驶技术中的域控制单元(DCU)及其重要性。首先介绍了ADAS(高级驾驶辅助系统)和AD(自动驾驶)的区别和发展现状。接着讨论了域控制单元作为高级ECU,在自动驾驶系统中扮演的重要角色,包括高性能计算、高效的数据处理能力和与其他子系统的紧密配合。文中详细解释了DCU的构成元素——收发器、SoC、MCU和电源管理等模块的工作原理和技术细节,同时也探讨了市场趋势和技术发展趋势,如高集成度、智能化、低功耗等方面。最后展望了DCU在未来域集中式EE架构下的广阔应用前景。 适用人群:从事汽车工程、自动驾驶技术和嵌入式软件开发的专业技术人员,以及对此领域感兴趣的科研工作者。 使用场景及目标:①帮助开发者深入了解自动驾驶系统组成尤其是DCU的设计理念和技术特征;②指导相关领域的研究者把握当前行业发展动态和技术前沿。 其他说明:本文不仅深入浅出地讲解了专业知识,而且引用了一些作者个人感悟的文字,增加了可读性和启发性。
内容概要:文章主要介绍了Java和Python这两种流行的编程语言之间的区别和联系。首先详细讲述了Java的基本特性,包括跨平台性、面向对象编程、类型安全、自动化内存管理和多线程支持等特点,并概述了其在企业级开发中的广泛应用。接着深入探讨了Python的特点,指出它的简明语法、灵活性以及丰富的生态体系,特别提到了其在数据分析、人工智能等前沿领域的优势。文中还比较了两者的应用场景和技术实现方式的不同之处。最后为初学者提出了基于个人职业发展目标来选择编程语言的建议。 适合人群:对编程有兴趣的学生、编程新手以及想要转换编程方向的技术人员。 使用场景及目标:有助于读者理解两种编程语言各自的优劣,便于在实际工作中或者个人兴趣发展中做出明智的选择。 其他说明:通过对比讲解,不仅展示了两种编程语言的共同点,还强调了它们各自独特的优势所在。这有助于加深读者对其本质特征的认识,从而更好地应对不同类型的编程任务和挑战。
Java 飞机订票系统实训报告,有数据库
easy-interceptor修改请求头和响应头.zip
Python身份证识别系统源码(精准度非常高).zip,个人大三大作业设计项目、经导师指导并认可通过的高分设计项目,评审分99分,代码完整确保可以运行,小白也可以亲自搞定,主要针对计算机相关专业的正在做毕设的学生和需要项目实战练习的学习者,也可作为课程设计、期末大作业。 Python身份证识别系统源码(精准度非常高).zipPython身份证识别系统源码(精准度非常高).zipPython身份证识别系统源码(精准度非常高).zipPython身份证识别系统源码(精准度非常高).zipPython身份证识别系统源码(精准度非常高).zipPython身份证识别系统源码(精准度非常高).zipPython身份证识别系统源码(精准度非常高).zipPython身份证识别系统源码(精准度非常高).zipPython身份证识别系统源码(精准度非常高).zipPython身份证识别系统源码(精准度非常高).zipPython身份证识别系统源码(精准度非常高).zipPython身份证识别系统源码(精准度非常高).zipPython身份证识别系统源码(精准度非常高).zipPython身份证识别系
Matlab领域上传的视频是由对应的完整代码运行得来的,完整代码皆可运行,亲测可用,适合小白; 1、从视频里可见完整代码的内容 主函数:main.m; 调用函数:其他m文件;无需运行 运行结果效果图; 2、代码运行版本 Matlab 2019b;若运行有误,根据提示修改;若不会,私信博主; 3、运行操作步骤 步骤一:将所有文件放到Matlab的当前文件夹中; 步骤二:双击打开main.m文件; 步骤三:点击运行,等程序运行完得到结果; 4、仿真咨询 如需其他服务,可私信博主; 4.1 博客或资源的完整代码提供 4.2 期刊或参考文献复现 4.3 Matlab程序定制 4.4 科研合作
功能:利用深度学习模型(LSTM 网络)对电商用户咨询文本进行意图分类,相比简单规则匹配,能处理更复杂、语义模糊的文本,精准识别用户需求。 技术要点:使用 TensorFlow 构建 LSTM 模型,包括文本预处理将文本数字化,Embedding 层将数字映射为向量,LSTM 层捕捉序列特征,Dense 层输出分类结果,通过训练优化模型参数,实现准确意图识别。
国产银河麒麟V10和统信系统(linux)没有root用户的解决办法。如何在没有root用户的情况下,开通和启用root用户