18. ReadKeyStroke 함수로 사용자 입력 처리
이번 장에서는 사용자의 입력을 처리할 수 있는 애플리케이션을 만든다.
사용자의 입력을 처리하기 위해서는 ReadKeyStroke
가 필요하다.
EFI_SIMPLE_TEXT_INPUT_PROTOCOL.ReadKeyStroke()
Summary:
Reads the next keystroke from the input device.
Prototype:
typedef
EFI_STATUS
(EFIAPI *EFI_INPUT_READ_KEY) (
IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
OUT EFI_INPUT_KEY *Key
);
Parameters:
This A pointer to the EFI_SIMPLE_TEXT_INPUT_PROTOCOL instance.
Key A pointer to a buffer that is filled in with the keystroke information
for the key that was pressed.
Description:
The ReadKeyStroke() function reads the next keystroke from the input device.
Status Codes Returned:
EFI_SUCCESS The keystroke information was returned.
EFI_NOT_READY There was no keystroke data available.
EFI_DEVICE_ERROR The keystroke information was not returned due to hardware errors.
EFI_INPUT_KEY 함수는 아래와 같이 정의된다.
typedef struct {
UINT16 ScanCode;
CHAR16 UnicodeChar;
} EFI_INPUT_KEY;
간단한 애플리케이션을 만들어 본다. 아래 코드는 ReadKeyStroke
를 사용해 사용자의 키 입력을 받는 간단한 프로그램이다. 애플리케이션은 무한 반복으로 사용자가 k
를 입력하면 Correct!
라는 문자열을 출력하고 종료되고 다른 키를 입력할 경우 Wrong!
을 출력하며 프로그램 종료는 q
를 입력하여 종료할 수 있다.
애플리케이션을 만드는 방법은 설명하지 않고 아래 코드에서는 UefiMain
을 사용하기 때문에 HelloWorld
애플리케이션의 *.inf
파일을 수정하여 사용한다.
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiLib.h>
EFI_STATUS
EFIAPI
UefiMain (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
UINTN Index;
EFI_INPUT_KEY Key;
Print(L"Try to guess the secret symbol!\n");
Print(L"To quit press 'q'\n");
while(TRUE) {
gBS->WaitForEvent(1, &(gST->ConIn->WaitForKey), &Index);
gST->ConIn->ReadKeyStroke(gST->ConIn, &Key);
Print(L"ScanCode = %04x, UnicodeChar = %04x (%c)\n", Key.ScanCode, Key.UnicodeChar, Key.UnicodeChar);
if (Key.UnicodeChar == 'k') {
Print(L"Correct!\n");
break;
} else if (Key.UnicodeChar == 'q') {
Print(L"Bye!\n");
break;
} else {
Print(L"Wrong!\n");
}
}
gST->ConIn->Reset(gST->ConIn, FALSE);
return EFI_SUCCESS;
}

QEMU에서 그래픽 옵션이 있는 경우와 없는 경우의 키 입력 차이
QEMU를 -nographic
옵션을 사용해 실행한다.
qemu-system-x86_64 \
-drive if=pflash,format=raw,file=Build/OvmfX64/RELEASE_GCC5/FV/OVMF.fd \
-drive format=raw,file=fat:rw:~/UEFI_disk \
-nographic
InteractiveApp.efi
을 실행해서 PageUp
키를 입력하면 아래와 같이 출력이 나타난다.
ScanCode = 0017, UnicodeChar = 0000 ( )
Wrong!
ScanCode = 0000, UnicodeChar = 005B ([)
Wrong!
ScanCode = 0000, UnicodeChar = 0035 (5)
Wrong!
ScanCode = 0000, UnicodeChar = 007E (~)
Wrong!
SimpleTextIn
프로토콜의 UEFI 스펙과 EDKII 헤더에 따르면 PageUp
키는 이스케이프 스캔 코드로 시작하는 4개의 기호가 아닌 다른 스캔 코드로 시작되어야 한다.
(https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Protocol/SimpleTextIn.h)
#define SCAN_PAGE_UP 0x0009
...
#define SCAN_ESC 0x0017
이 문제는 QEMU의 -nographic
옵션으로 인해 발생한다. QEMU를 사용하면 모든 특수 키를 변환하여 콘솔 터미널에서 발생하는 것처럼 시퀀스를 이스케이프한다.
정상적인 키 입력을 보기 위해서는 QEMU를 그래픽 모드로 실행한다.
qemu-system-x86_64 \
-drive if=pflash,format=raw,file=Build/OvmfX64/RELEASE_GCC5/FV/OVMF.fd \
-drive format=raw,file=fat:rw:~/UEFI_disk
시스템에서 기본 그래픽을 지원하지 않는 경우 VNC 옵션으로 QEMU를 실행할 수 있다. QEMU는 제공한 포트에 VNC 서버를 생성하며, VNC 클라이언트 앱을 통해 해당 포트에 연결할 수 있다. ex) VNC 뷰어(https://www.realvnc.com/en/connect/download/viewer/)
아래 명령은 127.0.0.1:1
주소로 VNC 서버를 생성한다.
qemu-system-x86_64 \
-drive if=pflash,format=raw,file=Build/OvmfX64/RELEASE_GCC5/FV/OVMF.fd \
-drive format=raw,file=fat:rw:~/UEFI_disk \
-vnc :1
그래픽 모드로 실행된 QEMU에서 Interactive.efi
를 실행해서 PageUp
키를 입력하면 정상적으로 입력받는 것을 볼 수 있다.

Last updated