[WinAPI] bitset 자료구조를 이용한 key매니저구현

jh Seo·2024년 1월 30일
0

winapi공부

목록 보기
6/6

개요

STL의 bitset 자료구조를 이용해 key매니저를 구현한 부분을 정리하는 글이다.

bitset이란

bool 자료형은 1바이트로 0,1을 저장한다.
하지만 1bit로도 0과 1을 표기할 수 있다. 7bit를 압축시키는 효율!
이렇게 bit를 이용해 0과 1을 저장하는 자료구조가 STL라이브러리의 bitset이다.
vector<bool> 이나 bool형 배열대신 사용하면 효율적일 것이다!

다음은 bitset의 멤버 함수들이다.

  • set() : bit 모두 1로 설정

  • reset() : bit 모두 0으로 설정

  • set(i,value) : i번째 값을 value로 설정

  • [] : 배열 형태의 access가 가능함 / bit[10]=false;

  • flip() : bit 값 전환 0->1 , 1->0

  • all() : 모든 비트가 1일 때 true

  • none() : 모든 비트가 0일 때 true

  • any() : 1개라도 1이면 true

  • count() : 값이 1로 세팅된 비트의 갯수 반환

이런 bitset의 원소들은 1bit인데 1bit를 표기할 수 있는 자료형이 없으므로
특별한 레퍼런스 타입으로 접근된다.

bitset::reference : bitset의 operator[]에 대한 도우미 클래스로서 개별 비트에 액세스하고 조작하는 데 사용되는 bitset에 포함된 비트를 참조하는 프록시 클래스입니다.

keymanager.h파일

싱글톤 템플릿 클래스를 상속받아 하나의 키매니저만 존재하도록 한다.

private 멤버 변수로 위에 언급한 bitset을 두개 선언했다.

	private:
		bitset<KEYMAX> m_bitKeyUp;
		bitset<KEYMAX> m_bitKeyDown;

public 멤버함수로 각 키의 상태에 따른 함수들을 선언했다

public:
	void Setup();						//키 매니저 초기화

	bool isOnceKeyDown(int key);		//키가 한번 눌림
	bool isOnceKeyUp(int key);			//키를 눌렀다 땜
	bool isStayKeyDown(int key);		//키를 누르고있음
	bool isToggleKey(int key);			//토글 키

keymanager.cpp파일

일단 keymanager코드를 보기 전에 알아야할 함수가 있다.

GetAsyncKeyState(int key)

인자 값인 key의 상태를 반환하는 함수다.

반환값으로 네 가지 값이 존재한다.

  • 0x0000
    이전에 누른적없고 호출 시점에도 안눌림
  • 0x0001
    이전에 누른적 있고 호출 시점에 안눌림
  • 0x8000
    이전에 누른적이 없고 호출 시점에는 눌려있음
  • 0x8001
    이전에 누른적이 있고 호출 시점에도 눌려있는 상태

이 네 값을 가지고 키 입력 판단을 한다.

Setup()

void KeyManager::Setup()
{
    m_bitKeyUp.reset();
    m_bitKeyDown.reset();
}

두 개의 bitset자료구조를 리셋시킨다.

isOnceKeyDown()

bool KeyManager::isOnceKeyDown(int key)
{
    if (GetAsyncKeyState(key) & 0x8000) {
        //키가 이전에 눌려있지 않은 상태
        if (!m_bitKeyDown[key]) {
            //눌린 상태로 변환
            m_bitKeyDown.set(key, true);
            return true;
        }
    }
    else
    {
        m_bitKeyDown.set(key, false);
    }
    return false;
}

GetAsyncKeyState함수를 통해 key의 상태를 알아온다.

0x8000값과 &연산자를 통해 true가 나오려면 GetAsyncKeyState함수의 반환값이
0x8001이거나 0x8000이면 된다.

따라서 if (GetAsyncKeyState(key) & 0x8000)의 의미는
현재 해당 버튼이 눌려있는 지 체크하는 것이다.

이전에 이미 눌려있는 상태라면 (m_bitKeyDown[key] = true)
사용자가 계속 누르고 있는 상황이므로 false를 return한다.

m_bitKeyDown[key]가 false여야만 처음 누른 상황이므로 true를 반환하도록 구현하였다.

isOnceKeyUp(int key)

bool KeyManager::isOnceKeyUp(int key)
{
    if (GetAsyncKeyState(key) & 0x8000) {
        m_bitKeyUp.set(key, true);
    }
    else {
        //이전에 키를 누르고 있었다면
        if (m_bitKeyUp[key]) {
            //뗀 상태로 변환
            m_bitKeyUp.set(key, false);
            return true;
        }
    }
    return false;
}

위 설명에서 GetAsyncKeyState(key) & 0x8000 조건문은 현재 해당 키가 눌려있는 지 조사하는 역할이므로
눌려있다면 m_bitKeyUp.set(key, true); 체크해준 후 false를 return한다.

else문ㅇ내부로 진입했다는 뜻은 0x0000 또는 0x0001을 반환한 상황이므로
키를 안 누르는 상황이다.

if (m_bitKeyUp[key]) 조건문 내부로 들어왔다는 말은
이전에 누르고 있었다는 뜻이므로 방금 키를 떼었다는 뜻이다.

따라서 m_bitKeyUp[key]값을 false로 세팅해주고 true를 반환한다.

isStayKeyDown(int Key)

bool KeyManager::isStayKeyDown(int key)
{
    if (GetAsyncKeyState(key) & 0x8000) return true;
    return false;
}

key를 누르고 있는가 체크하는 함수다.
0x8000과 &연산을 통해 누르고 있는지 체크한다.

isToggleKey(int key)

bool KeyManager::isToggleKey(int key)
{
    if (GetAsyncKeyState(key) & 0x0001) return true;
    return false;
}

키가 눌려있다가 떼어질 때를 측정하는 함수이다.
0x0001과 &연산을 통해 0x0001과 다른 값이 나오면 모두 0이 되므로
0x0001만 통과할 수 있다.

생각

눌렀을 때를 체크할 때는 0x8000과 비교하면 되고, 떼었을 때 비교할 때는 ( isToggleKey함수 )
0x0001과 비교한다는 게 처음 구현할 때 좀 긴가민가했다.

0x8000과 &연산을 하면 0x8001이든 0x8000이든 상위 비트에서 1이 나오므로
두 16진수 값이 다 통과하는데

0x0001과 &연산을 하면 0x0000도 0이 나오므로 0x0001만 통과시킨다.

0x0000과 &연산하면 당연한 말이지만 모든게 0으로 나온다

profile
코딩 창고!

0개의 댓글