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中通过。    
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值