`
hu_jiacheng
  • 浏览: 29813 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
博客专栏
Dfa6e97f-cd26-3ff8-984a-cafab311103b
Windows编程通俗演义...
浏览量:22465
文章分类
社区版块
存档分类
最新评论

Windows编程 第十回 鼠标的秘密

 
阅读更多

你平时使用的鼠标中藏着一个鲜为人知秘密,它与鼠标名字的起源有关,这回我就给大家揭开这个秘密。请看图:

哈哈,纯粹娱乐一下。不过这回我们确实要探一探鼠标在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值就是负值。


分享到:
评论

相关推荐

    Windows核心编程(第五版)源码

    《Windows核心编程(第五版)源码》是深入学习Windows操作系统编程的重要参考资料,结合Windows via C/C++ 5th edition这本书,提供了丰富的实践代码。这个压缩包中的源代码是作者精心设计的,旨在帮助读者理解并掌握...

    Windows编程新手乐园 CHM

    第十七章 第十五天课程——Windows 9x 控制导论 第十八章 第十六天课程——对话框和映像方式 第十九章 第十七天课程——高级对话:设置数据和获取数据 第二十章 第十八天课程——Windows 9x 对话和控制 第二十一...

    windows编程 推箱子游戏

    《Windows编程:推箱子游戏开发详解》 在计算机科学领域,Windows编程是一项基础且重要的技能,它涉及到系统级的交互和应用开发。本教程将通过一个经典的“推箱子”游戏来深入探讨Windows编程的原理与实践。推箱子...

    windows编程教学大纲

    **Windows编程教学大纲** Windows编程课程是针对计算机科学与技术专业的本科学生开设的专业选修课,旨在教授学生如何使用API开发Windows应用程序。课程的核心是让学生掌握Visual C++的开发环境,理解Windows程序...

    Windows API 编程_pdf_windowsAPI编程_

    **Windows API 编程详解** Windows API(Application Programming Interface)是微软为开发者提供的一套用于构建Windows应用程序的接口。它包含了大量的函数、常量、结构体、消息等元素,允许程序员控制操作系统,...

    Keylog_日志logkey_Windows编程_Windows键盘鼠标窗口事件记录器_visualc++_源码.zip

    标题中的“Keylog_日志logkey_Windows编程_Windows键盘鼠标窗口事件记录器_visualc++_源码”表明这是一个关于Windows平台上的键盘鼠标事件记录器的程序开发项目,使用了Visual C++作为编程语言。这个项目的重点在于...

    windows_编程技术

    10. **07界面编程5-鼠标、键盘与光标(windows_编程技术).doc**:这部分内容可能详细解释了如何处理鼠标和键盘事件,以及如何自定义和使用光标。了解这些能帮助开发者创建更响应用户输入的应用程序。 以上各部分都是...

    C++,Windows编程

    标题 "C++,Windows编程" 涉及到的是利用C++这一强大编程语言进行Windows平台下的应用程序开发。C++是一种通用、面向对象的编程语言,以其高效性、灵活性和广泛的库支持而闻名。Windows编程则涉及到如何利用Windows ...

    VB编程源代码 93鼠标取词

    VB编程源代码 93鼠标取词VB编程源代码 93鼠标取词VB编程源代码 93鼠标取词VB编程源代码 93鼠标取词VB编程源代码 93鼠标取词VB编程源代码 93鼠标取词VB编程源代码 93鼠标取词VB编程源代码 93鼠标取词VB编程源代码 93...

    Windows 网络编程1

    在IT行业中,网络编程是构建分布式系统和网络应用程序的基础,特别是在Windows操作系统环境下。"Windows网络编程1"可能涉及的是对Windows API的深入理解和应用,尤其是关于网络通信的部分。本篇文章将探讨Windows...

    windows编程80个案例

    7. **事件处理**:Windows编程中的事件包括鼠标和键盘事件,以及其他用户交互。通过重载窗口过程函数,可以处理这些事件,如`WM_COMMAND`, `WM_LBUTTONDOWN`, `WM_KEYDOWN`等。 8. **MFC(Microsoft Foundation ...

    白话windows编程.rar

    《白话Windows编程》是一本面向初学者和中级程序员的指南,旨在用通俗易懂的语言讲解Windows操作系统下的程序开发技术,主要关注C++语言在Windows平台的应用。这本书深入浅出地介绍了如何使用C++进行Windows API编程...

    windows编程中文版CHM

    《Windows编程中文版CHM》是一本专门为C++编程初学者和希望深入学习Windows编程的开发者准备的资源。CHM(Compiled Help Manual)文件是一种由微软开发的帮助文档格式,它将多个HTML页面、图像和其他资源合并成一个...

    windows forms编程实战

    windows forms 编程实战,扫描版。 windows forms 编程实战,扫描版。

    Windows-via-C-Code-January-29-2008_Windows编程_windows核心编程_

    《Windows 核心编程》是一本深入探讨Windows操作系统编程的权威书籍,涵盖了Windows API、系统调用、进程、线程、内存管理、I/O操作等多个关键领域的内容。这本书的源代码集合提供了丰富的实例,帮助读者理解和实践...

    Windows编程技术(修)

    在深入探讨"Windows编程技术(修)"这一主题之前,我们先来理解一下这个主题的背景。这本书显然是针对已经掌握了C++基础知识的读者,旨在通过使用VC++.net编译器和Windows XP操作系统,教授如何利用C++语言进行...

    windows 编程课件windows 编程课件

    3. **窗口类与窗口创建**:窗口类定义了窗口的行为和外观,而窗口创建是Windows编程的第一步。学习如何注册窗口类并使用CreateWindow函数创建窗口是基础。 4. **GDI(图形设备接口)**:GDI是Windows提供的一套绘图...

    深入windows编程

    《深入Windows编程》一书是面向那些希望通过VC++进行Windows应用程序开发的程序员们的重要参考资料。本书旨在帮助读者深入了解Windows操作系统的工作原理,同时提供VC++环境下编写高效、稳定的Windows程序的技巧和...

    Windows系统编程(原书第4版)

    《Windows系统编程(原书第4版)》作为学习编程的优质资料,深入探讨了Windows操作系统的核心编程技术,为读者提供了全面且深入的Windows编程知识体系。本书通过详实的案例、清晰的理论阐述和实践指导,帮助读者掌握...

Global site tag (gtag.js) - Google Analytics