HOWTO · C++

C++를 사용하여 Windows에서 키 누르기 감지

키 상태를 확인하고 낮은 수준의 키보드 이벤트를 처리하는 Windows C++ API를 비교합니다.

이 페이지의 내용

Windows C++ 애플리케이션에서 키보드 입력을 감지하려면 메시지를 처리할 때는 GetKeyState, 현재 키 상태를 폴링할 때는 GetAsyncKeyState, 낮은 수준의 키보드 이벤트가 필요할 때는 WH_KEYBOARD_LL 훅을 선택합니다. 각 방법은 서로 다른 작업에 적합합니다. 텍스트 입력과 바로 가기는 보통 창 메시지로 처리하고, 폴링과 훅은 더 제한된 모니터링 용도에 사용합니다.

Windows 애플리케이션의 키보드 입력

키보드 입력은 텍스트, Ctrl+O 같은 애플리케이션 바로 가기, 또는 Alt+Tab 같은 시스템 명령을 나타낼 수 있습니다. 키 상태 API는 키의 상태를 알려 주지만, 키보드 입력을 텍스트로 변환하지는 않습니다. 텍스트를 입력받으려면 창의 일반적인 문자 메시지 처리에 맡겨 키보드 레이아웃과 수정 키가 반영되도록 하세요.

가상 키 코드

스캔 코드는 키보드가 보고하는 물리적인 키 위치를 식별합니다. Windows는 키보드 입력을 가상 키 코드로 매핑하며, API는 이 코드로 키의 의미를 식별합니다. 문자와 숫자는 해당 문자의 값을 사용하는 가상 키 코드에 대응합니다. A부터 Z까지는 0x41부터 0x5A까지, 0부터 9까지는 0x30부터 0x39까지입니다. 다른 키에는 WinUser.h에 이름이 지정된 상수가 있습니다.

가상 키 상수 키
VK_SPACE 스페이스바
VK_SHIFT Shift
VK_ESCAPE Escape
VK_LEFT 왼쪽 화살표
VK_F1 F1

전체 목록은 Microsoft의 가상 키 코드 참조를 확인하세요.

GetKeyState로 메시지 큐의 상태 확인하기

GetKeyState는 호출 스레드의 메시지 큐와 연결된 키 상태를 반환합니다. 메시지를 처리하는 중에는 해당 입력 처리 흐름에 맞는 상태를 확인할 수 있습니다. 임의의 시점에 물리 키보드 상태를 가져오는 일반적인 스냅샷 함수는 아닙니다. 최상위 비트는 키가 눌려 있는지를 나타냅니다. 예를 들어 창 프로시저에서 키 누름 메시지를 처리할 때 if (message == WM_KEYDOWN && (GetKeyState(VK_SHIFT) & 0x8000)) { /* handle Shift+key */ }를 확인하면 Shift 키가 눌려 있는지 검사할 수 있습니다. 이 검사는 반복문을 계속 도는 대신 메시지 처리기 안에서 수행하세요.

게임에서 스페이스바 동작을 처리할 때도 이 차이가 중요합니다. 이미 창 메시지를 처리하는 애플리케이션이라면 해당 메시지로 입력을 처리할 수 있습니다. 적절한 게임 입력 설계는 입력 프레임워크와 업데이트 루프에 따라 달라지므로, 폴링이 항상 필요한 것은 아닙니다.

GetAsyncKeyState로 키 폴링하기

호출 스레드의 메시지 큐 상태에 의존하지 않고 반복문에서 현재 키가 눌려 있는지 확인해야 한다면 GetAsyncKeyState를 사용하세요. 키가 눌려 있는 동안 최상위 비트가 설정됩니다. 신뢰할 수 있는 감지를 위해 하위 비트인 “이전 호출 이후 눌림” 상태에 의존하지 마세요. 다른 애플리케이션이 그 상태를 소비할 수 있습니다. 폴링 주기를 조절하고 연속된 상태를 비교해 눌림 전환을 한 번만 보고하세요.

아래 이식 가능한 예제는 짧은 키 상태 값의 순서로 전환 로직을 보여 줍니다. Windows 폴링 루프에서는 각 값을 GetAsyncKeyState(VK_SPACE)에서 가져와 최상위 비트를 확인하고, 루프 주기를 조절하며, 별도로 Escape 키를 확인해 종료하세요.

#include <array>
#include <iostream>

int main() {
    bool spaceWasDown = false;
    const std::array<bool, 4> spaceStates{false, true, true, false};

    for (bool spaceIsDown : spaceStates) {
        if (spaceIsDown && !spaceWasDown) {
            std::cout << "Space pressed\n";
        }
        spaceWasDown = spaceIsDown;
    }
    return 0;
}
Space pressed

SetWindowsHookEx로 낮은 수준의 키보드 이벤트 처리하기

WH_KEYBOARD_LL 훅은 설치된 데스크톱의 낮은 수준 키보드 이벤트를 받습니다. 콜백은 훅을 설치한 프로세스의 컨텍스트에서 실행되므로 해당 스레드가 메시지 루프를 유지해야 합니다. 훅은 시스템 입력 처리에 영향을 주므로 이벤트 수준 모니터링이 필요한 경우에만 사용하세요. 콜백은 짧게 유지하고, 처리하지 않는 이벤트는 CallNextHookEx로 다음 훅에 전달합니다.

Windows 구현에서는 SetWindowsHookExW(WH_KEYBOARD_LL, ...)로 콜백을 설치하고, 메시지 루프에 들어가기 전에 반환된 훅 핸들이 null이 아닌지 확인하세요. 콜백에서는 code >= 0이고 메시지가 WM_KEYDOWN 또는 WM_SYSKEYDOWN일 때 KBDLLHOOKSTRUCT::vkCode를 살펴 관심 키인지 확인합니다. 애플리케이션이 의도적으로 억제하지 않는 이벤트에는 CallNextHookEx를 호출하세요. 설치 스레드는 GetMessageW 루프를 유지하고, 루프가 끝난 뒤 UnhookWindowsHookEx를 호출해야 합니다. 정상적으로 루프가 끝난 경우와 GetMessageW 오류가 발생한 경우 모두 훅을 정리하세요. 이 Windows API 개요는 플랫폼에 종속되며 이식 가능한 실행 예제가 아닙니다. 낮은 수준 훅 콜백은 신속히 반환해야 합니다. 제한 시간을 초과하면 Windows가 훅을 제거할 수 있습니다. 애플리케이션이 이벤트를 의도적으로 억제해야 하는 경우가 아니라면 다음 훅의 결과를 반환하세요.

적절한 키 감지 방법 선택하기

창 메시지를 처리하면서 메시지 큐와 연결된 상태를 확인하려면 GetKeyState를 사용하세요. 키가 현재 눌려 있는지 주기를 조절해 폴링하려면 GetAsyncKeyState를 사용합니다. 낮은 수준의 이벤트 모니터링이 필요하고 콜백과 메시지 루프를 올바르게 유지할 수 있을 때만 SetWindowsHookEx와 WH_KEYBOARD_LL을 선택하세요. 게임에서 스페이스바 동작을 처리한다면 먼저 게임의 기존 입력 시스템을 살펴보고, 그 이벤트 또는 업데이트 모델에 맞는 API를 사용하세요.