|
|
28f7f8 |
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
|
606ea6 |
From: Peter Jones <pjones@redhat.com>
|
|
|
606ea6 |
Date: Mon, 3 Feb 2014 15:21:46 -0500
|
|
|
28f7f8 |
Subject: [PATCH] Make CTRL and ALT keys work as expected on EFI systems
|
|
|
28f7f8 |
(version 5).
|
|
|
606ea6 |
|
|
|
606ea6 |
This is version 4.
|
|
|
606ea6 |
|
|
|
606ea6 |
Changes from version 1:
|
|
|
606ea6 |
- handles SHIFT as a modifier
|
|
|
606ea6 |
- handles F11 and F12 keys
|
|
|
606ea6 |
- uses the handle provided by the system table to find our _EX protocol.
|
|
|
606ea6 |
|
|
|
606ea6 |
Changes from version 2:
|
|
|
606ea6 |
- eliminate duplicate keycode translation.
|
|
|
606ea6 |
|
|
|
606ea6 |
Changes from version 3:
|
|
|
606ea6 |
- Do not add the shift modifier for any ascii character between space
|
|
|
606ea6 |
(0x20) and DEL (0x7f); the combination of the modifier and many of the
|
|
|
606ea6 |
keys causes it not to be recognized at all. Specifically, if we
|
|
|
606ea6 |
include the modifier on any querty punctuation character, i.e.
|
|
|
606ea6 |
anything the string "~!@#$%^&*()_+{}|:\"<>?" represents in C, it stops
|
|
|
606ea6 |
being recognized whatsoever.
|
|
|
606ea6 |
|
|
|
606ea6 |
Changes from version 4:
|
|
|
606ea6 |
- Always initialize term->data from locate protocol (i.e. make it
|
|
|
606ea6 |
unconditional.)
|
|
|
606ea6 |
|
|
|
606ea6 |
Signed-off-by: Peter Jones <pjones@redhat.com>
|
|
|
606ea6 |
---
|
|
|
606ea6 |
grub-core/term/efi/console.c | 118 +++++++++++++++++++++++++++++++++++--------
|
|
|
606ea6 |
include/grub/efi/api.h | 65 +++++++++++++++++++++++-
|
|
|
606ea6 |
2 files changed, 161 insertions(+), 22 deletions(-)
|
|
|
606ea6 |
|
|
|
606ea6 |
diff --git a/grub-core/term/efi/console.c b/grub-core/term/efi/console.c
|
|
|
28f7f8 |
index a37eb841c72..677eab5820f 100644
|
|
|
606ea6 |
--- a/grub-core/term/efi/console.c
|
|
|
606ea6 |
+++ b/grub-core/term/efi/console.c
|
|
|
606ea6 |
@@ -104,26 +104,12 @@ const unsigned efi_codes[] =
|
|
|
606ea6 |
GRUB_TERM_KEY_DC, GRUB_TERM_KEY_PPAGE, GRUB_TERM_KEY_NPAGE, GRUB_TERM_KEY_F1,
|
|
|
606ea6 |
GRUB_TERM_KEY_F2, GRUB_TERM_KEY_F3, GRUB_TERM_KEY_F4, GRUB_TERM_KEY_F5,
|
|
|
606ea6 |
GRUB_TERM_KEY_F6, GRUB_TERM_KEY_F7, GRUB_TERM_KEY_F8, GRUB_TERM_KEY_F9,
|
|
|
606ea6 |
- GRUB_TERM_KEY_F10, 0, 0, '\e'
|
|
|
606ea6 |
+ GRUB_TERM_KEY_F10, GRUB_TERM_KEY_F10, GRUB_TERM_KEY_F11, '\e'
|
|
|
606ea6 |
};
|
|
|
606ea6 |
|
|
|
606ea6 |
-
|
|
|
606ea6 |
static int
|
|
|
606ea6 |
-grub_console_getkey (struct grub_term_input *term __attribute__ ((unused)))
|
|
|
606ea6 |
+grub_efi_translate_key (grub_efi_input_key_t key)
|
|
|
606ea6 |
{
|
|
|
606ea6 |
- grub_efi_simple_input_interface_t *i;
|
|
|
606ea6 |
- grub_efi_input_key_t key;
|
|
|
606ea6 |
- grub_efi_status_t status;
|
|
|
606ea6 |
-
|
|
|
606ea6 |
- if (grub_efi_is_finished)
|
|
|
606ea6 |
- return 0;
|
|
|
606ea6 |
-
|
|
|
606ea6 |
- i = grub_efi_system_table->con_in;
|
|
|
606ea6 |
- status = efi_call_2 (i->read_key_stroke, i, &key);
|
|
|
606ea6 |
-
|
|
|
606ea6 |
- if (status != GRUB_EFI_SUCCESS)
|
|
|
606ea6 |
- return GRUB_TERM_NO_KEY;
|
|
|
606ea6 |
-
|
|
|
606ea6 |
if (key.scan_code == 0)
|
|
|
606ea6 |
{
|
|
|
606ea6 |
/* Some firmware implementations use VT100-style codes against the spec.
|
|
|
606ea6 |
@@ -139,9 +125,98 @@ grub_console_getkey (struct grub_term_input *term __attribute__ ((unused)))
|
|
|
606ea6 |
else if (key.scan_code < ARRAY_SIZE (efi_codes))
|
|
|
606ea6 |
return efi_codes[key.scan_code];
|
|
|
606ea6 |
|
|
|
606ea6 |
+ if (key.unicode_char >= 0x20 && key.unicode_char <= 0x7f)
|
|
|
606ea6 |
+ return key.unicode_char;
|
|
|
606ea6 |
+
|
|
|
606ea6 |
return GRUB_TERM_NO_KEY;
|
|
|
606ea6 |
}
|
|
|
606ea6 |
|
|
|
606ea6 |
+static int
|
|
|
606ea6 |
+grub_console_getkey_con (struct grub_term_input *term __attribute__ ((unused)))
|
|
|
606ea6 |
+{
|
|
|
606ea6 |
+ grub_efi_simple_input_interface_t *i;
|
|
|
606ea6 |
+ grub_efi_input_key_t key;
|
|
|
606ea6 |
+ grub_efi_status_t status;
|
|
|
606ea6 |
+
|
|
|
606ea6 |
+ i = grub_efi_system_table->con_in;
|
|
|
606ea6 |
+ status = efi_call_2 (i->read_key_stroke, i, &key);
|
|
|
606ea6 |
+
|
|
|
606ea6 |
+ if (status != GRUB_EFI_SUCCESS)
|
|
|
606ea6 |
+ return GRUB_TERM_NO_KEY;
|
|
|
606ea6 |
+
|
|
|
606ea6 |
+ return grub_efi_translate_key(key);
|
|
|
606ea6 |
+}
|
|
|
606ea6 |
+
|
|
|
606ea6 |
+static int
|
|
|
606ea6 |
+grub_console_getkey_ex(struct grub_term_input *term)
|
|
|
606ea6 |
+{
|
|
|
606ea6 |
+ grub_efi_key_data_t key_data;
|
|
|
606ea6 |
+ grub_efi_status_t status;
|
|
|
606ea6 |
+ grub_efi_uint32_t kss;
|
|
|
606ea6 |
+ int key = -1;
|
|
|
606ea6 |
+
|
|
|
606ea6 |
+ grub_efi_simple_text_input_ex_interface_t *text_input = term->data;
|
|
|
606ea6 |
+
|
|
|
606ea6 |
+ status = efi_call_2 (text_input->read_key_stroke, text_input, &key_data);
|
|
|
606ea6 |
+
|
|
|
606ea6 |
+ if (status != GRUB_EFI_SUCCESS)
|
|
|
606ea6 |
+ return GRUB_TERM_NO_KEY;
|
|
|
606ea6 |
+
|
|
|
606ea6 |
+ kss = key_data.key_state.key_shift_state;
|
|
|
606ea6 |
+ key = grub_efi_translate_key(key_data.key);
|
|
|
606ea6 |
+
|
|
|
606ea6 |
+ if (key == GRUB_TERM_NO_KEY)
|
|
|
606ea6 |
+ return GRUB_TERM_NO_KEY;
|
|
|
606ea6 |
+
|
|
|
606ea6 |
+ if (kss & GRUB_EFI_SHIFT_STATE_VALID)
|
|
|
606ea6 |
+ {
|
|
|
606ea6 |
+ if ((kss & GRUB_EFI_LEFT_SHIFT_PRESSED
|
|
|
606ea6 |
+ || kss & GRUB_EFI_RIGHT_SHIFT_PRESSED)
|
|
|
606ea6 |
+ && !(key >= 0x20 && key <= 0x7f))
|
|
|
606ea6 |
+ key |= GRUB_TERM_SHIFT;
|
|
|
606ea6 |
+ if (kss & GRUB_EFI_LEFT_ALT_PRESSED || kss & GRUB_EFI_RIGHT_ALT_PRESSED)
|
|
|
606ea6 |
+ key |= GRUB_TERM_ALT;
|
|
|
606ea6 |
+ if (kss & GRUB_EFI_LEFT_CONTROL_PRESSED
|
|
|
606ea6 |
+ || kss & GRUB_EFI_RIGHT_CONTROL_PRESSED)
|
|
|
606ea6 |
+ key |= GRUB_TERM_CTRL;
|
|
|
606ea6 |
+ }
|
|
|
606ea6 |
+
|
|
|
606ea6 |
+ return key;
|
|
|
606ea6 |
+}
|
|
|
606ea6 |
+
|
|
|
606ea6 |
+static grub_err_t
|
|
|
606ea6 |
+grub_efi_console_input_init (struct grub_term_input *term)
|
|
|
606ea6 |
+{
|
|
|
606ea6 |
+ grub_efi_guid_t text_input_ex_guid =
|
|
|
606ea6 |
+ GRUB_EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID;
|
|
|
606ea6 |
+
|
|
|
606ea6 |
+ if (grub_efi_is_finished)
|
|
|
606ea6 |
+ return 0;
|
|
|
606ea6 |
+
|
|
|
606ea6 |
+ grub_efi_simple_text_input_ex_interface_t *text_input = term->data;
|
|
|
606ea6 |
+ if (text_input)
|
|
|
606ea6 |
+ return 0;
|
|
|
606ea6 |
+
|
|
|
606ea6 |
+ text_input = grub_efi_open_protocol(grub_efi_system_table->console_in_handler,
|
|
|
606ea6 |
+ &text_input_ex_guid,
|
|
|
606ea6 |
+ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
|
|
606ea6 |
+ term->data = (void *)text_input;
|
|
|
606ea6 |
+
|
|
|
606ea6 |
+ return 0;
|
|
|
606ea6 |
+}
|
|
|
606ea6 |
+
|
|
|
606ea6 |
+static int
|
|
|
606ea6 |
+grub_console_getkey (struct grub_term_input *term)
|
|
|
606ea6 |
+{
|
|
|
606ea6 |
+ if (grub_efi_is_finished)
|
|
|
606ea6 |
+ return 0;
|
|
|
606ea6 |
+
|
|
|
606ea6 |
+ if (term->data)
|
|
|
606ea6 |
+ return grub_console_getkey_ex(term);
|
|
|
606ea6 |
+ else
|
|
|
606ea6 |
+ return grub_console_getkey_con(term);
|
|
|
606ea6 |
+}
|
|
|
606ea6 |
+
|
|
|
606ea6 |
static struct grub_term_coordinate
|
|
|
606ea6 |
grub_console_getwh (struct grub_term_output *term __attribute__ ((unused)))
|
|
|
606ea6 |
{
|
|
|
606ea6 |
@@ -243,7 +318,7 @@ grub_console_setcursor (struct grub_term_output *term __attribute__ ((unused)),
|
|
|
606ea6 |
}
|
|
|
606ea6 |
|
|
|
606ea6 |
static grub_err_t
|
|
|
606ea6 |
-grub_efi_console_init (struct grub_term_output *term)
|
|
|
606ea6 |
+grub_efi_console_output_init (struct grub_term_output *term)
|
|
|
606ea6 |
{
|
|
|
606ea6 |
grub_efi_set_text_mode (1);
|
|
|
606ea6 |
grub_console_setcursor (term, 1);
|
|
|
606ea6 |
@@ -251,7 +326,7 @@ grub_efi_console_init (struct grub_term_output *term)
|
|
|
606ea6 |
}
|
|
|
606ea6 |
|
|
|
606ea6 |
static grub_err_t
|
|
|
606ea6 |
-grub_efi_console_fini (struct grub_term_output *term)
|
|
|
606ea6 |
+grub_efi_console_output_fini (struct grub_term_output *term)
|
|
|
606ea6 |
{
|
|
|
606ea6 |
grub_console_setcursor (term, 0);
|
|
|
606ea6 |
grub_efi_set_text_mode (0);
|
|
|
606ea6 |
@@ -262,13 +337,14 @@ static struct grub_term_input grub_console_term_input =
|
|
|
606ea6 |
{
|
|
|
606ea6 |
.name = "console",
|
|
|
606ea6 |
.getkey = grub_console_getkey,
|
|
|
606ea6 |
+ .init = grub_efi_console_input_init,
|
|
|
606ea6 |
};
|
|
|
606ea6 |
|
|
|
606ea6 |
static struct grub_term_output grub_console_term_output =
|
|
|
606ea6 |
{
|
|
|
606ea6 |
.name = "console",
|
|
|
606ea6 |
- .init = grub_efi_console_init,
|
|
|
606ea6 |
- .fini = grub_efi_console_fini,
|
|
|
606ea6 |
+ .init = grub_efi_console_output_init,
|
|
|
606ea6 |
+ .fini = grub_efi_console_output_fini,
|
|
|
606ea6 |
.putchar = grub_console_putchar,
|
|
|
606ea6 |
.getwh = grub_console_getwh,
|
|
|
606ea6 |
.getxy = grub_console_getxy,
|
|
|
606ea6 |
@@ -291,8 +367,8 @@ grub_console_init (void)
|
|
|
606ea6 |
return;
|
|
|
606ea6 |
}
|
|
|
606ea6 |
|
|
|
606ea6 |
- grub_term_register_input ("console", &grub_console_term_input);
|
|
|
606ea6 |
grub_term_register_output ("console", &grub_console_term_output);
|
|
|
606ea6 |
+ grub_term_register_input ("console", &grub_console_term_input);
|
|
|
606ea6 |
}
|
|
|
606ea6 |
|
|
|
606ea6 |
void
|
|
|
606ea6 |
diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
|
|
|
28f7f8 |
index e5dd543a801..142340372e1 100644
|
|
|
606ea6 |
--- a/include/grub/efi/api.h
|
|
|
606ea6 |
+++ b/include/grub/efi/api.h
|
|
|
606ea6 |
@@ -111,7 +111,7 @@
|
|
|
606ea6 |
{ 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \
|
|
|
606ea6 |
}
|
|
|
606ea6 |
|
|
|
606ea6 |
-#define EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID \
|
|
|
606ea6 |
+#define GRUB_EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID \
|
|
|
606ea6 |
{ 0xdd9e7534, 0x7762, 0x4698, \
|
|
|
606ea6 |
{ 0x8c, 0x14, 0xf5, 0x85, 0x17, 0xa6, 0x25, 0xaa } \
|
|
|
606ea6 |
}
|
|
|
606ea6 |
@@ -952,6 +952,32 @@ struct grub_efi_input_key
|
|
|
606ea6 |
};
|
|
|
606ea6 |
typedef struct grub_efi_input_key grub_efi_input_key_t;
|
|
|
606ea6 |
|
|
|
606ea6 |
+typedef grub_efi_uint8_t grub_efi_key_toggle_state_t;
|
|
|
606ea6 |
+struct grub_efi_key_state
|
|
|
606ea6 |
+{
|
|
|
606ea6 |
+ grub_efi_uint32_t key_shift_state;
|
|
|
606ea6 |
+ grub_efi_key_toggle_state_t key_toggle_state;
|
|
|
606ea6 |
+};
|
|
|
606ea6 |
+typedef struct grub_efi_key_state grub_efi_key_state_t;
|
|
|
606ea6 |
+
|
|
|
606ea6 |
+#define GRUB_EFI_SHIFT_STATE_VALID 0x80000000
|
|
|
606ea6 |
+#define GRUB_EFI_RIGHT_SHIFT_PRESSED 0x00000001
|
|
|
606ea6 |
+#define GRUB_EFI_LEFT_SHIFT_PRESSED 0x00000002
|
|
|
606ea6 |
+#define GRUB_EFI_RIGHT_CONTROL_PRESSED 0x00000004
|
|
|
606ea6 |
+#define GRUB_EFI_LEFT_CONTROL_PRESSED 0x00000008
|
|
|
606ea6 |
+#define GRUB_EFI_RIGHT_ALT_PRESSED 0x00000010
|
|
|
606ea6 |
+#define GRUB_EFI_LEFT_ALT_PRESSED 0x00000020
|
|
|
606ea6 |
+#define GRUB_EFI_RIGHT_LOGO_PRESSED 0x00000040
|
|
|
606ea6 |
+#define GRUB_EFI_LEFT_LOGO_PRESSED 0x00000080
|
|
|
606ea6 |
+#define GRUB_EFI_MENU_KEY_PRESSED 0x00000100
|
|
|
606ea6 |
+#define GRUB_EFI_SYS_REQ_PRESSED 0x00000200
|
|
|
606ea6 |
+
|
|
|
606ea6 |
+#define GRUB_EFI_TOGGLE_STATE_VALID 0x80
|
|
|
606ea6 |
+#define GRUB_EFI_KEY_STATE_EXPOSED 0x40
|
|
|
606ea6 |
+#define GRUB_EFI_SCROLL_LOCK_ACTIVE 0x01
|
|
|
606ea6 |
+#define GRUB_EFI_NUM_LOCK_ACTIVE 0x02
|
|
|
606ea6 |
+#define GRUB_EFI_CAPS_LOCK_ACTIVE 0x04
|
|
|
606ea6 |
+
|
|
|
606ea6 |
struct grub_efi_simple_text_output_mode
|
|
|
606ea6 |
{
|
|
|
606ea6 |
grub_efi_int32_t max_mode;
|
|
|
606ea6 |
@@ -1294,6 +1320,43 @@ struct grub_efi_simple_input_interface
|
|
|
606ea6 |
};
|
|
|
606ea6 |
typedef struct grub_efi_simple_input_interface grub_efi_simple_input_interface_t;
|
|
|
606ea6 |
|
|
|
606ea6 |
+struct grub_efi_key_data {
|
|
|
606ea6 |
+ grub_efi_input_key_t key;
|
|
|
606ea6 |
+ grub_efi_key_state_t key_state;
|
|
|
606ea6 |
+};
|
|
|
606ea6 |
+typedef struct grub_efi_key_data grub_efi_key_data_t;
|
|
|
606ea6 |
+
|
|
|
606ea6 |
+typedef grub_efi_status_t (*grub_efi_key_notify_function_t) (
|
|
|
606ea6 |
+ grub_efi_key_data_t *key_data
|
|
|
606ea6 |
+ );
|
|
|
606ea6 |
+
|
|
|
606ea6 |
+struct grub_efi_simple_text_input_ex_interface
|
|
|
606ea6 |
+{
|
|
|
606ea6 |
+ grub_efi_status_t
|
|
|
606ea6 |
+ (*reset) (struct grub_efi_simple_text_input_ex_interface *this,
|
|
|
606ea6 |
+ grub_efi_boolean_t extended_verification);
|
|
|
606ea6 |
+
|
|
|
606ea6 |
+ grub_efi_status_t
|
|
|
606ea6 |
+ (*read_key_stroke) (struct grub_efi_simple_text_input_ex_interface *this,
|
|
|
606ea6 |
+ grub_efi_key_data_t *key_data);
|
|
|
606ea6 |
+
|
|
|
606ea6 |
+ grub_efi_event_t wait_for_key;
|
|
|
606ea6 |
+
|
|
|
606ea6 |
+ grub_efi_status_t
|
|
|
606ea6 |
+ (*set_state) (struct grub_efi_simple_text_input_ex_interface *this,
|
|
|
606ea6 |
+ grub_efi_key_toggle_state_t *key_toggle_state);
|
|
|
606ea6 |
+
|
|
|
606ea6 |
+ grub_efi_status_t
|
|
|
606ea6 |
+ (*register_key_notify) (struct grub_efi_simple_text_input_ex_interface *this,
|
|
|
606ea6 |
+ grub_efi_key_data_t *key_data,
|
|
|
606ea6 |
+ grub_efi_key_notify_function_t key_notification_function);
|
|
|
606ea6 |
+
|
|
|
606ea6 |
+ grub_efi_status_t
|
|
|
606ea6 |
+ (*unregister_key_notify) (struct grub_efi_simple_text_input_ex_interface *this,
|
|
|
606ea6 |
+ void *notification_handle);
|
|
|
606ea6 |
+};
|
|
|
606ea6 |
+typedef struct grub_efi_simple_text_input_ex_interface grub_efi_simple_text_input_ex_interface_t;
|
|
|
606ea6 |
+
|
|
|
606ea6 |
struct grub_efi_simple_text_output_interface
|
|
|
606ea6 |
{
|
|
|
606ea6 |
grub_efi_status_t
|