From 103b65209db362ee55acf65e50efaa8cd19c9d31 Mon Sep 17 00:00:00 2001 From: vanjeff Date: Fri, 29 Jun 2007 15:14:00 +0000 Subject: Port DriverSample.inf, HiiDatabase.inf and SetupBrowser.inf git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@2915 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Universal/SetupBrowserDxe/InputHandler.c | 1575 ++++++++++++++++++++ 1 file changed, 1575 insertions(+) create mode 100644 IntelFrameworkModulePkg/Universal/SetupBrowserDxe/InputHandler.c (limited to 'IntelFrameworkModulePkg/Universal/SetupBrowserDxe/InputHandler.c') diff --git a/IntelFrameworkModulePkg/Universal/SetupBrowserDxe/InputHandler.c b/IntelFrameworkModulePkg/Universal/SetupBrowserDxe/InputHandler.c new file mode 100644 index 0000000000..4c2189c476 --- /dev/null +++ b/IntelFrameworkModulePkg/Universal/SetupBrowserDxe/InputHandler.c @@ -0,0 +1,1575 @@ +/*++ + +Copyright (c) 2006 - 2007, 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 common header file for this module. +// +#include "CommonHeader.h" + +#include "Setup.h" +#include "Ui.h" +#include "Colors.h" + +#define EFI_MAX(_a, _b) ((_a) > (_b) ? (_a) : (_b)) + +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); + + 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: + FreePool (TempString); + 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; + FreePool (TempString); + 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); + FreePool (TempString); + 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 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; + UINTN WidthOfString; + + DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn; + DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow; + + VariableDefinition = NULL; + 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 + // + WidthOfString = GetStringWidth (Packet->String); + ScreenSize = EFI_MAX(WidthOfString, GetStringWidth (gPressEnter)) / 2; + CreatePopUp (ScreenSize, 4, &NullCharacter, Packet->String, gPressEnter, &NullCharacter); + FreePool (Packet); + + do { + Status = WaitForKeyStroke (&Key); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + } + + Status = EFI_NOT_READY; + goto Done; + } + } + + 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) { + WidthOfString = GetStringWidth (gConfirmError); + ScreenSize = EFI_MAX (WidthOfString, GetStringWidth (gPressEnter)) / 2; + CreatePopUp (ScreenSize, 4, &NullCharacter, gConfirmError, gPressEnter, &NullCharacter); + } else { + WidthOfString = GetStringWidth (Packet->String); + ScreenSize = EFI_MAX (WidthOfString, GetStringWidth (gPressEnter)) / 2; + CreatePopUp (ScreenSize, 4, &NullCharacter, Packet->String, gPressEnter, &NullCharacter); + FreePool (Packet); + } + + StringPtr[0] = CHAR_NULL; + do { + Status = WaitForKeyStroke (&Key); + + if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) { + Status = EFI_NOT_READY; + goto Done; + } + } while (1); + } else { + Status = EFI_NOT_READY; + goto Done; + } + } 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)) { + Status = EFI_DEVICE_ERROR; + goto Done; + } + } + } + + 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) { + Status = EFI_SUCCESS; + goto Done; + } else { + WidthOfString = GetStringWidth (gConfirmError); + ScreenSize = EFI_MAX (WidthOfString, GetStringWidth (gPressEnter)) / 2; + CreatePopUp (ScreenSize, 4, &NullCharacter, gConfirmError, gPressEnter, &NullCharacter); + StringPtr[0] = CHAR_NULL; + do { + Status = WaitForKeyStroke (&Key); + if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) { + Status = EFI_DEVICE_ERROR; + goto Done; + } + } while (1); + } + } + + if (PromptForPassword) { + // + // I was asked for a password, return it back in StringPtr + // + Status = EFI_SUCCESS; + goto Done; + } 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); + +Done: + FreePool (TempString); + 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); + + 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_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; + } + + 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 { + WaitForKeyStroke (&Key); + + switch (Key.UnicodeChar) { + + case CHAR_CARRIAGE_RETURN: + SelectionComplete = TRUE; + 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_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; + BOOLEAN FirstOptionFoundFlag; + INT32 SavedAttribute; + EFI_TAG TagBackup; + UINT8 *ValueArray; + UINT8 *ValueArrayBackup; + UINT8 ValueBackup; + BOOLEAN Initialized; + BOOLEAN KeyInitialized; + BOOLEAN ShowDownArrow; + BOOLEAN ShowUpArrow; + UINTN DimensionsWidth; + + DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn; + + 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; + + 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) { + 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); + } + + 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)); + ASSERT (TempStringPtr != NULL); + CopyMem (TempStringPtr, StringPtr, (sizeof (CHAR16) * (PopUpWidth - 5))); + 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); + } + + 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; + } + + 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) { + 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); + FreePool (ValueArrayBackup); + } else { + *Value = TempValue; + } + + goto Done; + + default: + break; + } + } while (1); + +Done: + 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; +} -- cgit v1.2.3