《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.pswp.cn/diannao/37766.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/37766.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/37766.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

UE5藍圖快速實現打開網頁與加群

藍圖節點&#xff1a;啟動URL 直接將對應的網址輸入&#xff0c;并使用即可快速打開對應的網頁&#xff0c;qq、discord等群聊的加入也可以直接通過該節點來完成。 使用后會直接打開瀏覽器。

第11章 規劃過程組(收集需求)

第11章 規劃過程組&#xff08;一&#xff09;11.3收集需求&#xff0c;在第三版教材第377~378頁&#xff1b; 文字圖片音頻方式 第一個知識點&#xff1a;主要輸出 1、需求跟蹤矩陣 內容 業務需要、機會、目的和目標 項目目標 項目范圍和 WBS 可…

【強化學習】第01期:緒論

筆者近期上了國科大周曉飛老師《強化學習及其應用》課程&#xff0c;計劃整理一個強化學習系列筆記。筆記中所引用的內容部分出自周老師的課程PPT。筆記中如有不到之處&#xff0c;敬請批評指正。 文章目錄 1.1 概述1.2 Markov決策過程1.2.1 Markov Process (MP) 馬爾科夫過程1…

(五)SvelteKit教程:錯誤頁和重定向

&#xff08;五&#xff09;SvelteKit教程&#xff1a;錯誤頁和重定向 設置404頁面和重定向非常容易&#xff0c;我們還是在 /about 目錄下學習這個知識&#xff0c;文件結構如下&#xff1a; ├── layout.svelte ├── page.svelte ├── about │ └── [aboutID] │…

基于深度學習的人臉關鍵點檢測

1. 任務和目標 人臉關鍵點檢測的主要任務是識別并定位人臉圖像中的特定關鍵點&#xff0c;例如眼睛的角點、眉毛的頂點、鼻子的底端、嘴角等。這些關鍵點不僅能提供面部結構的幾何信息&#xff0c;還可以用于分析表情、識別個體&#xff0c;甚至檢測面部姿勢。 2. 技術和方法…

什么是數據類型,Python 有哪些基本數據類型?

一、什么是數據類型 數據類型是計算機語言中一個基本概念&#xff0c;它定義了變量可以存儲什么樣的數據以及可以對這些數據執行什么樣的操作。在Python中&#xff0c;數據類型決定了變量的存儲方式、內存占用、數據的合法操作和表示方式等。 數據類型的作用包括&#xff1a;…

計算機中的16g加32g不對稱雙通道性能分析

計算機中的16g加32g不對稱雙通道性能分析 16GB加32GB不對稱雙通道配置會對性能產生一定影響&#xff0c;但仍然在穩定兼容的范圍內。 在探討16GB加32GB不對稱雙通道配置的性能影響時&#xff0c;我們首先需要理解雙通道技術的基本原理。雙通道技術通過同時向兩根內存中讀寫數…

數據結構速成--排序算法

由于是速成專題&#xff0c;因此內容不會十分全面&#xff0c;只會涵蓋考試重點&#xff0c;各學校課程要求不同 &#xff0c;大家可以按照考綱復習&#xff0c;不全面的內容&#xff0c;可以看一下小編主頁數據結構初階的內容&#xff0c;找到對應專題詳細學習一下。 這一章…

C語言中常用的運算符、表達式和語句

C語言是一種通用的、高級的編程語言&#xff0c;其歷史可以追溯到20世紀60年代末至70年代初。C語言最初是由丹尼斯里奇&#xff08;Dennis Ritchie&#xff09;在貝爾實驗室為開發UNIX操作系統而設計的。它繼承了許多B語言的特性&#xff0c;而B語言則是由迷糊老師&#xff08;…

安全與加密常識(0)安全與加密概述

文章目錄 一、信息安全的基本概念二、加密技術概述三、常見的安全協議和實踐四、加密的挑戰與應對 在數字時代&#xff0c;信息安全和加密已成為保護個人和企業數據不受侵犯的關鍵技術。本文將探討信息安全的基礎、加密的基本原理&#xff0c;以及實用的保護措施&#xff0c;以…

RAG一文讀懂!概念、場景、優勢、對比微調與項目代碼示例

本文結合“基于 ERNIE SDKLangChain 搭建個人知識庫”的代碼示例&#xff0c;為您講解 RAG 的相關概念。 01 概念 在2020年 Facebook AI Research(FAIR)團隊發表一篇名為《Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks》的論文。這篇論文首次提出了 RA…

Java應用cpu過高如何分析

1. 查看進程cpu使用情況 top 2. 根據PID查看指定進程的各線程的cpu使用情況 top -H -p PID 線程分析&#xff1a; jstack&#xff1a;生成Java線程堆棧&#xff0c;用于分析是否有線程處于忙等待狀態或死循環。命令&#xff1a; shell jstack -l <pid> > threaddu…

機器人控制系列教程之關節空間運動控制器搭建(1)

機器人位置控制類型 機器人位置控制分為兩種類型&#xff1a; 關節空間運動控制—在這種情況下&#xff0c;機器人的位置輸入被指定為一組關節角度或位置的向量&#xff0c;這被稱為機器人的關節配置&#xff0c;記作q。控制器跟蹤一個參考配置&#xff0c;記作 q r e f q_{re…

免費翻譯API及使用指南——百度、騰訊

目錄 一、百度翻譯API 二、騰訊翻譯API 一、百度翻譯API 百度翻譯API接口免費翻譯額度&#xff1a;標準版&#xff08;5萬字符免費/每月&#xff09;、高級版&#xff08;100萬字符免費/每月-需個人認證&#xff0c;基本都能通過&#xff09;、尊享版&#xff08;200萬字符免…

學習陽明心學,需要下真功夫,持續用功

陽明心學是功夫之學&#xff0c;看到善的就發揚光大&#xff0c;看到惡的就立即改正&#xff0c;這才是真功夫

Java基礎(五)——ArrayList

個人簡介 &#x1f440;個人主頁&#xff1a; 前端雜貨鋪 ?開源項目&#xff1a; rich-vue3 &#xff08;基于 Vue3 TS Pinia Element Plus Spring全家桶 MySQL&#xff09; &#x1f64b;?♂?學習方向&#xff1a; 主攻前端方向&#xff0c;正逐漸往全干發展 &#x1…

激光SLAM平面點的提取、使用學習

1.20240625 學習了PaGO-LOAM 論文地址&#xff1a; PaGO-LOAM: Robust Ground-Optimized LiDAR Odometry github地址&#xff1a; GitHub - url-kaist/AlterGround-LeGO-LOAM: The page for PaGO-LOAM: Robust Ground-Optimized LiDAR Odometry 其提取地面點方法采用了Pat…

centos7 xtrabackup mysql 基本測試(5)mysql 建立 測試 數據庫及內容

centos7 xtrabackup mysql 基本測試&#xff08;5&#xff09;mysql 建立 測試 數據庫及內容 登錄 mysql -u etc -p 1234aA~1創建數據庫 名字是company show databases ; create database company;在 company里面 創建表employee use company; DROP TABLE IF EXISTS employ…

linux中的各種指令

按文件的大小進行查找 find / usr -size 100M 在home路徑下創建txt文件 touch test.txt 查看test.txt文件中的內容&#xff1a; cat test.txt通過指令pwd可以查看當前所處路徑。 切換超級用戶的指令&#xff1a; su - root 離開時可以使用指令&#xff1a;exit grep指…

SPSS相關軟件安裝

Amos安裝添加鏈接描述 SPSS process插件安裝添加鏈接描述