끝나지 않는 프로그래밍 일기

[API 탐방기]


키의 상태를 확인하는

GetAsyncKeyState, GetKeyState




우선은 GetAsyncKeyState API에 대해 알아보기 전에 API의 원형을 먼저 살펴봅시다!

SHORT GetAsyncKeyState(int vKey)

반환값은 SHORT형이고, 첫번째 인수로는 가상 키코드가 오며, 우리가 만약 VK_UP을 넘겨주면, 방향키 중 위를 가르키는 키가 눌려있나 눌려있지 않나 확인할 수 있습니다. (키가 눌려진 상태에서는 최상위 비트(0x8000)이 1이 되며,  처음 입력되었을 때는 0x8001 비트가 1이 됩니다.)

(가상 키코드 목록을 보고싶으신 분들은 아래의 MSDN를 방문하셔서 참고하세요.)

MSDN: http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx


GetAsyncKeyState의 반환값은 아래와같이 4가지로 나뉩니다. 


반환값

설명 

0 (0x0000)

이전에 누른 적이 없고 호출 시점에서 안눌린 상태

0x8000 

이전에 누른 적이 없고 호출 시점에서 눌린 상태

0x8001 

이전에 누른 적이 있고 호출 시점에서 눌린 상태

1 (0x0001)

이전에 누른 적이 있고 호출 시점에서 안눌린 상태


이전에 누른 적이 없고 호출 시점에서 눌린 상태, 즉 키가 눌려진 시점에서 0x8000을 반환합니다. 만약 이전에도 누른 적이 있고 호출 시점에서도 눌렸으면 0x8001을 반환합니다. 이전에 키를 눌렀으면 0x0001을 반환하고, 눌리지 않았다면 0x0000을 반환합니다. 혹시, GetAsyncKeyState(VK_UP) & 0x8000 이런 코드를 보신적이 있으신가요? 0x8000과 GetAsyncKeyState 반환값을 AND 연산하는 이유는 정확한 시점에서 키의 상태를 확인하기 위함입니다. 만약에 키를 눌러 GetAsyncKeyState 함수가 0x8000을 반환한다면 이를 0x8000으로 AND 연산하여 키가 눌렸을때는 0x8000이 나옵니다. 그러나 눌려진 적이 있으면 GetAsyncKeyState 함수는 0x0001을 반환한다고 했었습니다. 0x0001에다 0x8000을 AND 연산하게되면 0이 나오게 됩니다. (만약에 AND 연산하지 않았을 경우에는 눌러진 적이 있는 상태도 참이 되어 동작을 수행할 것입니다.)


이제 GetAsyncKeyState API 함수를 이용해서, 방향키(상하좌우)가 입력됨에 따라 그 방향으로 @가 그려지는 프로그램을 간단히 만들어보도록 합시다.

#include <stdio.h>
#include <windows.h>
#include <conio.h>

void gotoxy(int x, int y)
{
     COORD Cur;
     Cur.X=x;
     Cur.Y=y;
     SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),Cur);
}

int main(void)
{
    int x=0;
    int y=0;

    while(true) {
        gotoxy(x,y);
        putch('@');

        if(GetAsyncKeyState(VK_UP) & 0x8000) y--;
        if(GetAsyncKeyState(VK_DOWN) & 0x8000) y++;
        if(GetAsyncKeyState(VK_LEFT) & 0x8000) x--;
        if(GetAsyncKeyState(VK_RIGHT) & 0x8000) x++;
        Sleep(50);
    }
	return 0;
}

결과:


컴파일 후 프로그램을 실행시키시면 방향키 입력에 따라 @가 움직입니다. 이번에는 GetKeyState API 함수를 살펴보도록 합시다. 다음은 GetKeyState API 함수의 원형입니다.

SHORT GetKeyState(int nVirtKey)

GetKeyState도 반환되는 값은 SHORT형이며, 첫번째 인수도 가상 키코드가 옵니다. "그럼, GetKeyState와 GetAsyncKeyState은 똑같은게 아닌가요?"라는 궁금증이 생겨나시는 분들도 계실텐데, GetKeyState는 메세지 큐에 저장된 메시지에 따라 반환되는 값이 다릅니다. 만약에 우리가 A 키를 눌렀다는 메세지가 메세지 큐에 남아 처리되지 않을때 있을때, 키가 눌렸다고 출력될 것입니다. 반대로 GetAsyncKeyState는 메세지 큐와 상관없이 입력되는 순간 즉각적으로 읽어들여 동작합니다. GetKeyState 함수는 해당 키가 눌렸으면 음수값(0xffffff80, 0xffffff81)을 반환하고, 아닐 경우에는 0을 반환합니다. 이것 역시 이전에 누른적이 있고, 호출 시점에서는 누르지 않았다면 계속 1로 남습니다.


이번에는 GetKeyState API 함수를 이용해서 @를 움직이는 프로그램을 만들어 보도록 합시다.

#include <stdio.h>
#include <windows.h>
#include <conio.h>

void gotoxy(int x, int y)
{
     COORD Cur;
     Cur.X=x;
     Cur.Y=y;
     SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),Cur);
}

int main(void)
{
    int x=0;
    int y=0;

    while(true) {
        gotoxy(x,y);
        putch('@');

        if(GetKeyState(VK_UP) < 0) y--;
        if(GetKeyState(VK_DOWN) < 0) y++;
        if(GetKeyState(VK_LEFT) < 0) x--;
        if(GetKeyState(VK_RIGHT) < 0) x++;
        Sleep(50);
    }
	return 0;
}

결과: