Windows程序设计-鼠标

基础

确认鼠标是否存在

fMouse = GetSystemMetrics (SM_MOUSEPRESENT); // True(非0)存在

确定按键个数

cButtons = GetSystemMetrics (SM_CMOUSEBUTTONS) ;

双击速度SystemParametersInfo

鼠标按键动作

  • Clicking按下并放开一个鼠标按键。
  • Double-clicking快速按下并放开鼠标按键两次。
  • Dragging按住鼠标按键并移动鼠标。

对三键鼠标来说,三个键分别称为左键、中键、右键。在Windows表头文件中定义的与鼠标有关的标识符使用缩写LBUTTON、MBUTTON和RBUTTON。

显示区域鼠标消息

只要鼠标跨越窗口或者在某窗口中按下鼠标按键,那么窗口消息处理程序就会收到鼠标消息,而不管该窗口是否活动或者是否拥有输入焦点。Windows为鼠标定义了21种消息,不过,其中有11个消息和显示区域无关(下面称之为「非显示区域」消息),Windows程序经常忽略这些消息。

只要鼠标跨越窗口或者在某窗口中按下鼠标按键,那么窗口消息处理程序就会收到鼠标消息,而不管该窗口是否活动或者是否拥有输入焦点。Windows为鼠标定义了21种消息,不过,其中有11个消息和显示区域无关(下面称之为「非显示区域」消息),Windows程序经常忽略这些消息。

当鼠标移过窗口的显示区域时,窗口消息处理程序收到 _WM_MOUSEMOVE*_消息。当在窗口的显示区域中按下或者释放一个鼠标按键时,窗口消息处理程序会接收到下面这些消息:

按下

释放

按下(双键)

WM_LBUTTONDOWN

WM_LBUTTONUP

WM_LBUTTONDBLCLK

WM_MBUTTONDOWN

WM_MBUTTONUP

WM_MBUTTONDBLCLK

WM_RBUTTONDOWN

WM_RBUTTONUP

WM_RBUTTONDBLCLK

对于所有这些消息来说,其 lParam值均含有鼠标的位置:低字组为x坐标,高字组为y坐标,这两个坐标是相对于窗口显示区域左上角的位置。您可以用LOWORD和HIWORD宏来提取这些值:

x = LOWORD (lParam) ;y = HIWORD (lParam) ;

wParam的值指示鼠标按键以及Shift和Ctrl键的状态。您可以使用表头文件WINUSER.H中定义的位屏蔽来测试wParam。MK前缀代表 鼠标按键

  • MK_LBUTTON 按下左键
  • MK_MBUTTON 按下中键
  • MK_RBUTTON 按下右键
  • MK_SHIFT 按下Shift键
  • MK_CONTROL 按下Ctrl键

例如,如果收到了WM_LBUTTONDOWN消息,而且值

wparam & MK_SHIFT

是TRUE(非0),您就知道当左键按下时也按下了Shift键。

如果希望您的窗口消息处理程序能够收到双按键的鼠标消息,那么在呼叫RegisterClass初始化窗口类别结构时,必须在窗口风格中包含 CS_DBLCLKS标识符:

wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS ;

如果您的窗口类别风格中包含了CS_DBLCLKS,那么双击时窗口消息处理程序将收到如下消息:
WM_LBUTTONDOWN
WM_LBUTTONUP
WM_LBUTTONDBLCLK
WM_LBUTTONUP
WM_LBUTTONDBLCLK消息简单地替换了第二个WM_LBUTTONDOWN消息。

非显示区域鼠标消息

如果鼠标在窗口的 显示区域之外但还 在窗口内,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和lParam参数不同。wParam参数指明移动或者按鼠标按键的非显示区域。它设定为WINUSER.H中定义的以HT开头的标识符之一(HT表示 命中测试)。

lParam参数的低位word为x坐标,高位word为y坐标,但是,它们是 屏幕坐标,而不是像显示区域鼠标消息那样指的是显示区域坐标。对屏幕坐标,显示器左上角的x和y的值为0。当往右移时x的值增加,往下移时y的值增加。

可以用两个Windows函数将屏幕坐标转换为 显示区域坐标或者反之:

POINT pt;ScreenToClient (hwnd, &pt) ;ClientToScreen (hwnd, &pt) ;

第21个鼠标消息:命中测试消息WM_NCHITTEST,代表 非显示区域命中测试。此消息优先于所有其它的显示区域和非显示区域鼠标消息。lParam参数含有鼠标位置的x和y屏幕坐标,wParam参数没有用。

Windows 应 用 程 序 通 常 把 这 个 消 息 传 送 给 DefWindowProc , 然 后 Windows 用WM_NCHITTEST消息产生与鼠标位置相关的所有其它鼠标消息。对于非显示区域鼠标消息,在处理WM_NCHITTEST时,从DefWindowProc传回的值将成为鼠标消息中的wParam参数,这个值可以是任意非显示区域鼠标消息的wParam值再加上以下内容:

  • HTCLIENT 显示区域
  • HTNOWHERE 不在窗口中
  • HTTRANSPARENT 窗口由另一个窗口覆盖
  • HTERROR 使DefWindowProc产生警示用的哔声

如果DefWindowProc在其处理WM_NCHITTEST消息后传回HTCLIENT,那么Windows将把屏幕坐标转换为显示区域坐标并产生显示区域鼠标消息。

命中测试例子

/*-------------------------------------------------------------------------CHECKER1.C -- Mouse Hit-Test Demo Program No. 1(c)  Charles  Petzold,--------------------------------------------------------------------------*/#include #define DIVISIONS 5LRESULT 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 = LOWORD(lParam) / cxBlock;        y = HIWORD(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

加入键盘接口

Windows程序设计-鼠标
/*----------------------------------------------------------------------------CHECKER2.C -- Mouse Hit-Test Demo Program No. 2(c) Charles Petzold, 1998----------------------------------------------------------------------------*/#include #define DIVISIONS 5LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,    PSTR szCmdLine, int iCmdShow){    static TCHAR szAppName[] = TEXT("Checker2");    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("Checker2 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;    POINT point;    RECT rect;    switch (message)    {    case WM_SIZE:        cxBlock = LOWORD(lParam) / DIVISIONS;        cyBlock = HIWORD(lParam) / DIVISIONS;        return 0;    case WM_SETFOCUS:        ShowCursor(TRUE);        return 0;    case WM_KILLFOCUS:        ShowCursor(FALSE);        return 0;    case WM_KEYDOWN:        GetCursorPos(&point);        ScreenToClient(hwnd, &point);        x = max(0, min(DIVISIONS - 1, point.x / cxBlock));        y = max(0, min(DIVISIONS - 1, point.y / cyBlock));        switch (wParam)        {        case VK_UP:            y--;            break;        case VK_DOWN:            y++;            break;        case VK_LEFT:            x--;            break;        case VK_RIGHT:            x++;            break;        case VK_HOME:            x = y = 0;            break;        case VK_END:            x = y = DIVISIONS - 1;            break;        case VK_RETURN:        case VK_SPACE:            SendMessage(hwnd,                WM_LBUTTONDOWN, MK_LBUTTON,                MAKELONG(x * cxBlock, y * cyBlock));            break;        }        x = (x + DIVISIONS) % DIVISIONS;        y = (y + DIVISIONS) % DIVISIONS;        point.x = x * cxBlock + cxBlock / 2;        point.y = y * cyBlock + cyBlock / 2;        ClientToScreen(hwnd, &point);        SetCursorPos(point.x, point.y);        return 0;    case WM_LBUTTONDOWN:        x = LOWORD(lParam) / cxBlock;        y = HIWORD(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

子窗口

/*---------------------------------------------------------------------------CHECKER3.C -- Mouse Hit-Test Demo Program No. 3(c) Charles Petzold, 1998----------------------------------------------------------------------------*/#include #define DIVISIONS 5LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);LRESULT CALLBACK ChildWndProc(HWND, UINT, WPARAM, LPARAM);TCHAR szChildClass[] = TEXT("Checker3_Child");int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,    PSTR szCmdLine, int    iCmdShow){    static TCHAR szAppName[] = TEXT("Checker3");    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;    }    wndclass.lpfnWndProc = ChildWndProc;    wndclass.cbWndExtra = sizeof (long);    wndclass.hIcon = NULL;    wndclass.lpszClassName = szChildClass;    RegisterClass(&wndclass);    hwnd = CreateWindow(szAppName, TEXT("Checker3 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 HWND hwndChild[DIVISIONS][DIVISIONS];    int cxBlock, cyBlock, x, y;    switch (message)    {    case WM_CREATE:        for (x = 0; x < DIVISIONS; x++)        for (y = 0; y < DIVISIONS; y++)            hwndChild[x][y] = CreateWindow(szChildClass, NULL,            WS_CHILDWINDOW | WS_VISIBLE,            0, 0, 0, 0,            hwnd, (HMENU)(y << 8 | x),            (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE),            NULL);        return 0;    case WM_SIZE:        cxBlock = LOWORD(lParam) / DIVISIONS;        cyBlock = HIWORD(lParam) / DIVISIONS;        for (x = 0; x < DIVISIONS; x++)        for (y = 0; y < DIVISIONS; y++)            MoveWindow            (hwndChild[x][y],            x * cxBlock, y * cyBlock,            cxBlock, cyBlock, TRUE);        return 0;    case WM_LBUTTONDOWN:        MessageBeep(0);        return 0;    case WM_DESTROY:        PostQuitMessage(0);        return 0;    }    return DefWindowProc(hwnd, message, wParam, lParam);}LRESULT CALLBACK ChildWndProc(HWND hwnd, UINT message,    WPARAM wParam, LPARAM lParam){    HDC hdc;    PAINTSTRUCT ps;    RECT rect;    switch (message)    {    case WM_CREATE:        SetWindowLong(hwnd, 0, 0); // on/off flag        return 0;    case WM_LBUTTONDOWN:        SetWindowLong(hwnd, 0, 1 ^ GetWindowLong(hwnd, 0));        InvalidateRect(hwnd, NULL, FALSE);        return 0;    case WM_PAINT:        hdc = BeginPaint(hwnd, &ps);        GetClientRect(hwnd, &rect);        Rectangle(hdc, 0, 0, rect.right, rect.bottom);        if (GetWindowLong(hwnd, 0))        {            MoveToEx(hdc, 0, 0, NULL);            LineTo(hdc, rect.right, rect.bottom);            MoveToEx(hdc, 0,                rect.bottom, NULL);            LineTo(hdc, rect.right, 0);        }        EndPaint(hwnd, &ps);        return 0;    }    return

在WinMain中CreateWindow呼叫的参数,与在建立25个子窗口的WndProc中CreateWindow呼叫的参数间的比较:

参数

主窗口

子窗口

窗口类别

「Checker3」

「Checker3_Child」

窗口标题

「Checker3…」

NULL

窗口样式

WS_OVERLAPPEDWINDOW

&#x200B;WS_CHILDWINDOW |WS_VISIBLE&#x200B;

水平位置

CW_USEDEFAULT

0

垂直位置

CW_USEDEFAULT

0

宽度

CW_USEDEFAULT

0

高度

CW_USEDEFAULT

0

父窗口句柄

NULL

hwnd

菜单句柄/子ID

NULL

&#x200B;(HMENU) (y << 8 | x)&#x200B;

执行实体句柄

hInstance

&#x200B;(HINSTANCE)GetWindowLong (hwnd, GWL_HINSTANCE)&#x200B;

额外参数

NULL

NULL

子窗口和键盘

Windows程序设计-鼠标
/*---------------------------------------------------------------------------
CHECKER4.C -- Mouse Hit-Test Demo Program No. 4
(c) Charles Petzold, 1998
---------------------------------------------------------------------------*/
#include
#define DIVISIONS 5
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK ChildWndProc(HWND, UINT, WPARAM, LPARAM);
int idFocus = 0;
TCHAR szChildClass[] = TEXT("Checker4_Child");
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int
iCmdShow)
{
static TCHAR szAppName[] = TEXT("Checker4");
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;
}
wndclass.lpfnWndProc =
ChildWndProc;
wndclass.cbWndExtra = sizeof
(long);
wndclass.hIcon = NULL;
wndclass.lpszClassName = szChildClass;
RegisterClass(&wndclass);
hwnd = CreateWindow(szAppName, TEXT("Checker4 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 HWND hwndChild[DIVISIONS][DIVISIONS];
int cxBlock, cyBlock, x, y;
switch (message)
{
case WM_CREATE:
for (x = 0; x < DIVISIONS; x++)
for (y = 0; y < DIVISIONS; y++)
hwndChild[x][y] = CreateWindow(szChildClass, NULL,
WS_CHILDWINDOW | WS_VISIBLE,
0, 0, 0, 0,
hwnd, (HMENU)(y << 8 | x),
(HINSTANCE) GetWindowLong(hwnd, GWL_HINSTANCE),
NULL);
return 0;
case WM_SIZE:
cxBlock = LOWORD(lParam) / DIVISIONS;
cyBlock = HIWORD(lParam) / DIVISIONS;
for (x = 0; x < DIVISIONS; x++)
for (y = 0; y < DIVISIONS; y++)
MoveWindow(hwndChild[x][y],
x * cxBlock, y * cyBlock,
cxBlock, cyBlock, TRUE);
return 0;
case WM_LBUTTONDOWN:
MessageBeep(0);
return 0;
// On set-focus message, set focus to child window
case WM_SETFOCUS:
SetFocus(GetDlgItem(hwnd, idFocus));
return 0;
// On key-down message, possibly change the focus window
case WM_KEYDOWN:
x = idFocus & 0xFF;
y = idFocus >> 8;
switch (wParam)
{
case VK_UP: y--;
break;
case VK_DOWN: y++;
break;
case VK_LEFT: x--;
break;
case VK_RIGHT: x++; break;
case VK_HOME: x = y = 0;
break;
case VK_END: x = y = DIVISIONS - 1;
break;
default: return 0;
}
x = (x + DIVISIONS) % DIVISIONS;
y = (y + DIVISIONS) % DIVISIONS;
idFocus = y << 8 | x;
SetFocus(GetDlgItem(hwnd, idFocus));
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
LRESULT CALLBACK ChildWndProc(HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
RECT rect;
switch (message)
{
case WM_CREATE:
SetWindowLong(hwnd, 0, 0); // on/off flag
return 0;
case WM_KEYDOWN:
// Send most key presses to the parent window
if (wParam != VK_RETURN && wParam != VK_SPACE)
{
SendMessage(GetParent(hwnd), message, wParam,
lParam);
return 0;
}
// For Return and Space, fall through to toggle the square
case WM_LBUTTONDOWN:
SetWindowLong(hwnd, 0, 1 ^ GetWindowLong(hwnd, 0));
SetFocus(hwnd);
InvalidateRect(hwnd, NULL, FALSE);
return 0;
// For focus messages, invalidate the window for repaint
case WM_SETFOCUS:
idFocus = GetWindowLong(hwnd, GWL_ID);
// Fall through
case WM_KILLFOCUS:
InvalidateRect(hwnd, NULL, TRUE);
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &rect);
Rectangle(hdc, 0, 0, rect.right, rect.bottom);
// Draw the "x" mark
if (GetWindowLong(hwnd, 0))
{
MoveToEx(hdc, 0, 0, NULL);
LineTo(hdc, rect.right, rect.bottom);
MoveToEx(hdc, 0, rect.bottom,
NULL);
LineTo(hdc, rect.right, 0);
}
// Draw the "focus" rectangle
if (hwnd == GetFocus())
{
rect.left += rect.right / 10;
rect.right -= rect.left;
rect.top += rect.bottom / 10;
rect.bottom -= rect.top;
SelectObject(hdc, GetStockObject
(NULL_BRUSH));
SelectObject(hdc, CreatePen(PS_DASH, 0,
0));
Rectangle(hdc, rect.left, rect.top, rect.right,
rect.bottom);
DeleteObject(SelectObject(hdc,
GetStockObject(BLACK_PEN)));
}
EndPaint(hwnd, &ps);
return 0;
}
return

拦截鼠标

Windows程序设计-鼠标
/*----------------------------------------------------------------------------BLOKOUT2.C -- Mouse Button & Capture Demo Program(c) Charles Petzold, 1998----------------------------------------------------------------------------*/#include LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,    PSTR szCmdLine, int iCmdShow){    static TCHAR szAppName[] = TEXT("BlokOut2");    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("Mouse Button & Capture 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;}void DrawBoxOutline(HWND hwnd, POINT ptBeg, POINT ptEnd){    HDC hdc;    hdc = GetDC(hwnd);    SetROP2(hdc, R2_NOT);    SelectObject(hdc, GetStockObject(NULL_BRUSH));    Rectangle(hdc, ptBeg.x, ptBeg.y, ptEnd.x, ptEnd.y);    ReleaseDC(hwnd, hdc);}LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM    wParam, LPARAM lParam){    static BOOL fBlocking, fValidBox;    static POINT ptBeg, ptEnd, ptBoxBeg, ptBoxEnd;    HDC hdc;    PAINTSTRUCT ps;    switch (message)    {    case WM_LBUTTONDOWN:        ptBeg.x = ptEnd.x = LOWORD(lParam);        ptBeg.y = ptEnd.y = HIWORD(lParam);        DrawBoxOutline(hwnd, ptBeg, ptEnd);        SetCapture(hwnd);        SetCursor(LoadCursor(NULL, IDC_CROSS));        fBlocking = TRUE;        return 0;    case WM_MOUSEMOVE:        if (fBlocking)        {            SetCursor(LoadCursor(NULL, IDC_CROSS));            DrawBoxOutline(hwnd, ptBeg, ptEnd);            ptEnd.x = LOWORD(lParam);            ptEnd.y = HIWORD(lParam);            DrawBoxOutline(hwnd, ptBeg, ptEnd);        }        return 0;    case WM_LBUTTONUP:        if (fBlocking)        {            DrawBoxOutline(hwnd, ptBeg, ptEnd);            ptBoxBeg = ptBeg;            ptBoxEnd.x = LOWORD                (lParam);            ptBoxEnd.y = HIWORD                (lParam);            ReleaseCapture();            SetCursor(LoadCursor(NULL, IDC_ARROW));            fBlocking = FALSE;            fValidBox = TRUE;            InvalidateRect(hwnd, NULL, TRUE);        }        return 0;    case WM_CHAR:        if (fBlocking & wParam == '\x1B') // i.e., Escape        {            DrawBoxOutline(hwnd, ptBeg, ptEnd);            ReleaseCapture();            SetCursor(LoadCursor(NULL, IDC_ARROW));            fBlocking = FALSE;        }        return 0;    case WM_PAINT:        hdc = BeginPaint(hwnd, &ps);        if (fValidBox)        {            SelectObject(hdc, GetStockObject                (BLACK_BRUSH));            Rectangle(hdc, ptBoxBeg.x, ptBoxBeg.y,                ptBoxEnd.x, ptBoxEnd.y);        }        if (fBlocking)        {            SetROP2(hdc, R2_NOT);            SelectObject(hdc, GetStockObject                (NULL_BRUSH));            Rectangle(hdc, ptBeg.x, ptBeg.y, ptEnd.x,                ptEnd.y);        }        EndPaint(hwnd, &ps);        return 0;    case WM_DESTROY:        PostQuitMessage(0);        return 0;    }    return
SetCapture (hwnd) ;

在这个函数调用之后,Windows将 所有鼠标消息发给窗口句柄为hwnd的窗口消息处理程序。之后收到鼠标消息都是以显示区域消息的型态出现,即使鼠标正在窗口的非显示区域。lParam参数将指示鼠标在显示区域坐标中的位置。不过,当鼠标位于显示区域的左边或者上方时,这些x和y坐标可以是负的。当您想释放鼠标时,调用:

ReleaseCapture () ;

从而使处理恢复正常。

鼠标滑轮

消息:WM_MOUSEWHEEL

Original: https://blog.51cto.com/lilongsy/5456642
Author: lilongsy
Title: Windows程序设计-鼠标

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/516644/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球