鼠标

判断鼠标是否连接:
fMouse = GetSystemMetrics(SM_MOUSEPRESENT) ;

连接时,fMouse 的值为 非0,否则为 0。

鼠标的按钮个数:

cButtons = GetSystemMetrics(SM_CMOUSEBUTTONS) ;

如果没安装鼠标,则 cButtons 为 0。

鼠标指针具有一个单像素精度的“热点”。(箭头的顶点即热点) 热点在显示设备上指示了一个精确的位置。

 

当鼠标移经窗口客户区时,窗口过程接收 WM_MOUSEMOVE 消息。

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

按钮 标识符 按下 释放 第二次按下按钮
左键 LBUTTON WM_LBUTTONDOWN WM_LBUTTONUP WM_LBUTTONDBLCLK
中键 MBUTTON WM_MBUTTONDOWN WM_MBUTTONUP WM_MBUTTONDBLCLK
右键 RBUTTON WM_RBUTTONDOWN WM_RBUTTONUP WM_RBUTTONDBLCLK

对所有这些消息来说,参数 lParam 包含了鼠标的位置信息,其中低位字表示 x 坐标,髙位字表示 y 坐标,

它们都是相对于窗口客户区左上角的相对坐标。利用 LOWORD 和 HIWORD 宏,可以获取这些坐标值:

x = LOWORD(lParam) ;

y = HIWORD(lParam) ;

参数 wParam 表示鼠标按钮,Shift 和 Ctrl 键的状态。前缀 MK 代表“鼠标键”。

状态码 按键行为
MK_LBUTTON 按下左键
MK_MBUTTON 按下中键
MK_RBUTTON 按下右键
MK_SHIFT 按下 Shift 键
MK_CONTROL 按下 Ctrl 键

例如,当接受到 WM_LBUTTONDOWN 消息时,若 wParam & MK_SHIFT 的值为 非0,则表示按下左键的同时按下了 Shift 键。

wParam & SHIFT 是使用位操作进行判断。

 

DEMO CODE:

#include <windows.h>
#include <windowsx.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") ;
     HWND         hwnd ;
     MSG          msg ;
     WNDCLASS     wndclass ;
     
     wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
     wndclass.lpfnWndProc   = WndProc ;
     wndclass.cbClsExtra    = 0 ;
     wndclass.cbWndExtra    = 0 ;
     wndclass.hInstance     = hInstance ;
     wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
     wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
     wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
     wndclass.lpszMenuName  = NULL ;
     wndclass.lpszClassName = szAppName ;
     
     if (!RegisterClass (&wndclass))
     {
          MessageBox (NULL, TEXT ("Program requires Windows NT!"), 
                      szAppName, MB_ICONERROR) ;
          return 0 ;
     }
     
     hwnd = CreateWindow (szAppName, TEXT ("Connect-the-Points Mouse Demo"),
                          WS_OVERLAPPEDWINDOW,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          NULL, NULL, hInstance, NULL) ;
     
     ShowWindow (hwnd, iCmdShow) ;
     UpdateWindow (hwnd) ;
     
     while (GetMessage (&msg, NULL, 0, 0))
     {
          TranslateMessage (&msg) ;
          DispatchMessage (&msg) ;
     }
     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)
     {
     case WM_LBUTTONDOWN:
          iCount = 0 ;
          InvalidateRect (hwnd, NULL, TRUE) ;
          return 0 ;
          
     case WM_MOUSEMOVE:
          if (wParam & MK_LBUTTON && iCount < 1000)
          {
               pt[iCount  ].x = GET_X_LPARAM (lParam) ;
               pt[iCount++].y = GET_Y_LPARAM (lParam) ;
               
               hdc = GetDC (hwnd) ;
               SetPixel (hdc, GET_X_LPARAM (lParam), GET_Y_LPARAM (lParam), 0) ;
               ReleaseDC (hwnd, hdc) ;
          }
          return 0 ;
          
     case WM_LBUTTONUP:
          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 = i + 1 ; j < iCount ; 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) ;
}

 

鼠标双击:

鼠标双击是指连续两次快速地单击。为了达到双击的效果,两次单击不仅要在物理位置上十分靠近,

还必须发生在特定的时间间隔内。这个间隔称为“双击速度”。

如果想让窗口过程接收鼠标双击消息,那么在调用 RegisterClass 初始化窗口类结构时,

必须在窗口风格字段中包含标识符 CS_DBLCLKS :

wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS ;

如果窗口类型没有包含 CS_DBLCLKS, 那么当用户连续两次快速单击左键时,

窗口过程接收的消息顺序如下:
WM_LBUTTONDOWN

WM_LBUTTONUP

WM_LBUTTONDOWN

WM_LBUTTONUP

如果包含的话:

WM_LBUTTONDOWN

WM_LBUTTONUP

WM_LBUTTONDBLCLK

WM_LBUTTONUP

 

非客户区鼠标消息:

系统一般不需要用户处理非客户区鼠标消息。用户只需要将这些消息发送给 DefWindowProc,从而使 Windows 执行系统函数。

消息的标识符包含了字母"NC",表示非客户区。如果鼠标在窗口的非客户区移动,窗口过程就会接收 WM_NCMOUSEMOVE 消息。

鼠标按钮产生的消息如下表所示:

按钮 按下 释放 第二次按下按钮
左键 WM_NCLBUTTONDOWN WM_NCLBUTTONUP WM_NCLBUTTONDBLCLK
中键 WM_NCMBUTTONDOWN WM_NCMBUTTONUP WM_NCMBUTTONDBLCLK
右键 WM_NCRBUTTONDOWN WM_NCRBUTTONUP WM_NCRBUTTONDBLCLK

非客户区鼠标消息的参数 wParam 和 lParam 与客户区鼠标消息的参数有些不同。

参数 wParam 表示非客户区鼠标移动或单击的位置。它的值被设定成一个以 HT 为 首的标识符。

参数 lParam 的低位字包含 x 坐标,高位字包含 y 坐标。这些都是屏幕坐标而不是客户区坐标。

 

击中测试消息:
WM_NCHITTEST 表示“非客户区击中测试”。这个消息的优先级高于其他所有客户区和非客户区鼠标消息。

Windows 应用程序通常会把这个消息发送给 DefWindowProc()。

然后 Windows 会利用 WM_NCHITTEST 消息来产生所有其他和鼠标位置相关的鼠标消息。

对非客户区消息来说,DefWindowProc() 处理 WM_NCHITTEST 消息后返回一个可用于鼠标消息参数 wParam 的值。

这个返回值可以是任何一个非客户区鼠标消息的 wParam 参数的值,也可以是如下所示的一些值:

意思
HTCLIENT 客户区
HTNOWHERE 不在任何窗口
HTTRANSPARENT 被另一个窗口覆盖的窗口
HTERROR 使函数 DefWindowProc 产生一个警示声

DEMO CODE:

#include <windows.h>
#include <windowsx.h>
#define DIVISIONS 5
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR  szCmdLine, int iCmdShow)
{
     static TCHAR szAppName[] = TEXT ("Checker1") ;
     HWND         hwnd ;
     MSG          msg ;
     WNDCLASS     wndclass ;
     
     wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
     wndclass.lpfnWndProc   = WndProc ;
     wndclass.cbClsExtra    = 0 ;
     wndclass.cbWndExtra    = 0 ;
     wndclass.hInstance     = hInstance ;
     wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
     wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
     wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
     wndclass.lpszMenuName  = NULL ;
     wndclass.lpszClassName = szAppName ;
     
     if (!RegisterClass (&wndclass))
     {
          MessageBox (NULL, TEXT ("Program requires Windows NT!"), 
                      szAppName, MB_ICONERROR) ;
          return 0 ;
     }
     
     hwnd = CreateWindow (szAppName, TEXT ("Checker1 Mouse Hit-Test Demo"),
                          WS_OVERLAPPEDWINDOW,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          NULL, NULL, hInstance, NULL) ;
     
     ShowWindow (hwnd, iCmdShow) ;
     UpdateWindow (hwnd) ;
     
     while (GetMessage (&msg, NULL, 0, 0))
     {
          TranslateMessage (&msg) ;
          DispatchMessage (&msg) ;
     }
     return msg.wParam ;
}

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
     static BOOL fState[DIVISIONS][DIVISIONS] ;
     static int  cxBlock, cyBlock ;
     HDC         hdc ;
     int         x, y ;
     PAINTSTRUCT ps ;
     RECT        rect ;
     
     switch (message)
     {
     case WM_SIZE :
          cxBlock = LOWORD (lParam) / DIVISIONS ;
          cyBlock = HIWORD (lParam) / DIVISIONS ;
          return 0 ;
          
     case WM_LBUTTONDOWN :
          x = GET_X_LPARAM (lParam) / cxBlock ;
          y = GET_Y_LPARAM (lParam) / cyBlock ;
          
          if (x < DIVISIONS && y < DIVISIONS)
          {
               fState [x][y] ^= 1 ;
               
               rect.left   = x * cxBlock ;
               rect.top    = y * cyBlock ;
               rect.right  = (x + 1) * cxBlock ;
               rect.bottom = (y + 1) * cyBlock ;
               
               InvalidateRect (hwnd, &rect, FALSE) ;
          }
          else
               MessageBeep (0) ;
          return 0 ;
          
     case WM_PAINT :
          hdc = BeginPaint (hwnd, &ps) ;
          
          for (x = 0 ; x < DIVISIONS ; x++)
          for (y = 0 ; y < DIVISIONS ; y++)
          {
               Rectangle (hdc, x * cxBlock, y * cyBlock,
                         (x + 1) * cxBlock, (y + 1) * cyBlock) ;
                    
               if (fState [x][y])
               {
                    MoveToEx (hdc,  x    * cxBlock,  y    * cyBlock, NULL) ;
                    LineTo   (hdc, (x+1) * cxBlock, (y+1) * cyBlock) ;
                    MoveToEx (hdc,  x    * cxBlock, (y+1) * cyBlock, NULL) ;
                    LineTo   (hdc, (x+1) * cxBlock,  y    * cyBlock) ;
               }
          }
          EndPaint (hwnd, &ps) ;
          return 0 ;
               
     case WM_DESTROY :
          PostQuitMessage (0) ;
          return 0 ;
     }
     return DefWindowProc (hwnd, message, wParam, lParam) ;
}

 

posted @ 2018-07-20 08:50  M-Anonymous  阅读(241)  评论(0)    收藏  举报