WinAPI 13 Key Manager

CJB_ny·2022년 8월 31일
0

WinAPI

목록 보기
13/79
post-thumbnail

키 입력 처리를 할 것이다.

포커싱 되어있지 않으면 입력 무시하고 그런것들...

update함수안에서 if로 체크함.

매순간순간마다 update호출한다.

이렇게 update가 끝나면 화면에 변경점들을 render함수를 통해 그려낼 것이다.

이과정이

1 frame의 과정이다. 이 한 프레임이 발생했을 때 걸리는 시간값을 DeltaTime이라고 하는 것이다.

이게 지금 900프레임정도가 나오는 것이다.

DT라는 시간안에서 A라는 물체는 왼쪽으로 움직이고 B라는 물체는 오른쪽으로 움직이는데

어쨋든 컴퓨터는 일을 순차적으로 처리를 하기 때문에 DT시간 안에서 A가 먼저 왼쪽으로 이동한다는 처리를 했을 때

이것을 A가 먼저 움직였다고 봐야하나?

작업 순서가 먼저라고 해서 먼저 이동한것임?

그래서 나는 개별적으로 움직이는 것을 볼 수 없다.

실제 내부적으로 한놈한놈씩 움직이는데.

ㅇㅋ?

다 움직이고 나서 캡쳐하는 느낌?

근데 코드 안에서 처음에 Left키를 눌렸다가

이 DT라는 시간 내에서 정말 찰나의 순간으로 Left키를 눌렸을때 어떤 처리를 하겠다라는게 update의 마지막 부분에 있는데 그전에 딱 Left키를 땟다고 가정을 하자.

누구는 왼쪽키 입력 받았다는 처리를 했지만 누구는 못하는 상황이 발생할 수 있다.

key Manager가 필요한 이유

그래서 이런 문제를 해결하기 위해서 '프레임 동기화'를 해야한다.

한 프레임에서 발생하는 일들을 '동기화'해주어야한다.

한프레임에서 발생한 키 입력을 동일하게 적용받아야한다.

그래서 해당 프레임이 시작하는 초입 부분에 key update를 해주고

입력받은 키를 해당 프레임안에서는 동일하게 적용시키는 것이다.

1) 프레임 동기화

동일 프레임 내에서 같은 키에 대해서 동일한 이벤트를 가진다.

2) 키 입력 이벤트의 구체적인 처리

tap, hold, away

구조를 잘 알아야한다.

지금 우리가 만든 enum class 는 윈도우API의 키 입력값(16진수)와 다르기 때문에

위치만 같은 enum class를 하나 만들어서 똑같이 동작하게 해주어야한다.

int g_arrVK[static_cast<int>(KEY::LAST)] = 
{
	VK_LEFT, //LEFT,
	VK_UP,//UP,
	VK_DOWN,//DOWN,
	VK_RIGHT, //RIGFHT,
	'Q',
	'W',
	'E',
	'R',
	'T',
	'Y',
	'U',
	'I',
	'O',
	'P',
	'A',
	'S',
	'D',
	'F',
	'G',
	'Z',
	'X',
	'C',
	'V',
	'B',
	
	VK_MENU,
	VK_LSHIFT,
	VK_SPACE,
	VK_CONTROL,
	VK_RETURN,
	VK_ESCAPE,
	
	//LAST,
};
void CKeyManager::init()
{
	for (int i = 0; i < static_cast<int>(KEY::LAST); ++i)
	{
		_vecKey.push_back(KeyInfo{ KEY_STATE::NONE, false } );
	}
}

void CKeyManager::update()
{
	for (int i = 0; i < static_cast<int>(KEY::LAST); ++i)
	{
		// 키가 눌려있다.
		if (GetAsyncKeyState(g_arrVK[i]) & 0x8000)
		{
			if (_vecKey[i]._isPrevInput)
			{
				// 이전에도 눌려있다.
				_vecKey[i]._state = KEY_STATE::HOLD;
			}
			else
			{
				// 이전에 눌려있지 않았다.
				_vecKey[i]._state = KEY_STATE::TAP;
			}
			_vecKey[i]._isPrevInput = true;
		}
		else // 키가 안 눌려있다.
		{
			if (_vecKey[i]._isPrevInput) // 지금은 안눌려있는데 이전프레임에 눌려있을 경우
			{
				// 이전에 눌려있다.
				_vecKey[i]._state = KEY_STATE::AWAY;
			}
			else
			{
				// 이전에도 안눌려 있었다.
				_vecKey[i]._state = KEY_STATE::NONE;
			}
			_vecKey[i]._isPrevInput = false;
		}
	}
}

KEY_STATE CKeyManager::GetKeyState(KEY key)
{
	return _vecKey[static_cast<int>(key)]._state;
}

CCore에서 init을 먼저 호출하고 update를 매번 호출할 텐데

init에서 먼저 for문을 돌면서 우리가 직접만든 enum class 길이 만큼 돌면서 _vecKey에다가 키 등록하는 부분을 다 해준다.

처음에는 NONE, false로 다 등록을 해주고 나서

update를 매 프레임마다 호출을 하는데 GetAsyncKeyState(g_arrVK[i]) 윈도우 입력을 받는 키로 전역 enum class에 해당하는 키입력을 먼저 찾는다.

찾았다면 이제(VK_LEFT를 눌렸을 경우)

우리가 만든 enum class KEY에 해당하는 KEY::LEFT값을 찾는다.

이미 init에서 _vecKey에 등록을 해놓았기 대문에 인덱스 접근으로 바로 찾아버린다.

그리고 해당 if문의 조건에 따라 _vecKey에 해당하는 Key를 (LEFT든 RIGHT든 뭐든)
번째의 KEY_STATE를 -> TAP 인지 뭔지로 바꿔준다.

그러면 _vecKey의 [ i ] 번째의 _state는 update의 if문에 따라 TAP으로 바꼈다고 가정하자.

그리고나서

CCore의 update함수 안에서


KEY_STATE CKeyManager::GetKeyState(KEY key)
{
	return _vecKey[static_cast<int>(key)]._state;
}

현재 _vecKey의 LEFT번째에 해당하는 인덱스 번호는 _state가 TAP으로 바뀌어있는데

이녀석을 호출하는 부분인 CCore의 update에서

KEY::LEFT를 GetKeyState의 인자로 넣어주면 이것을 캐스팅하여 _vecKey의 인덱스에 넘겨주어 해당 키가 지금 TAP이기 때문에 TAP이라는 KEY_STATE를 바로 반환하게 된다.

profile
https://cjbworld.tistory.com/ <- 이사중

0개의 댓글