GetAsyncKeyState() 함수와 GetKeyState() 함수는 키보드의 키가 눌렸는지를 체크하는 함수들이다.
GetAsyncKeyState() 함수는 비 동기(Asynchronism)로 처리한다. 즉, 호출된 시점에서 키 상태를 조사하여, 메시지 큐를 거치지 않고 바로 리턴을 해 주므로 키 입력을 바로 처리해 줄 수가 있다.
GetKeyState() 함수는 호출된 시점에서 메시지 큐를 거치며, 메시지 발생 후의 상태를 리턴하게 되므로, 키보드 메시지 처리 루틴내에서 사용해야 한다. 게임과 같이 키 입력에 바로 반응을 해 줘야 하는 프로그램에서는 GetAsyncKeyState()함수를 사용하는 편이 좋다.
GetAsyncKeyState() 함수의 사용은
[code]if ( GetAsyncKeyState(VK_RETURN) ) // enter 키가 눌렀다면
{ // 처리 }
[/code]
이렇게 직접 쓰여도 되지만, 아래와 같은 형식으로 많이 사용한다.
[code]if ( GetAsyncKeyState(VK_RETURN) & 0x8000 ) // enter 키가 눌렀다면
{ // 처리 }
[/code]
왜? 0x8000으로 AND 연산을 통하여 키 눌림을 체크할까?
GetAsyncKeyState() 함수는, 키가 눌려진 시점에서 0x8000 값을 리턴해 준다. 그리고 함수가 호출되었을때 키가 눌려져 있었다고 0x0001 값을 리턴해 준다. 즉, 0x8000 은 현재 키가 눌려진 상태를 뜻하고, 0x0001은 지난번 호출과 이번 호출 사이에 키가 눌려진 적이 있었다 라는 것을 뜻한다.
예를 들어, 아래 방향키가 게임내에서 비행기도 움직이고, 메뉴에서 위아래 선택에도 쓰인다고 가정해 보자. AND 연산없이 그냥 사용하여 비행기를 움직이다가, F1키를 눌러 메뉴를 띄웠을 때 커서가 자동으로 아래쪽으로 내려갈 위험성이 생긴다. 왜냐하면, F1키를 누르는 시점에서 - if ( GetAsyncKeyState(VK_F1) ) - VK_DOWN은 눌리지 않았지만 리턴값이 0x0001이 되어 if ( GetAsyncKeyState(VK_F1) ) 전에 호출된 if ( GetAsyncKeyState(VK_DOWN) ) 이 참이 되기 때문이다. 하지만, 0x8000으로 AND 연산을 하면,
1000 0000 0000 0000 (키눌림 0x8000) 0000 0000 0000 0001 (눌러진 적이 있음 0x0001)
& 1000 0000 0000 0000 (AND 연산 0x8000) & 1000 0000 0000 0000 (AND 연산 0x8000)
--------------------------------------- -----------------------------------------------
1000 0000 0000 0000 (키눌림 0x8000) 0000 0000 0000 0000 (키 안 눌림)
위와 같은 결과가 되어, 정확한 시점에서 키가 눌러진 상태를 체크할 수가 있는 것이다. 즉, 정확한 시점에서 키눌림 상태를 체크하기 위해서 0x8000으로 AND 연산을 해 주는 것이다.
GetKeyState() 함수의 사용 예
[code]// 키보드 메시지 처리루틴이 있는 콜백 함수 내에서...
// char szTemp[256];
case WM_KEYDOWN:
// Ctrl + 왼쪽 화살표키가 눌렸는지 조사
if ( wParam == VK_LEFT ) && (GetKeyState(VK_CONTROL) < 0) )
{
wsprintf(szTemp, "Ctrl키와 왼쪽 화살표 키가 눌림");
}
return 0;
[/code]
GetKeyState() 함수의 리턴값이 음수일 경우는 해당키가 눌린 상태이고, 음수가 아닐 경우는 해당키가 눌리지 않은 상태이다.
GetAsyncKeyState와 GetKeyState는 둘 다 키의 상태값을 알아내는 함수이다. 하지만 이 둘 사이에는 차이점이 있는데 다음과 같은 것들이다.
GetAsyncKeyState는 "키가 눌렸는가?"와 "언제부터 눌렸는가?"를 알아낼 때 사용한다. 키가 눌렸을 때 GetAsyncKeyState는 0x8000 bit가 1이된다. 그리고, 이전에 GetAsyncKeyState가 호출되었을 때부터 이번에 GetAsyncKeyState가 호출될 때까지 중간에 끊기지 않고 계속 눌려있는 상태라면 0x0001 bit는 0이 되고, 그렇지 않은 경우는 1이 된다.
1) CTRL 키가 눌린 상태이다.
2) GetAsyncKeyState(VK_CONTROL)를 호출하면 0x8001을 리턴한다.
3) GetAsycnKeyState(VK_CONTROL)을 한번 더 호출하면 0x8000을 리턴한다.
1) CTRL 키가 눌린 상태이다.
2) GetAsyncKeyState(VK_CONTROL)를 호출하면 0x8001을 리턴한다.
3) CTRL 키를 뗬다가 다시 눌렸다.
4) GetAsycnKeyState(VK_CONTROL)을 한번 더 호출해도 0x8001을 리턴한다.
키가 눌리지 않았을 때, GetAsyncKeyState는 항상 0x0000을 리턴한다.
GetKeyState는 "키가 눌렸는가?"와 "키의 토글상태가 무엇인가?"를 알아낼 때 사용한다. 키의 토글 상태란 Caps Lock, Num Lock의 키가 한번 누르면 불이 켜지고 다시 한번 누르면 불이 꺼지는 것을 생각하면 이해가 빠를것 같다.
키보드 상에는 위에서 말한 키만 불이 켜졌다 꺼졌다하면서 토글상태를 알려주고 있지만 다른 키들도 토글 상태를 갖고 있으며 단지 우리 눈에 보이지 않을 뿐이다. 이 토글 상태를 GetKeyState 함수로 알아낼 수 있다.
GetKeyState의 리턴값은 SHORT가 아닌 CHAR로 생각된다.
리턴값을 살펴보면 0xffffff81, 0xffffff80, 0x00000001, 0x00000000이 되는 것을 볼 수 있기 때문이다.
참고로 같은 SHORT형을 리턴하는 GetAsyncKeyState의 리턴값은 다음과 같다.
0xffff8001, 0xffff8000, 0x00000000 셋 중 하나
** MSDN에는 현재 하드웨어(키보드)의 상태값을 알아내길 원한다면 GetAsyncKeyState를 사용하라고 나와있다. GetKeyState는 메시지큐에 저장된 메시지에 따라 값이 변하기 때문이다.
메시지큐에 처리되지 않은 CTRL키가 눌렸다는 메시지가 쌓여있을 때,사용자가 CTRL키를 더이상 누르지 않고 있다면. GetAsyncKeyState는 "키가 눌리지 않았음"을, GetKeyState는 "키가 눌렸음"을 리턴할 것이다.
출처 : http://www.silverwolf.co.kr/4842