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을 찾아야 한다.
언로드 기능에도 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL이 필요하므로, 변수를 전역으로 선언해준다.
이제 RegisterKeyNotify API를 사용한다. LCtrl + LAlt + Z로 실행되는 callback을 만들어 보자.
파일 시작 부분에서 NotifyHandle에 대한 전역 변수(드라이버 언로드함수에서 사용되므로)를추가하고, MyKeyNotificationFunction callback 함수를 정의한다.
지금부턴 numlock이 활성화된 경우 z를 누를 때마다 실행이 되는 또 다른 callback을 작성해 보겠다.
드라이버 언로드 시, callback 함수의 등록을 취소해야 한다고 위에서 언급했다. 이에 대한 이유가 궁금할 것이다.
MyKeyNotificationFunction 및 MyKeyNotificationFunction1와 같은 함수는 HotKeyDriver 메모리에 정의되어 있기 때문이다. 메모리에서 HotKeyDriver를 언로드하면 이 메모리는 해제/비활성화 된다.
그리고 바로가기 키 조합에서 push 시스템은 포인터에서 유효하지 않은 영역에 대한 callback 함수를 역참조하고자 시도한다. 이 점이 예외로 이어진다.
등록 취소 실행의 경우, EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL은 UnreisterKeyNotify 함수를 정의한다.
callback 함수를 등록 취소하는 데 사용
이제 다 되었으니 드라이버를 빌드하고 테스트하자.
일반적이지 않은 키를 escape sequence로 터미널 변환하는 것을 방지하려면, -nograpic 옵션을 빼고 QEMU를 실행해야 한다.
기본 그래픽으로 부팅하거나, vnc 서버를 통해 그래픽으로 부팅할 수 있다.
QEMU를 부팅하면, 드라이버를 OVMF로 로드한다.
numlock이 비활성화된 경우, 하나의 callback만이 가능하다.
LCtrl + LAlt + Z
numlock이 활성화된 경우,
Z
LCtrl + LAlt + Z
다른 키 입력 조합 사이에 UEFI shell에서 cls 명령으로 화면을 clear하여 새로운 출력 확인에 방해가 안되도록 하자.
또한, QEMU가 -nographic 모드에서 실행되는 경우, 모든 수정 사항이 파싱되지 않는다는 점에 유의하자. 따라서, Z를 누를 때마다 항상 callback이 모두 발생한다.
Last updated