Windows應用程式中幾種特殊滑鼠事件的識別

來源:互聯網
上載者:User
Windows應用程式中幾種特殊滑鼠事件的識別
  滑鼠作為電腦輸入裝置隨著Windows的流行而逐漸成為電腦的標準配置。在
Windows中滑鼠的操作可以產生二十多個訊息,主要分為客戶區滑鼠訊息和非客戶區
滑鼠訊息兩大類,包括滑鼠的移動,左中右鍵的按下、釋放、雙擊等。事實上,實
際的應用程式中往往會用到一些特殊的滑鼠事件,如滑鼠三擊、左右滑鼠同步選取
、按一下滑鼠雙擊三擊的獨立識別或依次處理等。下面結合筆者編程的體會來談一下
Windows中這幾種特殊的滑鼠事件的識別方法。

  一、獨立處理單擊、雙擊和三擊

  我們先看一下Windows對滑鼠的響應。對左鍵而言,如果滑鼠按下,則產生
WM_LBUTTONDOWN訊息。接著,滑鼠釋放產生WM_LBUTTONUP訊息;但如果滑鼠雙擊,
則Windows並不僅僅只產生WM_LBUTTONDBLCLK 訊息,而是先產生WM_LBUTTONDOWN消
息,然後產生WM_LBUTTONDBLCLK訊息,其中還有WM_LBUTTONUP等訊息,這裡暫不討
論。對於滑鼠的三擊,Windows沒有提供獨立的訊息,但我們不妨認為三擊是在
WM_LBUTTONDBLCLK訊息之後再發一個WM_LBUTTONDOWN訊息。所以,在應用程式編程
時若要視窗分別獨立地響應滑鼠的單擊、雙擊、三擊訊息,只有使用者自己動手去處
理。例如,Winows95中的檔案夾改名就是一個例子,用按一下滑鼠一個已經加亮的文
件夾名稱時稍作停留便可改名,如果雙擊則可開啟該檔案。這時,就必須單獨處理
滑鼠的單擊和雙擊,否則執行順序應該是先響應WM_LBUTTONDOWN訊息,然後再響應
WM_LBUTTONDBLCLK,即先改名再開啟,這是事與願違的。

  為了單獨識別這三個滑鼠訊息,我們不能直接使用WM_LBUTTONDOWN和
WM_LBUTTONDBLCLK訊息來判斷滑鼠的單擊和雙擊。這裡,定義三個“偽”訊息
WM_MYSNGCLK、WM_MYDBLCLK、WM_MYTHRCLK,用它們分別標識滑鼠的單擊、雙擊和三
擊事件。由於我們在兩次連續的按一下滑鼠後還不能確定是否有三擊,所以再增加一
個 WM_MYDBLCLKT偽訊息,在處理該偽訊息時再進一步判斷雙擊與三擊。我們只處理
WM_LBUTTONDOWN訊息,所以註冊視窗類別時不設定CS_DBLCLKS風格。

  具體處理過程如下:設定邏輯標誌FLAG1及FLAG2,初始值均為FALSE,當已經單
擊時將FLAG1置為TRUE,已經雙擊時將FLAG2置為TRUE。在處理WM_LBUTTONDOWN訊息
時通過函數 SetTimer增加一個計時器ID_TIMER1,計時器的時間參數置為滑鼠雙擊
的時間間隔(用GetDoubleClickTime取得),並將FLAG1置為TRUE。如果計時器
D_TIMER1發出訊息,則表明在規定時間內沒有按鍵,可以判斷滑鼠為單擊,可發出
WM_MYSNGCLK訊息,同時將FLAG1置為FALSE;如果計時器訊息沒有產生,則表明在規
定的時間內有滑鼠鍵按下,此時滑鼠已經雙擊,將FLAG2置為TRUE,但是否有三擊還
需要繼續判斷,此時發出WM_MYDBLCLKT訊息,我們用同樣的方法在偽訊息
WM_MYDBLCLKT中再定義一個計時器ID_TIMER2。同理,如果計時器ID_TIMER2發出消
息,則表明在規定時間內沒有按鍵,可以判斷滑鼠為雙擊,可發出WM_MYDBLCLK訊息
;如果計時器ID_TIMER2沒有發出訊息,則表明在規定的時間內有滑鼠鍵被按下,此
時滑鼠已經三擊,可以發出WM_MYTHRCLK訊息。至此已完成識別,當然計時器要使用
KillTimer及時刪除。另外要注意的是,滑鼠雙擊的時間間隔不要設定太大,否則延
時感太明顯。

  下面是具體的實現方法,本文只給出視窗過程WndProc的部分內容,其它函數與
通常的Windows應用程式大同小異,故從略。

  #define ID_TIMER1 1001 /* 計時器1*/

  #define ID_TIMER2 1002 /* 計時器2*/

  #define WM_MYDBLCLKT WM_USER+100 /*當已經雙擊但還不能決定三擊時發出*/

  #define WM_MYSNGCLK WM_USER+101 /*已經確定為單擊時發出*/

  #define WM_MYDBLCLK WM_USER+102 /*已經確定為雙擊時發出*/

  #define WM_MYTHRCLK WM_USER+103 /*已經確定為三擊時發出*/

  LRESULT CALLBACK WndProc(HWND hwnd,UINT uMessage,WPARAM wparam,LPARAM lparam)

  {

   static int FLAG1,FLAG2;

   int wTime;

   POINT pt;

   switch (uMessage)

   {

   case WM_LBUTTONDOWN: /*程式只對單擊訊息進行處理,不處理雙擊訊息*/

   GetCursorPos(&pt); /*取滑鼠位置用於傳遞訊息中的LPARAM*/

   ScreenToClient(hwnd,&pt);

   if(! FLAG2) /*FLAG2不為真時,滑鼠狀態為第一次單擊或第二次單擊*/

   {if(!FLAG1) /*FLAG1不為真時為第一次單擊*/

   { wTime=GetDoubleClickTime(); /*取滑鼠雙擊時間間隔*/

   SetTimer(hwnd,ID_TIMER1,wTime,NULL); /*第一次單擊後建立計時器*/

   }

   if(FLAG1) /*FLAG1為真,已經確定為雙擊,發出WM_MYDBLCLKT繼續判斷*/

   {PostMessage(hwnd,WM_MYDBLCLKT,0,MAKELPARAM(pt.x,pt.y));

   FLAG1=FALSE;

   KillTimer(hwnd,ID_TIMER1);

   break;

   }

   FLAG1=TRUE;

   }

   if(FLAG2) /*FLAG2為真,已經確定為三擊*/

   {PostMessage(hwnd,WM_MYTHRCLK,0,MAKELPARAM(pt.x,pt.y));

   FLAG2=FALSE;

   KillTimer(hwnd,ID_TIMER2);

   break;

   }

   break;

   case WM_TIMER: /*計時器訊息產生,說明滑鼠沒有按鍵動作*/

   switch(wparam)

   {

   case ID_TIMER1: /*第一次按鍵後沒有後續按鍵,故確定為單擊*/

   { KillTimer(hwnd,wparam);

   FLAG1=FALSE;

   GetCursorPos(&pt);

   ScreenToClient(hwnd,&pt);

   PostMessage(hwnd,WM_MYSNGCLK,0,MAKELPARAM(pt.x,pt.y));

   }

   break;

   case ID_TIMER2: /*第二次按鍵後沒有後續按鍵,故確定為雙擊*/

   {KillTimer(hwnd,wparam);

   FLAG2=FALSE;

   GetCursorPos(&pt);

   ScreenToClient(hwnd,&pt);

   PostMessage(hwnd,WM_MYDBLCLK,0,MAKELPARAM(pt.x,pt.y));

   }

   break;

   }

   break;

   case WM_MOUSEMOVE: /*如果滑鼠移動,則不認為是雙擊或三擊*/

   FLAG1=FALSE;

   FLAG2=FALSE;

   break;

   case WM_MYDBLCLKT: /*雙擊後等待再次按滑鼠鍵*/

   wTime=GetDoubleClickTime();

   SetTimer(hwnd,ID_TIMER2,wTime,NULL);

   FLAG2=TRUE;

   break;

   case WM_MYSNGCLK: /*處理單擊*/ break;

   case WM_MYDBLCLK: /*處理雙擊*/ break;

   case WM_MYTHRCLK: /*處理三擊*/ break;

   //其它訊息

   }

  二、 依次處理單擊、雙擊和三擊

  滑鼠的單擊、雙擊、三擊處理還有一種情況。例如,Word及其它文書處理軟體中
用滑鼠選擇編輯地區的處理方法,單擊則定位插入點,雙擊則選中一個詞,三擊則
選中一個段落。這種處理滑鼠的方法是依次處理單擊、雙擊、三擊。下面要介紹的
這種滑鼠事件的處理方法與上述獨立識別方法的思路基本相同,不同之處在於註冊
視窗類別時風格設定為CS_DBLCLKS,以便視窗類別識別滑鼠雙擊。

  具體方法是:在處理滑鼠雙擊訊息處理時發出WM_MYDBLCLK訊息,同時設定計時
器,共置標誌FLAG為TRUE(初始值為FALSE),這樣在處理WM_LBUTTINDOWN時判斷
FLAG的值:若為FALSE則為單擊,發送WM_MYSNGCLK訊息;若為TRUE則為雙擊之後的
一次單擊(即三擊),發送WM_MYTHRCLK訊息,從而完成訊息的識別。計時器的作用
,只是等待雙擊之後是否出現單擊。如果計時器訊息已經發出則說明後面已經沒有
按鍵,這時可以刪除計時器,從單擊處重新進行識別。

  下面是視窗函數WndProc的部分內容,程式注釋部分說明了與上例的差別。

  #define ID_TIMER 1001

  #define WM_MYSNGCLK WM_USER+101

  #define WM_MYDBLCLK WM_USER+102

  #define WM_MYTHRCLK WM_USER+103

  LRESULT CALLBACK WndProc(HWND hwnd,UINT uMessage,WPARAM wparam,LPARAM lparam)

  {

   static int FLAG;

   int wTime;

   POINT pt;

   switch (uMessage)

   {

   case WM_LBUTTONDOWN:

   GetCursorPos(&pt);

   ScreenToClient(hwnd,&pt);

   if(FLAG){/*若為TRUE,則說明為雙擊之後的單擊(即三擊)*/

   PostMessage(hwnd,WM_MYTHRCLK,0,MAKELPARAM(pt.x,pt.y));

   FLAG=FALSE;

   KillTimer(hwnd,ID_TIMER);

   }

   else /*否則為單擊*/

   PostMessage(hwnd,WM_MYSNGCLK,0,MAKELPARAM(pt.x,pt.y));

   break;

   case WM_TIMER:

   switch(wparam)

   {

   case ID_TIMER:

   {KillTimer(hwnd,wparam); /*計時器產生時,簡單刪除*/

   FLAG=FALSE;

   }

   break;

   }

   break;

   case WM_LBUTTONDBLCLK:

   GetCursorPos(&pt);

   ScreenToClient(hwnd,&pt);

   wTime=GetDoubleClickTime();

   SetTimer(hwnd,ID_TIMER,wTime,NULL); /*設定計時器*/

   PostMessage(hwnd,WM_MYDBLCLK,0,MAKELPARAM(pt.x,pt.y));

   FLAG=TRUE;

   break;

   case WM_MOUSEMOVE:/*滑鼠移動,則從單擊重新開始判斷*/

   FLAG=FALSE;

   break;

   case WM_MYSNGCLK: /*處理單擊*/ break;

   case WM_MYDBLCLK: /*處理雙擊*/ break;

   case WM_MYTHRCLK: /*處理三擊*/ break;

   //其它訊息

  }

  三、滑鼠左右鍵同步選取與滑鼠與鍵盤同步選取的識別

  玩過Windows的掃雷遊戲嗎?該遊戲中就有一個同步選取滑鼠左右鍵的操作,其
實對同步選取滑鼠左右鍵的判斷並不複雜,判斷方法與判斷滑鼠按鍵是否與Ctrl和
Shift同步選取的方法相同,這裡要用到滑鼠訊息中的wparam項,其中含有我們想要
的幾個按鍵的狀態。定義如下:

  (1)MK_CONTROL:Ctrl鍵按下時置1;

  (2)MK_LBUTTON:滑鼠左鍵按下時置1;

  (3)MK_MBUTTON:滑鼠中鍵按下時置1;

  (4)MK_RBUTTON:滑鼠右鍵按下時置1;

  (5)MK_SHIFT:Shift鍵按下時置1。

  通過判斷這幾個標誌位可以得到同步選取的幾個鍵的狀態,從而判斷是否有其
它鍵同步選取。

  滑鼠訊息是Windows中經常要處理的內容,以上方法是筆者在編程過程中的一些
體會,實現方法僅供參考。上述程式在Borland C++ 5.0中通過。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.