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