EFI_SIMPLE_TEXT_INPUT_PROTOCOLよりも少し高機能なEFI_SIMPLE_TEXT_INPUT_EX_PROTOCOLがあります。この章ではEFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL関係のTIPSを紹介します。
EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOLのGUIDと定義はリスト2.1の通りです。
この章ではRegisterKeyNotify()を紹介します。
RegisterKeyNotify()を使用すると、特定のキー入力で呼び出される関数を登録できます(リスト2.2)。
サンプルのディレクトリは"020_simple_text_input_ex_register_key_notify"です。
RegisterKeyNotify()は、第2引数へイベントとして扱うキー入力を指定し、第3引数へイベント発生を通知する関数を設定します。第2引数で指定するstruct EFI_KEY_DATAの定義はリスト2.3の通りです。
「どういう状態で何のキーが押されたか」を指定するためにEFI_KEY_DATAにはキーボードのトグル状態なども含まれますが、今回はEFI_INPUT_KEYのみ使用し、その他は0を設定しておきます。EFI_KEY_STATEの定義について詳しくは、仕様書の"Protocols - Console Support"の"Simple Text Input Ex Protocol"の"EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.ReadKeyStrokeEx()"を見てみてください。
RegisterKeyNotify()の使用例はリスト2.4の通りです。
1: #include "efi.h" 2: #include "common.h" 3: 4: unsigned char is_exit = FALSE; 5: 6: unsigned long long key_notice( 7: struct EFI_KEY_DATA *KeyData __attribute__ ((unused))) 8: { 9: is_exit = TRUE; 10: 11: return EFI_SUCCESS; 12: } 13: 14: void efi_main(void *ImageHandle __attribute__ ((unused)), 15: struct EFI_SYSTEM_TABLE *SystemTable) 16: { 17: unsigned long long status; 18: struct EFI_KEY_DATA key_data = {{0, L'q'}, {0, 0}}; 19: void *notify_handle; 20: 21: efi_init(SystemTable); 22: ST->ConOut->ClearScreen(ST->ConOut); 23: 24: puts(L"Waiting for the 'q' key input...\r\n"); 25: 26: status = STIEP->RegisterKeyNotify(STIEP, &key_data, key_notice, 27: ¬ify_handle); 28: assert(status, L"RegisterKeyNotify"); 29: 30: while (!is_exit); 31: 32: puts(L"exit.\r\n"); 33: 34: while (TRUE); 35: }
リスト2.4は、'q'キーの入力でefi_main()内の特定の処理を抜けるサンプルになっています。
まず、'q'キーをイベント通知対象とするため、struct EFI_KEY_DATA key_dataへはstruct EFI_INPUT_KEYのUnicodeCharへ'q'を登録し、その他は0を設定しています。
そして、RegisterKeyNotify()を使用し、'q'キー入力でkey_notice()が呼び出される様に登録しています。
key_notice()では、グローバル変数is_exitへTRUEを設定するため、'q'キー入力でefi_main()内の"while (!is_exit);"を抜けます。
Unicode外のキー入力を検出するには、struct EFI_KEY_DATAのScanCodeを使用します。仕様書"12.1.2 ConsoleIn Definition"からの引用ですが、指定できるスキャンコードは表2.1の通りです。
スキャンコード | 説明 | スキャンコード | 説明 |
---|---|---|---|
0x00 | Nullスキャンコード | 0x15 | F11 |
0x01 | 上 | 0x16 | F12 |
0x02 | 下 | 0x68 | F13 |
0x03 | 右 | 0x69 | F14 |
0x04 | 左 | 0x6A | F15 |
0x05 | Home | 0x6B | F16 |
0x06 | End | 0x6C | F17 |
0x07 | Insert | 0x6D | F18 |
0x08 | Delete | 0x6E | F19 |
0x09 | Page Up | 0x6F | F20 |
0x0a | Page Down | 0x70 | F21 |
0x0b | F1 | 0x71 | F22 |
0x0c | F2 | 0x72 | F23 |
0x0d | F3 | 0x73 | F24 |
0x0e | F4 | 0x7F | ミュート |
0x0f | F5 | 0x80 | 音量を上げる |
0x10 | F6 | 0x81 | 音量を下げる |
0x11 | F7 | 0x100 | 画面の明るさを上げる |
0x12 | F8 | 0x101 | 画面の明るさを下げる |
0x13 | F9 | 0x102 | サスペンド |
0x14 | F10 | 0x103 | ハイバネート |
0x17 | Escape | 0x104 | ディスプレイトグル |
0x105 | リカバリー | ||
0x106 | イジェクト | ||
0x8000-0xFFFF | OEM予約領域 |
表2.1から、Escapeキーを検出したい場合は、struct EFI_KEY_DATAのScanCodeへ0x17を設定しておけば良いことが分かります。
そのため、リスト2.4を、「Escapeキーでwhileループを抜ける」へ変更する場合、18行目の変数"key_data"への代入処理をリスト2.5へ変更すれば良いです。