본문 바로가기

Win32 api

Win32 api 강의 13 - 14화.

- KeyManager 설계.

// CKeyMgr.h
...
enum class KEY_STATE
{
    NONE,        // 아무것도 안 눌렀을 때
    TAP,        // 막 눌렀을 때
    HOLD,       // 누르고 있을 때
    RELEASE,    // 놓았을 때
};

enum class KEY
{
    LEFT,
    RIGHT,
    UP,
    DOWN,
    Q, W, E, R, T, Y, U, I, O, P, 
    A, S, D, F, G, H, J, K, L, 
    Z, X, C, V, B, N, M,
    ALT,
    CTRL,
    LSHIFT,
    SPACE,
    ENTER,
    ESC,
    END
};
...

 

먼저 enum 값으로 사용할 키 값과 키 상태 4가지를 정의해줌.

// CKeyMgr.h
...
struct tKeyInfo
{
    KEY_STATE    eState;
    bool         bPrevPress; // 이전 프레임에서 눌렸는지 여부
};
class CKeyMgr
{
    SINGLETON(CKeyMgr)
private:
    vector<tKeyInfo>    m_vecKey;

public:
    void init();
    void update();

public:
    KEY_STATE GetKeyState(KEY _eKey) const { return m_vecKey[(int)_eKey].eState; }
};

 

그리고 이를 구조체 형태로 해서 → tKeyInfo

vector 로 만든 것을 멤버 변수로 선언해줌.

 

매 프레임마다 이 수십 개의 키 정보들을 update() 함수에서 갱신해주면 됨.

 

int g_arrVK[(int)KEY::END] =
{
    VK_LEFT,
    VK_RIGHT,
    VK_UP,
    VK_DOWN,
    'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P',
    'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L',
    'Z', 'X', 'C', 'V', 'B', 'N', 'M',
    VK_MENU,    // ALT
    VK_CONTROL, // CTRL
    VK_LSHIFT,  // LSHIFT
    VK_SPACE,   // SPACE
    VK_RETURN,  // ENTER
    VK_ESCAPE,  // ESC
};

 

이건 사용자가 설정한 enum class KEY 를 윈도우에서 제공하는 키로 바꿔주기 위한 배열. 귀찮지만 입력을 추가하고 싶을 때마다 여길 바꿔줘야 할 듯.

 

void CKeyMgr::update()
{
    for (int i = 0; i < (int)KEY::END; ++i)
    {
        // 이전 프레임에서 눌렸는지 여부와 현재 프레임에서 눌렸는지 여부를 비교.
        // 4가지 상태로 구분. - NONE, TAP, HOLD, RELEASE.
        bool bCurPress = (GetAsyncKeyState(g_arrVK[i]) & 0x8000);
        if (bCurPress)
        {
            if (m_vecKey[i].bPrevPress)
            {
                m_vecKey[i].eState = KEY_STATE::HOLD;
            }
            else
            {
                m_vecKey[i].eState = KEY_STATE::TAP;
            }
        }
        else
        {
            if (m_vecKey[i].bPrevPress)
            {
                m_vecKey[i].eState = KEY_STATE::RELEASE;
            }
            else
            {
                m_vecKey[i].eState = KEY_STATE::NONE;
            }
        }
        m_vecKey[i].bPrevPress = bCurPress;
    }
}

 

모든 KeyInfo 마다 bPrevPress 에서 이전 프레임에 눌렸는지를 저장함.

현재 프레임에서 눌렸는지를 나타내는 bCurPress 값과 비교하면 4 가지 상태를 알 수 있음.

이를 그냥 if-else if-else 해서 갱신해주는 코드.

    // 키 눌렸을 때 한번만 이동.
    if (CKeyMgr::GetInstance()->GetKeyState(KEY::LEFT) == KEY_STATE::TAP)
    {
        pos.x -= 100.f;
    }

 

이제 키 입력 상태에 따라 다양한 계산이 가능.

 

- 윈도우 포커스 유무에 따른 키 입력 처리

void CKeyMgr::update()
{
    // GetFocus: 현재 포커싱된 윈도우 핸들 반환.
    HWND hWnd = GetFocus();

    // 포커싱이 되어 있으면 키 상태 갱신.
    if(hWnd != nullptr)
    {
    	...
    }
    // 포커싱이 안되어 있으면 모든 키 상태 NONE으로 초기화.
    else
    {
        for (int i = 0; i < (int)KEY::END; ++i)
        {
            m_vecKey[i].bPrevPress = false;
            
            if(m_vecKey[i].eState == KEY_STATE::TAP ||
               m_vecKey[i].eState == KEY_STATE::HOLD)
            {
                m_vecKey[i].eState = KEY_STATE::RELEASE;
                continue;
            }
            m_vecKey[i].eState = KEY_STATE::NONE;
        }
    }
}

 

GetFocus 함수를 통해 현재 윈도우에 포커스가 있는지 확인 후, 있으면 기존의 키 입력 처리를 해줌.

 

없다면 전체 키에 대해 bPrevPress 값은 false 로, 

eState 값은 RELEASE 나 NONE 으로 변경해준다.

'Win32 api' 카테고리의 다른 글

Win32 api 강의 17 - 18화.  (0) 2025.09.15
Win32 api 15 - 16화.  (0) 2025.09.14
Win32 api 강의 12화.  (0) 2025.09.13
Win32 api 강의 11화.  (0) 2025.09.13
Win32 api 강의 10화.  (0) 2025.09.12