4. 读取键盘输入
任务目标
本案例实现一个UEFI应用程序:通过标准输入协议EFI_SIMPLE_TEXT_INPUT_PROTOCOL读取键盘按键,并将按键字符回显到屏幕上,按ESC键退出程序。
环境与依赖
- EDK2开发环境(已配置好
OVMF或真实UEFI固件运行环境) - 使用EDK2标准库:
UefiLib、UefiApplicationEntryPoint
核心实现
在UefiMain中获取ConIn(简单文本输入协议)和ConOut(简单文本输出协议)句柄。循环调用ReadKeyStroke读取按键,若按键为可打印ASCII字符则通过OutputString回显;若为ESC(扫描码0x17)则退出循环。
#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/PrintLib.h>
EFI_STATUS
EFIAPI
UefiMain (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_SIMPLE_TEXT_INPUT_PROTOCOL *ConIn;
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;
EFI_INPUT_KEY Key;
EFI_STATUS Status;
CHAR16 Buffer[3];
ConIn = SystemTable->ConIn;
ConOut = SystemTable->ConOut;
ConOut->OutputString (ConOut, L"Keyboard Reader Started. Press ESC to exit.\r\n");
while (TRUE) {
// 等待并读取下一个按键
Status = ConIn->ReadKeyStroke (ConIn, &Key);
if (EFI_ERROR (Status)) {
continue;
}
// 检查是否为ESC键(扫描码0x17)
if (Key.ScanCode == SCAN_ESC) {
ConOut->OutputString (ConOut, L"\r\nESC pressed. Exiting.\r\n");
break;
}
// 回显可打印的Unicode字符
if (Key.UnicodeChar >= 0x20 && Key.UnicodeChar <= 0x7E) {
Buffer[0] = Key.UnicodeChar;
Buffer[1] = L'\0';
ConOut->OutputString (ConOut, Buffer);
} else if (Key.UnicodeChar == 0x0D) {
// 回车键:输出换行
ConOut->OutputString (ConOut, L"\r\n");
}
// 其他控制字符(如功能键)不处理,仅忽略
}
return EFI_SUCCESS;
}
编译与运行
- 将上述代码保存为
KeyboardReader.c,并在.inf文件中声明源码文件与依赖库:
[Sources]
KeyboardReader.c
[LibraryClasses]
UefiLib
UefiBootServicesTableLib
- 在EDK2环境中执行
build编译生成KeyboardReader.efi。 - 将
.efi文件放入FAT格式的启动U盘或OVMF虚拟磁盘中,在UEFI Shell下运行:
Shell> fs0:
FS0:\> KeyboardReader.efi
验证方法
- 程序启动后屏幕显示
Keyboard Reader Started. Press ESC to exit. - 输入字母、数字或符号(如
abc123),这些字符会立即在屏幕上回显。 - 按
Enter键,光标换到下一行。 - 按
ESC键,程序打印ESC pressed. Exiting.并返回UEFI Shell。
满足以上行为即判定程序工作正常。注意:功能键(如F1~F12)和方向键不会回显字符,这是预期行为,因为代码仅处理可打印字符与回车。