diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c index b2f4f873c3..f6706c68fc 100644 --- a/src/boot/efi/boot.c +++ b/src/boot/efi/boot.c @@ -182,6 +182,9 @@ static BOOLEAN line_edit( cursor_color = TEXT_ATTR_SWAP(cursor_color); err = console_key_read(&key, 750 * 1000); + if (!IN_SET(err, EFI_SUCCESS, EFI_TIMEOUT, EFI_NOT_READY)) + return FALSE; + print_at(cursor + 1, y_pos, COLOR_EDIT, print + cursor); } while (EFI_ERROR(err)); @@ -436,8 +439,16 @@ static void ps_bool(const CHAR16 *fmt, BOOLEAN value) { Print(fmt, yes_no(value)); } -static void print_status(Config *config, CHAR16 *loaded_image_path) { +static BOOLEAN ps_continue(void) { UINT64 key; + EFI_STATUS err; + + Print(L"\n--- Press any key to continue, ESC or q to quit. ---\n\n"); + err = console_key_read(&key, UINT64_MAX); + return !EFI_ERROR(err) && !IN_SET(key, KEYPRESS(0, SCAN_ESC, 0), KEYPRESS(0, 0, 'q'), KEYPRESS(0, 0, 'Q')); +} + +static void print_status(Config *config, CHAR16 *loaded_image_path) { UINTN x_max, y_max; UINT32 screen_width = 0, screen_height = 0; SecureBootMode secure; @@ -468,8 +479,8 @@ static void print_status(Config *config, CHAR16 *loaded_image_path) { ps_bool(L" TPM: %s\n", tpm_present()); Print(L" console mode: %d/%d (%lux%lu @%ux%u)\n", ST->ConOut->Mode->Mode, ST->ConOut->Mode->MaxMode - 1LL, x_max, y_max, screen_width, screen_height); - Print(L"\n--- Press any key to continue. ---\n\n"); - console_key_read(&key, UINT64_MAX); + if (!ps_continue()) + return; switch (config->timeout_sec_config) { case TIMEOUT_UNSET: @@ -519,8 +530,8 @@ static void print_status(Config *config, CHAR16 *loaded_image_path) { if (config->console_mode_efivar != CONSOLE_MODE_KEEP) Print(L"console-mode (EFI var): %ld\n", config->console_mode_efivar); - Print(L"\n--- Press any key to continue. ---\n\n"); - console_key_read(&key, UINT64_MAX); + if (!ps_continue()) + return; for (UINTN i = 0; i < config->entry_count; i++) { ConfigEntry *entry = config->entries[i]; @@ -545,10 +556,8 @@ static void print_status(Config *config, CHAR16 *loaded_image_path) { Print(L" next path: %s\\%s\n", entry->path, entry->next_name); } - Print(L"\n--- Press any key to continue, ESC or q to quit. ---\n\n"); - console_key_read(&key, UINT64_MAX); - if (key == KEYPRESS(0, SCAN_ESC, 0) || key == KEYPRESS(0, 0, 'q') || key == KEYPRESS(0, 0, 'Q')) - break; + if (!ps_continue()) + return; } } @@ -734,7 +743,12 @@ static BOOLEAN menu_run( beep(idx_highlight + 1); err = console_key_read(&key, timeout_remain > 0 ? 1000 * 1000 : UINT64_MAX); + if (err == EFI_NOT_READY) + /* No input device returned a key, try again. This + * normally should not happen. */ + continue; if (err == EFI_TIMEOUT) { + assert(timeout_remain > 0); timeout_remain--; if (timeout_remain == 0) { exit = TRUE; @@ -743,8 +757,13 @@ static BOOLEAN menu_run( /* update status */ continue; - } else - timeout_remain = 0; + } + if (EFI_ERROR(err)) { + exit = TRUE; + break; + } + + timeout_remain = 0; /* clear status after keystroke */ if (status) { diff --git a/src/boot/efi/console.c b/src/boot/efi/console.c index cd5c8b6348..937ad7ddfd 100644 --- a/src/boot/efi/console.c +++ b/src/boot/efi/console.c @@ -124,29 +124,27 @@ EFI_STATUS console_key_read(UINT64 *key, UINT64 timeout_usec) { * The two may be out of sync on some firmware, giving us double input. */ if (conInEx) { EFI_KEY_DATA keydata; - UINT64 keypress; UINT32 shift = 0; err = conInEx->ReadKeyStrokeEx(conInEx, &keydata); if (EFI_ERROR(err)) return err; - /* do not distinguish between left and right keys */ - if (keydata.KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) { - if (keydata.KeyState.KeyShiftState & (EFI_RIGHT_CONTROL_PRESSED|EFI_LEFT_CONTROL_PRESSED)) + if (FLAGS_SET(keydata.KeyState.KeyShiftState, EFI_SHIFT_STATE_VALID)) { + /* Do not distinguish between left and right keys (set both flags). */ + if (keydata.KeyState.KeyShiftState & EFI_SHIFT_PRESSED) + shift |= EFI_SHIFT_PRESSED; + if (keydata.KeyState.KeyShiftState & EFI_CONTROL_PRESSED) shift |= EFI_CONTROL_PRESSED; - if (keydata.KeyState.KeyShiftState & (EFI_RIGHT_ALT_PRESSED|EFI_LEFT_ALT_PRESSED)) + if (keydata.KeyState.KeyShiftState & EFI_ALT_PRESSED) shift |= EFI_ALT_PRESSED; + if (keydata.KeyState.KeyShiftState & EFI_LOGO_PRESSED) + shift |= EFI_LOGO_PRESSED; } /* 32 bit modifier keys + 16 bit scan code + 16 bit unicode */ - keypress = KEYPRESS(shift, keydata.Key.ScanCode, keydata.Key.UnicodeChar); - if (keypress > 0) { - *key = keypress; - return EFI_SUCCESS; - } - - return EFI_NOT_READY; + *key = KEYPRESS(shift, keydata.Key.ScanCode, keydata.Key.UnicodeChar); + return EFI_SUCCESS; } else if (!EFI_ERROR(BS->CheckEvent(ST->ConIn->WaitForKey))) { EFI_INPUT_KEY k; diff --git a/src/boot/efi/console.h b/src/boot/efi/console.h index c27c19b39f..cada643077 100644 --- a/src/boot/efi/console.h +++ b/src/boot/efi/console.h @@ -3,10 +3,15 @@ #include "missing_efi.h" -#define EFI_CONTROL_PRESSED (EFI_RIGHT_CONTROL_PRESSED|EFI_LEFT_CONTROL_PRESSED) -#define EFI_ALT_PRESSED (EFI_RIGHT_ALT_PRESSED|EFI_LEFT_ALT_PRESSED) +enum { + EFI_SHIFT_PRESSED = EFI_RIGHT_SHIFT_PRESSED|EFI_LEFT_SHIFT_PRESSED, + EFI_CONTROL_PRESSED = EFI_RIGHT_CONTROL_PRESSED|EFI_LEFT_CONTROL_PRESSED, + EFI_ALT_PRESSED = EFI_RIGHT_ALT_PRESSED|EFI_LEFT_ALT_PRESSED, + EFI_LOGO_PRESSED = EFI_RIGHT_LOGO_PRESSED|EFI_LEFT_LOGO_PRESSED, +}; + #define KEYPRESS(keys, scan, uni) ((((UINT64)keys) << 32) | (((UINT64)scan) << 16) | (uni)) -#define KEYCHAR(k) ((k) & 0xffff) +#define KEYCHAR(k) ((CHAR16)(k)) #define CHAR_CTRL(c) ((c) - 'a' + 1) enum { diff --git a/src/boot/efi/missing_efi.h b/src/boot/efi/missing_efi.h index b0bd00365f..f9700e3422 100644 --- a/src/boot/efi/missing_efi.h +++ b/src/boot/efi/missing_efi.h @@ -13,10 +13,14 @@ #define SimpleTextInputExProtocol ((EFI_GUID)EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID) #define EFI_SHIFT_STATE_VALID 0x80000000 +#define EFI_RIGHT_SHIFT_PRESSED 0x00000001 +#define EFI_LEFT_SHIFT_PRESSED 0x00000002 #define EFI_RIGHT_CONTROL_PRESSED 0x00000004 #define EFI_LEFT_CONTROL_PRESSED 0x00000008 #define EFI_RIGHT_ALT_PRESSED 0x00000010 #define EFI_LEFT_ALT_PRESSED 0x00000020 +#define EFI_RIGHT_LOGO_PRESSED 0x00000040 +#define EFI_LEFT_LOGO_PRESSED 0x00000080 struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL;