mirror of
				https://github.com/acidanthera/audk.git
				synced 2025-11-04 05:25:45 +01:00 
			
		
		
		
	git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3401 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			1562 lines
		
	
	
		
			52 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1562 lines
		
	
	
		
			52 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/**@file
 | 
						|
   Implementation for handling user input from the User Interface
 | 
						|
 | 
						|
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.
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#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;
 | 
						|
}
 |