다음을 통해 공유


키보드 입력(Win32 및 C++ 시작)

키보드는 다음을 포함하여 여러 가지 유형의 입력에 사용됩니다.

  • 문자 입력. 사용자가 문서 또는 입력란에 입력하는 텍스트입니다.
  • 바로 가기 키. 애플리케이션 기능을 호출하는 키 입력입니다. 예를 들어 Ctrl+O를 사용하여 파일을 엽니다.
  • 시스템 명령. 시스템 기능을 호출하는 키 입력입니다. 예를 들어 Alt+Tab을 사용하여 창을 전환합니다.

키보드 입력에 대해 생각할 때 키 입력이 문자와 동일하지 않다는 점을 기억해야 합니다. 예를 들어 A 키를 누르면 다음과 같은 문자가 표시될 수 있습니다.

  • a
  • A
  • á(키보드가 분음 부호 결합을 지원하는 경우)

또한 Alt 키를 누른 상태에서 A 키를 누르면 Alt+A가 생성되어 시스템은 문자로 처리하지 않고 시스템 명령으로 처리합니다.

키 코드

키를 누르면 하드웨어가 스캔 코드를 생성합니다. 스캔 코드는 키보드마다 다르며 키 놓음 이벤트와 키 누름 이벤트에 대해 별도의 스캔 코드가 있습니다. 스캔 코드는 거의 신경 쓰지 않을 것입니다. 키보드 드라이버는 스캔 코드를 가상 키 코드로 변환합니다. 가상 키 코드는 디바이스 독립적입니다. 키보드에서 A 키를 누르면 동일한 가상 키 코드가 생성됩니다.

일반적으로 가상 키 코드는 ASCII 코드 또는 다른 문자 인코딩 표준에 해당하지 않습니다. 동일한 키가 서로 다른 문자(a, A, á)를 생성할 수 있고 기능 키와 같은 일부 키는 문자에 해당하지 않기 때문에 생각해 보면 분명합니다.

즉, 다음 가상 키 코드는 ASCII 코드에 매핑됩니다.

  • 키 0~9 = ASCII ‘0’~‘9’(0x30~0x39)
  • 키 A~Z keys = ASCII ‘A’~‘Z’(0x41~0x5A)

앞서 설명한 이유로 인해 가상 키 코드는 문자로 생각해서는 안 됩니다. 이런 면에서 이 매핑은 아쉬운 점이 있습니다.

헤더 파일 WinUser.h는 대부분의 가상 키 코드에 대한 상수를 정의합니다. 예를 들어 왼쪽 화살표 키의 가상 키 코드는 VK_LEFT(0x25)입니다. 가상 키 코드의 전체 목록은 가상 키 코드를 참조하세요. ASCII 값과 일치하는 가상 키 코드에 대해서는 상수가 정의되지 않습니다. 예를 들어 A 키의 가상 키 코드는 0x41이지만 VK_A라는 상수가 없습니다. 대신 숫자 값만 사용합니다.

키 누름 및 키 놓음 메시지

키를 누르면 키보드 포커스가 있는 창이 다음 메시지 중 하나를 받습니다.

WM_SYSKEYDOWN 메시지는 시스템 명령을 호출하는 키 입력인 시스템 키를 나타냅니다. 시스템 키는 다음과 같은 두 가지 유형이 있습니다.

  • Alt+모든 키
  • F10

F10 키는 창의 메뉴 모음을 활성화합니다. 다양한 Alt 키 조합은 시스템 명령을 호출합니다. 예를 들어 Alt+Tab을 누르면 새 창으로 전환됩니다. 또한 창에 메뉴가 있는 경우 Alt 키를 사용하여 메뉴 항목을 활성화할 수 있습니다. 일부 Alt 키 조합은 아무 것도 수행하지 않습니다.

다른 모든 키 입력은 비시스템 키로 간주되며 WM_KEYDOWN 메시지를 생성합니다. 여기에는 F10 키 이외의 기능 키가 포함됩니다.

키를 놓으면 시스템이 해당 키 놓음 메시지를 보냅니다.

키보드의 반복 기능을 시작할 수 있을 만큼 길게 키를 누르고 있으면 시스템은 여러 키 누름 메시지를 보내고 그다음에 단일 키 놓음 메시지를 보냅니다.

지금까지 설명한 네 개의 키보드 메시지에서 wParam 매개 변수에는 키의 가상 키 코드가 포함됩니다. lParam 매개 변수에는 32비트로 압축된 몇 가지 기타 정보가 포함됩니다. 일반적으로 lParam의 정보는 필요하지 않습니다. 유용할 수 있는 하나의 플래그는 비트 30, “이전 키 상태” 플래그이며 반복된 키 누름 메시지에 대해 1로 설정됩니다.

이름에서 알 수 있듯이 시스템 키 입력은 주로 운영 체제에서 사용하기 위한 것입니다. WM_SYSKEYDOWN 메시지를 가로채면 이후에 DefWindowProc을 호출합니다. 그러지 않으면 운영 체제가 명령을 처리하지 못하도록 차단합니다.

문자 메시지

키 입력은 모듈 1에서 처음 살펴본 TranslateMessage 함수에 의해 문자로 변환됩니다. 이 함수는 키 누름 메시지를 검사하고 문자로 변환합니다. 생성되는 각 문자에 대해 TranslateMessage 함수는 WM_CHAR 또는 WM_SYSCHAR 메시지를 창의 메시지 큐에 넣습니다. 메시지의 wParam 매개 변수에는 UTF-16 문자가 포함됩니다.

짐작할 수 있듯이, WM_CHAR 메시지는 WM_KEYDOWN 메시지에서 생성되고 WM_SYSCHAR 메시지는 WM_SYSKEYDOWN 메시지에서 생성됩니다. 예를 들어 사용자가 Shift 키를 누르고 그다음에 A 키를 누른다고 가정합니다. 표준 키보드 레이아웃을 가정하면 다음과 같은 메시지 시퀀스가 표시됩니다.

WM_KEYDOWN: Shift
WM_KEYDOWN: A
WM_CHAR: ‘A’

반면 Alt+P 조합은 다음 메시지를 생성합니다.

WM_SYSKEYDOWN: VK_MENU
WM_SYSKEYDOWN: 0x50
WM_SYSCHAR: ‘p’
WM_SYSKEYUP: 0x50
WM_KEYUP: VK_MENU

기록상의 이유로 Alt 키의 가상 키 코드의 이름은 VK_MENU가 됩니다.

WM_SYSCHAR 메시지는 시스템 문자를 나타냅니다. WM_SYSKEYDOWN처럼 일반적으로 이 메시지를 DefWindowProc에 직접 전달해야 합니다. 그러지 않으면 표준 시스템 명령을 방해할 수 있습니다. 특히 WM_SYSCHAR를 사용자가 입력한 텍스트로 처리하지 마세요.

WM_CHAR 메시지는 일반적으로 문자 입력으로 생각하는 것입니다. 문자의 데이터 형식은 UTF-16 유니코드 문자를 나타내는 wchar_t입니다. 문자 입력에는 특히 미국 외부에서 일반적으로 사용되는 키보드 레이아웃을 사용하는 ASCII 범위 밖의 문자가 포함될 수 있습니다. 지역별 키보드를 설치한 다음 화상 키보드 기능을 사용하여 다른 키보드 레이아웃을 사용할 수 있습니다.

사용자는 IME(입력기)를 설치하여 표준 키보드로 일본어 문자와 같은 복잡한 스크립트를 입력할 수도 있습니다. 예를 들어 일본어 IME를 사용하여 가타카나 문자 カ(ka)를 입력하면 다음 메시지가 표시될 수 있습니다.

WM_KEYDOWN: VK_PROCESSKEY(IME PROCESS 키)
WM_KEYUP: 0x4B
WM_KEYDOWN: VK_PROCESSKEY
WM_KEYUP: 0x41
WM_KEYDOWN: VK_PROCESSKEY
WM_CHAR: カ
WM_KEYUP: VK_RETURN

일부 Ctrl 키 조합은 ASCII 제어 문자로 변환됩니다. 예를 들어 Ctrl+A는 ASCII ctrl-A(SOH) 문자(ASCII 값 0x01)로 변환됩니다. 텍스트 입력의 경우 일반적으로 제어 문자를 필터링해야 합니다. 또한 WM_CHAR를 사용하여 바로 가기 키를 구현하지 마세요. 대신 WM_KEYDOWN 메시지를 사용하거나, 오히려 액셀러레이터 키 테이블을 사용하는 것이 좋습니다. 액셀러레이터 키 테이블은 다음 항목 액셀러레이터 키 테이블에서 설명합니다.

다음 코드는 디버거의 주요 키보드 메시지를 표시합니다. 다양한 키 입력 조합을 사용해 보고 어떤 메시지가 생성되는지 확인하세요.

참고

wchar.h를 포함해야 합니다. 그러지 않으면 swprintf_s가 정의되지 않습니다.

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    wchar_t msg[32];
    switch (uMsg)
    {
    case WM_SYSKEYDOWN:
        swprintf_s(msg, L"WM_SYSKEYDOWN: 0x%x\n", wParam);
        OutputDebugString(msg);
        break;

    case WM_SYSCHAR:
        swprintf_s(msg, L"WM_SYSCHAR: %c\n", (wchar_t)wParam);
        OutputDebugString(msg);
        break;

    case WM_SYSKEYUP:
        swprintf_s(msg, L"WM_SYSKEYUP: 0x%x\n", wParam);
        OutputDebugString(msg);
        break;

    case WM_KEYDOWN:
        swprintf_s(msg, L"WM_KEYDOWN: 0x%x\n", wParam);
        OutputDebugString(msg);
        break;

    case WM_KEYUP:
        swprintf_s(msg, L"WM_KEYUP: 0x%x\n", wParam);
        OutputDebugString(msg);
        break;

    case WM_CHAR:
        swprintf_s(msg, L"WM_CHAR: %c\n", (wchar_t)wParam);
        OutputDebugString(msg);
        break;

    /* Handle other messages (not shown) */

    }
    return DefWindowProc(m_hwnd, uMsg, wParam, lParam);
}

기타 키보드 메시지

일부 다른 키보드 메시지는 대부분의 애플리케이션에서 무시해도 됩니다.

  • WM_DEADCHAR 메시지는 분음 부호와 같은 결합 키에 대해 전송됩니다. 예를 들어 스페인어 키보드에서 악센트(')를 입력하고 그다음에 E를 입력하면 문자 é가 생성됩니다. 악센트 문자에 대해 WM_DEADCHAR가 전송됩니다.
  • WM_UNICHAR 메시지는 사용되지 않습니다. 이 메시지를 통해 ANSI 프로그램에서 유니코드 문자 입력을 받을 수 있습니다.
  • WM_IME_CHAR 문자는 IME가 키 입력 시퀀스를 문자로 변환할 때 전송됩니다. 일반적인 WM_CHAR 메시지와 함께 전송됩니다.

키보드 상태

키보드 메시지는 이벤트 기반입니다. 즉, 키 누름과 같은 흥미로운 일이 발생하면 메시지가 표시되고 메시지는 방금 발생한 일을 알려 줍니다. 그러나 GetKeyState 함수를 호출하여 언제든지 키의 상태를 테스트할 수도 있습니다.

예를 들어 마우스 왼쪽 클릭+Alt 키 조합을 감지하는 방법을 생각해 보겠습니다. 키 입력 메시지를 수신 대기하고 플래그를 저장하여 Alt 키의 상태를 추적할 수 있지만 GetKeyState를 사용하면 수고를 덜 수 있습니다. WM_LBUTTONDOWN 메시지가 표시되면 다음과 같이 GetKeyState를 호출하면 됩니다.

if (GetKeyState(VK_MENU) & 0x8000)
{
    // ALT key is down.
}

GetKeyState 메시지는 가상 키 코드를 입력으로 사용하여 비트 플래그 세트(실제로는 단 두 개의 플래그)를 반환합니다. 0x8000 값에는 현재 키가 눌려져 있는지 여부를 테스트하는 비트 플래그가 포함되어 있습니다.

대부분의 키보드에는 왼쪽과 오른쪽 두 개의 Alt 키가 있습니다. 위의 예제에서는 둘 중 하나가 눌려져 있는지 여부를 테스트합니다. GetKeyState를 사용하여 Alt, Shift 또는 Ctrl 키의 왼쪽과 오른쪽 인스턴스를 구분할 수도 있습니다. 예를 들어 다음 코드는 오른쪽 Alt 키가 눌려져 있는지 테스트합니다.

if (GetKeyState(VK_RMENU) & 0x8000)
{
    // Right ALT key is down.
}

GetKeyState 함수는 가상 키보드 상태를 보고하기 때문에 흥미롭습니다. 이 가상 상태는 메시지 큐의 내용을 기반으로 하며 큐에서 메시지를 제거하면 업데이트됩니다. 프로그램이 창 메시지를 처리할 때 GetKeyState는 각 메시지가 큐에 있는 시점의 키보드 스냅샷을 제공합니다. 예를 들어 큐의 마지막 메시지가 WM_LBUTTONDOWN인 경우 GetKeyState는 사용자가 마우스 단추를 클릭한 순간에 키보드 상태를 보고합니다.

GetKeyState는 메시지 큐를 기반으로 하기 때문에 다른 프로그램으로 전송된 키보드 입력도 무시합니다. 사용자가 다른 프로그램으로 전환하면 해당 프로그램으로 전송되는 모든 키 누름이 GetKeyState에서 무시됩니다. 키보드의 즉각적인 물리적 상태를 정말 알고 싶다면 GetAsyncKeyState 함수가 있습니다. 그러나 대부분의 UI 코드에서 올바른 함수는 GetKeyState입니다.

다음

액셀러레이터 키 테이블