본문 바로가기

프로그램언어/C++

API 키도드 입력로 도형제어

시작

#include <windows.h>

#include <TCHAR.H>

LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)

{

    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 = _T("Window Class Name");     // 클래스 이름

    RegisterClass(&WndClass);                                         // 윈도우 클래스를 커널에 등록

    hwnd = CreateWindow(_T("Window Class Name"),    // 윈도우 클래스 이름

        _T("Window Title Name"),                                // 윈도우 타이틀 이름

        WS_OVERLAPPEDWINDOW,                             // 윈도우 스타일

        CW_USEDEFAULT,                                          // 윈도우 x좌표

        CW_USEDEFAULT,                                          // 윈도우 y좌표
        CW_USEDEFAULT,                                          // 윈도우 가로 크기

        CW_USEDEFAULT,                                          // 윈도우 세로 크기

        NULL,                                                          // 부모 윈도우 핸들

        NULL,                                                          // 메뉴 핸들

        hInstance,                                                     // 응용 프로그램 인스턴스

        NULL );                                                         // 생성 원도우 정보

    ShowWindow(hwnd, nCmdShow);

    UpdateWindow(hwnd);

    while(GetMessage(&msg, NULL, 0, 0)) {

        TranslateMessage(&msg);               // 키보드 입력 이벤트 중 문자 입력을 처리하는 함수, 문자 입력이 아닐 
                                                        // 경우 DispatchMessage 함수로 너어간다.

        DispatchMessage(&msg);               // 전달된 메시지를 윈도우 프로시저로 보낸다.  

    }

    return (int)msg.wParam;

}

 

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

{

    switch (iMsg)

    {

    case WM_CREATE:

        break;

    case WM_DESTROY:

        PostQuitMessage(0);

        break;

    }

    return DefWindowProc(hwnd, iMsg, wParam, lParam);   // 윈도우 프로시저에서 case문으로 처리 못한 메시지를 처리

}

 

 

 

 

키보드 입력 메시지의 종류

키보드 메시지 설명
WM_KEYDOWN 키보드의 키가 눌려졌을 때
WM_KEYUP 키보드의 키가 떼어졌을 때
WM_CHAR 문자 키가 눌려졌을 때

키보드의 키가 입력되면 기본적으로 WM_KEYDOWN과 WM_KEYUP 메시지가 발생하고 , 문자키 입력시 WM_CHAR 메시지가 발생한다.

 

가상 키코드

가상 키코드란 시스템에 장착된 기보드의 종류화 상관없이 키를 입력 받기 위해 정의된 코드값으로 각 키마다 가상 키코드와 매핑되어 있으며, winuser.h에 정의 되어 있다. WM_KEYDOWN메시지가 발생했을 때, 키 이벤트가 들어오면 wparam으로 가상 키코드가 들어오는데 키코드값은 다음과 같다.

가상 키코드 코드값 설명
VK_CANCEL 0x03 Ctrl+Break 키를 눌렀을 때
VK_BACK 0x08 BackSpace 키를 눌렀을 때
VK_TAB 0x09 Top 키를 눌렀을 때
VK_RETURN 0x0D Enter 키를 눌렀을 때
VK_SHIFT 0x10 Shift 키를 눌렀을 때
VK_CONTROL 0x11 Ctrl 키를 눌렀을 때
VK_MENU 0x12 Alt 키를 눌렀을 때
VK_CAPITAL 0x14 Caps Lock 키를 눌렀을 때
VK_ESCAPE  0x1B Esc 키를 눌렀을 때
VK_SPACE 0x20 Space 키를 눌렀을 때
VK_PRIOR 0x21 Page Up 키를 눌렀을 때
VK_NEXT  0x22 Page Down 키를 눌렀을 때
VK_END 0x23 End 키를 눌렀을 때
VK_HOME 0x24 Home 키를 눌렀을 때
VK_LEFT  0x25 왼쪽 방향키를 눌렸을 때
VK_UP 0x26 위쪽 방향키를 눌렸을 때
VK_RIGHT  0x27 오른쪽 방향키를 눌렸을 때
VK_DOWN  0x28 아래쪽 방향키를 눌렸을 때
VK_INSERT  0x2D Insert 키를 눌렀을 때
VK_DELETE  0x2E Delete 키를 눌렀을 때
VK_F1 ~ F24  0x70 ~ 0x87 F1 ~ F24 키를 눌렀을 때
VK_NUMLOCK  0x90 NumLock 키를 눌렀을 때
VK_SCROLL  0x91 ScrollLock 키를 눌렀을 때

 

윈도우의 크기 메시지( WM_SIZE와 GetClientRect() )

WM_SIZE
wParam  윈도우의 크기가 어떻게 변했는지 알려주는 상수
- SIZE_MAXIMIZED : 윈도우 최대화
- SIZE_MINIMIZED : 윈도우 최소화
- SIZE_RESTORED : 윈도우의 크기가 변경됨
lParam 변경된 윈도우의 클라이언트 크기
- HIWORD(lParam) : 변경된 윈도우의 높이
- LOWORD(lParam) : 변경된 윈도우의 너비

 

GetClientRect() 함수는 클라이언트 영역의 왼쪽 상단 꼭지점 좌표와 오른쪽 하단 꼭지점 좌표가 RECT 구조체에 저장된다. 그러므로 RECT 구조체의 left와 right 값은 x축의 좌우 경계 값으로 사용하고, top과 bottom 값은 y축의 상하 경계 값으로 사용한다.

GetClientRect() 함수
BOOL GetClientRect( 
    HWND hwnd,              // 측정하려는 윈도우의 핸들
    LPRECT lpRect             // RECT 구조체의 주소
);

 

 

WM_KEYDOWN 메시지를 이용하여 도형을 이동해 보자.

 

#include <windows.h>
#include <TCHAR.H>

LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)

{

    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 = _T("Window Class Name");

    RegisterClass(&WndClass);

    hwnd = CreateWindow(_T("Window Class Name"), _T("Window Title Name"), WS_OVERLAPPEDWINDOW,

               CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL );

    ShowWindow(hwnd, nCmdShow);

    UpdateWindow(hwnd);

    while (GetMessage(&msg, NULL, 0, 0))

    {

        TranslateMessage(&msg);

        DispatchMessage(&msg);

    }

    return (int)msg.wParam;

}

 

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

{

    HDChdc;

    PAINTSTRUCT ps;

    static int x, y;

 

    switch (iMsg)

    {

    case WM_CREATE:

        x = 20; y = 20;

        break;

    case WM_PAINT:

        hdc = BeginPaint(hwnd, &ps);

        Ellipse(hdc, x - 20, y - 20, x + 20, y + 20);

        EndPaint(hwnd, &ps);

        break;

    case WM_KEYDOWN:

        if (wParam == VK_RIGHT)

            x += 40;

        else if (wParam == VK_LEFT)

            x -= 40;

        else if (wParam == VK_UP)

            y -= 40;

        else if (wParam == VK_DOWN)

            y += 40;

        InvalidateRgn(hwnd, NULL, TRUE);

        break;

    case WM_DESTROY:

        PostQuitMessage(0);

        break;

    }

    return(DefWindowProc(hwnd, iMsg, wParam, lParam));

}

실행 결과(방향키로 이동)

 

윈도우 경계를 만나면 더 이상 진행하지 않도록변경하고 위도우 안에서만 이동할 수 있도록 한다. 이동시 원 내부가 회색으로 바뀌고 손을 떼면 원래대로 돌아가게 작성해 보자.

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

{

    HDChdc;

    PAINTSTRUCT ps;

    static int x, y;
    static RECT rectView;
    static bool flag;

 

    switch (iMsg)

    {

    case WM_CREATE:
        GetClientRect(hwnd, &rectView);

        x = 20; y = 20;

        break;

    case WM_PAINT:

        hdc = BeginPaint(hwnd, &ps);
        if (flag)
            SelectObject(hdc, GetStockObject(LTGRAY_BRUSH));

        Ellipse(hdc, x - 20, y - 20, x + 20, y + 20);

        EndPaint(hwnd, &ps);

        break;
    case WM_KEYUP:
        flag = false;
        InvalidateRgn(hwnd, NULL, TRUE);
        break;

    case WM_KEYDOWN:

        if (wParam == VK_RIGHT) {

            flag = true;

            x += 40;

            if (x + 20 > rectView.right)

                x -= 40;

        }

        else if (wParam == VK_LEFT) {

            flag = true;

            x -= 40;

            if (x - 20 < rectView.left)

                x += 40;

        }

        else if (wParam == VK_UP) {

            flag = true;

            y -= 40;

            if (y - 20 < rectView.top)

                y += 40;

        }

        else if (wParam == VK_DOWN) {

            flag = true;

            y += 40;

            if (y + 20 > rectView.bottom)

                y -= 40;

        }

        InvalidateRgn(hwnd, NULL, TRUE);

        break;

    case WM_DESTROY:

        PostQuitMessage(0);

        break;

    }

    return(DefWindowProc(hwnd, iMsg, wParam, lParam));

}

실행 결과

'프로그램언어 > C++' 카테고리의 다른 글

API 마우스  (0) 2020.09.22
API 타이머  (0) 2020.09.21
파일 입출력  (0) 2020.08.24
템플릿  (0) 2020.08.20
클래스 예제2  (0) 2020.08.10