grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] Make CTRL and ALT keys work as expected on EFI systems.


From: Peter Jones
Subject: [PATCH] Make CTRL and ALT keys work as expected on EFI systems.
Date: Tue, 4 Feb 2014 11:30:56 -0500

Signed-off-by: Peter Jones <address@hidden>
---
 grub-core/term/efi/console.c | 119 +++++++++++++++++++++++++++++++++++++++----
 include/grub/efi/api.h       |  65 ++++++++++++++++++++++-
 2 files changed, 174 insertions(+), 10 deletions(-)

diff --git a/grub-core/term/efi/console.c b/grub-core/term/efi/console.c
index a37eb84..8c3b52b 100644
--- a/grub-core/term/efi/console.c
+++ b/grub-core/term/efi/console.c
@@ -109,15 +109,12 @@ const unsigned efi_codes[] =
 
 
 static int
-grub_console_getkey (struct grub_term_input *term __attribute__ ((unused)))
+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;
 
-  if (grub_efi_is_finished)
-    return 0;
-
   i = grub_efi_system_table->con_in;
   status = efi_call_2 (i->read_key_stroke, i, &key);
 
@@ -142,6 +139,109 @@ grub_console_getkey (struct grub_term_input *term 
__attribute__ ((unused)))
   return GRUB_TERM_NO_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;
+
+  if (key_data.key.scan_code == 0)
+    {
+      /* Some firmware implementations use VT100-style codes against the spec.
+        This is especially likely if driven by serial.
+       */
+      if (key_data.key.unicode_char < 0x20
+         && key_data.key.unicode_char != 0
+         && key_data.key.unicode_char != '\t'
+         && key_data.key.unicode_char != '\b'
+         && key_data.key.unicode_char != '\n'
+         && key_data.key.unicode_char != '\r')
+       key = GRUB_TERM_CTRL | (key_data.key.unicode_char - 1 + 'a');
+      else
+       key = key_data.key.unicode_char;
+    }
+  else if (key_data.key.scan_code < ARRAY_SIZE (efi_codes))
+    key = efi_codes[key_data.key.scan_code];
+
+  if (key == -1)
+    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_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_uintn_t num_handles = 0;
+  grub_efi_handle_t *handles = NULL;
+  grub_efi_handle_t *handle = NULL;
+  grub_efi_guid_t text_input_ex_guid =
+    GRUB_EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID;
+  grub_efi_guid_t text_input_guid = GRUB_EFI_SIMPLE_TEXT_INPUT_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;
+
+  handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL,
+                                   &text_input_ex_guid,
+                                   0, &num_handles);
+
+  for (handle = handles; num_handles--; handle++)
+    {
+      grub_efi_simple_input_interface_t *st;
+
+      st = grub_efi_open_protocol(*handle, &text_input_guid,
+                                 GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+
+      if (st != grub_efi_system_table->con_in)
+       continue;
+      if (st == NULL)
+       continue;
+
+      text_input = grub_efi_open_protocol(*handle, &text_input_ex_guid,
+                                         GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+      break;
+    }
+    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 +343,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 +351,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 +362,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 +392,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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]