Windows鼠标键盘消息处理

转载自
https://www.cnblogs.com/ht-beyond/p/4445439.html

#include <windows.h>
#include <tchar.h>    //swprintf_s函数所需的头文件

#pragma comment(lib, "winmm.lib")    //playSound
#pragma comment(lib, "Msimg32.lib")    //TransparentBlt

#define WINDOW_WIDTH    800
#define WINDOW_HEIGHT    600
#define WINDOW_TITLE    L"Windows鼠标键盘消息处理"

// 环境,内存句柄
HDC    g_hdc = NULL, g_mdc = NULL, g_bufdc = NULL;
// 四张方向图,存储背景图的句柄, 人物2
HBITMAP g_hSprite[4] = { NULL }, g_hBackGround = NULL, g_hMan = NULL;
// 上一次绘图时间,此次准备绘图的时间
DWORD g_tPre = 0, g_tNow = 0;
// 图号,人物1横纵坐标,鼠标坐标,鼠标控制人物2坐标
int    g_iNum = 0, g_iX = 0, g_iY = 0, g_mouseX = 0, g_mouseY = 0, g_iXnow = 0, g_iYnow = 0;
// 人物移动方向,以0,1,2,3代表人物上,下,左,右
int    g_iDirection = 0;

// 回调函数,窗口过程函数
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
BOOL Game_Init(HWND hwnd);
VOID Game_Paint(HWND hwnd);
BOOL Game_CleanUp(HWND hwnd);


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
    WNDCLASSEX wndClass = { 0 };
    wndClass.cbSize = sizeof(WNDCLASSEX);
    wndClass.style = CS_HREDRAW | CS_VREDRAW;
    wndClass.lpfnWndProc = WndProc;
    wndClass.cbClsExtra = 0;
    wndClass.cbWndExtra = 0;
    wndClass.hInstance = hInstance;
    wndClass.hIcon = 0;
    wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    // 白色画刷句柄
    wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    // 用一个以空终止的字符串,指定菜单资源的名字
    wndClass.lpszMenuName = NULL;
    //窗口类的名字
    wndClass.lpszClassName = L"Game Develop";

    if (!RegisterClassEx(&wndClass))
        return -1;

    // 正式创建窗口
    HWND hwnd = CreateWindow(L"Game Develop", WINDOW_TITLE,
        WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, WINDOW_WIDTH,
        WINDOW_HEIGHT, NULL, NULL, hInstance, NULL);

    MoveWindow(hwnd, 250, 80, WINDOW_WIDTH, WINDOW_HEIGHT, true);
    ShowWindow(hwnd, nShowCmd);
    UpdateWindow(hwnd);

    if (!Game_Init(hwnd))
    {
        MessageBox(hwnd, L"资源初始化失败", L"消息窗口", 0);
        return FALSE;
    }

    PlaySound(L"music.wav", NULL, SND_FILENAME | SND_ASYNC | SND_LOOP);

    MSG msg = { 0 };
    while (msg.message != WM_QUIT)
    {
        // 查看应用程序消息队列,有消息时将队列中的消息派发出去
        if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        else
        {
            g_tNow = GetTickCount();
            // 重绘
            if (g_tNow - g_tPre >= 40)
                Game_Paint(hwnd);
        }
    }

    // 程序准备结束,注销窗口类
    UnregisterClass(L"Game Develop", wndClass.hInstance);  
    return 0;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{

    switch (message)                        
    {
        //键盘消息
    case WM_KEYDOWN:         
        switch (wParam)
        {
            //按下Esc键
        case VK_ESCAPE:           
            DestroyWindow(hwnd);   
            PostQuitMessage(0);  
            break;
        case VK_UP:                 
            g_iY -= 10;
            g_iDirection = 0;
            if (g_iY < 0)
                g_iY = 0;
            break;
        case VK_DOWN:             
            g_iY += 10;
            g_iDirection = 1;
            if (g_iY > WINDOW_HEIGHT - 135)
                g_iY = WINDOW_HEIGHT - 135;
            break;
        case VK_LEFT:                     
            g_iX -= 10;
            g_iDirection = 2;
            if (g_iX < 0)
                g_iX = 0;
            break;
        case VK_RIGHT:               
            g_iX += 10;
            g_iDirection = 3;
            if (g_iX > WINDOW_WIDTH - 75)
                g_iX = WINDOW_WIDTH - 75;
            break;
        }
        break;    

        // 单击鼠标左键消息
    case WM_LBUTTONDOWN:            
                break;

        // 鼠标移动消息
    case WM_MOUSEMOVE:   
        // 取得鼠标X坐标
        g_mouseX = LOWORD(lParam);            
        if (g_mouseX > WINDOW_WIDTH - 292)    
            g_mouseX = WINDOW_WIDTH - 292;
        else if (g_mouseX < 0)
            g_mouseX = 0;
        // 取得鼠标Y坐标
        g_mouseY = HIWORD(lParam);            
        if (g_mouseY  > WINDOW_HEIGHT - 190)
            g_mouseY = WINDOW_HEIGHT - 190;
        else if (g_mouseY  < 0)
            g_mouseY = 0;
        break;

    case WM_DESTROY:                    
        Game_CleanUp(hwnd);            
        PostQuitMessage(0);            
        break;                                    

        //调用缺省的窗口过程
    default:                                        
        return DefWindowProc(hwnd, message, wParam, lParam);        
    }
    return 0;                                
}

BOOL Game_Init(HWND hwnd)
{
    HBITMAP bmp;
    g_hdc = GetDC(hwnd);
    // 创建一个和hdc兼容的内存DC
    g_mdc = CreateCompatibleDC(g_hdc);
    // hdc兼容的缓冲DC
    g_bufdc = CreateCompatibleDC(g_hdc);
    bmp = CreateCompatibleBitmap(g_hdc, WINDOW_WIDTH, WINDOW_HEIGHT);

    g_iX = 100;
    g_iY = 350;
    g_mouseX = 300;
    g_mouseY = 100;
    g_iXnow = 300;
    g_iYnow = 100;
    g_iDirection = 3;
    g_iNum = 0;

    SelectObject(g_mdc, bmp);
    g_hSprite[0] = (HBITMAP)LoadImage(NULL, L"go1.bmp", IMAGE_BITMAP, 480, 216, LR_LOADFROMFILE);
    g_hSprite[1] = (HBITMAP)LoadImage(NULL, L"go2.bmp", IMAGE_BITMAP, 480, 216, LR_LOADFROMFILE);
    g_hSprite[2] = (HBITMAP)LoadImage(NULL, L"go3.bmp", IMAGE_BITMAP, 480, 216, LR_LOADFROMFILE);
    g_hSprite[3] = (HBITMAP)LoadImage(NULL, L"go4.bmp", IMAGE_BITMAP, 480, 216, LR_LOADFROMFILE);
    g_hBackGround = (HBITMAP)LoadImage(NULL, L"bg.bmp", IMAGE_BITMAP, WINDOW_WIDTH, WINDOW_HEIGHT, LR_LOADFROMFILE);
    g_hMan = (HBITMAP)LoadImage(NULL, L"man2.bmp", IMAGE_BITMAP, 292, 190, LR_LOADFROMFILE);

    POINT pt, lt, rb;
    RECT rect;
    // 设定光标位置
    pt.x = 300;
    pt.y = 100;
    // 将指定点或者矩形的用户坐标转换成屏幕坐标
    ClientToScreen(hwnd, &pt);
    SetCursorPos(pt.x, pt.y);
    // 隐藏鼠标光标
    ShowCursor(false);        
    // 限制鼠标光标移动区域
    // 取得窗口内部矩形
    GetClientRect(hwnd, &rect);  
    // 将矩形左上点坐标存入lt中
    lt.x = rect.left;
    lt.y = rect.top;
    // 将矩形右下坐标存入rb中
    rb.x = rect.right;
    rb.y = rect.bottom;
    // 将lt和rb的窗口坐标转换为屏幕坐标
    ClientToScreen(hwnd, &lt);
    ClientToScreen(hwnd, &rb);
    // 以屏幕坐标重新设定矩形区域
    rect.left = lt.x;
    rect.top = lt.y;
    rect.right = rb.x;
    rect.bottom = rb.y;
    // 限制鼠标光标移动区域
    ClipCursor(&rect);

    Game_Paint(hwnd);
    return TRUE;
}

VOID Game_Paint(HWND hwnd)
{
    // 先在mdc中贴上背景图
    SelectObject(g_bufdc, g_hBackGround);
    // 将源矩形区域直接拷贝到目标矩形区域
    BitBlt(g_mdc, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, g_bufdc, 0, 0, SRCCOPY);

    // 按照目前的移动方向取出对应人物的连续走动图,并确定截取人物图的宽度与高度
    SelectObject(g_bufdc, g_hSprite[g_iDirection]);
    // 使用AND(与)操作符来将源和目标矩形区域内的颜色合并
    BitBlt(g_mdc, g_iX, g_iY, 60, 108, g_bufdc, g_iNum * 60, 108, SRCAND);
    // 使用布尔型的OR(或)操作符将源和目标矩形区域的颜色合并
    BitBlt(g_mdc, g_iX, g_iY, 60, 108, g_bufdc, g_iNum * 60, 0, SRCPAINT);

    // 计算人物2的贴图坐标,设定每次进行贴图时,其坐标(g_iXnow,g_iYnow)会以每20个单位慢慢向鼠标光标所在的目的点(x,y)接近,直到两个坐标相同为止
    if (g_iXnow < g_mouseX)
    {
        g_iXnow += 20;
        if (g_iXnow > g_mouseX)
            g_iXnow = g_mouseX;
    }
    else  
    {
        g_iXnow -= 20;
        if (g_iXnow < g_mouseX)
            g_iXnow = g_mouseX;
    }

    if (g_iYnow < g_mouseY)  
    {
        g_iYnow += 20;
        if (g_iYnow > g_mouseY)
            g_iYnow = g_mouseY;
    }
    else  
    {
        g_iYnow -= 20;
        if (g_iYnow < g_mouseY)
            g_iYnow = g_mouseY;
    }
    // 贴上人物2图
    SelectObject(g_bufdc, g_hMan);
    // 对指定的源设备环境中的矩形区域数据进行位块转换,并将结果置于目标设备环境
    TransparentBlt(g_mdc, g_iXnow, g_iYnow, 292, 190, g_bufdc, 0, 0, 292, 190, RGB(0, 0, 0));

    HFONT hFont;
    // 创建字体
    hFont = CreateFont(20, 0, 0, 0, 0, 0, 0, 0, GB2312_CHARSET, 0, 0, 0, 0, TEXT("微软雅黑"));  
    SelectObject(g_mdc, hFont);
    // 设置文字背景透明
    SetBkMode(g_mdc, TRANSPARENT);
    // 设置文字颜色
    SetTextColor(g_mdc, RGB(255, 255, 0));  
    //在左上角进行文字输出
    wchar_t str[20] = {};
    swprintf_s(str, L"鼠标X坐标为%d", g_mouseX);
    TextOut(g_mdc, 0, 0, str, wcslen(str));
    swprintf_s(str, L"鼠标Y坐标为%d", g_mouseY);
    TextOut(g_mdc, 0, 20, str, wcslen(str));

    // 贴上背景图
    BitBlt(g_hdc, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, g_mdc, 0, 0, SRCCOPY);

    // 记录此次绘图时间
    g_tPre = GetTickCount();
    // go1.bmp有8个人物1动作图,用来实现人物1运动
    g_iNum++;
    if (g_iNum == 8)
        g_iNum = 0;
}

BOOL Game_CleanUp(HWND hwnd)
{
    // 释放资源对象
    DeleteObject(g_hBackGround);
    for (int i = 0; i<4; i++)
    {
        DeleteObject(g_hSprite[i]);
    }
    DeleteObject(g_hMan);
    DeleteDC(g_bufdc);
    DeleteDC(g_mdc);
    ReleaseDC(hwnd, g_hdc);
    return TRUE;
}

猜你喜欢

转载自blog.csdn.net/u012719076/article/details/83757861