WIN32 Timer, KeyManager

Date:     Updated:

카테고리:

태그:

7일차

  • Default
    • Client.h
    • framework.h
    • Resouce.h
    • targetver.h
  • Engine
    1. Header
      1. define.h
      2. struct.h
    2. Core
      1. CCore.cpp
      2. CCore.h
    3. Manager
      1. KeyMgr
        1. CkeyMgr.cpp
        2. CkeyMgr.h
      2. TimeMgr
        1. CTimeMgr.cpp
        2. CTimeMgr.h
    4. Object
      1. CObject.cpp
      2. CObject.h
  • 리소스 파일
  • main.cpp
  • pch.h.
    1. struct.h
  • 이번에 한 것은 KeyManager이다. 왜 필요한가?
  • 한 프레임에 모든 키입력과 관련된 이벤트가 필요하기 때문
  • KeyDown(키를 딱 누른 순간), KeyHold(키를 계속 누르고 있다), KeyUp(키를 눌렀다가 막 올린 상태) 와 같은 이벤트 처리가 필요하다.
  • 또한, 현재 사용자가 보고있는 윈도우가 우리가 만든 윈도우가 아닐때에는 키 입력을 받지 않아야 한다. 하지만, 기본 세팅은 메인 윈도우(우리가 보고 있는 윈도우)가 아님에도 키 입력을 받으니 그걸 처리해줘야한다.
  1. CkeyMgr.h
#pragma once

//#include 거는 거 불편함. 그래서. 

//순차적이기 때문에, 한 프레임 시간이 지났을 때. DT라는 시간이 지난만큼 각각 변경점을 적용함 -> 그렇게 그린 걸 우리가 봄
//A 물체를 이동시켰을 때, B물체보다 먼저 일어난 건가? 그건 아니지 않나? 그런데 절차지향대로라면 그렇게 됨. 

//이 모든 작업이 완료 됐을 때 모두가 동시에 일어난 사건으로 봐야만 함. 
//만약 누구는 처리 받고, 누구는 처리 받지 못할수도 있음. 
// 
//따라서 KeyManager가 필요한 이유 
//1. 프레임 동기화. 한 프레임에 모두 일어나야 함. 

//2. 윈도우에서 만들어준 함수로는 구체적인 이벤트가 적용되어 있지 않음
//EX) 엔터키가 눌려있다만 궁금한 게 아니라, 이번에 눌렸다(Down), 이번에 뗏다(Up) <- 이런 것도 지정해줘야함. 
#include "define.h"

//키 상태.
enum class KEY_STATE {
	TAP,	//막 누른 시점
	HOLD,	//누르고 있는
	AWAY,	//막 뗀 시점
	NONE,	// 눌리지 않은 상태. 이전에도 눌리지 않은 상태. 
};

//지원해줄 수 있는 키 

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

struct tKeyInfo{
	KEY_STATE		eState;			//키의 상태값. 
	bool			bPrevPush;		//이전에 이 키가 눌렸는지 안 눌렸는지
};
class CkeyMgr
{
	SINGLE(CkeyMgr);

private:
	//벡터의 INDEX값이, 곧 KEY값. 
	vector<tKeyInfo> m_vecKey;

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

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

  1. CkeyMgr.cpp

#include "pch.h"
#include "CkeyMgr.h"
#include "CCore.h"

int g_arrVK[(int)KEY::LAST] = {
	VK_LEFT,	//LEFT,
	VK_RIGHT,	//RIGHT,
	VK_UP,		//UP,
	VK_DOWN,	//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,
	VK_CONTROL,
	VK_LSHIFT,
	VK_SPACE,
	VK_RETURN,
	VK_ESCAPE,

	//LAST,
};

CkeyMgr::CkeyMgr() {

}

CkeyMgr::~CkeyMgr() {

}

void CkeyMgr::init()
{

	for (int keyIDX = 0; keyIDX < (int)KEY::LAST; keyIDX++) {
		m_vecKey.push_back(tKeyInfo{ KEY_STATE::NONE, false });
	}

	//아래처럼 상태확인, 이전에 눌렸는지.
	//m_vecKey[(int)KEY::LEFT].bPrev
	//m_vecKey[(int)KEY::LEFT].eState
}

//뭔가를 하고 있다가, 창을 바꾸면 키를 떼지는 것까지는 구현해야하지 않을까?
//TAB상태였던 애는 바로 떼진 AWAY로 가야함 -> NONE
//HOLD였던 애는 AWAY로 갔다가 -> NONE

void CkeyMgr::update() {

	//윈도우 포커싱 알아내기 
	HWND hMainWnd = CCore::GetInstance()->GetMainHwnd();
	HWND hWnd = GetFocus();//현재 포커싱 되어 있는 윈도우의 핸들값을 알려줌. 

	//지금 포커싱 중인게, 이 프로그램의 메인 윈도우라면 같은지 아닌지만 확인해주면 됨.
	//윈도우 포커싱 중일 때, 키 이벤트 동작. 
	if (nullptr != hWnd) {

		for (int keyIDX = 0; keyIDX < (int)KEY::LAST; keyIDX++) {
			//키가 눌렸다면. 
			if (GetAsyncKeyState(g_arrVK[keyIDX]) & 0x8000) {
				if (m_vecKey[keyIDX].bPrevPush) {
					//이전에 눌려있었다. 
					m_vecKey[keyIDX].eState = KEY_STATE::HOLD;
				}
				else {
					//이전에 눌려있지 않았다. 
					m_vecKey[keyIDX].eState = KEY_STATE::TAP;
				}
				m_vecKey[keyIDX].bPrevPush = true;
			}
			else {//현재 키가 눌려있지 않다면. 
				if (m_vecKey[keyIDX].bPrevPush) {
					//이전에 키가 눌려있다면. 
					m_vecKey[keyIDX].eState = KEY_STATE::AWAY;
				}
				else {
					//이전에 키가 눌려있지 않았다면. 
					m_vecKey[keyIDX].eState = KEY_STATE::NONE;
				}
				m_vecKey[keyIDX].bPrevPush = false;
			}
		}
	}
	else {
		//윈도우 포커싱 해제 상태
		for (int keyIDX = 0; keyIDX < (int)KEY::LAST; keyIDX++) {
			m_vecKey[keyIDX].bPrevPush = false;
			if (m_vecKey[keyIDX].eState == KEY_STATE::TAP || m_vecKey[keyIDX].eState == KEY_STATE::HOLD) {
				m_vecKey[keyIDX].eState = KEY_STATE::AWAY;
			}
			else if (m_vecKey[keyIDX].eState == KEY_STATE::AWAY) {
				m_vecKey[keyIDX].eState = KEY_STATE::NONE;
			}
		}
	}
}

  1. CCore.cpp의 update함수
void CCore::update()
{
	Vec2 vPos = g_obj.GetPos();
	//비동기 키 입출력 함수. <- 코드가 바로 실행됨. 백그라운드여도 바로 수행됨
	//return 되는 건 어느정도 상태 값을 알려줌.
	

	//여기까지 와야, 이 키가 어떤 상태인지 알 수 있음. 우리 프로그램은 매 순간 update를 거침. 
	//모든 업데이트가 끝나면, 변경점을 적용시켜 물체들을 그려냄. 
	

	if (CkeyMgr::GetInstance()->GetKeyState(KEY::LEFT) == KEY_STATE::HOLD) {
		vPos.x -= 200.f * fDT;
	}

	if (CkeyMgr::GetInstance()->GetKeyState(KEY::RIGHT) == KEY_STATE::HOLD) {
		vPos.x += 200.f * fDT;
	}

	g_obj.SetPos(vPos);
}

WINAPI 카테고리 내 다른 글 보러가기

댓글 남기기