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;
}

编译与运行

  1. 将上述代码保存为KeyboardReader.c,并在.inf文件中声明源码文件与依赖库:
[Sources]
  KeyboardReader.c

[LibraryClasses]
  UefiLib
  UefiBootServicesTableLib
  1. 在EDK2环境中执行build编译生成KeyboardReader.efi。
  2. 将.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)和方向键不会回显字符,这是预期行为,因为代码仅处理可打印字符与回车。