This is version 3. Changes from version 1: - handles SHIFT as a modifier - handles F11 and F12 keys - uses the handle provided by the system table to find our _EX protocol.
Changes from version 2: - eliminate duplicate keycode translation. Signed-off-by: Peter Jones <pjo...@redhat.com> --- grub-core/term/efi/console.c | 115 +++++++++++++++++++++++++++++++++++-------- include/grub/efi/api.h | 65 +++++++++++++++++++++++- 2 files changed, 158 insertions(+), 22 deletions(-) diff --git a/grub-core/term/efi/console.c b/grub-core/term/efi/console.c index a37eb84..95aedb7 100644 --- a/grub-core/term/efi/console.c +++ b/grub-core/term/efi/console.c @@ -104,26 +104,12 @@ const unsigned efi_codes[] = GRUB_TERM_KEY_DC, GRUB_TERM_KEY_PPAGE, GRUB_TERM_KEY_NPAGE, GRUB_TERM_KEY_F1, GRUB_TERM_KEY_F2, GRUB_TERM_KEY_F3, GRUB_TERM_KEY_F4, GRUB_TERM_KEY_F5, GRUB_TERM_KEY_F6, GRUB_TERM_KEY_F7, GRUB_TERM_KEY_F8, GRUB_TERM_KEY_F9, - GRUB_TERM_KEY_F10, 0, 0, '\e' + GRUB_TERM_KEY_F10, GRUB_TERM_KEY_F10, GRUB_TERM_KEY_F11, '\e' }; - static int -grub_console_getkey (struct grub_term_input *term __attribute__ ((unused))) +grub_efi_translate_key (grub_efi_input_key_t key) { - grub_efi_simple_input_interface_t *i; - grub_efi_input_key_t key; - grub_efi_status_t status; - - if (grub_efi_is_finished) - return 0; - - i = grub_efi_system_table->con_in; - status = efi_call_2 (i->read_key_stroke, i, &key); - - if (status != GRUB_EFI_SUCCESS) - return GRUB_TERM_NO_KEY; - if (key.scan_code == 0) { /* Some firmware implementations use VT100-style codes against the spec. @@ -142,6 +128,92 @@ grub_console_getkey (struct grub_term_input *term __attribute__ ((unused))) return GRUB_TERM_NO_KEY; } +static int +grub_console_getkey_con (struct grub_term_input *term __attribute__ ((unused))) +{ + grub_efi_simple_input_interface_t *i; + grub_efi_input_key_t key; + grub_efi_status_t status; + + i = grub_efi_system_table->con_in; + status = efi_call_2 (i->read_key_stroke, i, &key); + + if (status != GRUB_EFI_SUCCESS) + return GRUB_TERM_NO_KEY; + + return grub_efi_translate_key(key); +} + +static int +grub_console_getkey_ex(struct grub_term_input *term) +{ + grub_efi_key_data_t key_data; + grub_efi_status_t status; + grub_efi_uint32_t kss; + int key = -1; + + grub_efi_simple_text_input_ex_interface_t *text_input = term->data; + + status = efi_call_2 (text_input->read_key_stroke, text_input, &key_data); + + if (status != GRUB_EFI_SUCCESS) + return GRUB_TERM_NO_KEY; + + key = grub_efi_translate_key(key_data.key); + + if (key == GRUB_TERM_NO_KEY) + return GRUB_TERM_NO_KEY; + + kss = key_data.key_state.key_shift_state; + if (kss & GRUB_EFI_SHIFT_STATE_VALID) + { + if (kss & GRUB_EFI_LEFT_SHIFT_PRESSED + || kss & GRUB_EFI_RIGHT_SHIFT_PRESSED) + key |= GRUB_TERM_SHIFT; + if (kss & GRUB_EFI_LEFT_ALT_PRESSED || kss & GRUB_EFI_RIGHT_ALT_PRESSED) + key |= GRUB_TERM_ALT; + if (kss & GRUB_EFI_LEFT_CONTROL_PRESSED + || kss & GRUB_EFI_RIGHT_CONTROL_PRESSED) + key |= GRUB_TERM_CTRL; + } + + return key; +} + +static grub_err_t +grub_efi_console_input_init (struct grub_term_input *term) +{ + grub_efi_guid_t text_input_ex_guid = + GRUB_EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID; + + if (grub_efi_is_finished) + return 0; + + grub_efi_simple_text_input_ex_interface_t *text_input = term->data; + if (text_input) + return 0; + + text_input = grub_efi_open_protocol(grub_efi_system_table->console_in_handler, + &text_input_ex_guid, + GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (text_input) + term->data = (void *)text_input; + + return 0; +} + +static int +grub_console_getkey (struct grub_term_input *term) +{ + if (grub_efi_is_finished) + return 0; + + if (term->data) + return grub_console_getkey_ex(term); + else + return grub_console_getkey_con(term); +} + static struct grub_term_coordinate grub_console_getwh (struct grub_term_output *term __attribute__ ((unused))) { @@ -243,7 +315,7 @@ grub_console_setcursor (struct grub_term_output *term __attribute__ ((unused)), } static grub_err_t -grub_efi_console_init (struct grub_term_output *term) +grub_efi_console_output_init (struct grub_term_output *term) { grub_efi_set_text_mode (1); grub_console_setcursor (term, 1); @@ -251,7 +323,7 @@ grub_efi_console_init (struct grub_term_output *term) } static grub_err_t -grub_efi_console_fini (struct grub_term_output *term) +grub_efi_console_output_fini (struct grub_term_output *term) { grub_console_setcursor (term, 0); grub_efi_set_text_mode (0); @@ -262,13 +334,14 @@ static struct grub_term_input grub_console_term_input = { .name = "console", .getkey = grub_console_getkey, + .init = grub_efi_console_input_init, }; static struct grub_term_output grub_console_term_output = { .name = "console", - .init = grub_efi_console_init, - .fini = grub_efi_console_fini, + .init = grub_efi_console_output_init, + .fini = grub_efi_console_output_fini, .putchar = grub_console_putchar, .getwh = grub_console_getwh, .getxy = grub_console_getxy, @@ -291,8 +364,8 @@ grub_console_init (void) return; } - grub_term_register_input ("console", &grub_console_term_input); grub_term_register_output ("console", &grub_console_term_output); + grub_term_register_input ("console", &grub_console_term_input); } void diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h index e5dd543..1423403 100644 --- a/include/grub/efi/api.h +++ b/include/grub/efi/api.h @@ -111,7 +111,7 @@ { 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \ } -#define EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID \ +#define GRUB_EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID \ { 0xdd9e7534, 0x7762, 0x4698, \ { 0x8c, 0x14, 0xf5, 0x85, 0x17, 0xa6, 0x25, 0xaa } \ } @@ -952,6 +952,32 @@ struct grub_efi_input_key }; typedef struct grub_efi_input_key grub_efi_input_key_t; +typedef grub_efi_uint8_t grub_efi_key_toggle_state_t; +struct grub_efi_key_state +{ + grub_efi_uint32_t key_shift_state; + grub_efi_key_toggle_state_t key_toggle_state; +}; +typedef struct grub_efi_key_state grub_efi_key_state_t; + +#define GRUB_EFI_SHIFT_STATE_VALID 0x80000000 +#define GRUB_EFI_RIGHT_SHIFT_PRESSED 0x00000001 +#define GRUB_EFI_LEFT_SHIFT_PRESSED 0x00000002 +#define GRUB_EFI_RIGHT_CONTROL_PRESSED 0x00000004 +#define GRUB_EFI_LEFT_CONTROL_PRESSED 0x00000008 +#define GRUB_EFI_RIGHT_ALT_PRESSED 0x00000010 +#define GRUB_EFI_LEFT_ALT_PRESSED 0x00000020 +#define GRUB_EFI_RIGHT_LOGO_PRESSED 0x00000040 +#define GRUB_EFI_LEFT_LOGO_PRESSED 0x00000080 +#define GRUB_EFI_MENU_KEY_PRESSED 0x00000100 +#define GRUB_EFI_SYS_REQ_PRESSED 0x00000200 + +#define GRUB_EFI_TOGGLE_STATE_VALID 0x80 +#define GRUB_EFI_KEY_STATE_EXPOSED 0x40 +#define GRUB_EFI_SCROLL_LOCK_ACTIVE 0x01 +#define GRUB_EFI_NUM_LOCK_ACTIVE 0x02 +#define GRUB_EFI_CAPS_LOCK_ACTIVE 0x04 + struct grub_efi_simple_text_output_mode { grub_efi_int32_t max_mode; @@ -1294,6 +1320,43 @@ struct grub_efi_simple_input_interface }; typedef struct grub_efi_simple_input_interface grub_efi_simple_input_interface_t; +struct grub_efi_key_data { + grub_efi_input_key_t key; + grub_efi_key_state_t key_state; +}; +typedef struct grub_efi_key_data grub_efi_key_data_t; + +typedef grub_efi_status_t (*grub_efi_key_notify_function_t) ( + grub_efi_key_data_t *key_data + ); + +struct grub_efi_simple_text_input_ex_interface +{ + grub_efi_status_t + (*reset) (struct grub_efi_simple_text_input_ex_interface *this, + grub_efi_boolean_t extended_verification); + + grub_efi_status_t + (*read_key_stroke) (struct grub_efi_simple_text_input_ex_interface *this, + grub_efi_key_data_t *key_data); + + grub_efi_event_t wait_for_key; + + grub_efi_status_t + (*set_state) (struct grub_efi_simple_text_input_ex_interface *this, + grub_efi_key_toggle_state_t *key_toggle_state); + + grub_efi_status_t + (*register_key_notify) (struct grub_efi_simple_text_input_ex_interface *this, + grub_efi_key_data_t *key_data, + grub_efi_key_notify_function_t key_notification_function); + + grub_efi_status_t + (*unregister_key_notify) (struct grub_efi_simple_text_input_ex_interface *this, + void *notification_handle); +}; +typedef struct grub_efi_simple_text_input_ex_interface grub_efi_simple_text_input_ex_interface_t; + struct grub_efi_simple_text_output_interface { grub_efi_status_t -- 1.8.5.3 _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel