kern/term: Accept ESC, F4 and holding SHIFT as user interrupt keys

On some devices the ESC key is the hotkey to enter the BIOS/EFI setup
screen, making it really hard to time pressing it right. Besides that
ESC is also pretty hard to discover for a user who does not know it
will unhide the menu.

This commit makes F4, which was chosen because is not used as a hotkey
to enter the BIOS setup by any vendor, also interrupt sleeps / stop the
menu countdown.

This solves the ESC gets into the BIOS setup and also somewhat solves
the discoverability issue, but leaves the timing issue unresolved.

This commit fixes the timing issue by also adding support for keeping
SHIFT pressed during boot to stop the menu countdown. This matches
what Ubuntu is doing, which should also help with discoverability.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
This commit is contained in:
Hans de Goede 2020-04-15 12:26:22 +02:00 committed by Daniel Kiper
parent 2d7c3abd87
commit 12341958d2
5 changed files with 41 additions and 18 deletions

View file

@ -1330,12 +1330,12 @@ menu and then wait for the timeout set by @samp{GRUB_TIMEOUT} to expire
before booting the default entry. Pressing a key interrupts the timeout. before booting the default entry. Pressing a key interrupts the timeout.
If this option is set to @samp{countdown} or @samp{hidden}, then, before If this option is set to @samp{countdown} or @samp{hidden}, then, before
displaying the menu, GRUB will wait for the timeout set by displaying the menu, GRUB will wait for the timeout set by @samp{GRUB_TIMEOUT}
@samp{GRUB_TIMEOUT} to expire. If @key{ESC} is pressed during that time, it to expire. If @key{ESC} or @key{F4} are pressed, or @key{SHIFT} is held down
will display the menu and wait for input. If a hotkey associated with a during that time, it will display the menu and wait for input. If a hotkey
menu entry is pressed, it will boot the associated menu entry immediately. associated with a menu entry is pressed, it will boot the associated menu entry
If the timeout expires before either of these happens, it will boot the immediately. If the timeout expires before either of these happens, it will
default entry. In the @samp{countdown} case, it will show a one-line boot the default entry. In the @samp{countdown} case, it will show a one-line
indication of the remaining time. indication of the remaining time.
@item GRUB_DEFAULT_BUTTON @item GRUB_DEFAULT_BUTTON
@ -1559,16 +1559,16 @@ configurations, but have better replacements:
@table @samp @table @samp
@item GRUB_HIDDEN_TIMEOUT @item GRUB_HIDDEN_TIMEOUT
Wait this many seconds before displaying the menu. If @key{ESC} is pressed Wait this many seconds before displaying the menu. If @key{ESC} or @key{F4} are
during that time, display the menu and wait for input according to pressed, or @key{SHIFT} is held down during that time, display the menu and wait
@samp{GRUB_TIMEOUT}. If a hotkey associated with a menu entry is pressed, for input according to @samp{GRUB_TIMEOUT}. If a hotkey associated with a menu
boot the associated menu entry immediately. If the timeout expires before entry is pressed, boot the associated menu entry immediately. If the timeout
either of these happens, display the menu for the number of seconds expires before either of these happens, display the menu for the number of
specified in @samp{GRUB_TIMEOUT} before booting the default entry. seconds specified in @samp{GRUB_TIMEOUT} before booting the default entry.
If you set @samp{GRUB_HIDDEN_TIMEOUT}, you should also set If you set @samp{GRUB_HIDDEN_TIMEOUT}, you should also set
@samp{GRUB_TIMEOUT=0} so that the menu is not displayed at all unless @samp{GRUB_TIMEOUT=0} so that the menu is not displayed at all unless
@key{ESC} is pressed. @key{ESC} or @key{F4} are pressed, or @key{SHIFT} is held down.
This option is unset by default, and is deprecated in favour of the less This option is unset by default, and is deprecated in favour of the less
confusing @samp{GRUB_TIMEOUT_STYLE=countdown} or confusing @samp{GRUB_TIMEOUT_STYLE=countdown} or
@ -5162,9 +5162,10 @@ Alias for @code{hashsum --hash sha512 arg @dots{}}. See command @command{hashsum
@deffn Command sleep [@option{--verbose}] [@option{--interruptible}] count @deffn Command sleep [@option{--verbose}] [@option{--interruptible}] count
Sleep for @var{count} seconds. If option @option{--interruptible} is given, Sleep for @var{count} seconds. If option @option{--interruptible} is given,
allow @key{ESC} to interrupt sleep. With @option{--verbose} show countdown allow pressing @key{ESC}, @key{F4} or holding down @key{SHIFT} to interrupt
of remaining seconds. Exit code is set to 0 if timeout expired and to 1 sleep. With @option{--verbose} show countdown of remaining seconds. Exit code
if timeout was interrupted by @key{ESC}. is set to 0 if timeout expired and to 1 if timeout was interrupted using any
of the mentioned keys.
@end deffn @end deffn

View file

@ -55,7 +55,7 @@ grub_interruptible_millisleep (grub_uint32_t ms)
start = grub_get_time_ms (); start = grub_get_time_ms ();
while (grub_get_time_ms () - start < ms) while (grub_get_time_ms () - start < ms)
if (grub_getkey_noblock () == GRUB_TERM_ESC) if (grub_key_is_interrupt (grub_getkey_noblock ()))
return 1; return 1;
return 0; return 0;

View file

@ -138,6 +138,27 @@ grub_getkeystatus (void)
return status; return status;
} }
int
grub_key_is_interrupt (int key)
{
/*
* ESC sometimes is the BIOS setup hotkey and may be hard to discover, also
* check F4, which was chosen because is not used as a hotkey to enter the
* BIOS setup by any vendor.
*/
if (key == GRUB_TERM_ESC || key == GRUB_TERM_KEY_F4)
return 1;
/*
* Pressing keys at the right time during boot is hard to time, also allow
* interrupting sleeps / the menu countdown by keeping shift pressed.
*/
if (grub_getkeystatus() & (GRUB_TERM_STATUS_LSHIFT | GRUB_TERM_STATUS_RSHIFT))
return 1;
return 0;
}
void void
grub_refresh (void) grub_refresh (void)
{ {

View file

@ -623,7 +623,7 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot)
if (entry >= 0) if (entry >= 0)
break; break;
} }
if (key == GRUB_TERM_ESC) if (grub_key_is_interrupt (key))
{ {
timeout = -1; timeout = -1;
break; break;

View file

@ -330,6 +330,7 @@ void grub_putcode (grub_uint32_t code, struct grub_term_output *term);
int EXPORT_FUNC(grub_getkey) (void); int EXPORT_FUNC(grub_getkey) (void);
int EXPORT_FUNC(grub_getkey_noblock) (void); int EXPORT_FUNC(grub_getkey_noblock) (void);
int EXPORT_FUNC(grub_getkeystatus) (void); int EXPORT_FUNC(grub_getkeystatus) (void);
int EXPORT_FUNC(grub_key_is_interrupt) (int key);
void grub_cls (void); void grub_cls (void);
void EXPORT_FUNC(grub_refresh) (void); void EXPORT_FUNC(grub_refresh) (void);
void grub_puts_terminal (const char *str, struct grub_term_output *term); void grub_puts_terminal (const char *str, struct grub_term_output *term);