audk/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/InputHandler.c

1581 lines
53 KiB
C
Raw Normal View History

/*++
Copyright (c) 2006, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
InputHandler.C
Abstract:
Implementation for handling user input from the User Interface
Revision History
--*/
#include "Setup.h"
#include "Ui.h"
#include "Colors.h"
#ifndef EFI_MAX
#define EFI_MAX(_a, _b) ((_a) > (_b) ? (_a) : (_b))
#endif
EFI_STATUS
ReadString (
IN UI_MENU_OPTION *MenuOption,
OUT CHAR16 *StringPtr
)
{
EFI_STATUS Status;
EFI_INPUT_KEY Key;
CHAR16 NullCharacter;
UINTN ScreenSize;
EFI_TAG *Tag;
CHAR16 Space[2];
CHAR16 KeyPad[2];
BOOLEAN SelectionComplete;
CHAR16 *TempString;
CHAR16 *BufferedString;
UINTN Index;
UINTN Count;
UINTN Start;
UINTN Top;
CHAR16 *PromptForDataString;
UINTN DimensionsWidth;
UINTN DimensionsHeight;
BOOLEAN CursorVisible;
DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;
DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow;
PromptForDataString = GetToken (STRING_TOKEN (PROMPT_FOR_DATA), gHiiHandle);
NullCharacter = CHAR_NULL;
ScreenSize = GetStringWidth (PromptForDataString) / 2;
Tag = MenuOption->ThisTag;
Space[0] = L' ';
Space[1] = CHAR_NULL;
SelectionComplete = FALSE;
TempString = AllocateZeroPool (MenuOption->ThisTag->Maximum * 2);
ASSERT (TempString);
if (ScreenSize < (Tag->Maximum / (UINTN) 2)) {
ScreenSize = Tag->Maximum / 2;
}
if ((ScreenSize + 2) > DimensionsWidth) {
ScreenSize = DimensionsWidth - 2;
}
BufferedString = AllocateZeroPool (ScreenSize * 2);
ASSERT (BufferedString);
Start = (DimensionsWidth - ScreenSize - 2) / 2 + gScreenDimensions.LeftColumn + 1;
Top = ((DimensionsHeight - 6) / 2) + gScreenDimensions.TopRow - 1;
//
// Display prompt for string
//
CreatePopUp (ScreenSize, 4, &NullCharacter, PromptForDataString, Space, &NullCharacter);
gBS->FreePool (PromptForDataString);
gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY));
CursorVisible = gST->ConOut->Mode->CursorVisible;
gST->ConOut->EnableCursor (gST->ConOut, TRUE);
do {
Status = WaitForKeyStroke (&Key);
gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY));
switch (Key.UnicodeChar) {
case CHAR_NULL:
switch (Key.ScanCode) {
case SCAN_LEFT:
break;
case SCAN_RIGHT:
break;
case SCAN_ESC:
gBS->FreePool (TempString);
gBS->FreePool (BufferedString);
gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
gST->ConOut->EnableCursor (gST->ConOut, CursorVisible);
return EFI_DEVICE_ERROR;
default:
break;
}
break;
case CHAR_CARRIAGE_RETURN:
if (GetStringWidth (StringPtr) >= MenuOption->ThisTag->Minimum) {
SelectionComplete = TRUE;
gBS->FreePool (TempString);
gBS->FreePool (BufferedString);
gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
gST->ConOut->EnableCursor (gST->ConOut, CursorVisible);
return EFI_SUCCESS;
} else {
ScreenSize = GetStringWidth (gMiniString) / 2;
CreatePopUp (ScreenSize, 4, &NullCharacter, gMiniString, gPressEnter, &NullCharacter);
//
// Simply create a popup to tell the user that they had typed in too few characters.
// To save code space, we can then treat this as an error and return back to the menu.
//
do {
Status = WaitForKeyStroke (&Key);
} while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
gBS->FreePool (TempString);
gBS->FreePool (BufferedString);
gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
gST->ConOut->EnableCursor (gST->ConOut, CursorVisible);
return EFI_DEVICE_ERROR;
}
break;
case CHAR_BACKSPACE:
if (StringPtr[0] != CHAR_NULL) {
for (Index = 0; StringPtr[Index] != CHAR_NULL; Index++) {
TempString[Index] = StringPtr[Index];
}
//
// Effectively truncate string by 1 character
//
TempString[Index - 1] = CHAR_NULL;
StrCpy (StringPtr, TempString);
}
default:
//
// If it is the beginning of the string, don't worry about checking maximum limits
//
if ((StringPtr[0] == CHAR_NULL) && (Key.UnicodeChar != CHAR_BACKSPACE)) {
StrnCpy (StringPtr, &Key.UnicodeChar, 1);
StrnCpy (TempString, &Key.UnicodeChar, 1);
} else if ((GetStringWidth (StringPtr) < MenuOption->ThisTag->Maximum) && (Key.UnicodeChar != CHAR_BACKSPACE)) {
KeyPad[0] = Key.UnicodeChar;
KeyPad[1] = CHAR_NULL;
StrCat (StringPtr, KeyPad);
StrCat (TempString, KeyPad);
}
//
// If the width of the input string is now larger than the screen, we nee to
// adjust the index to start printing portions of the string
//
SetUnicodeMem (BufferedString, ScreenSize - 1, L' ');
PrintStringAt (Start + 1, Top + 3, BufferedString);
if ((GetStringWidth (StringPtr) / 2) > (DimensionsWidth - 2)) {
Index = (GetStringWidth (StringPtr) / 2) - DimensionsWidth + 2;
} else {
Index = 0;
}
for (Count = 0; Index + 1 < GetStringWidth (StringPtr) / 2; Index++, Count++) {
BufferedString[Count] = StringPtr[Index];
}
PrintStringAt (Start + 1, Top + 3, BufferedString);
break;
}
gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
gST->ConOut->SetCursorPosition (gST->ConOut, Start + GetStringWidth (StringPtr) / 2, Top + 3);
} while (!SelectionComplete);
gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
gST->ConOut->EnableCursor (gST->ConOut, CursorVisible);
return Status;
}
EFI_STATUS
ReadPassword (
IN UI_MENU_OPTION *MenuOption,
IN BOOLEAN PromptForPassword,
IN EFI_TAG *Tag,
IN EFI_IFR_DATA_ARRAY *PageData,
IN BOOLEAN SecondEntry,
IN EFI_FILE_FORM_TAGS *FileFormTags,
OUT CHAR16 *StringPtr
)
{
EFI_STATUS Status;
UINTN PasswordSize;
UINTN ScreenSize;
CHAR16 NullCharacter;
CHAR16 Space[2];
EFI_INPUT_KEY Key;
CHAR16 KeyPad[2];
UINTN Index;
UINTN Start;
UINTN Top;
CHAR16 *TempString;
CHAR16 *TempString2;
BOOLEAN Confirmation;
BOOLEAN ConfirmationComplete;
EFI_HII_CALLBACK_PACKET *Packet;
EFI_FORM_CALLBACK_PROTOCOL *FormCallback;
EFI_VARIABLE_DEFINITION *VariableDefinition;
UINTN DimensionsWidth;
UINTN DimensionsHeight;
EFI_IFR_DATA_ENTRY *DataEntry;
DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;
DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow;
VariableDefinition = NULL;
PasswordSize = 0;
NullCharacter = CHAR_NULL;
Space[0] = L' ';
Space[1] = CHAR_NULL;
Confirmation = FALSE;
ConfirmationComplete = FALSE;
Status = EFI_SUCCESS;
FormCallback = NULL;
Packet = NULL;
//
// Remember that dynamic pages in an environment where all pages are not
// dynamic require us to call back to the user to give them an opportunity
// to register fresh information in the HII database so that we can extract it.
//
Status = gBS->HandleProtocol (
(VOID *) (UINTN) MenuOption->Tags[0].CallbackHandle,
&gEfiFormCallbackProtocolGuid,
(VOID **) &FormCallback
);
TempString = AllocateZeroPool (MenuOption->ThisTag->Maximum * 2);
TempString2 = AllocateZeroPool (MenuOption->ThisTag->Maximum * 2);
ASSERT (TempString);
ASSERT (TempString2);
if (Tag->Flags & EFI_IFR_FLAG_INTERACTIVE) {
//
// Password requires a callback to determine if a password exists
//
DataEntry = (EFI_IFR_DATA_ENTRY *) (PageData + 1);
DataEntry->OpCode = EFI_IFR_PASSWORD_OP;
DataEntry->Length = 3;
ExtractRequestedNvMap (FileFormTags, Tag->VariableNumber, &VariableDefinition);
//
// The user is about to be prompted with a password field, Data = 0 (Return Status determines the type of prompt)
//
DataEntry->Data = (VOID *) (UINTN) (UINT8) (0 + SecondEntry * 2);
PageData->NvRamMap = VariableDefinition->NvRamMap;
if ((FormCallback != NULL) && (FormCallback->Callback != NULL)) {
Status = FormCallback->Callback (
FormCallback,
Tag->Key,
PageData,
&Packet
);
}
//
// If error on return, continue with the reading of a typed in password to verify user knows password
// If no error, there is no password set, so prompt for new password
// if the previous callback was to verify the user knew password, and user typed it correctly - should return no error
//
if (!EFI_ERROR (Status)) {
PromptForPassword = FALSE;
//
// Simulate this as the second entry into this routine for an interactive behavior
//
SecondEntry = TRUE;
} else if (Status == EFI_NOT_READY) {
Error:
if (Packet != NULL) {
//
// Upon error, we will likely receive a string to print out
// Display error popup
//
ScreenSize = EFI_MAX(GetStringWidth (Packet->String), GetStringWidth (gPressEnter)) / 2;
CreatePopUp (ScreenSize, 4, &NullCharacter, Packet->String, gPressEnter, &NullCharacter);
gBS->FreePool (Packet);
do {
Status = WaitForKeyStroke (&Key);
} while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
}
gBS->FreePool (TempString);
gBS->FreePool (TempString2);
return EFI_NOT_READY;
}
}
do {
//
// Display PopUp Screen
//
ScreenSize = GetStringWidth (gPromptForNewPassword) / 2;
if (GetStringWidth (gConfirmPassword) / 2 > ScreenSize) {
ScreenSize = GetStringWidth (gConfirmPassword) / 2;
}
Start = (DimensionsWidth - ScreenSize - 4) / 2 + gScreenDimensions.LeftColumn + 2;
Top = ((DimensionsHeight - 6) / 2) + gScreenDimensions.TopRow - 1;
if (!Confirmation) {
if (PromptForPassword) {
CreatePopUp (ScreenSize, 4, &NullCharacter, gPromptForPassword, Space, &NullCharacter);
} else {
CreatePopUp (ScreenSize, 4, &NullCharacter, gPromptForNewPassword, Space, &NullCharacter);
}
} else {
CreatePopUp (ScreenSize, 4, &NullCharacter, gConfirmPassword, Space, &NullCharacter);
StringPtr[0] = CHAR_NULL;
}
do {
Status = WaitForKeyStroke (&Key);
switch (Key.UnicodeChar) {
case CHAR_NULL:
if (Key.ScanCode == SCAN_ESC) {
return EFI_NOT_READY;
}
ConfirmationComplete = FALSE;
break;
case CHAR_CARRIAGE_RETURN:
if (Tag->Flags & EFI_IFR_FLAG_INTERACTIVE) {
//
// User just typed a string in
//
DataEntry = (EFI_IFR_DATA_ENTRY *) (PageData + 1);
DataEntry->OpCode = EFI_IFR_PASSWORD_OP;
//
// If the user just typed in a password, Data = 1
// If the user just typed in a password to confirm the previous password, Data = 2
//
if (!Confirmation) {
DataEntry->Length = 3;
DataEntry->Data = (VOID *) (UINTN) (UINT8) (1 + SecondEntry * 2);
if ((FormCallback != NULL) && (FormCallback->Callback != NULL)) {
Status = FormCallback->Callback (
FormCallback,
Tag->Key,
PageData,
&Packet
);
}
DataEntry->Length = sizeof (EFI_IFR_DATA_ENTRY);
DataEntry->Data = (VOID *) TempString;
} else {
DataEntry->Length = 3;
DataEntry->Data = (VOID *) (UINTN) (UINT8) (2 + SecondEntry * 2);
if ((FormCallback != NULL) && (FormCallback->Callback != NULL)) {
Status = FormCallback->Callback (
FormCallback,
Tag->Key,
PageData,
&Packet
);
}
DataEntry->Length = sizeof (EFI_IFR_DATA_ENTRY);
DataEntry->Data = (VOID *) TempString2;
}
if ((FormCallback != NULL) && (FormCallback->Callback != NULL)) {
Status = FormCallback->Callback (
FormCallback,
Tag->Key,
PageData,
&Packet
);
}
//
// If this was the confirmation round of callbacks
// and an error comes back, display an error
//
if (Confirmation) {
if (EFI_ERROR (Status)) {
if (Packet->String == NULL) {
ScreenSize = EFI_MAX (GetStringWidth (gConfirmError), GetStringWidth (gPressEnter)) / 2;
CreatePopUp (ScreenSize, 4, &NullCharacter, gConfirmError, gPressEnter, &NullCharacter);
} else {
ScreenSize = EFI_MAX (GetStringWidth (Packet->String), GetStringWidth (gPressEnter)) / 2;
CreatePopUp (ScreenSize, 4, &NullCharacter, Packet->String, gPressEnter, &NullCharacter);
gBS->FreePool (Packet);
}
StringPtr[0] = CHAR_NULL;
do {
Status = WaitForKeyStroke (&Key);
if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
gBS->FreePool (TempString);
gBS->FreePool (TempString2);
return EFI_NOT_READY;
}
} while (1);
} else {
gBS->FreePool (TempString);
gBS->FreePool (TempString2);
return EFI_NOT_READY;
}
} else {
//
// User typed a string in and it wasn't valid somehow from the callback
// For instance, callback may have said that some invalid characters were contained in the string
//
if (Status == EFI_NOT_READY) {
goto Error;
}
if (PromptForPassword && EFI_ERROR (Status)) {
gBS->FreePool (TempString);
gBS->FreePool (TempString2);
return EFI_DEVICE_ERROR;
}
}
}
if (Confirmation) {
//
// Compare tempstring and tempstring2, if the same, return with StringPtr success
// Otherwise, kick and error box, and return an error
//
if (StrCmp (TempString, TempString2) == 0) {
gBS->FreePool (TempString);
gBS->FreePool (TempString2);
return EFI_SUCCESS;
} else {
ScreenSize = EFI_MAX (GetStringWidth (gConfirmError), GetStringWidth (gPressEnter)) / 2;
CreatePopUp (ScreenSize, 4, &NullCharacter, gConfirmError, gPressEnter, &NullCharacter);
StringPtr[0] = CHAR_NULL;
do {
Status = WaitForKeyStroke (&Key);
if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
gBS->FreePool (TempString);
gBS->FreePool (TempString2);
return EFI_DEVICE_ERROR;
}
} while (1);
}
}
if (PromptForPassword) {
//
// I was asked for a password, return it back in StringPtr
//
gBS->FreePool (TempString);
gBS->FreePool (TempString2);
return EFI_SUCCESS;
} else {
//
// If the two passwords were not the same kick an error popup
//
Confirmation = TRUE;
ConfirmationComplete = TRUE;
break;
}
case CHAR_BACKSPACE:
if (StringPtr[0] != CHAR_NULL) {
if (!Confirmation) {
for (Index = 0; StringPtr[Index] != CHAR_NULL; Index++) {
TempString[Index] = StringPtr[Index];
}
//
// Effectively truncate string by 1 character
//
TempString[Index - 1] = CHAR_NULL;
StrCpy (StringPtr, TempString);
} else {
for (Index = 0; StringPtr[Index] != CHAR_NULL; Index++) {
TempString2[Index] = StringPtr[Index];
}
//
// Effectively truncate string by 1 character
//
TempString2[Index - 1] = CHAR_NULL;
StrCpy (StringPtr, TempString2);
}
ConfirmationComplete = FALSE;
} else {
ConfirmationComplete = FALSE;
}
//
// Must be a character we are interested in!
//
default:
if ((StringPtr[0] == CHAR_NULL) && (Key.UnicodeChar != CHAR_BACKSPACE)) {
if (!Confirmation) {
StrnCpy (StringPtr, &Key.UnicodeChar, 1);
StrnCpy (TempString, &Key.UnicodeChar, 1);
} else {
StrnCpy (StringPtr, &Key.UnicodeChar, 1);
StrnCpy (TempString2, &Key.UnicodeChar, 1);
ConfirmationComplete = FALSE;
}
} else if ((GetStringWidth (StringPtr) / 2 <= (UINTN) (MenuOption->ThisTag->Maximum - 1) / 2) &&
(Key.UnicodeChar != CHAR_BACKSPACE)
) {
KeyPad[0] = Key.UnicodeChar;
KeyPad[1] = CHAR_NULL;
if (!Confirmation) {
StrCat (StringPtr, KeyPad);
StrCat (TempString, KeyPad);
} else {
StrCat (StringPtr, KeyPad);
StrCat (TempString2, KeyPad);
}
}
gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY));
for (Index = 1; Index < ScreenSize; Index++) {
PrintCharAt (Start + Index, Top + 3, L' ');
}
gST->ConOut->SetCursorPosition (
gST->ConOut,
(DimensionsWidth - GetStringWidth (StringPtr) / 2) / 2 + gScreenDimensions.LeftColumn,
Top + 3
);
for (Index = 0; Index + 1 < GetStringWidth (StringPtr) / 2; Index++) {
PrintChar (L'*');
}
gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
break;
}
//
// end switch
//
} while (!ConfirmationComplete);
} while (1);
gBS->FreePool (TempString);
gBS->FreePool (TempString2);
return Status;
}
VOID
EncodePassword (
IN CHAR16 *Password,
IN UINT8 MaxSize
)
{
UINTN Index;
UINTN Loop;
CHAR16 *Buffer;
CHAR16 *Key;
Key = (CHAR16 *) L"MAR10648567";
Buffer = AllocateZeroPool (MaxSize);
ASSERT (Buffer);
for (Index = 0; Key[Index] != 0; Index++) {
for (Loop = 0; Loop < (UINT8) (MaxSize / 2); Loop++) {
Buffer[Loop] = (CHAR16) (Password[Loop] ^ Key[Index]);
}
}
CopyMem (Password, Buffer, MaxSize);
gBS->FreePool (Buffer);
return ;
}
EFI_STATUS
GetNumericInput (
IN UI_MENU_OPTION *MenuOption,
IN EFI_FILE_FORM_TAGS *FileFormTagsHead,
IN BOOLEAN ManualInput,
IN EFI_TAG *Tag,
IN UINTN NumericType,
OUT UINT16 *Value
)
/*++
Routine Description:
This routine reads a numeric value from the user input.
Arguments:
MenuOption - Pointer to the current input menu.
FileFormTagsHead - Pointer to the root of formset.
ManualInput - If the input is manual or not.
Tag - Pointer to all the attributes and values associated with a tag.
Value - Pointer to the numeric value that is going to be read.
Returns:
EFI_SUCCESS - If numerical input is read successfully
EFI_DEVICE_ERROR - If operation fails
--*/
{
EFI_INPUT_KEY Key;
BOOLEAN SelectionComplete;
UINTN Column;
UINTN Row;
CHAR16 FormattedNumber[6];
UINTN PreviousNumber[6];
INTN Number;
UINTN Count;
UINT16 BackupValue;
STRING_REF PopUp;
CHAR16 NullCharacter;
CHAR16 *StringPtr;
EFI_FILE_FORM_TAGS *FileFormTags;
EFI_STATUS Status;
EFI_VARIABLE_DEFINITION *VariableDefinition;
UINTN Loop;
NullCharacter = CHAR_NULL;
StringPtr = NULL;
Column = MenuOption->OptCol;
Row = MenuOption->Row;
Number = 0;
PreviousNumber[0] = 0;
Count = 0;
SelectionComplete = FALSE;
BackupValue = Tag->Value;
FileFormTags = FileFormTagsHead;
if (ManualInput) {
PrintAt (Column, Row, (CHAR16 *) L"[ ]");
Column++;
if (Tag->Operand != EFI_IFR_TIME_OP) {
*Value = BackupValue;
}
}
//
// First time we enter this handler, we need to check to see if
// we were passed an increment or decrement directive
//
do {
Key.UnicodeChar = CHAR_NULL;
if (gDirection != 0) {
Key.ScanCode = gDirection;
gDirection = 0;
goto TheKey2;
}
Status = WaitForKeyStroke (&Key);
TheKey2:
switch (Key.UnicodeChar) {
case '+':
case '-':
if ((Tag->Operand == EFI_IFR_DATE_OP) || (Tag->Operand == EFI_IFR_TIME_OP)) {
Key.UnicodeChar = CHAR_NULL;
if (Key.UnicodeChar == '+') {
Key.ScanCode = SCAN_RIGHT;
} else {
Key.ScanCode = SCAN_LEFT;
}
goto TheKey2;
}
break;
case CHAR_NULL:
switch (Key.ScanCode) {
case SCAN_LEFT:
case SCAN_RIGHT:
if ((Tag->Operand == EFI_IFR_DATE_OP) || (Tag->Operand == EFI_IFR_TIME_OP)) {
//
// By setting this value, we will return back to the caller.
// We need to do this since an auto-refresh will destroy the adjustment
// based on what the real-time-clock is showing. So we always commit
// upon changing the value.
//
gDirection = SCAN_DOWN;
}
if (!ManualInput) {
Tag->Value = *Value;
if (Key.ScanCode == SCAN_LEFT) {
Number = *Value - Tag->Step;
if (Number < Tag->Minimum) {
Number = Tag->Minimum;
}
} else if (Key.ScanCode == SCAN_RIGHT) {
Number = *Value + Tag->Step;
if (Number > Tag->Maximum) {
Number = Tag->Maximum;
}
}
Tag->Value = (UINT16) Number;
*Value = (UINT16) Number;
UnicodeValueToString (
FormattedNumber,
FALSE,
(UINTN) Number,
(sizeof (FormattedNumber) / sizeof (FormattedNumber[0]))
);
Number = (UINT16) GetStringWidth (FormattedNumber);
gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);
if ((Tag->Operand == EFI_IFR_DATE_OP) || (Tag->Operand == EFI_IFR_TIME_OP)) {
for (Loop = 0; Loop < (UINTN) ((Number >= 8) ? 4 : 2); Loop++) {
PrintAt (MenuOption->OptCol + Loop, MenuOption->Row, (CHAR16 *) L" ");
}
} else {
for (Loop = 0; Loop < gOptionBlockWidth; Loop++) {
PrintAt (MenuOption->OptCol + Loop, MenuOption->Row, (CHAR16 *) L" ");
}
}
gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT);
if ((MenuOption->Col + gPromptBlockWidth + 1) == MenuOption->OptCol) {
PrintCharAt (MenuOption->OptCol, Row, LEFT_NUMERIC_DELIMITER);
Column = MenuOption->OptCol + 1;
}
//
// If Number looks like "3", convert it to "03/"
//
if (Number == 4 && (NumericType == DATE_NUMERIC)) {
FormattedNumber[3] = FormattedNumber[1];
FormattedNumber[2] = DATE_SEPARATOR;
FormattedNumber[1] = FormattedNumber[0];
FormattedNumber[0] = L'0';
Number = 8;
}
//
// If Number looks like "13", convert it to "13/"
//
if (Number == 6 && (NumericType == DATE_NUMERIC)) {
FormattedNumber[3] = FormattedNumber[2];
FormattedNumber[2] = DATE_SEPARATOR;
Number = 8;
}
if (Number == 4 &&
(NumericType == TIME_NUMERIC) &&
(MenuOption->Col + gPromptBlockWidth + 8) != MenuOption->OptCol
) {
FormattedNumber[3] = FormattedNumber[1];
FormattedNumber[2] = TIME_SEPARATOR;
FormattedNumber[1] = FormattedNumber[0];
FormattedNumber[0] = L'0';
Number = 8;
}
if (Number == 4 &&
(NumericType == TIME_NUMERIC) &&
(MenuOption->Col + gPromptBlockWidth + 8) == MenuOption->OptCol
) {
FormattedNumber[3] = FormattedNumber[1];
FormattedNumber[2] = RIGHT_NUMERIC_DELIMITER;
FormattedNumber[1] = FormattedNumber[0];
FormattedNumber[0] = L'0';
Number = 8;
}
PrintStringAt (Column, Row, FormattedNumber);
if (Number == 10 && (NumericType == DATE_NUMERIC)) {
PrintChar (RIGHT_NUMERIC_DELIMITER);
}
if (NumericType == REGULAR_NUMERIC) {
PrintChar (RIGHT_NUMERIC_DELIMITER);
}
}
break;
case SCAN_UP:
case SCAN_DOWN:
goto EnterCarriageReturn;
case SCAN_ESC:
return EFI_DEVICE_ERROR;
default:
break;
}
break;
EnterCarriageReturn:
case CHAR_CARRIAGE_RETURN:
//
// Check to see if the Value is something reasonable against consistency limitations.
// If not, let's kick the error specified.
//
//
// This gives us visibility to the FileFormTags->NvRamMap to check things
// ActiveIfr is a global maintained by the menuing code to ensure that we
// are pointing to the correct formset's file data.
//
for (Count = 0; Count < gActiveIfr; Count++) {
FileFormTags = FileFormTags->NextFile;
}
ExtractRequestedNvMap (FileFormTags, Tag->VariableNumber, &VariableDefinition);
CopyMem (&VariableDefinition->NvRamMap[Tag->StorageStart], &Tag->Value, Tag->StorageWidth);
//
// Data associated with a NULL device (in the fake NV storage)
//
if (Tag->StorageWidth == (UINT16) 0) {
CopyMem (&VariableDefinition->FakeNvRamMap[Tag->StorageStart], &Tag->Value, 2);
}
//
// If a late check is required save off the information. This is used when consistency checks
// are required, but certain values might be bound by an impossible consistency check such as
// if two questions are bound by consistency checks and each only has two possible choices, there
// would be no way for a user to switch the values. Thus we require late checking.
//
if (Tag->Flags & EFI_IFR_FLAG_LATE_CHECK) {
CopyMem (&Tag->OldValue, &BackupValue, Tag->StorageWidth);
} else {
//
// In theory, passing the value and the Id are sufficient to determine what needs
// to be done. The Id is the key to look for the entry needed in the Inconsistency
// database. That will yields operand and ID data - and since the ID's correspond
// to the NV storage, we can determine the values for other IDs there.
//
if (ValueIsNotValid (TRUE, 0, Tag, FileFormTags, &PopUp)) {
if (PopUp == 0x0000) {
SelectionComplete = TRUE;
break;
}
StringPtr = GetToken (PopUp, MenuOption->Handle);
CreatePopUp (GetStringWidth (StringPtr) / 2, 3, &NullCharacter, StringPtr, &NullCharacter);
do {
Status = WaitForKeyStroke (&Key);
switch (Key.UnicodeChar) {
case CHAR_CARRIAGE_RETURN:
SelectionComplete = TRUE;
gBS->FreePool (StringPtr);
break;
default:
break;
}
} while (!SelectionComplete);
Tag->Value = BackupValue;
*Value = BackupValue;
CopyMem (&VariableDefinition->NvRamMap[Tag->StorageStart], &Tag->Value, Tag->StorageWidth);
//
// Data associated with a NULL device (in the fake NV storage)
//
if (Tag->StorageWidth == (UINT16) 0) {
CopyMem (&VariableDefinition->FakeNvRamMap[Tag->StorageStart], &Tag->Value, 2);
}
return EFI_DEVICE_ERROR;
}
}
return EFI_SUCCESS;
break;
case CHAR_BACKSPACE:
if (ManualInput) {
if (Count == 0) {
break;
}
//
// Remove a character
//
Number = PreviousNumber[Count - 1];
*Value = (UINT16) Number;
UpdateStatusBar (INPUT_ERROR, Tag->Flags, FALSE);
Count--;
Column--;
PrintAt (Column, Row, (CHAR16 *) L" ");
}
break;
default:
if (ManualInput) {
if (Key.UnicodeChar > L'9' || Key.UnicodeChar < L'0') {
UpdateStatusBar (INPUT_ERROR, Tag->Flags, TRUE);
break;
}
//
// If Count 0-4 is complete, there is no way more is valid
//
if (Count > 4) {
break;
}
//
// Someone typed something valid!
//
if (Count != 0) {
Number = Number * 10 + (Key.UnicodeChar - L'0');
} else {
Number = Key.UnicodeChar - L'0';
}
if (Number > Tag->Maximum) {
UpdateStatusBar (INPUT_ERROR, Tag->Flags, TRUE);
Number = PreviousNumber[Count];
break;
} else {
UpdateStatusBar (INPUT_ERROR, Tag->Flags, FALSE);
}
Count++;
PreviousNumber[Count] = Number;
*Value = (UINT16) Number;
Tag->Value = (UINT16) Number;
PrintCharAt (Column, Row, Key.UnicodeChar);
Column++;
}
break;
}
} while (!SelectionComplete);
return EFI_SUCCESS;
}
//
// Notice that this is at least needed for the ordered list manipulation.
// Left/Right doesn't make sense for this op-code
//
EFI_STATUS
GetSelectionInputPopUp (
IN UI_MENU_OPTION *MenuOption,
IN EFI_TAG *Tag,
IN UINTN ValueCount,
OUT UINT16 *Value,
OUT UINT16 *KeyValue
)
{
EFI_STATUS Status;
EFI_INPUT_KEY Key;
UINTN Index;
UINTN TempIndex;
CHAR16 *StringPtr;
CHAR16 *TempStringPtr;
UINT16 Token;
UINTN Index2;
UINTN TopOptionIndex;
UINTN HighlightPosition;
UINTN Start;
UINTN End;
UINTN Top;
UINTN Bottom;
UINT16 TempValue;
UINTN Count;
UINTN PopUpMenuLines;
UINTN MenuLinesInView;
UINTN PopUpWidth;
CHAR16 Character;
UINTN FirstOption;
BOOLEAN FirstOptionFoundFlag;
INT32 SavedAttribute;
EFI_TAG TagBackup;
UINT8 *ValueArray;
UINT8 *ValueArrayBackup;
UINT8 ValueBackup;
BOOLEAN Initialized;
BOOLEAN KeyInitialized;
BOOLEAN ShowDownArrow;
BOOLEAN ShowUpArrow;
UINTN DimensionsWidth;
UINTN DimensionsHeight;
DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;
DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow;
TempValue = 0;
TempIndex = 0;
ValueArray = (UINT8 *) Value;
ValueArrayBackup = NULL;
Initialized = FALSE;
KeyInitialized = FALSE;
ShowDownArrow = FALSE;
ShowUpArrow = FALSE;
if (Tag->Operand == EFI_IFR_ORDERED_LIST_OP) {
ValueArrayBackup = AllocateZeroPool (Tag->StorageWidth);
ASSERT (ValueArrayBackup != NULL);
CopyMem (ValueArrayBackup, ValueArray, ValueCount);
TempValue = *(UINT8 *) (ValueArray);
if (ValueArray[0] != 0x00) {
Initialized = TRUE;
}
for (Index = 0; ValueArray[Index] != 0x00; Index++)
;
ValueCount = Index;
} else {
TempValue = *Value;
}
Count = 0;
PopUpWidth = 0;
FirstOption = MenuOption->TagIndex;
FirstOptionFoundFlag = FALSE;
StringPtr = AllocateZeroPool ((gOptionBlockWidth + 1) * 2);
ASSERT (StringPtr);
//
// Initialization for "One of" pop-up menu
//
//
// Get the number of one of options present and its size
//
for (Index = MenuOption->TagIndex; MenuOption->Tags[Index].Operand != EFI_IFR_END_ONE_OF_OP; Index++) {
if (MenuOption->Tags[Index].Operand == EFI_IFR_ONE_OF_OPTION_OP &&
!MenuOption->Tags[Index].Suppress) {
if (!FirstOptionFoundFlag) {
FirstOption = Index;
FirstOptionFoundFlag = TRUE;
}
Count++;
Token = MenuOption->Tags[Index].Text;
//
// If this is an ordered list that is initialized
//
if (Initialized) {
for (ValueBackup = (UINT8) MenuOption->TagIndex;
MenuOption->Tags[ValueBackup].Operand != EFI_IFR_END_OP;
ValueBackup++
) {
if (MenuOption->Tags[ValueBackup].Value == ((UINT8 *) ValueArrayBackup)[Index - MenuOption->TagIndex - 1]) {
StringPtr = GetToken (MenuOption->Tags[ValueBackup].Text, MenuOption->Handle);
break;
}
}
} else {
StringPtr = GetToken (Token, MenuOption->Handle);
}
if (StrLen (StringPtr) > PopUpWidth) {
PopUpWidth = StrLen (StringPtr);
}
gBS->FreePool (StringPtr);
}
}
//
// Perform popup menu initialization.
//
PopUpMenuLines = Count;
PopUpWidth = PopUpWidth + POPUP_PAD_SPACE_COUNT;
SavedAttribute = gST->ConOut->Mode->Attribute;
gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);
if ((PopUpWidth + POPUP_FRAME_WIDTH) > DimensionsWidth) {
PopUpWidth = DimensionsWidth - POPUP_FRAME_WIDTH;
}
Start = (DimensionsWidth - PopUpWidth - POPUP_FRAME_WIDTH) / 2 + gScreenDimensions.LeftColumn;
End = Start + PopUpWidth + POPUP_FRAME_WIDTH;
Top = gScreenDimensions.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT;
Bottom = gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT;
MenuLinesInView = Bottom - Top - 1;
if (MenuLinesInView >= PopUpMenuLines) {
Top = Top + (MenuLinesInView - PopUpMenuLines) / 2;
Bottom = Top + PopUpMenuLines + 1;
} else {
TempValue = MenuOption->Tags[MenuOption->TagIndex + 1].Value;
ShowDownArrow = TRUE;
}
TopOptionIndex = 1;
HighlightPosition = 0;
do {
if (Initialized) {
for (Index = MenuOption->TagIndex, Index2 = 0; Index2 < ValueCount; Index++, Index2++) {
//
// Set the value for the item we are looking for
//
Count = ValueArrayBackup[Index2];
//
// If we hit the end of the Array, we are complete
//
if (Count == 0) {
break;
}
if (MenuOption->Tags[Index].Operand == EFI_IFR_ONE_OF_OPTION_OP) {
for (ValueBackup = (UINT8) MenuOption->TagIndex;
MenuOption->Tags[ValueBackup].Operand != EFI_IFR_END_ONE_OF_OP;
ValueBackup++
) {
//
// We just found what we are looking for
//
if (MenuOption->Tags[ValueBackup].Value == Count) {
//
// As long as the two indexes aren't the same, we have
// two different op-codes we need to swap internally
//
if (Index != ValueBackup) {
//
// Backup destination tag, then copy source to destination, then copy backup to source location
//
CopyMem (&TagBackup, &MenuOption->Tags[Index], sizeof (EFI_TAG));
CopyMem (&MenuOption->Tags[Index], &MenuOption->Tags[ValueBackup], sizeof (EFI_TAG));
CopyMem (&MenuOption->Tags[ValueBackup], &TagBackup, sizeof (EFI_TAG));
} else {
//
// If the indexes are the same, then the op-code is where he belongs
//
}
}
}
} else {
//
// Since this wasn't an option op-code (likely the ordered list op-code) decerement Index2
//
Index2--;
}
}
}
//
// Clear that portion of the screen
//
ClearLines (Start, End, Top, Bottom, POPUP_TEXT | POPUP_BACKGROUND);
//
// Draw "One of" pop-up menu
//
Character = (CHAR16) BOXDRAW_DOWN_RIGHT;
PrintCharAt (Start, Top, Character);
for (Index = Start; Index + 2 < End; Index++) {
if ((ShowUpArrow) && ((Index + 1) == (Start + End) / 2)) {
Character = (CHAR16) GEOMETRICSHAPE_UP_TRIANGLE;
} else {
Character = (CHAR16) BOXDRAW_HORIZONTAL;
}
PrintChar (Character);
}
Character = (CHAR16) BOXDRAW_DOWN_LEFT;
PrintChar (Character);
Character = (CHAR16) BOXDRAW_VERTICAL;
for (Index = Top + 1; Index < Bottom; Index++) {
PrintCharAt (Start, Index, Character);
PrintCharAt (End - 1, Index, Character);
}
//
// Display the One of options
//
Index2 = Top + 1;
for (Index = MenuOption->TagIndex + TopOptionIndex;
(MenuOption->Tags[Index].Operand != EFI_IFR_END_ONE_OF_OP) && (Index2 < Bottom);
Index++
) {
if (MenuOption->Tags[Index].Operand == EFI_IFR_ONE_OF_OPTION_OP) {
Token = MenuOption->Tags[Index].Text;
if (Initialized) {
for (ValueBackup = (UINT8) MenuOption->TagIndex;
MenuOption->Tags[ValueBackup].Operand != EFI_IFR_END_ONE_OF_OP;
ValueBackup++
) {
if (MenuOption->Tags[ValueBackup].Value == ((UINT8 *) ValueArrayBackup)[Index - MenuOption->TagIndex - 1]) {
StringPtr = GetToken (MenuOption->Tags[ValueBackup].Text, MenuOption->Handle);
break;
}
}
} else {
ValueBackup = (UINT8) Index;
StringPtr = GetToken (Token, MenuOption->Handle);
}
//
// If the string occupies multiple lines, truncate it to fit in one line,
// and append a "..." for indication.
//
if (StrLen (StringPtr) > (PopUpWidth - 1)) {
TempStringPtr = AllocateZeroPool (sizeof (CHAR16) * (PopUpWidth - 1));
CopyMem (TempStringPtr, StringPtr, (sizeof (CHAR16) * (PopUpWidth - 5)));
gBS->FreePool (StringPtr);
StringPtr = TempStringPtr;
StrCat (StringPtr, (CHAR16 *) L"...");
}
//
// Code to display the text should go here. Follwed by the [*]
//
if (MenuOption->Tags[ValueBackup].Suppress == TRUE) {
//
// Don't show the one, so decrease the Index2 for balance
//
Index2--;
} else if (MenuOption->Tags[ValueBackup].GrayOut == TRUE) {
//
// Gray Out the one
//
gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | POPUP_BACKGROUND);
PrintStringAt (Start + 2, Index2, StringPtr);
gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);
} else if (MenuOption->Tags[ValueBackup].Value == TempValue) {
//
// Highlight the selected one
//
gST->ConOut->SetAttribute (gST->ConOut, PICKLIST_HIGHLIGHT_TEXT | PICKLIST_HIGHLIGHT_BACKGROUND);
PrintStringAt (Start + 2, Index2, StringPtr);
gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);
HighlightPosition = Index2;
} else {
gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);
PrintStringAt (Start + 2, Index2, StringPtr);
}
gBS->FreePool (StringPtr);
Index2 = Index2 + 1;
}
}
Character = (CHAR16) BOXDRAW_UP_RIGHT;
PrintCharAt (Start, Bottom, Character);
for (Index = Start; Index + 2 < End; Index++) {
if ((ShowDownArrow) && ((Index + 1) == (Start + End) / 2)) {
Character = (CHAR16) GEOMETRICSHAPE_DOWN_TRIANGLE;
} else {
Character = (CHAR16) BOXDRAW_HORIZONTAL;
}
PrintChar (Character);
}
Character = (CHAR16) BOXDRAW_UP_LEFT;
PrintChar (Character);
//
// Get User selection and change TempValue if necessary
//
//
// Stop: One of pop-up menu
//
Key.UnicodeChar = CHAR_NULL;
if ((gDirection == SCAN_UP) || (gDirection == SCAN_DOWN)) {
Key.ScanCode = gDirection;
gDirection = 0;
goto TheKey;
}
if (!KeyInitialized) {
if (MenuOption->ThisTag->Operand == EFI_IFR_ONE_OF_OP) {
*KeyValue = MenuOption->Tags[MenuOption->TagIndex + 1].Key;
} else {
*KeyValue = MenuOption->ThisTag->Key;
}
KeyInitialized = TRUE;
}
Status = WaitForKeyStroke (&Key);
TheKey:
switch (Key.UnicodeChar) {
case '+':
case '-':
//
// If an ordered list op-code, we will allow for a popup of +/- keys
// to create an ordered list of items
//
if (Tag->Operand == EFI_IFR_ORDERED_LIST_OP) {
if (Key.UnicodeChar == '+') {
if ((TopOptionIndex > 1) && (HighlightPosition == (Top + 1))) {
//
// Highlight reaches the top of the popup window, scroll one menu item.
//
TopOptionIndex--;
ShowDownArrow = TRUE;
}
if (TopOptionIndex == 1) {
ShowUpArrow = FALSE;
}
} else {
if (((TopOptionIndex + MenuLinesInView) <= PopUpMenuLines) && (HighlightPosition == (Bottom - 1))) {
//
// Highlight reaches the bottom of the popup window, scroll one menu item.
//
TopOptionIndex++;
ShowUpArrow = TRUE;
}
if ((TopOptionIndex + MenuLinesInView) == (PopUpMenuLines + 1)) {
ShowDownArrow = FALSE;
}
}
for (Index = MenuOption->TagIndex + TopOptionIndex;
MenuOption->Tags[Index].Operand != EFI_IFR_END_ONE_OF_OP;
Index++
) {
if (MenuOption->Tags[Index].Operand == EFI_IFR_ORDERED_LIST_OP) {
continue;
}
if (Key.UnicodeChar == '+') {
TempIndex = Index - 1;
} else {
TempIndex = Index + 1;
}
//
// Is this the current tag we are on?
//
if (MenuOption->Tags[Index].Value == TempValue) {
//
// Is this prior tag a valid choice? If not, bail out
//
if (MenuOption->Tags[TempIndex].Operand == EFI_IFR_ONE_OF_OPTION_OP) {
//
// Copy the destination tag to the local variable
//
CopyMem (&TagBackup, &MenuOption->Tags[TempIndex], sizeof (EFI_TAG));
//
// Copy the current tag to the tag location before us
//
CopyMem (&MenuOption->Tags[TempIndex], &MenuOption->Tags[Index], sizeof (EFI_TAG));
//
// Copy the backed up tag to the current location
//
CopyMem (&MenuOption->Tags[Index], &TagBackup, sizeof (EFI_TAG));
//
// Adjust the array of values
//
for (Index = 0; Index < ValueCount; Index++) {
if (ValueArrayBackup[Index] == (UINT8) TempValue) {
if (Key.UnicodeChar == '+') {
if (Index == 0) {
//
// It is the top of the array already
//
break;
}
TempIndex = Index - 1;
} else {
if ((Index + 1) == ValueCount) {
//
// It is the bottom of the array already
//
break;
}
TempIndex = Index + 1;
}
ValueBackup = ValueArrayBackup[TempIndex];
ValueArrayBackup[TempIndex] = ValueArrayBackup[Index];
ValueArrayBackup[Index] = ValueBackup;
Initialized = TRUE;
break;
}
}
break;
} else {
break;
}
}
}
}
break;
case CHAR_NULL:
switch (Key.ScanCode) {
case SCAN_UP:
case SCAN_DOWN:
if (Key.ScanCode == SCAN_UP) {
if ((TopOptionIndex > 1) && (HighlightPosition == (Top + 1))) {
//
// Highlight reaches the top of the popup window, scroll one menu item.
//
TopOptionIndex--;
ShowDownArrow = TRUE;
}
if (TopOptionIndex == 1) {
ShowUpArrow = FALSE;
}
} else {
if (((TopOptionIndex + MenuLinesInView) <= PopUpMenuLines) && (HighlightPosition == (Bottom - 1))) {
//
// Highlight reaches the bottom of the popup window, scroll one menu item.
//
TopOptionIndex++;
ShowUpArrow = TRUE;
}
if ((TopOptionIndex + MenuLinesInView) == (PopUpMenuLines + 1)) {
ShowDownArrow = FALSE;
}
}
for (Index = MenuOption->TagIndex + TopOptionIndex;
MenuOption->Tags[Index].Operand != EFI_IFR_END_ONE_OF_OP;
Index++
) {
if (MenuOption->Tags[Index].Operand == EFI_IFR_ONE_OF_OPTION_OP) {
if (Initialized) {
for (Index = 0; (ValueArrayBackup[Index] != TempValue) && (Index < ValueCount); Index++)
;
//
// Did we hit the end of the array? Either get the first TempValue or the next one
//
if (Key.ScanCode == SCAN_UP) {
if (Index == 0) {
TempValue = ValueArrayBackup[0];
} else {
TempValue = ValueArrayBackup[Index - 1];
}
} else {
if ((Index + 1) == ValueCount) {
TempValue = ValueArrayBackup[Index];
} else {
TempValue = ValueArrayBackup[Index + 1];
}
}
break;
} else {
if (Key.ScanCode == SCAN_UP) {
TempIndex = Index - 1;
//
// Keep going until meets meaningful tag.
//
while ((MenuOption->Tags[TempIndex].Operand != EFI_IFR_ONE_OF_OPTION_OP &&
MenuOption->Tags[TempIndex].Operand != EFI_IFR_ONE_OF_OP &&
MenuOption->Tags[TempIndex].Operand != EFI_IFR_END_ONE_OF_OP)
||
(MenuOption->Tags[TempIndex].Operand == EFI_IFR_ONE_OF_OPTION_OP &&
(MenuOption->Tags[TempIndex].Suppress || MenuOption->Tags[TempIndex].GrayOut))) {
TempIndex--;
}
} else {
TempIndex = Index + 1;
//
// Keep going until meets meaningful tag.
//
while ((MenuOption->Tags[TempIndex].Operand != EFI_IFR_ONE_OF_OPTION_OP &&
MenuOption->Tags[TempIndex].Operand != EFI_IFR_ONE_OF_OP &&
MenuOption->Tags[TempIndex].Operand != EFI_IFR_END_ONE_OF_OP)
||
(MenuOption->Tags[TempIndex].Operand == EFI_IFR_ONE_OF_OPTION_OP &&
(MenuOption->Tags[TempIndex].Suppress || MenuOption->Tags[TempIndex].GrayOut))) {
TempIndex++;
}
}
//
// The option value is the same as what is stored in NV store. This is where we take action
//
if (MenuOption->Tags[Index].Value == TempValue) {
//
// Only if the previous op-code is an option can we select it, otherwise we are at the left-most option
//
if (MenuOption->Tags[TempIndex].Operand == EFI_IFR_ONE_OF_OPTION_OP) {
TempValue = MenuOption->Tags[TempIndex].Value;
*KeyValue = MenuOption->Tags[TempIndex].Key;
} else {
TempValue = MenuOption->Tags[Index].Value;
*KeyValue = MenuOption->Tags[Index].Key;
}
break;
}
}
}
}
break;
case SCAN_ESC:
gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);
if (ValueArrayBackup != NULL) {
gBS->FreePool (ValueArrayBackup);
}
return EFI_DEVICE_ERROR;
default:
break;
}
break;
case CHAR_CARRIAGE_RETURN:
//
// return the current selection
//
if (Tag->Operand == EFI_IFR_ORDERED_LIST_OP) {
CopyMem (ValueArray, ValueArrayBackup, ValueCount);
gBS->FreePool (ValueArrayBackup);
} else {
*Value = TempValue;
}
gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);
return EFI_SUCCESS;
default:
break;
}
} while (1);
gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);
return EFI_SUCCESS;
}
EFI_STATUS
WaitForKeyStroke (
OUT EFI_INPUT_KEY *Key
)
{
EFI_STATUS Status;
do {
UiWaitForSingleEvent (gST->ConIn->WaitForKey, 0);
Status = gST->ConIn->ReadKeyStroke (gST->ConIn, Key);
} while (EFI_ERROR(Status));
return Status;
}