39. RegisterKeyNotify / UnrigisterKeyNotify 함수를 사용해 단축키 기능을 추가하는 드라이버 만들기
39장에서는 단축키 조합에 대한 callback을 등록하는 드라이버를 만든다
UEFI에서는 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL의 RegisterKeyNotify 함수를 사용할 수 있다.
EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.RegisterKeyNotify()
Summary:
Register a notification function for a particular keystroke for the input device.
Prototype:
typedef
EFI_STATUS
(EFIAPI *EFI_REGISTER_KEYSTROKE_NOTIFY) (
IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
IN EFI_KEY_DATA *KeyData,
IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction,
OUT VOID **NotifyHandle
);
Parameters:
This A pointer to the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL instance.
KeyData A pointer to a buffer that is filled in with the keystroke information
for the key that was pressed. If KeyData.Key, KeyData.KeyState.KeyToggleState and
KeyData.KeyState.KeyShiftState are 0, then any incomplete keystroke will trigger a
notification of the KeyNotificationFunction.
KeyNotificationFunction Points to the function to be called when the key sequence is typed
specified by KeyData.
NotifyHandle Points to the unique handle assigned to the registered notification.
Description:
The RegisterKeystrokeNotify() function registers a function which will be called when a specified
keystroke will occur. The keystroke being specified can be for any combination of KeyData.Key or
KeyData.KeyState information.
callback 함수의 프로토타입은 다음과 같다.
EFI_KEY_DATA의 경우, 두 개의 필드가 있는 구조이다.
EFI_INPUT_KEY 유형은 SimpleTextIn.h 파일에 정의되어 있다.
InteractiveApp 애플리케이션에서 한 번 사용했던 적이 있다.
EFI_KEY_STATE 유형이 새로 추가되었으며, SimpleTestInEx.h 파일에서 찾을 수 있다.
KeyShiftState / KeyToggleState 필드에 코딩되어 있는 정보를 이해하려면, 동일한 파일에서 이 정의를 살펴보자.
또한 이런 EDKII 파일(SimpleTextInEx.h)에는 스캔 코드(위, 아래, 오른쪽, 왼쪽, home, end, delete, f1-f24 등)에 대한 정의가 포함되어 있다. 따라서 단축키에 대한 스캔 코드를 사용하려는 경우, 해당 파일을 살펴보자.
마지막으로 드라이버에 대한 코드를 작성한다.
이 드라이버의 이름은 HotKeyDriver라고 짓는다. entry point 함수에 바로가기 키 조합을 등록하고 언로드 기능에서 등록 취소한다.
먼저 드라이버 entrypoint 함수에서 guid gEfiSimpleTextInputExProtocolGuid(HotKeyDriver.c)로 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL을 찾아야 한다.
typedef
EFI_STATUS
(EFIAPI *EFI_KEY_NOTIFY_FUNCTION) (
IN EFI_KEY_DATA *KeyData
);
typedef struct {
EFI_INPUT_KEY Key; // 입력 장치에서 반환된 EFI scan code 및 UNICODE 값이다.
EFI_KEY_STATE KeyState; // input modifier 값 뿐만 아니라, 다양한 토글 속성의 현 상태이다.
} EFI_KEY_DATA
///
/// EFI_KEY_TOGGLE_STATE. The toggle states are defined.
/// They are: EFI_TOGGLE_STATE_VALID, EFI_SCROLL_LOCK_ACTIVE
/// EFI_NUM_LOCK_ACTIVE, EFI_CAPS_LOCK_ACTIVE
///
typedef UINT8 EFI_KEY_TOGGLE_STATE;
typedef struct _EFI_KEY_STATE {
///
/// Reflects the currently pressed shift
/// modifiers for the input device. The
/// returned value is valid only if the high
/// order bit has been set.
///
UINT32 KeyShiftState;
///
/// Reflects the current internal state of
/// various toggled attributes. The returned
/// value is valid only if the high order
/// bit has been set.
///
EFI_KEY_TOGGLE_STATE KeyToggleState;
} EFI_KEY_STATE;
//
// Any Shift or Toggle State that is valid should have
// high order bit set.
//
// Shift state
//
#define EFI_SHIFT_STATE_VALID 0x80000000
#define EFI_RIGHT_SHIFT_PRESSED 0x00000001
#define EFI_LEFT_SHIFT_PRESSED 0x00000002
#define EFI_RIGHT_CONTROL_PRESSED 0x00000004
#define EFI_LEFT_CONTROL_PRESSED 0x00000008
#define EFI_RIGHT_ALT_PRESSED 0x00000010
#define EFI_LEFT_ALT_PRESSED 0x00000020
#define EFI_RIGHT_LOGO_PRESSED 0x00000040
#define EFI_LEFT_LOGO_PRESSED 0x00000080
#define EFI_MENU_KEY_PRESSED 0x00000100
#define EFI_SYS_REQ_PRESSED 0x00000200
//
// Toggle state
//
#define EFI_TOGGLE_STATE_VALID 0x80
#define EFI_KEY_STATE_EXPOSED 0x40
#define EFI_SCROLL_LOCK_ACTIVE 0x01
#define EFI_NUM_LOCK_ACTIVE 0x02
#define EFI_CAPS_LOCK_ACTIVE 0x04
EFI_HANDLE NotifyHandle;
EFI_STATUS EFIAPI MyKeyNotificationFunction(EFI_KEY_DATA* KeyData)
{
Print(L"\nHot Key 1 is pressed\n"); // we add '\n' in the begining, so the output wouldn't interfere with the UEFI shell prompt
return EFI_SUCCESS;
}
EFI_HANDLE NotifyHandle1;
EFI_STATUS EFIAPI MyKeyNotificationFunction1(EFI_KEY_DATA* KeyData)
{
Print(L"\nHot Key 2 is pressed\n"); // we add '\n' in the begining, so the output wouldn't interfere with the UEFI shell prompt
return EFI_SUCCESS; // or another our callback function
}
EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.UnregisterKeyNotify()
Summary:
Remove the notification that was previously registered.
Prototype:
typedef
EFI_STATUS
(EFIAPI *EFI_UNREGISTER_KEYSTROKE_NOTIFY) (
IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
IN VOID *NotificationHandle
);
Parameters:
This A pointer to the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL instance.
NotificationHandle The handle of the notification function being unregistered.
Description:
The UnregisterKeystrokeNotify() function removes the notification which was previously registered.
EFI_STATUS
EFIAPI
HotKeyDriverUnload(
IN EFI_HANDLE ImageHandle
)
{
if (!InputEx)
return EFI_SUCCESS;
EFI_STATUS Status;
if (!NotifyHandle) {
Status = InputEx->UnregisterKeyNotify(InputEx,
(VOID*)NotifyHandle);
if (EFI_ERROR(Status)) {
Print(L"Error! Can't perform RegisterKeyNotify: %r", Status);
return Status;
}
}
if (!NotifyHandle1) {
Status = InputEx->UnregisterKeyNotify(InputEx,
(VOID*)NotifyHandle1);
if (EFI_ERROR(Status)) {
Print(L"Error! Can't perform RegisterKeyNotify: %r", Status);
return Status;
}
}
return EFI_SUCCESS;
}