《Windows API每日一练》6.2 客户区鼠标消息

第五章已经讲到,Windows只会把键盘消息发送到当前具有输入焦点的窗口。鼠标消息则不同:当鼠标经过窗口或在窗口内被单击,则即使该窗口是非活动窗口或不带输入焦点, 窗口过程还是会收到鼠标消息。Windows定义了 21种鼠标消息。不过,其中11种消息与 客户区无关,称为“非客户区消息”。Windows应用程序经常忽略这类消息。

本节必须掌握的知识点:

        客户区鼠标消息

        第35练:客户区鼠标消息的处理

6.2.1 客户区鼠标消息

客户区鼠标消息

当鼠标移经窗口客户区时,窗口过程接收WM_MOUSEMOVE消息。在窗口客户区内按下或释放鼠标按钮时,窗口过程接收如下表所示的消息:

按钮

按下

释放

第二次按下按钮

左键

WM_LBUTTONDOWN

WM_LBUTTONUP

WM_LBUTTONDBLCLK

中键

WM_MBUTTONDOWN

WM_MBUTTONUP

WM_MBUTTONDBLCLK

右键

WM_RBUTTONDOWN

WM_RBUTTONUP

WM_RBUTTONDBLCLK

窗口过程只对三键鼠标接收MBUTTON消息,只对双键鼠标接收RBUTTON消息。而只有当窗口类被定义成接收鼠标双击时,窗口过程才接收DBLCLK(双击)消息。

对所有这些消息来说,参数IParam包含了鼠标的位置信息,其中低位字表示x坐标, 高位字表示y坐标,它们都是相对于窗口客户区左上角的相对坐标。利用LOWORD宏和 HIWORD宏,可以获取这些坐标值:

X = LOWORD (IParam);

y = HIWORD (IParam);

参数wParam表示鼠标按钮、Shift键和Ctrl键的状态。可以利用WINUSER.H头文件中定义的位掩码来测试参数wParam。前缀MK代表“鼠标键”(mouse key)。

MK_LBUTTON       按下左键

MK_MBUTTON      按下中键

MK_RBUTTON       按下右键

MK_SHIFT             按下 Shift 键

MK_CONTROL      按下 Ctrl 键

例如,当接收到WM_LBUTTONDOWN消息时,若wparam & MK_SHIFT 的值为TRUE(非零),则表示按下鼠标左键的同时按下了 Shift键。

●处理Shift键

处理过程依赖ShiftCtrl键的逻辑处理

单键鼠标模拟双键鼠标

if (wParam & MK_SHIFT)  //按下Shift

{

    if (wParam & MK_CONTROL)

    {

        [按下Shift + Ctrl];

     }

    else{

        [只按下Shift];

    }

}else{                  //未按Shift

    if (wParam & MK_CONTROL)

    {

        [只按下Ctrl];

    }else{

        [ShiftCtrl都没被按下];

    }

}

case WM_LBUTTONDOWN:

//未按Shift时,直接处理左键

    if (!(wParam & MK_SHIFT))

    {

        [这里处理左键];

        return 0;

     }   //注意,这里没有return

    //用户按下了鼠标左键+Shift,执行以下代码,模拟右键。

case WM_RBUTTONDOWN: 

    [这里处理右键];

    return 0;

【注意】双键鼠标也是可以正常处理的。单键鼠标可以通过按住鼠标左键+Shift,来模拟鼠标右键的功能。

【注意】GetKeyState可以通过VK_LBUTTON、VK_RBUTTON、VK_SHIFT、VK_CONTROL等获取鼠标当前状态。但鼠标或键盘未被按下的键不能使用GetKeyState。只有被按下时才会报告其按下状态。(while(GetKeyState(VK_LBUTTON)>=0))是错误的代码。

●鼠标移经窗口的客户区时,Windows系统不会为鼠标经过的每个像素位置都产生 WM_MOUSEMOVE消息。程序收到的WM_MOUSEMOVE消息个数取决于鼠标硬件和窗口过程处理鼠标移动消息的速度。换言之,如果消息队列里还有未处理的 WM_MOUSEMOVE消息,Windows就不会重复向消息队列中添加该消息。试验下面这个 CONNECT程序,可以对WM_MOUSEMOVE消息的产生速度有一个全面的了解。

●若在非活动窗口的客户区内按下鼠标左键,Windows会将该窗口变为活动窗口,并向窗口过程发送WM_LBUTTONDOWN消息。当窗口过程接收到WM_LBUTTONDOWN消息时,程序就能够安全地保证该窗口是活动窗口。但是,在事先没有接收 WM_LBUTTONDOWN消息的情况下,窗口过程仍然可以接收WM_LBUTTONUP消息。 比如,当用户在其他窗口内按下鼠标,再移动到用户窗口,然后释此时就会发生这种情况。类似地,当移动鼠标到另一个窗口再释放时,前一个窗口过程在接收 WM_LBUTTONDOWN消息后,就接收不到相应的WM_LBUTTONUP消息。

前面这些规则有两个例外:

●即使鼠标位于窗口的客户区之外,窗口过程也有办法“捕获鼠标”,并且继续接收鼠标消息。本章会在后面讲述如何捕获鼠标。

●若正在显示一个系统模式消息框或系统模式对话框,则其他任何程序都不能接收鼠标消息。当系统模式消息框或对话框处于活动状态时,它们会阻止系统切换到另一个窗口。例如,关闭Windows时弹出的消息框就是一个系统模式消息框。

6.2.2 第35练:客户区鼠标消息的处理

/*---------------------------------------------------------------

035  WIN32 API 每日一练

     第35个例子CONNECT.C:客户区鼠标消息的处理

     SetPixel函数

     SetCursor函数

     ShowCursor函数

     WM_LBUTTONDOWNE消息

     WM_MOUSEMOVE消息

     WM_LBUTTONUP消息

(c) www.bcdaren.com, 2020

----------------------------------------------------------------*/

#include <windows.h>

#define MAXPOINTS 1000

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,

 PSTR szCmdLine, int iCmdShow)

{

     static TCHAR szAppName[] = TEXT("Connect");

    (略)

     return msg.wParam;

}

LRESULT CALLBACK WndProc ( HWND hwnd, UINT message, WPARAM wParam,LPARAM

lParam)

{

     static POINT pt[MAXPOINTS];//鼠标经过窗口区像素点坐标数组

     static int iCount;

     HDC hdc;

     int i,j;

     PAINTSTRUCT ps;

     switch (message)

     {

     /*测试:非客户区消息

     //用于通知应用程序在非客户区(Non-Client Area)

//接收到鼠标消息时进行的命中测试(Hit Test)。

     case WM_NCHITTEST:

         //直接返回位置信息,阻止系统向所有窗口客户区和非窗口客户区发送鼠标消息

         return (LRESULT)HTNOWHERE;

     //测试:按下ALT+F、Ctrl+C等系统消息

     case WM_SYSKEYDOWN:

        //直接返回,使所有系统键盘消息失效

         return 0;*/

     //按下鼠标左键消息

     case WM_LBUTTONDOWN:    

          iCount = 0;

          InvalidateRect(hwnd,NULL,TRUE);//重绘窗口---清除背景

          return 0;

     //鼠标移动消息

     case WM_MOUSEMOVE:  

          //按下鼠标左键并且iCount小于1000

          if (wParam & MK_LBUTTON && iCount < 1000)

          {

               //填充坐标数组

               pt[iCount].x = LOWORD(lParam);

               pt[iCount++].y = HIWORD(lParam);

               hdc = GetDC(hwnd);

               //设置像素点颜色,RGB(0)黑色

               SetPixel(hdc,LOWORD(lParam),HIWORD(lParam),0);

               ReleaseDC(hwnd,hdc);

          }

          return 0;

     //松开鼠标左键消息

     case WM_LBUTTONUP

          //重新绘制窗口---不清除背景,保留WM_MOUSEMOVE里画下的点。

          InvalidateRect(hwnd,NULL,FALSE);

          return 0;

     case WM_PAINT:

          hdc = BeginPaint(hwnd,&ps);

          SetCursor(LoadCursor(NULL,IDC_WAIT));//设置鼠标形状为等待状态

          ShowCursor(TRUE);//显示鼠标

          //像素点之间画线

          for (i = 0;i < iCount - 1;i++)

          {

               for (j = 0;j < iCount - 1;j++)

               {

                    MoveToEx(hdc,pt[i].x,pt[i].y,NULL);

                    LineTo(hdc,pt[j].x,pt[j].y);

               }

          }

          ShowCursor(FALSE);//隐藏鼠标

          SetCursor(LoadCursor(NULL,IDC_ARROW));//设置鼠标位图“箭头形状”

          EndPaint(hwnd,&ps);

          return 0;

     case WM_DESTROY:

          PostQuitMessage(0);

          return 0;

     }

     return DefWindowProc(hwnd, message, wParam, lParam);

}

/***************************************************************************

SetPixel函数:指定坐标到指定的颜色设置像素

COLORREF SetPixel(

  HDC      hdc,

  int      x,  //坐标

  int      y,

  COLORREF color    //RGB颜色

);

***************************************************************************

SetCursor函数:设置鼠标形状

HCURSOR SetCursor(

  HCURSOR hCursor   //IDC_ARROW,IDC_WAIT

);

ShowCursor函数:显示/隐藏鼠标

int ShowCursor(

  BOOL bShow   //TRUE显示,FALSE隐藏

);

***************************************************************************

WM_LBUTTONDOWNE消息:当光标在窗口的客户区域中时用户按下鼠标左键时发布。

如果未捕获鼠标,则消息将发布到光标下方的窗口。否则,该消息将发布到捕获鼠标的窗口中。

参数wParam:指示各种虚拟键是否按下。此参数可以是以下一个或多个值。

MK_CONTROL  0x0008  CTRL键按下。

MK_LBUTTON  0x0001  鼠标左键按下。

MK_MBUTTON  0x0010  鼠标中键按下。

MK_RBUTTON  0x0002  鼠标右键按下。

MK_SHIFT    0x0004  SHIFT键按下。

MK_XBUTTON1 0x0020  第一个X按钮按下。

MK_XBUTTON2 0x0040  第二个X按钮按下。

lParam

低位字指定光标的x坐标。坐标相对于客户区域的左上角。

高阶字指定光标的y坐标。坐标相对于客户区域的左上角。

返回值

如果应用程序处理此消息,则应返回零。

***************************************************************************

WM_MOUSEMOVE消息:光标移动时张贴到窗口。如果未捕获鼠标,则消息将发布到包含光标的窗口中。否则,该消息将发布到捕获鼠标的窗口中。

参数与WM_LBUTTONDOWNE消息相同

***************************************************************************

WM_LBUTTONUP消息:当光标在窗口的客户区域中时,用户释放鼠标左键时发布。

如果未捕获鼠标,则消息将发布到光标下方的窗口。否则,该消息将发布到捕获鼠标的窗口中。

参数与WM_LBUTTONDOWNE消息相同

*/

       运行结果:

图6-1 客户区鼠标消息

 

总结

●实例操作方法:

1.第一种——在客户区按下左键,略微移动,再松开左键。

2.第二种——在客户区按下左键,快速移动鼠标。

●己知的问题:在客户区外释放左键,Connnect不会连接这些点,因为没收到WM_LBUTTONUP消息。

●该程序较耗时,绘制时,鼠标变沙漏形,处理WM_PAINT完后回原来的状态。用SetCursor来切换鼠标。ShowCursor隐藏或显示鼠标指针。

●窗口过程:

1.实例CONNECT.C处理了三个鼠标消息。

WM_LBUTTONDOWNE消息:按下鼠标左键时,调用InvalidateRect函数清除背景,重绘窗口。

WM_MOUSEMOVE消息:移动鼠标时,采集不超过1000个鼠标移动坐标点,保存在pt数组中,然后使用SetPixel函数绘制坐标点(系统默认黑色画笔)。

WM_LBUTTONUP消息:松开鼠标左键时,重绘窗口,但是并不清除背景。

2.处理WM_PAINT消息时,CONNECT程序需要耗费一定的时间来绘制直线,因此鼠标指针会变成等待位图。调用SetCursor函数,加载并设置鼠标位图为等待位图,显示鼠标位图。接着使用双循环将所有坐标点连接起来。然后再恢复原鼠标位图。

3.在用户释放左键时,如果鼠标指针已经移出客户区,CONNECT程序就不会连接这些点, 因为程序没有接收到WM_LBUTTONUP消息。此时如果再将鼠标移入客户区,并按下左键,CONNECT程序就会清空客户区。如果想在客户区外释放鼠标,并继续设计图形,就可以在客户区外按下鼠标的左键,再将鼠标移入客户区。

4.动手实验:处理WM_NCHITTEST消息时可以直接返回鼠标位置信息,阻止系统向所有窗口客户区和非窗口客户区发送鼠标消息。

处理WM_SYSKEYDOWN消息时,可以让所有系统键盘消息失效。

下一节我们讲述如何在非窗口客户区捕捉鼠标消息。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/361031.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

当前的网安行业绝对不是高薪行业

昨天&#xff0c;面试了一个刚毕业两年的同学小A。第一学历为某大专&#xff0c;第二学历为某省地区的本科院校。面试过程表现一般偏下&#xff0c;但动不动就要薪资15K 这个人&#xff0c;我当场就PASS了。主要原因是&#xff0c;并非是否定小A同学的能力&#xff0c;而是他…

QT中的样式表.qss文件

一、前言 qt中样式表的改变有几种方法&#xff0c;第一种就是直接在ui界面对应的组件右键修改样式表&#xff0c;还有一种就是直接在程序里面修改样式表&#xff0c;我知道的还有一种就是qss文件&#xff0c;这个文件就是将在程序中写的修改样式表的语句写道qss文件中&#xff…

windows git配置多个账号

window下git多账号配置_百度搜索 (baidu.com) 最重要的是这里生成新的id_rsa文件的时候&#xff0c;bash窗口是在 .ssh路径下 其实就是这个窗口在什么路径下执行的就是生成在什么路径 下面窗口路径不对&#xff0c;不是Desktop&#xff0c;应该是.ssh 如果是Desktop或者任何一…

无芯封装基板适用于先进封装技术 我国行业发展面临一定挑战

无芯封装基板适用于先进封装技术 我国行业发展面临一定挑战 无芯封装基板指去除作为核心支撑层的芯板&#xff0c;仅由积层板构成的封装基板。与传统带有芯层的封装基板相比&#xff0c;无芯封装基板具有轻量化、密度高、信号传输质量高、散热性能好、布线灵活性好等优势&#…

聊聊 oracle varchar2 字段的gbk/utf8编码格式和字段长度问题

聊聊 oracle varchar2 字段的gbk/utf8编码格式和字段长度问题 1 问题现象 最近在排查某客户现场的数据同步作业报错问题时&#xff0c;发现了部分 ORACLE 表的 varchar2 字段&#xff0c;因为上游 ORACLE数据库采用 GBK 编码格式&#xff0c;而下游 ORACLE 数据库采用UTF8 编…

吉时利 Keithley2460 图形数字源表

Keithley2460吉时利图形SMU数字源表 2460 型图形化高电流 SourceMeter SMU 2460 高电流 SourceMeter 源测量单元 (SMU) 仪器凭借其 7A 直流电流和脉冲电流能力&#xff0c;优化用于检定和测试大功率材料、器件和模块&#xff0c;例如碳化硅 (SiC)、氮化镓 (GaN)、DC-DC 转换器…

基于STM32+华为云IOT设计的智能冰箱(华为云IOT)

文章目录 一、前言1.1 项目介绍【1】项目开发背景【2】设计实现的功能【3】项目硬件模块组成【4】摘要 1.2 设计思路1.3 系统功能总结1.4 开发工具的选择【1】设备端开发【2】上位机开发 二、部署华为云物联网平台2.1 物联网平台介绍2.2 开通物联网服务2.3 创建产品&#xff08…

Animate如何将图层内容转换为元件

不管是Flash还是现在的Animate软件&#xff0c;都没有直接将整个图层转换为元件的功能&#xff0c;虽然现在的Animate软件有高级图层的选项&#xff0c;但是也有一定的使用限制。 所以如果是想将某个图层或者多个图层转换为元件效果&#xff0c;可以尝试使用剪切帧和粘贴帧两个…

Vue - HTML基础学习

一、元素及属性 1.元素 <p>我是一级标题</p>2.嵌套元素 把元素放到其他元素之中——这被称作嵌套。 <p>我是<strong>一级</strong>标题</p>3.块级元素 块级元素在页面中以块的形式展现&#xff0c;会换行&#xff0c;可嵌套内联元素。 …

gMLP(NeurIPS 2021)原理与代码解析

paper&#xff1a;Pay Attention to MLPs third-party implementation&#xff1a;https://github.com/huggingface/pytorch-image-models/blob/main/timm/models/mlp_mixer.py 方法介绍 gMLP和MLP-Mixer以及ResMLP都是基于MLP的网络结构&#xff0c;非常简单&#xff0c;关…

CesiumJS加载天地图数据后,可以实现什么效果?

说起地图&#xff0c;大家耳熟能详的百度地图、高德地图、腾讯地图等&#xff0c;由于授权的原因&#xff0c;使用起来心惊胆战的&#xff0c;而天地图就没有这方面的困扰&#xff0c;本文介绍下如何在cesium中时候用天地图数据&#xff0c;已经能够实现哪些交互效果。 一、关…

C# 任务调度 c# TaskScheduler

摘要 在C#中&#xff0c;TaskScheduler是一种非常有用的功能&#xff0c;它允许您在指定的时间或间隔内执行任务。TaskScheduler是一个抽象类&#xff0c;它提供了一个通用的方法来计划和执行任务。您可以使用TaskScheduler来调度多个任务&#xff0c;并且在多线程环境中控制它…

创建github个人博客

文章目录 安装Hexo安装git安装Node.js安装 Hexo git配置SSH key配置ssh 搭建个人博客新建博客生成静态网页 本文主要参考 【保姆级】利用Github搭建自己的个人博客&#xff0c;看完就会 安装Hexo 参考官方文档&#xff1a;https://hexo.io/zh-cn/docs/ Hexo 是一个快速、简洁且…

【STM32】USART串口通讯

1.USART简介 STM32芯片具有多个USART外设用于串口通讯&#xff0c;它是 Universal Synchronous Asynchronous Receiver and Transmitter的缩写&#xff0c; 即通用同步异步收发器可以灵活地与外部设备进行全双工数据交换。有别于USART&#xff0c; 它还有具有UART外设(Univers…

6.18 多态

多态相较于继承是更加重要的体现面向对象的特征。 多态&#xff1a; 同一个消息、同一种调用&#xff0c;在不同的场合&#xff0c;不同的情况下&#xff0c;执行不同的行为 。 背景需求&#xff1a;继承是实现可以在圆柱或者圆锥中复用圆的特征&#xff0c;多态是可以通过一…

东南亚本地化游戏

通常&#xff0c;亚洲电子游戏市场首先与中国联系在一起。但最近&#xff0c;分析人士越来越关注一个邻近地区&#xff1a;东南亚。而且有充分的理由。 该地区包括中南半岛、马来群岛和邻近岛屿上的十一个国家。1967年&#xff0c;其中10个国家&#xff08;除东帝汶外&#xf…

反射及动态代理

反射 定义&#xff1a; 反射允许对封装类的字段&#xff0c;方法和构造 函数的信息进行编程访问 图来自黑马程序员 获取class对象的三种方式&#xff1a; 1&#xff09;Class.forName("全类名") 2&#xff09;类名.class 3) 对象.getClass() 图来自黑马程序员 pac…

2024广东省职业技能大赛云计算赛项实战——构建CICD

构建CI/CD 前言 题目如下&#xff1a; 构建CI/CD 编写流水线脚本.gitlab-ci.yml触发自动构建&#xff0c;具体要求如下&#xff1a; &#xff08;1&#xff09;基于镜像maven:3.6-jdk-8构建项目的drone分支&#xff1b; &#xff08;2&#xff09;构建镜像的名称&#xff1a…

Qt | 子类化 QStyle(Qt自带图标大全)

01、简介 1、把绘制自定义部件外观的步骤大致分为三大板块,如下: ①、样式元素:即指定需要绘制的图形元素(比如焦点框、按钮,工具栏等)。样式元素使 用 QStyle 类中的一系列枚举(共有 11 个枚举)进行描述。 ②、样式选项:包含了需要绘制的图形元素的所有信息,比如包含…

DDR3控制器(一)DDR3 IP调用

目录 一、DDR3 IP核简介 二、DDR3 IP核调用 在千兆以太网通信中用到了DDR3控制器&#xff0c;但是并没有对其做相关介绍。这次准备重新整理一下DDR3控制相关知识&#xff0c;复习巩固一下。 一、DDR3 IP核简介 MIG IP核&#xff08;Memory Interface Generator&#xff09;是…