1. 程式人生 > >Windows滑鼠鍵盤訊息處理

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;
}