UEFI的鼠标事件
鼠标属于Pointer设备,UEFI的SPEC中使用Pointer设备的Protocols为Simple Pointer Protocol和Absolute Pointer Protocol,本文使用Simple Pointer Protocol来实现UEFI鼠标事件,并打印鼠标的状态(XYZ轴位置、left键、中轴键)。
步骤如下:
1:使用LocateProtocol找出Protocol的第一个实例。
2:打开鼠标指针协议(参考 EFI_SIMPLE_POINTER_PROTOCOL)
3:无线循环监听鼠标事件,在循环中使用gBS->WaitEvent等待事件,然后获取鼠标的状态(参考 EFI_SIMPLE_POINTER_PROTOCOL),如果获取到之后打印鼠标的状态。
对应的Protocol如下图1所示:
图1 Protocol
本文在EmulatorPkg/Application/Foundation3/下创建Foundation3.c和Foundation3.inf文件。其中Foundation3.c如下所示。注意!!!!(RightButton不是右键而是中间的键)。
#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Protocol/SimplePointer.h>
EFI_STATUS
EFIAPI
UefiMain(
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable)
{
EFI_STATUS Status;
EFI_SIMPLE_POINTER_PROTOCOL *SimplePointerProtocol;
//找到对应的Protocol实例
Status = gBS->LocateProtocol(&gEfiSimplePointerProtocolGuid, NULL, (VOID **)&SimplePointerProtocol);
if (EFI_ERROR(Status))
{
Print(L"无法定位鼠标协议!\n");
return Status;
}
// 打开鼠标指针协议,验证是否可以用
Status = SimplePointerProtocol->Reset(SimplePointerProtocol, FALSE);
if (EFI_ERROR(Status))
{
Print(L"鼠标初始化失败!\n");
return Status;
}
// 无限循环监听鼠标事件
while (TRUE)
{
EFI_EVENT WaitEvent = SimplePointerProtocol->WaitForInput;
UINTN EventIndex;
gBS->WaitForEvent(1, &WaitEvent, &EventIndex);
// 获取鼠标状态
EFI_SIMPLE_POINTER_STATE State;
Status = SimplePointerProtocol->GetState(SimplePointerProtocol, &State);
if (EFI_ERROR(Status))
{
Print(L"无法获取鼠标状态!\n");
continue;
}
// 打印鼠标状态,经过实验。RightButton不是右键而是中间的键
Print(L"X:%d Y:%d Z:%d L:%d R:%d\n",
State.RelativeMovementX,
State.RelativeMovementY,
State.RelativeMovementZ,
State.LeftButton,
State.RightButton);
}
return EFI_SUCCESS;
}
根据上述步骤,先使用gBS->LocateProtocol,LocateProtocol参考图2,第一个参数为带查询的Protocol,第二个参数为是可选的此处填NULL,第三个参数为对应的Protocol实例,先EFI_SIMPLE_POINTER_PROTOCOL *SimplePointerProtocol,由于是VOID**类型的指针,所以要加&后强制类型转换,因此最终为Status = gBS>LocateProtocol(&gEfiSimplePointerProtocolGuid, NULL, (VOID **)&SimplePointerProtocol);
图2 LocateProtocol
上面找到第一个Protocol实例之后,打开Protocol,使用内部的Reset方法先重置一下,并且判断是否可用,即Status = SimplePointerProtocol->Reset(SimplePointerProtocol, FALSE)。
重置完之后,在循环中不断的获取鼠标的状态,因此先在循环里创建一个鼠标事件,即鼠标等待事件EFI_EVENT WaitEvent = SimplePointerProtocol->WaitForInput,然后使用gBS->WaitForEvent(1, &WaitEvent, &EventIndex);等待事件的发生,如果检测到有设备输入的时候,使用Status = SimplePointerProtocol->GetState(SimplePointerProtocol, &State)获取鼠标的状态,其中GetState函数的定义如下图3所示,GetState的State的定义又如下图4所示。
图3 GetState函数定义
图4 State
之后将状态打印出来。
相关的工程文件如下所示。
[Defines]
INF_VERSION = 0x0001000b
BASE_NAME = MyProject
FILE_GUID = 01234567-89AB-CDEF-0123-456789ABCDEF
MODULE_TYPE = UEFI_APPLICATION
VERSION_STRING = 1.0
ENTRY_POINT = UefiMain
[Sources]
Foundation3.c
:
[Packages]
MdePkg/MdePkg.dec
[LibraryClasses]
UefiApplicationEntryPoint
UefiLib
UefiBootServicesTableLib
PrintLib
[Protocols]
gEfiSimplePointerProtocolGuid
编译运行之后运行结果如下图5所示。
图5 运行结果