From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from list by lists.gnu.org with archive (Exim 4.71) id 1ZkzrW-0005fB-OW for mharc-grub-devel@gnu.org; Sat, 10 Oct 2015 15:31:22 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:34301) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZkzCe-00052J-Ld for grub-devel@gnu.org; Sat, 10 Oct 2015 14:49:10 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ZkzCZ-00082J-HT for grub-devel@gnu.org; Sat, 10 Oct 2015 14:49:08 -0400 Received: from mail-lb0-x236.google.com ([2a00:1450:4010:c04::236]:35669) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZkzCZ-00082D-7U for grub-devel@gnu.org; Sat, 10 Oct 2015 14:49:03 -0400 Received: by lbwr8 with SMTP id r8so109246943lbw.2 for ; Sat, 10 Oct 2015 11:49:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=subject:to:references:from:message-id:date:user-agent:mime-version :in-reply-to:content-type:content-transfer-encoding; bh=JDXhYDiz7R11kk3xSyl0YtZ/gIaIgr0dFHS83+1HYd8=; b=j5Gywjsi3Rm0CMSIV7iZgEZsmD6Xl59h1yBLBXnhaEMcHKdpz8RqsArV0Xz8MUeh8N JNyQiP8vwpg2hDsrogOHMdEj7HL4bOK5cEX0996QpAIbmCXsFeiU3Q9557LhpzwZsiM7 uxtwFAbERb+fbt2J9EaojUcJ/7eSw0kgy1Tfhtm1tYdr7vaU6+WP86VPW/LoUXXCRzyz iR+wMKIcc6c5hf5ai7ykgWQFN3lBjTUJxXfimo5WarNZJnzuCvZSFnu965BcoBtGHwQY CQKZPxGUhAkrQh2lZ31EtugzxftbSwhgUOzuJpIynlbhKYcZjS510f5Z3Zsj4l0icagH XjyQ== X-Received: by 10.112.170.35 with SMTP id aj3mr921203lbc.108.1444502942250; Sat, 10 Oct 2015 11:49:02 -0700 (PDT) Received: from [192.168.1.43] (ppp91-76-142-206.pppoe.mtu-net.ru. [91.76.142.206]) by smtp.gmail.com with ESMTPSA id w143sm1385907lfd.2.2015.10.10.11.49.01 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sat, 10 Oct 2015 11:49:01 -0700 (PDT) Subject: Re: [PATCH] Make CTRL and ALT keys work as expected on EFI systems (version 5). To: The development of GNU GRUB References: <1393366348-22020-1-git-send-email-pjones@redhat.com> From: Andrei Borzenkov Message-ID: <56195D9A.2010306@gmail.com> Date: Sat, 10 Oct 2015 21:48:58 +0300 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Thunderbird/38.3.0 MIME-Version: 1.0 In-Reply-To: <1393366348-22020-1-git-send-email-pjones@redhat.com> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2a00:1450:4010:c04::236 X-BeenThere: grub-devel@gnu.org X-Mailman-Version: 2.1.14 Precedence: list Reply-To: The development of GNU GRUB List-Id: The development of GNU GRUB List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 10 Oct 2015 18:49:10 -0000 26.02.2014 02:12, Peter Jones пишет: > This is version 4. > > 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. > > Changes from version 3: > - Do not add the shift modifier for any ascii character between space > (0x20) and DEL (0x7f); the combination of the modifier and many of the > keys causes it not to be recognized at all. Specifically, if we > include the modifier on any querty punctuation character, i.e. > anything the string "~!@#$%^&*()_+{}|:\"<>?" represents in C, it stops > being recognized whatsoever. > > Changes from version 4: > - Always initialize term->data from locate protocol (i.e. make it > unconditional.) > Are there open issues with this patch? Is it used by Fedora? The part about SHIFT state bothers me, what happens for non-ASCII printable characters? UEFI spec is extremely vague here. As currently there is no way to actually input Ctrl-X or similar this is needed. It may also allow us to actually implement keystatus on EFI. > Signed-off-by: Peter Jones > --- > grub-core/term/efi/console.c | 118 +++++++++++++++++++++++++++++++++++-------- > include/grub/efi/api.h | 65 +++++++++++++++++++++++- > 2 files changed, 161 insertions(+), 22 deletions(-) > > diff --git a/grub-core/term/efi/console.c b/grub-core/term/efi/console.c > index a37eb84..677eab5 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. > @@ -139,9 +125,98 @@ grub_console_getkey (struct grub_term_input *term __attribute__ ((unused))) > else if (key.scan_code < ARRAY_SIZE (efi_codes)) > return efi_codes[key.scan_code]; > > + if (key.unicode_char >= 0x20 && key.unicode_char <= 0x7f) > + return key.unicode_char; > + > 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; > + > + kss = key_data.key_state.key_shift_state; > + key = grub_efi_translate_key(key_data.key); > + > + if (key == GRUB_TERM_NO_KEY) > + return GRUB_TERM_NO_KEY; > + > + if (kss & GRUB_EFI_SHIFT_STATE_VALID) > + { > + if ((kss & GRUB_EFI_LEFT_SHIFT_PRESSED > + || kss & GRUB_EFI_RIGHT_SHIFT_PRESSED) > + && !(key >= 0x20 && key <= 0x7f)) > + 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); > + 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 +318,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 +326,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 +337,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 +367,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 >