]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/SetupBrowserDxe/InputHandler.c
Refine the logic about processing options for oneof opcode.
[mirror_edk2.git] / MdeModulePkg / Universal / SetupBrowserDxe / InputHandler.c
index 5257f32b66b7194519f2c34a3c3e0285aa40cf65..844590770a68d9a867bf4294dc189a48dad2dc67 100644 (file)
-/** @file
-
-Copyright (c) 2004 - 2007, Intel Corporation
-All rights reserved. This program and the accompanying materials
-are licensed and made available under the terms and conditions of the BSD License
-which accompanies this distribution.  The full text of the license may be found at
-http://opensource.org/licenses/bsd-license.php
-
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
-
-Module Name:
-
-  InputHandler.c
-
-Abstract:
-
-  Implementation for handling user input from the User Interface
-
-Revision History
-
-
-**/
-
-#include "Ui.h"
-#include "Setup.h"
-
-
-/**
-  Get string or password input from user.
-
-  @param  MenuOption        Pointer to the current input menu.
-  @param  Prompt            The prompt string shown on popup window.
-  @param  StringPtr         Destination for use input string.
-
-  @retval EFI_SUCCESS       If string input is read successfully
-  @retval EFI_DEVICE_ERROR  If operation fails
-
-**/
-EFI_STATUS
-ReadString (
-  IN  UI_MENU_OPTION              *MenuOption,
-  IN  CHAR16                      *Prompt,
-  OUT CHAR16                      *StringPtr
-  )
-{
-  EFI_STATUS              Status;
-  EFI_INPUT_KEY           Key;
-  CHAR16                  NullCharacter;
-  UINTN                   ScreenSize;
-  CHAR16                  Space[2];
-  CHAR16                  KeyPad[2];
-  CHAR16                  *TempString;
-  CHAR16                  *BufferedString;
-  UINTN                   Index;
-  UINTN                   Count;
-  UINTN                   Start;
-  UINTN                   Top;
-  UINTN                   DimensionsWidth;
-  UINTN                   DimensionsHeight;
-  BOOLEAN                 CursorVisible;
-  UINTN                   Minimum;
-  UINTN                   Maximum;
-  FORM_BROWSER_STATEMENT  *Question;
-  BOOLEAN                 IsPassword;
-
-  DimensionsWidth  = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;
-  DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow;
-
-  NullCharacter    = CHAR_NULL;
-  ScreenSize       = GetStringWidth (Prompt) / sizeof (CHAR16);
-  Space[0]         = L' ';
-  Space[1]         = CHAR_NULL;
-
-  Question         = MenuOption->ThisTag;
-  Minimum          = (UINTN) Question->Minimum;
-  Maximum          = (UINTN) Question->Maximum;
-
-  if (Question->Operand == EFI_IFR_PASSWORD_OP) {
-    IsPassword = TRUE;
-  } else {
-    IsPassword = FALSE;
-  }
-
-  TempString = AllocateZeroPool ((Maximum + 1)* sizeof (CHAR16));
-  ASSERT (TempString);
-
-  if (ScreenSize < (Maximum + 1)) {
-    ScreenSize = Maximum + 1;
-  }
-
-  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, Prompt, Space, &NullCharacter);
-
-  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);
-    ASSERT_EFI_ERROR (Status);
-
-    gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY));
-    switch (Key.UnicodeChar) {
-    case CHAR_NULL:
-      switch (Key.ScanCode) {
-      case SCAN_LEFT:
-        break;
-
-      case SCAN_RIGHT:
-        break;
-
-      case SCAN_ESC:
-        gBS->FreePool (TempString);
-        gBS->FreePool (BufferedString);
-        gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
-        gST->ConOut->EnableCursor (gST->ConOut, CursorVisible);
-        return EFI_DEVICE_ERROR;
-
-      default:
-        break;
-      }
-
-      break;
-
-    case CHAR_CARRIAGE_RETURN:
-      if (GetStringWidth (StringPtr) >= ((Minimum + 1) * sizeof (CHAR16))) {
-
-        gBS->FreePool (TempString);
-        gBS->FreePool (BufferedString);
-        gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
-        gST->ConOut->EnableCursor (gST->ConOut, CursorVisible);
-        return EFI_SUCCESS;
-      } else {
-        //
-        // 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 {
-          CreateDialog (4, TRUE, 0, NULL, &Key, &NullCharacter, gMiniString, gPressEnter, &NullCharacter);
-        } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
-
-        gBS->FreePool (TempString);
-        gBS->FreePool (BufferedString);
-        gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
-        gST->ConOut->EnableCursor (gST->ConOut, CursorVisible);
-        return EFI_DEVICE_ERROR;
-      }
-
-      break;
-
-    case CHAR_BACKSPACE:
-      if (StringPtr[0] != CHAR_NULL) {
-        for (Index = 0; StringPtr[Index] != CHAR_NULL; Index++) {
-          TempString[Index] = StringPtr[Index];
-        }
-        //
-        // Effectively truncate string by 1 character
-        //
-        TempString[Index - 1] = CHAR_NULL;
-        StrCpy (StringPtr, TempString);
-      }
-
-    default:
-      //
-      // If it is the beginning of the string, don't worry about checking maximum limits
-      //
-      if ((StringPtr[0] == CHAR_NULL) && (Key.UnicodeChar != CHAR_BACKSPACE)) {
-        StrnCpy (StringPtr, &Key.UnicodeChar, 1);
-        StrnCpy (TempString, &Key.UnicodeChar, 1);
-      } else if ((GetStringWidth (StringPtr) < ((Maximum + 1) * sizeof (CHAR16))) && (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;
-      }
-
-      if (IsPassword) {
-        gST->ConOut->SetCursorPosition (gST->ConOut, Start + 1, Top + 3);
-      }
-
-      for (Count = 0; Index + 1 < GetStringWidth (StringPtr) / 2; Index++, Count++) {
-        BufferedString[Count] = StringPtr[Index];
-
-        if (IsPassword) {
-          PrintChar (L'*');
-        }
-      }
-
-      if (!IsPassword) {
-        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 (TRUE);
-
-}
-
-
-/**
-  This routine reads a numeric value from the user input.
-
-  @param  Selection         Pointer to current selection.
-  @param  MenuOption        Pointer to the current input menu.
-
-  @retval EFI_SUCCESS       If numerical input is read successfully
-  @retval EFI_DEVICE_ERROR  If operation fails
-
-**/
-EFI_STATUS
-GetNumericInput (
-  IN  UI_MENU_SELECTION           *Selection,
-  IN  UI_MENU_OPTION              *MenuOption
-  )
-{
-  EFI_STATUS              Status;
-  UINTN                   Column;
-  UINTN                   Row;
-  CHAR16                  InputText[23];
-  CHAR16                  FormattedNumber[22];
-  UINT64                  PreviousNumber[20];
-  UINTN                   Count;
-  UINTN                   Loop;
-  BOOLEAN                 ManualInput;
-  BOOLEAN                 HexInput;
-  BOOLEAN                 DateOrTime;
-  UINTN                   InputWidth;
-  UINT64                  EditValue;
-  UINT64                  Step;
-  UINT64                  Minimum;
-  UINT64                  Maximum;
-  UINTN                   EraseLen;
-  UINT8                   Digital;
-  EFI_INPUT_KEY           Key;
-  EFI_HII_VALUE           *QuestionValue;
-  FORM_BROWSER_FORM       *Form;
-  FORM_BROWSER_FORMSET    *FormSet;
-  FORM_BROWSER_STATEMENT  *Question;
-
-  Column            = MenuOption->OptCol;
-  Row               = MenuOption->Row;
-  PreviousNumber[0] = 0;
-  Count             = 0;
-  InputWidth        = 0;
-  Digital           = 0;
-
-  FormSet       = Selection->FormSet;
-  Form          = Selection->Form;
-  Question      = MenuOption->ThisTag;
-  QuestionValue = &Question->HiiValue;
-  Step          = Question->Step;
-  Minimum       = Question->Minimum;
-  Maximum       = Question->Maximum;
-
-  if ((Question->Operand == EFI_IFR_DATE_OP) || (Question->Operand == EFI_IFR_TIME_OP)) {
-    DateOrTime = TRUE;
-  } else {
-    DateOrTime = FALSE;
-  }
-
-  //
-  // Prepare Value to be edit
-  //
-  EraseLen = 0;
-  EditValue = 0;
-  if (Question->Operand == EFI_IFR_DATE_OP) {
-    Step = 1;
-    Minimum = 1;
-
-    switch (MenuOption->Sequence) {
-    case 0:
-      Maximum = 12;
-      EraseLen = 4;
-      EditValue = QuestionValue->Value.date.Month;
-      break;
-
-    case 1:
-      Maximum = 31;
-      EraseLen = 3;
-      EditValue = QuestionValue->Value.date.Day;
-      break;
-
-    case 2:
-      Maximum = 0xffff;
-      EraseLen = 5;
-      EditValue = QuestionValue->Value.date.Year;
-      break;
-
-    default:
-      break;
-    }
-  } else if (Question->Operand == EFI_IFR_TIME_OP) {
-    Step = 1;
-    Minimum = 0;
-
-    switch (MenuOption->Sequence) {
-    case 0:
-      Maximum = 23;
-      EraseLen = 4;
-      EditValue = QuestionValue->Value.time.Hour;
-      break;
-
-    case 1:
-      Maximum = 59;
-      EraseLen = 3;
-      EditValue = QuestionValue->Value.time.Minute;
-      break;
-
-    case 2:
-      Maximum = 59;
-      EraseLen = 3;
-      EditValue = QuestionValue->Value.time.Second;
-      break;
-
-    default:
-      break;
-    }
-  } else {
-    //
-    // Numeric
-    //
-    EraseLen = gOptionBlockWidth;
-    EditValue = QuestionValue->Value.u64;
-    if (Maximum == 0) {
-      Maximum = (UINT64) -1;
-    }
-  }
-
-  if (Step == 0) {
-    ManualInput = TRUE;
-  } else {
-    ManualInput = FALSE;
-  }
-
-  if ((Question->Operand == EFI_IFR_NUMERIC_OP) &&
-      ((Question->Flags & EFI_IFR_DISPLAY) == EFI_IFR_DISPLAY_UINT_HEX)) {
-    HexInput = TRUE;
-  } else {
-    HexInput = FALSE;
-  }
-
-  if (ManualInput) {
-    if (HexInput) {
-      InputWidth = Question->StorageWidth * 2;
-    } else {
-      switch (Question->StorageWidth) {
-      case 1:
-        InputWidth = 3;
-        break;
-
-      case 2:
-        InputWidth = 5;
-        break;
-
-      case 4:
-        InputWidth = 10;
-        break;
-
-      case 8:
-        InputWidth = 20;
-        break;
-
-      default:
-        InputWidth = 0;
-        break;
-      }
-    }
-
-    InputText[0] = LEFT_NUMERIC_DELIMITER;
-    SetUnicodeMem (InputText + 1, InputWidth, L' ');
-    InputText[InputWidth + 1] = RIGHT_NUMERIC_DELIMITER;
-    InputText[InputWidth + 2] = L'\0';
-
-    PrintAt (Column, Row, InputText);
-    Column++;
-  }
-
-  //
-  // First time we enter this handler, we need to check to see if
-  // we were passed an increment or decrement directive
-  //
-  do {
-    Key.UnicodeChar = CHAR_NULL;
-    if (gDirection != 0) {
-      Key.ScanCode  = gDirection;
-      gDirection    = 0;
-      goto TheKey2;
-    }
-
-    Status = WaitForKeyStroke (&Key);
-
-TheKey2:
-    switch (Key.UnicodeChar) {
-
-    case '+':
-    case '-':
-      if (Key.UnicodeChar == '+') {
-        Key.ScanCode = SCAN_RIGHT;
-      } else {
-        Key.ScanCode = SCAN_LEFT;
-      }
-      Key.UnicodeChar = CHAR_NULL;
-      goto TheKey2;
-
-    case CHAR_NULL:
-      switch (Key.ScanCode) {
-      case SCAN_LEFT:
-      case SCAN_RIGHT:
-        if (DateOrTime) {
-          //
-          // 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) {
-          if (Key.ScanCode == SCAN_LEFT) {
-            if (EditValue > Step) {
-              EditValue = EditValue - Step;
-            } else {
-              EditValue = Minimum;
-            }
-          } else if (Key.ScanCode == SCAN_RIGHT) {
-            EditValue = EditValue + Step;
-            if (EditValue > Maximum) {
-              EditValue = Maximum;
-            }
-          }
-
-          ZeroMem (FormattedNumber, 21 * sizeof (CHAR16));
-          if (Question->Operand == EFI_IFR_DATE_OP) {
-            if (MenuOption->Sequence == 2) {
-              //
-              // Year
-              //
-              UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%04d", EditValue);
-            } else {
-              //
-              // Month/Day
-              //
-              UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%02d", EditValue);
-            }
-
-            if (MenuOption->Sequence == 0) {
-              FormattedNumber[EraseLen - 2] = DATE_SEPARATOR;
-            } else if (MenuOption->Sequence == 1) {
-              FormattedNumber[EraseLen - 1] = DATE_SEPARATOR;
-            }
-          } else if (Question->Operand == EFI_IFR_TIME_OP) {
-            UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%02d", EditValue);
-
-            if (MenuOption->Sequence == 0) {
-              FormattedNumber[EraseLen - 2] = TIME_SEPARATOR;
-            } else if (MenuOption->Sequence == 1) {
-              FormattedNumber[EraseLen - 1] = TIME_SEPARATOR;
-            }
-          } else {
-            QuestionValue->Value.u64 = EditValue;
-            PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16));
-          }
-
-          gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);
-          for (Loop = 0; Loop < EraseLen; Loop++) {
-            PrintAt (MenuOption->OptCol + Loop, MenuOption->Row, L" ");
-          }
-          gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT);
-
-          if (MenuOption->Sequence == 0) {
-            PrintCharAt (MenuOption->OptCol, Row, LEFT_NUMERIC_DELIMITER);
-            Column = MenuOption->OptCol + 1;
-          }
-
-          PrintStringAt (Column, Row, FormattedNumber);
-
-          if (!DateOrTime || MenuOption->Sequence == 2) {
-            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:
-      //
-      // Store Edit value back to Question
-      //
-      if (Question->Operand == EFI_IFR_DATE_OP) {
-        switch (MenuOption->Sequence) {
-        case 0:
-          QuestionValue->Value.date.Month = (UINT8) EditValue;
-          break;
-
-        case 1:
-          QuestionValue->Value.date.Day = (UINT8) EditValue;
-          break;
-
-        case 2:
-          QuestionValue->Value.date.Year = (UINT16) EditValue;
-          break;
-
-        default:
-          break;
-        }
-      } else if (Question->Operand == EFI_IFR_TIME_OP) {
-        switch (MenuOption->Sequence) {
-        case 0:
-          QuestionValue->Value.time.Hour = (UINT8) EditValue;
-          break;
-
-        case 1:
-          QuestionValue->Value.time.Minute = (UINT8) EditValue;
-          break;
-
-        case 2:
-          QuestionValue->Value.time.Second = (UINT8) EditValue;
-          break;
-
-        default:
-          break;
-        }
-      } else {
-        //
-        // Numeric
-        //
-        QuestionValue->Value.u64 = EditValue;
-      }
-
-      //
-      // Check to see if the Value is something reasonable against consistency limitations.
-      // If not, let's kick the error specified.
-      //
-      Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF);
-      if (EFI_ERROR (Status)) {
-        //
-        // Input value is not valid, restore Question Value
-        //
-        GetQuestionValue (FormSet, Form, Question, TRUE);
-      } else {
-        SetQuestionValue (FormSet, Form, Question, TRUE);
-        if (!DateOrTime || (Question->Storage != NULL)) {
-          //
-          // NV flag is unnecessary for RTC type of Date/Time
-          //
-          UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);
-        }
-      }
-
-      return Status;
-      break;
-
-    case CHAR_BACKSPACE:
-      if (ManualInput) {
-        if (Count == 0) {
-          break;
-        }
-        //
-        // Remove a character
-        //
-        EditValue = PreviousNumber[Count - 1];
-        UpdateStatusBar (INPUT_ERROR, Question->QuestionFlags, FALSE);
-        Count--;
-        Column--;
-        PrintAt (Column, Row, L" ");
-      }
-      break;
-
-    default:
-      if (ManualInput) {
-        if (HexInput) {
-          if (!R8_IsHexDigit (&Digital, Key.UnicodeChar)) {
-            UpdateStatusBar (INPUT_ERROR, Question->QuestionFlags, TRUE);
-            break;
-          }
-        } else {
-          if (Key.UnicodeChar > L'9' || Key.UnicodeChar < L'0') {
-            UpdateStatusBar (INPUT_ERROR, Question->QuestionFlags, TRUE);
-            break;
-          }
-        }
-
-        //
-        // If Count exceed input width, there is no way more is valid
-        //
-        if (Count >= InputWidth) {
-          break;
-        }
-        //
-        // Someone typed something valid!
-        //
-        if (Count != 0) {
-          if (HexInput) {
-            EditValue = LShiftU64 (EditValue, 4) + Digital;
-          } else {
-            EditValue = MultU64x32 (EditValue, 10) + (Key.UnicodeChar - L'0');
-          }
-        } else {
-          if (HexInput) {
-            EditValue = Digital;
-          } else {
-            EditValue = Key.UnicodeChar - L'0';
-          }
-        }
-
-        if (EditValue > Maximum) {
-          UpdateStatusBar (INPUT_ERROR, Question->QuestionFlags, TRUE);
-          EditValue = PreviousNumber[Count];
-          break;
-        } else {
-          UpdateStatusBar (INPUT_ERROR, Question->QuestionFlags, FALSE);
-        }
-
-        Count++;
-        PreviousNumber[Count] = EditValue;
-
-        PrintCharAt (Column, Row, Key.UnicodeChar);
-        Column++;
-      }
-      break;
-    }
-  } while (TRUE);
-
-}
-
-
-/**
-  Get selection for OneOf and OrderedList (Left/Right will be ignored).
-
-  @param  Selection         Pointer to current selection.
-  @param  MenuOption        Pointer to the current input menu.
-
-  @retval EFI_SUCCESS       If Option input is processed successfully
-  @retval EFI_DEVICE_ERROR  If operation fails
-
-**/
-EFI_STATUS
-GetSelectionInputPopUp (
-  IN  UI_MENU_SELECTION           *Selection,
-  IN  UI_MENU_OPTION              *MenuOption
-  )
-{
-  EFI_STATUS              Status;
-  EFI_INPUT_KEY           Key;
-  UINTN                   Index;
-  CHAR16                  *StringPtr;
-  CHAR16                  *TempStringPtr;
-  UINTN                   Index2;
-  UINTN                   TopOptionIndex;
-  UINTN                   HighlightOptionIndex;
-  UINTN                   Start;
-  UINTN                   End;
-  UINTN                   Top;
-  UINTN                   Bottom;
-  UINTN                   PopUpMenuLines;
-  UINTN                   MenuLinesInView;
-  UINTN                   PopUpWidth;
-  CHAR16                  Character;
-  INT32                   SavedAttribute;
-  BOOLEAN                 ShowDownArrow;
-  BOOLEAN                 ShowUpArrow;
-  UINTN                   DimensionsWidth;
-  LIST_ENTRY              *Link;
-  BOOLEAN                 OrderedList;
-  UINT8                   *ValueArray;
-  EFI_HII_VALUE           HiiValue;
-  EFI_HII_VALUE           *HiiValueArray;
-  UINTN                   OptionCount;
-  QUESTION_OPTION         *OneOfOption;
-  QUESTION_OPTION         *CurrentOption;
-  FORM_BROWSER_STATEMENT  *Question;
-
-  DimensionsWidth   = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;
-
-  ValueArray        = NULL;
-  CurrentOption     = NULL;
-  ShowDownArrow     = FALSE;
-  ShowUpArrow       = FALSE;
-
-  StringPtr = AllocateZeroPool ((gOptionBlockWidth + 1) * 2);
-  ASSERT (StringPtr);
-
-  Question = MenuOption->ThisTag;
-  if (Question->Operand == EFI_IFR_ORDERED_LIST_OP) {
-    ValueArray = Question->BufferValue;
-    OrderedList = TRUE;
-  } else {
-    OrderedList = FALSE;
-  }
-
-  //
-  // Calculate Option count
-  //
-  if (OrderedList) {
-    for (Index = 0; Index < Question->MaxContainers; Index++) {
-      if (ValueArray[Index] == 0) {
-        break;
-      }
-    }
-
-    OptionCount = Index;
-  } else {
-    OptionCount = 0;
-    Link = GetFirstNode (&Question->OptionListHead);
-    while (!IsNull (&Question->OptionListHead, Link)) {
-      OneOfOption = QUESTION_OPTION_FROM_LINK (Link);
-
-      OptionCount++;
-
-      Link = GetNextNode (&Question->OptionListHead, Link);
-    }
-  }
-
-  //
-  // Prepare HiiValue array
-  //
-  HiiValueArray = AllocateZeroPool (OptionCount * sizeof (EFI_HII_VALUE));
-  ASSERT (HiiValueArray != NULL);
-  Link = GetFirstNode (&Question->OptionListHead);
-  for (Index = 0; Index < OptionCount; Index++) {
-    if (OrderedList) {
-      HiiValueArray[Index].Type = EFI_IFR_TYPE_NUM_SIZE_8;
-      HiiValueArray[Index].Value.u8 = ValueArray[Index];
-    } else {
-      OneOfOption = QUESTION_OPTION_FROM_LINK (Link);
-      CopyMem (&HiiValueArray[Index], &OneOfOption->Value, sizeof (EFI_HII_VALUE));
-      Link = GetNextNode (&Question->OptionListHead, Link);
-    }
-  }
-
-  //
-  // Move Suppressed Option to list tail
-  //
-  PopUpMenuLines = 0;
-  for (Index = 0; Index < OptionCount; Index++) {
-    OneOfOption = ValueToOption (Question, &HiiValueArray[OptionCount - Index - 1]);
-    if (OneOfOption == NULL) {
-      return EFI_NOT_FOUND;
-    }
-
-    RemoveEntryList (&OneOfOption->Link);
-
-    if ((OneOfOption->SuppressExpression != NULL) &&
-        (OneOfOption->SuppressExpression->Result.Value.b)) {
-      //
-      // This option is suppressed, insert to tail
-      //
-      InsertTailList (&Question->OptionListHead, &OneOfOption->Link);
-    } else {
-      //
-      // Insert to head
-      //
-      InsertHeadList (&Question->OptionListHead, &OneOfOption->Link);
-
-      PopUpMenuLines++;
-    }
-  }
-
-  //
-  // Get the number of one of options present and its size
-  //
-  PopUpWidth = 0;
-  HighlightOptionIndex = 0;
-  Link = GetFirstNode (&Question->OptionListHead);
-  for (Index = 0; Index < PopUpMenuLines; Index++) {
-    OneOfOption = QUESTION_OPTION_FROM_LINK (Link);
-
-    StringPtr = GetToken (OneOfOption->Text, MenuOption->Handle);
-    if (StrLen (StringPtr) > PopUpWidth) {
-      PopUpWidth = StrLen (StringPtr);
-    }
-    gBS->FreePool (StringPtr);
-
-    if (!OrderedList && CompareHiiValue (&Question->HiiValue, &OneOfOption->Value, NULL) == 0) {
-      //
-      // Find current selected Option for OneOf
-      //
-      HighlightOptionIndex = Index;
-    }
-
-    Link = GetNextNode (&Question->OptionListHead, Link);
-  }
-
-  //
-  // Perform popup menu initialization.
-  //
-  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 - 1;
-
-  MenuLinesInView = Bottom - Top - 1;
-  if (MenuLinesInView >= PopUpMenuLines) {
-    Top     = Top + (MenuLinesInView - PopUpMenuLines) / 2;
-    Bottom  = Top + PopUpMenuLines + 1;
-  } else {
-    ShowDownArrow = TRUE;
-  }
-
-  if (HighlightOptionIndex > (MenuLinesInView - 1)) {
-    TopOptionIndex = HighlightOptionIndex - MenuLinesInView + 1;
-  } else {
-    TopOptionIndex = 0;
-  }
-
-  do {
-    //
-    // Clear that portion of the screen
-    //
-    ClearLines (Start, End, Top, Bottom, POPUP_TEXT | POPUP_BACKGROUND);
-
-    //
-    // Draw "One of" pop-up menu
-    //
-    Character = BOXDRAW_DOWN_RIGHT;
-    PrintCharAt (Start, Top, Character);
-    for (Index = Start; Index + 2 < End; Index++) {
-      if ((ShowUpArrow) && ((Index + 1) == (Start + End) / 2)) {
-        Character = GEOMETRICSHAPE_UP_TRIANGLE;
-      } else {
-        Character = BOXDRAW_HORIZONTAL;
-      }
-
-      PrintChar (Character);
-    }
-
-    Character = BOXDRAW_DOWN_LEFT;
-    PrintChar (Character);
-    Character = BOXDRAW_VERTICAL;
-    for (Index = Top + 1; Index < Bottom; Index++) {
-      PrintCharAt (Start, Index, Character);
-      PrintCharAt (End - 1, Index, Character);
-    }
-
-    //
-    // Move to top Option
-    //
-    Link = GetFirstNode (&Question->OptionListHead);
-    for (Index = 0; Index < TopOptionIndex; Index++) {
-      Link = GetNextNode (&Question->OptionListHead, Link);
-    }
-
-    //
-    // Display the One of options
-    //
-    Index2 = Top + 1;
-    for (Index = TopOptionIndex; (Index < PopUpMenuLines) && (Index2 < Bottom); Index++) {
-      OneOfOption = QUESTION_OPTION_FROM_LINK (Link);
-      Link = GetNextNode (&Question->OptionListHead, Link);
-
-      StringPtr = GetToken (OneOfOption->Text, 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)));
-        gBS->FreePool (StringPtr);
-        StringPtr = TempStringPtr;
-        StrCat (StringPtr, L"...");
-      }
-
-      if (Index == HighlightOptionIndex) {
-          //
-          // Highlight the selected one
-          //
-          CurrentOption = OneOfOption;
-
-          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);
-        } else {
-          gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);
-          PrintStringAt (Start + 2, Index2, StringPtr);
-        }
-
-      Index2++;
-      gBS->FreePool (StringPtr);
-    }
-
-    Character = BOXDRAW_UP_RIGHT;
-    PrintCharAt (Start, Bottom, Character);
-    for (Index = Start; Index + 2 < End; Index++) {
-      if ((ShowDownArrow) && ((Index + 1) == (Start + End) / 2)) {
-        Character = GEOMETRICSHAPE_DOWN_TRIANGLE;
-      } else {
-        Character = BOXDRAW_HORIZONTAL;
-      }
-
-      PrintChar (Character);
-    }
-
-    Character = BOXDRAW_UP_LEFT;
-    PrintChar (Character);
-
-    //
-    // Get User selection
-    //
-    Key.UnicodeChar = CHAR_NULL;
-    if ((gDirection == SCAN_UP) || (gDirection == SCAN_DOWN)) {
-      Key.ScanCode  = gDirection;
-      gDirection    = 0;
-      goto TheKey;
-    }
-
-    Status = WaitForKeyStroke (&Key);
-
-TheKey:
-    switch (Key.UnicodeChar) {
-    case '+':
-      if (OrderedList) {
-        if ((TopOptionIndex > 0) && (TopOptionIndex == HighlightOptionIndex)) {
-          //
-          // Highlight reaches the top of the popup window, scroll one menu item.
-          //
-          TopOptionIndex--;
-          ShowDownArrow = TRUE;
-        }
-
-        if (TopOptionIndex == 0) {
-          ShowUpArrow = FALSE;
-        }
-
-        if (HighlightOptionIndex > 0) {
-          HighlightOptionIndex--;
-
-          SwapListEntries (CurrentOption->Link.BackLink, &CurrentOption->Link);
-        }
-      }
-      break;
-
-    case '-':
-      //
-      // If an ordered list op-code, we will allow for a popup of +/- keys
-      // to create an ordered list of items
-      //
-      if (OrderedList) {
-        if (((TopOptionIndex + MenuLinesInView) < PopUpMenuLines) &&
-            (HighlightOptionIndex == (TopOptionIndex + MenuLinesInView - 1))) {
-          //
-          // Highlight reaches the bottom of the popup window, scroll one menu item.
-          //
-          TopOptionIndex++;
-          ShowUpArrow = TRUE;
-        }
-
-        if ((TopOptionIndex + MenuLinesInView) == PopUpMenuLines) {
-          ShowDownArrow = FALSE;
-        }
-
-        if (HighlightOptionIndex < (PopUpMenuLines - 1)) {
-          HighlightOptionIndex++;
-
-          SwapListEntries (&CurrentOption->Link, CurrentOption->Link.ForwardLink);
-        }
-      }
-      break;
-
-    case CHAR_NULL:
-      switch (Key.ScanCode) {
-      case SCAN_UP:
-      case SCAN_DOWN:
-        if (Key.ScanCode == SCAN_UP) {
-          if ((TopOptionIndex > 0) && (TopOptionIndex == HighlightOptionIndex)) {
-            //
-            // Highlight reaches the top of the popup window, scroll one menu item.
-            //
-            TopOptionIndex--;
-            ShowDownArrow = TRUE;
-          }
-
-          if (TopOptionIndex == 0) {
-            ShowUpArrow = FALSE;
-          }
-
-          if (HighlightOptionIndex > 0) {
-            HighlightOptionIndex--;
-          }
-        } else {
-          if (((TopOptionIndex + MenuLinesInView) < PopUpMenuLines) &&
-              (HighlightOptionIndex == (TopOptionIndex + MenuLinesInView - 1))) {
-            //
-            // Highlight reaches the bottom of the popup window, scroll one menu item.
-            //
-            TopOptionIndex++;
-            ShowUpArrow = TRUE;
-          }
-
-          if ((TopOptionIndex + MenuLinesInView) == PopUpMenuLines) {
-            ShowDownArrow = FALSE;
-          }
-
-          if (HighlightOptionIndex < (PopUpMenuLines - 1)) {
-            HighlightOptionIndex++;
-          }
-        }
-        break;
-
-      case SCAN_ESC:
-        gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);
-
-        //
-        // Restore link list order for orderedlist
-        //
-        if (OrderedList) {
-          HiiValue.Type = EFI_IFR_TYPE_NUM_SIZE_8;
-          HiiValue.Value.u64 = 0;
-          for (Index = 0; Index < Question->MaxContainers; Index++) {
-            HiiValue.Value.u8 = ValueArray[Index];
-            if (HiiValue.Value.u8) {
-              break;
-            }
-
-            OneOfOption = ValueToOption (Question, &HiiValue);
-            if (OneOfOption == NULL) {
-              return EFI_NOT_FOUND;
-            }
-
-            RemoveEntryList (&OneOfOption->Link);
-            InsertTailList (&Question->OptionListHead, &OneOfOption->Link);
-          }
-        }
-
-        gBS->FreePool (HiiValueArray);
-        return EFI_DEVICE_ERROR;
-
-      default:
-        break;
-      }
-
-      break;
-
-    case CHAR_CARRIAGE_RETURN:
-      //
-      // return the current selection
-      //
-      if (OrderedList) {
-        Index = 0;
-        Link = GetFirstNode (&Question->OptionListHead);
-        while (!IsNull (&Question->OptionListHead, Link)) {
-          OneOfOption = QUESTION_OPTION_FROM_LINK (Link);
-
-          Question->BufferValue[Index] = OneOfOption->Value.Value.u8;
-
-          Index++;
-          if (Index > Question->MaxContainers) {
-            break;
-          }
-
-          Link = GetNextNode (&Question->OptionListHead, Link);
-        }
-      } else {
-        CopyMem (&Question->HiiValue, &CurrentOption->Value, sizeof (EFI_HII_VALUE));
-      }
-
-      gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);
-      gBS->FreePool (HiiValueArray);
-
-      Status = ValidateQuestion (Selection->FormSet, Selection->Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF);
-      if (EFI_ERROR (Status)) {
-        //
-        // Input value is not valid, restore Question Value
-        //
-        GetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);
-      } else {
-        SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);
-        UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);
-      }
-
-      return Status;
-
-    default:
-      break;
-    }
-  } while (TRUE);
-
-}
-
-EFI_STATUS
-WaitForKeyStroke (
-  OUT  EFI_INPUT_KEY           *Key
-  )
-{
-  EFI_STATUS  Status;
-
-  do {
-    UiWaitForSingleEvent (gST->ConIn->WaitForKey, 0, 0);
-    Status = gST->ConIn->ReadKeyStroke (gST->ConIn, Key);
-  } while (EFI_ERROR(Status));
-
-  return Status;
-}
+/** @file\r
+Implementation for handling user input from the User Interfaces.\r
+\r
+Copyright (c) 2004 - 2012, Intel Corporation. All rights reserved.<BR>\r
+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
+**/\r
+\r
+#include "Setup.h"\r
+\r
+\r
+/**\r
+  Get string or password input from user.\r
+\r
+  @param  MenuOption        Pointer to the current input menu.\r
+  @param  Prompt            The prompt string shown on popup window.\r
+  @param  StringPtr         Old user input and destination for use input string.\r
+\r
+  @retval EFI_SUCCESS       If string input is read successfully\r
+  @retval EFI_DEVICE_ERROR  If operation fails\r
+\r
+**/\r
+EFI_STATUS\r
+ReadString (\r
+  IN     UI_MENU_OPTION              *MenuOption,\r
+  IN     CHAR16                      *Prompt,\r
+  IN OUT CHAR16                      *StringPtr\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EFI_INPUT_KEY           Key;\r
+  CHAR16                  NullCharacter;\r
+  UINTN                   ScreenSize;\r
+  CHAR16                  Space[2];\r
+  CHAR16                  KeyPad[2];\r
+  CHAR16                  *TempString;\r
+  CHAR16                  *BufferedString;\r
+  UINTN                   Index;\r
+  UINTN                   Index2;\r
+  UINTN                   Count;\r
+  UINTN                   Start;\r
+  UINTN                   Top;\r
+  UINTN                   DimensionsWidth;\r
+  UINTN                   DimensionsHeight;\r
+  UINTN                   CurrentCursor;\r
+  BOOLEAN                 CursorVisible;\r
+  UINTN                   Minimum;\r
+  UINTN                   Maximum;\r
+  FORM_BROWSER_STATEMENT  *Question;\r
+  BOOLEAN                 IsPassword;\r
+\r
+  DimensionsWidth  = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;\r
+  DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow;\r
+\r
+  NullCharacter    = CHAR_NULL;\r
+  ScreenSize       = GetStringWidth (Prompt) / sizeof (CHAR16);\r
+  Space[0]         = L' ';\r
+  Space[1]         = CHAR_NULL;\r
+\r
+  Question         = MenuOption->ThisTag;\r
+  Minimum          = (UINTN) Question->Minimum;\r
+  Maximum          = (UINTN) Question->Maximum;\r
+\r
+  if (Question->Operand == EFI_IFR_PASSWORD_OP) {\r
+    IsPassword = TRUE;\r
+  } else {\r
+    IsPassword = FALSE;\r
+  }\r
+\r
+  TempString = AllocateZeroPool ((Maximum + 1)* sizeof (CHAR16));\r
+  ASSERT (TempString);\r
+\r
+  if (ScreenSize < (Maximum + 1)) {\r
+    ScreenSize = Maximum + 1;\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
+  CreateMultiStringPopUp (ScreenSize, 4, &NullCharacter, Prompt, Space, &NullCharacter);\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
+  CurrentCursor = GetStringWidth (StringPtr) / 2 - 1;\r
+  if (CurrentCursor != 0) {\r
+    //\r
+    // Show the string which has beed saved before.\r
+    //\r
+    SetUnicodeMem (BufferedString, ScreenSize - 1, L' ');\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
+    if (IsPassword) {\r
+      gST->ConOut->SetCursorPosition (gST->ConOut, Start + 1, Top + 3);\r
+    }\r
+\r
+    for (Count = 0; Index + 1 < GetStringWidth (StringPtr) / 2; Index++, Count++) {\r
+      BufferedString[Count] = StringPtr[Index];\r
+\r
+      if (IsPassword) {\r
+        PrintChar (L'*');\r
+      }\r
+    }\r
+\r
+    if (!IsPassword) {\r
+      PrintStringAt (Start + 1, Top + 3, BufferedString);\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
+  }\r
+  \r
+  do {\r
+    Status = WaitForKeyStroke (&Key);\r
+    ASSERT_EFI_ERROR (Status);\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
+        if (CurrentCursor > 0) {\r
+          CurrentCursor--;\r
+        }\r
+        break;\r
+\r
+      case SCAN_RIGHT:\r
+        if (CurrentCursor < (GetStringWidth (StringPtr) / 2 - 1)) {\r
+          CurrentCursor++;\r
+        }\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) >= ((Minimum + 1) * sizeof (CHAR16))) {\r
+\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
+        //\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
+          CreateDialog (4, TRUE, 0, NULL, &Key, &NullCharacter, gMiniString, gPressEnter, &NullCharacter);\r
+        } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+\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 && CurrentCursor != 0) {\r
+        for (Index = 0; Index < CurrentCursor - 1; Index++) {\r
+          TempString[Index] = StringPtr[Index];\r
+        }\r
+        Count = GetStringWidth (StringPtr) / 2 - 1;\r
+        if (Count >= CurrentCursor) {\r
+          for (Index = CurrentCursor - 1, Index2 = CurrentCursor; Index2 < Count; Index++, Index2++) {\r
+            TempString[Index] = StringPtr[Index2];\r
+          }\r
+          TempString[Index] = CHAR_NULL;\r
+        }\r
+        //\r
+        // Effectively truncate string by 1 character\r
+        //\r
+        StrCpy (StringPtr, TempString);\r
+        CurrentCursor --;\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
+        CurrentCursor++;\r
+      } else if ((GetStringWidth (StringPtr) < ((Maximum + 1) * sizeof (CHAR16))) && (Key.UnicodeChar != CHAR_BACKSPACE)) {\r
+        KeyPad[0] = Key.UnicodeChar;\r
+        KeyPad[1] = CHAR_NULL;\r
+        Count = GetStringWidth (StringPtr) / 2 - 1;\r
+        if (CurrentCursor < Count) {\r
+          for (Index = 0; Index < CurrentCursor; Index++) {\r
+            TempString[Index] = StringPtr[Index];\r
+          }\r
+                 TempString[Index] = CHAR_NULL;\r
+          StrCat (TempString, KeyPad);\r
+          StrCat (TempString, StringPtr + CurrentCursor);\r
+          StrCpy (StringPtr, TempString);\r
+        } else {\r
+          StrCat (StringPtr, KeyPad);\r
+        }\r
+        CurrentCursor++;\r
+      }\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
+      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
+      if (IsPassword) {\r
+        gST->ConOut->SetCursorPosition (gST->ConOut, Start + 1, Top + 3);\r
+      }\r
+\r
+      for (Count = 0; Index + 1 < GetStringWidth (StringPtr) / 2; Index++, Count++) {\r
+        BufferedString[Count] = StringPtr[Index];\r
+\r
+        if (IsPassword) {\r
+          PrintChar (L'*');\r
+        }\r
+      }\r
+\r
+      if (!IsPassword) {\r
+        PrintStringAt (Start + 1, Top + 3, BufferedString);\r
+      }\r
+      break;\r
+    }\r
+\r
+    gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
+    gST->ConOut->SetCursorPosition (gST->ConOut, Start + CurrentCursor + 1, Top + 3);\r
+  } while (TRUE);\r
+\r
+}\r
+\r
+/**\r
+  Adjust the value to the correct one. Rules follow the sample:\r
+  like:  Year change:  2012.02.29 -> 2013.02.29 -> 2013.02.01\r
+         Month change: 2013.03.29 -> 2013.02.29 -> 2013.02.28\r
+\r
+  @param  Question          Pointer to current question.\r
+  @param  Sequence          The sequence of the field in the question.\r
+**/\r
+VOID\r
+AdjustQuestionValue (\r
+  IN  FORM_BROWSER_STATEMENT  *Question,\r
+  IN  UINT8                   Sequence\r
+  )\r
+{\r
+  UINT8     Month;\r
+  UINT16    Year;\r
+  UINT8     Maximum;\r
+  UINT8     Minimum;\r
+\r
+  if (Question->Operand != EFI_IFR_DATE_OP) {\r
+    return;\r
+  }\r
+\r
+  Month   = Question->HiiValue.Value.date.Month;\r
+  Year    = Question->HiiValue.Value.date.Year;\r
+  Minimum = 1;\r
+\r
+  switch (Month) {\r
+  case 2:\r
+    if ((Year % 4) == 0 && ((Year % 100) != 0 || (Year % 400) == 0)) {\r
+      Maximum = 29;\r
+    } else {\r
+      Maximum = 28;\r
+    }\r
+    break;\r
+  case 4:\r
+  case 6:\r
+  case 9:\r
+  case 11:\r
+    Maximum = 30;\r
+    break;\r
+  default:\r
+    Maximum = 31;\r
+    break;\r
+  }\r
+\r
+  //\r
+  // Change the month area.\r
+  //\r
+  if (Sequence == 0) {\r
+    if (Question->HiiValue.Value.date.Day > Maximum) {\r
+      Question->HiiValue.Value.date.Day = Maximum;\r
+    }\r
+  }\r
+  \r
+  //\r
+  // Change the Year area.\r
+  //\r
+  if (Sequence == 2) {\r
+    if (Question->HiiValue.Value.date.Day > Maximum) {\r
+      Question->HiiValue.Value.date.Day = Minimum;\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  This routine reads a numeric value from the user input.\r
+\r
+  @param  Selection         Pointer to current selection.\r
+  @param  MenuOption        Pointer to the current input menu.\r
+\r
+  @retval EFI_SUCCESS       If numerical input is read successfully\r
+  @retval EFI_DEVICE_ERROR  If operation fails\r
+\r
+**/\r
+EFI_STATUS\r
+GetNumericInput (\r
+  IN  UI_MENU_SELECTION           *Selection,\r
+  IN  UI_MENU_OPTION              *MenuOption\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  UINTN                   Column;\r
+  UINTN                   Row;\r
+  CHAR16                  InputText[MAX_NUMERIC_INPUT_WIDTH];\r
+  CHAR16                  FormattedNumber[MAX_NUMERIC_INPUT_WIDTH - 1];\r
+  UINT64                  PreviousNumber[MAX_NUMERIC_INPUT_WIDTH - 3];\r
+  UINTN                   Count;\r
+  UINTN                   Loop;\r
+  BOOLEAN                 ManualInput;\r
+  BOOLEAN                 HexInput;\r
+  BOOLEAN                 DateOrTime;\r
+  UINTN                   InputWidth;\r
+  UINT64                  EditValue;\r
+  UINT64                  Step;\r
+  UINT64                  Minimum;\r
+  UINT64                  Maximum;\r
+  UINTN                   EraseLen;\r
+  UINT8                   Digital;\r
+  EFI_INPUT_KEY           Key;\r
+  EFI_HII_VALUE           *QuestionValue;\r
+  FORM_BROWSER_FORM       *Form;\r
+  FORM_BROWSER_FORMSET    *FormSet;\r
+  FORM_BROWSER_STATEMENT  *Question;\r
+\r
+  Column            = MenuOption->OptCol;\r
+  Row               = MenuOption->Row;\r
+  PreviousNumber[0] = 0;\r
+  Count             = 0;\r
+  InputWidth        = 0;\r
+  Digital           = 0;\r
+\r
+  FormSet       = Selection->FormSet;\r
+  Form          = Selection->Form;\r
+  Question      = MenuOption->ThisTag;\r
+  QuestionValue = &Question->HiiValue;\r
+  Step          = Question->Step;\r
+  Minimum       = Question->Minimum;\r
+  Maximum       = Question->Maximum;\r
+\r
+  //\r
+  // Only two case, user can enter to this function: Enter and +/- case.\r
+  // In Enter case, gDirection = 0; in +/- case, gDirection = SCAN_LEFT/SCAN_WRIGHT\r
+  //\r
+  ManualInput        = (BOOLEAN)(gDirection == 0 ? TRUE : FALSE);\r
+\r
+  if ((Question->Operand == EFI_IFR_DATE_OP) || (Question->Operand == EFI_IFR_TIME_OP)) {\r
+    DateOrTime = TRUE;\r
+  } else {\r
+    DateOrTime = FALSE;\r
+  }\r
+\r
+  //\r
+  // Prepare Value to be edit\r
+  //\r
+  EraseLen = 0;\r
+  EditValue = 0;\r
+  if (Question->Operand == EFI_IFR_DATE_OP) {\r
+    Step = 1;\r
+    Minimum = 1;\r
+\r
+    switch (MenuOption->Sequence) {\r
+    case 0:\r
+      Maximum = 12;\r
+      EraseLen = 4;\r
+      EditValue = QuestionValue->Value.date.Month;\r
+      break;\r
+\r
+    case 1:\r
+      switch (QuestionValue->Value.date.Month) {\r
+      case 2:\r
+        if ((QuestionValue->Value.date.Year % 4) == 0  && \r
+            ((QuestionValue->Value.date.Year % 100) != 0 || \r
+            (QuestionValue->Value.date.Year % 400) == 0)) {\r
+          Maximum = 29;\r
+        } else {\r
+          Maximum = 28;\r
+        }\r
+        break;\r
+      case 4:\r
+      case 6:\r
+      case 9:\r
+      case 11:\r
+        Maximum = 30;\r
+        break;\r
+      default:\r
+        Maximum = 31;\r
+        break;\r
+      } \r
+\r
+      EraseLen = 3;\r
+      EditValue = QuestionValue->Value.date.Day;\r
+      break;\r
+\r
+    case 2:\r
+      Maximum = 0xffff;\r
+      EraseLen = 5;\r
+      EditValue = QuestionValue->Value.date.Year;\r
+      break;\r
+\r
+    default:\r
+      break;\r
+    }\r
+  } else if (Question->Operand == EFI_IFR_TIME_OP) {\r
+    Step = 1;\r
+    Minimum = 0;\r
+\r
+    switch (MenuOption->Sequence) {\r
+    case 0:\r
+      Maximum = 23;\r
+      EraseLen = 4;\r
+      EditValue = QuestionValue->Value.time.Hour;\r
+      break;\r
+\r
+    case 1:\r
+      Maximum = 59;\r
+      EraseLen = 3;\r
+      EditValue = QuestionValue->Value.time.Minute;\r
+      break;\r
+\r
+    case 2:\r
+      Maximum = 59;\r
+      EraseLen = 3;\r
+      EditValue = QuestionValue->Value.time.Second;\r
+      break;\r
+\r
+    default:\r
+      break;\r
+    }\r
+  } else {\r
+    //\r
+    // Numeric\r
+    //\r
+    EraseLen = gOptionBlockWidth;\r
+    EditValue = QuestionValue->Value.u64;\r
+    if (Maximum == 0) {\r
+      Maximum = (UINT64) -1;\r
+    }\r
+  }\r
+\r
+  if ((Question->Operand == EFI_IFR_NUMERIC_OP) &&\r
+      ((Question->Flags & EFI_IFR_DISPLAY) == EFI_IFR_DISPLAY_UINT_HEX)) {\r
+    HexInput = TRUE;\r
+  } else {\r
+    HexInput = FALSE;\r
+  }\r
+\r
+  //\r
+  // Enter from "Enter" input, clear the old word showing.\r
+  //\r
+  if (ManualInput) {\r
+    if (Question->Operand == EFI_IFR_NUMERIC_OP) {\r
+      if (HexInput) {\r
+        InputWidth = Question->StorageWidth * 2;\r
+      } else {\r
+        switch (Question->StorageWidth) {\r
+        case 1:\r
+          InputWidth = 3;\r
+          break;\r
+\r
+        case 2:\r
+          InputWidth = 5;\r
+          break;\r
+\r
+        case 4:\r
+          InputWidth = 10;\r
+          break;\r
+\r
+        case 8:\r
+          InputWidth = 20;\r
+          break;\r
+\r
+        default:\r
+          InputWidth = 0;\r
+          break;\r
+        }\r
+      }\r
+\r
+      InputText[0] = LEFT_NUMERIC_DELIMITER;\r
+      SetUnicodeMem (InputText + 1, InputWidth, L' ');\r
+      ASSERT (InputWidth + 2 < MAX_NUMERIC_INPUT_WIDTH);\r
+      InputText[InputWidth + 1] = RIGHT_NUMERIC_DELIMITER;\r
+      InputText[InputWidth + 2] = L'\0';\r
+\r
+      PrintAt (Column, Row, InputText);\r
+      Column++;\r
+    }\r
+\r
+    if (Question->Operand == EFI_IFR_DATE_OP) {\r
+      if (MenuOption->Sequence == 2) {\r
+        InputWidth = 4;\r
+      } else {\r
+        InputWidth = 2;\r
+      }\r
+\r
+      if (MenuOption->Sequence == 0) {\r
+        InputText[0] = LEFT_NUMERIC_DELIMITER;\r
+        SetUnicodeMem (InputText + 1, InputWidth, L' ');\r
+      } else {\r
+        SetUnicodeMem (InputText, InputWidth, L' ');\r
+      }\r
+\r
+      if (MenuOption->Sequence == 2) {\r
+        InputText[InputWidth + 1] = RIGHT_NUMERIC_DELIMITER;\r
+      } else {\r
+        InputText[InputWidth + 1] = DATE_SEPARATOR;\r
+      }\r
+      InputText[InputWidth + 2] = L'\0';\r
+\r
+      PrintAt (Column, Row, InputText);\r
+      if (MenuOption->Sequence == 0) {\r
+        Column++;\r
+      }\r
+    }\r
+\r
+    if (Question->Operand == EFI_IFR_TIME_OP) {\r
+      InputWidth = 2;\r
+\r
+      if (MenuOption->Sequence == 0) {\r
+        InputText[0] = LEFT_NUMERIC_DELIMITER;\r
+        SetUnicodeMem (InputText + 1, InputWidth, L' ');\r
+      } else {\r
+        SetUnicodeMem (InputText, InputWidth, L' ');\r
+      }\r
+\r
+      if (MenuOption->Sequence == 2) {\r
+        InputText[InputWidth + 1] = RIGHT_NUMERIC_DELIMITER;\r
+      } else {\r
+        InputText[InputWidth + 1] = TIME_SEPARATOR;\r
+      }\r
+      InputText[InputWidth + 2] = L'\0';\r
+\r
+      PrintAt (Column, Row, InputText);\r
+      if (MenuOption->Sequence == 0) {\r
+        Column++;\r
+      }\r
+    }\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
+    Status = WaitForKeyStroke (&Key);\r
+\r
+TheKey2:\r
+    switch (Key.UnicodeChar) {\r
+\r
+    case '+':\r
+    case '-':\r
+      if (Key.UnicodeChar == '+') {\r
+        Key.ScanCode = SCAN_RIGHT;\r
+      } else {\r
+        Key.ScanCode = SCAN_LEFT;\r
+      }\r
+      Key.UnicodeChar = CHAR_NULL;\r
+      goto TheKey2;\r
+\r
+    case CHAR_NULL:\r
+      switch (Key.ScanCode) {\r
+      case SCAN_LEFT:\r
+      case SCAN_RIGHT:\r
+        if (DateOrTime && !ManualInput) {\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 ((Step != 0) && !ManualInput) {\r
+          if (Key.ScanCode == SCAN_LEFT) {\r
+            if (EditValue >= Minimum + Step) {\r
+              EditValue = EditValue - Step;\r
+            } else if (EditValue > Minimum){\r
+              EditValue = Minimum;\r
+            } else {\r
+              EditValue = Maximum;\r
+            }\r
+          } else if (Key.ScanCode == SCAN_RIGHT) {\r
+            if (EditValue + Step <= Maximum) {\r
+              EditValue = EditValue + Step;\r
+            } else if (EditValue < Maximum) {\r
+              EditValue = Maximum;\r
+            } else {\r
+              EditValue = Minimum;\r
+            }\r
+          }\r
+\r
+          ZeroMem (FormattedNumber, 21 * sizeof (CHAR16));\r
+          if (Question->Operand == EFI_IFR_DATE_OP) {\r
+            if (MenuOption->Sequence == 2) {\r
+              //\r
+              // Year\r
+              //\r
+              UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%04d", (UINT16) EditValue);\r
+            } else {\r
+              //\r
+              // Month/Day\r
+              //\r
+              UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%02d", (UINT8) EditValue);\r
+            }\r
+\r
+            if (MenuOption->Sequence == 0) {\r
+              ASSERT (EraseLen >= 2);\r
+              FormattedNumber[EraseLen - 2] = DATE_SEPARATOR;\r
+            } else if (MenuOption->Sequence == 1) {\r
+              ASSERT (EraseLen >= 1);\r
+              FormattedNumber[EraseLen - 1] = DATE_SEPARATOR;\r
+            }\r
+          } else if (Question->Operand == EFI_IFR_TIME_OP) {\r
+            UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%02d", (UINT8) EditValue);\r
+\r
+            if (MenuOption->Sequence == 0) {\r
+              ASSERT (EraseLen >= 2);\r
+              FormattedNumber[EraseLen - 2] = TIME_SEPARATOR;\r
+            } else if (MenuOption->Sequence == 1) {\r
+              ASSERT (EraseLen >= 1);\r
+              FormattedNumber[EraseLen - 1] = TIME_SEPARATOR;\r
+            }\r
+          } else {\r
+            QuestionValue->Value.u64 = EditValue;\r
+            PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16));\r
+          }\r
+\r
+          gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND);\r
+          for (Loop = 0; Loop < EraseLen; Loop++) {\r
+            PrintAt (MenuOption->OptCol + Loop, MenuOption->Row, L" ");\r
+          }\r
+          gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextHighlightColor) | PcdGet8 (PcdBrowserFieldBackgroundHighlightColor));\r
+\r
+          if (MenuOption->Sequence == 0) {\r
+            PrintCharAt (MenuOption->OptCol, Row, LEFT_NUMERIC_DELIMITER);\r
+            Column = MenuOption->OptCol + 1;\r
+          }\r
+\r
+          PrintStringAt (Column, Row, FormattedNumber);\r
+\r
+          if (!DateOrTime || MenuOption->Sequence == 2) {\r
+            PrintChar (RIGHT_NUMERIC_DELIMITER);\r
+          }\r
+        }\r
+\r
+        goto EnterCarriageReturn;\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
+      // Validate input value with Minimum value.\r
+      //\r
+      if (EditValue < Minimum) {\r
+        UpdateStatusBar (Selection, INPUT_ERROR, Question->QuestionFlags, TRUE);\r
+        break;\r
+      } else {\r
+        UpdateStatusBar (Selection, INPUT_ERROR, Question->QuestionFlags, FALSE);\r
+      }\r
+\r
+      //\r
+      // Store Edit value back to Question\r
+      //\r
+      if (Question->Operand == EFI_IFR_DATE_OP) {\r
+        switch (MenuOption->Sequence) {\r
+        case 0:\r
+          QuestionValue->Value.date.Month = (UINT8) EditValue;\r
+          break;\r
+\r
+        case 1:\r
+          QuestionValue->Value.date.Day = (UINT8) EditValue;\r
+          break;\r
+\r
+        case 2:\r
+          QuestionValue->Value.date.Year = (UINT16) EditValue;\r
+          break;\r
+\r
+        default:\r
+          break;\r
+        }\r
+      } else if (Question->Operand == EFI_IFR_TIME_OP) {\r
+        switch (MenuOption->Sequence) {\r
+        case 0:\r
+          QuestionValue->Value.time.Hour = (UINT8) EditValue;\r
+          break;\r
+\r
+        case 1:\r
+          QuestionValue->Value.time.Minute = (UINT8) EditValue;\r
+          break;\r
+\r
+        case 2:\r
+          QuestionValue->Value.time.Second = (UINT8) EditValue;\r
+          break;\r
+\r
+        default:\r
+          break;\r
+        }\r
+      } else {\r
+        //\r
+        // Numeric\r
+        //\r
+        QuestionValue->Value.u64 = EditValue;\r
+      }\r
+\r
+      //\r
+      // Adjust the value to the correct one.\r
+      // Sample like: 2012.02.29 -> 2013.02.29 -> 2013.02.01\r
+      //              2013.03.29 -> 2013.02.29 -> 2013.02.28\r
+      //\r
+      if (Question->Operand == EFI_IFR_DATE_OP && \r
+        (MenuOption->Sequence == 0 || MenuOption->Sequence == 2)) {\r
+        AdjustQuestionValue (Question, (UINT8)MenuOption->Sequence);\r
+      }\r
+\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
+      Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF);\r
+      if (EFI_ERROR (Status)) {\r
+        //\r
+        // Input value is not valid, restore Question Value\r
+        //\r
+        GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);\r
+      } else {\r
+        SetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);\r
+        if (!DateOrTime || (Question->Storage != NULL)) {\r
+          //\r
+          // NV flag is unnecessary for RTC type of Date/Time\r
+          //\r
+          UpdateStatusBar (Selection, NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);\r
+        }\r
+      }\r
+\r
+      return Status;\r
+      break;\r
+\r
+    case CHAR_BACKSPACE:\r
+      if (ManualInput) {\r
+        if (Count == 0) {\r
+          break;\r
+        }\r
+        //\r
+        // Remove a character\r
+        //\r
+        EditValue = PreviousNumber[Count - 1];\r
+        UpdateStatusBar (Selection, INPUT_ERROR, Question->QuestionFlags, FALSE);\r
+        Count--;\r
+        Column--;\r
+        PrintAt (Column, Row, L" ");\r
+      }\r
+      break;\r
+\r
+    default:\r
+      if (ManualInput) {\r
+        if (HexInput) {\r
+          if ((Key.UnicodeChar >= L'0') && (Key.UnicodeChar <= L'9')) {\r
+            Digital = (UINT8) (Key.UnicodeChar - L'0');\r
+          } else if ((Key.UnicodeChar >= L'A') && (Key.UnicodeChar <= L'F')) {\r
+            Digital = (UINT8) (Key.UnicodeChar - L'A' + 0x0A);\r
+          } else if ((Key.UnicodeChar >= L'a') && (Key.UnicodeChar <= L'f')) {\r
+            Digital = (UINT8) (Key.UnicodeChar - L'a' + 0x0A);\r
+          } else {\r
+            UpdateStatusBar (Selection, INPUT_ERROR, Question->QuestionFlags, TRUE);\r
+            break;\r
+          }\r
+        } else {\r
+          if (Key.UnicodeChar > L'9' || Key.UnicodeChar < L'0') {\r
+            UpdateStatusBar (Selection, INPUT_ERROR, Question->QuestionFlags, TRUE);\r
+            break;\r
+          }\r
+        }\r
+\r
+        //\r
+        // If Count exceed input width, there is no way more is valid\r
+        //\r
+        if (Count >= InputWidth) {\r
+          break;\r
+        }\r
+        //\r
+        // Someone typed something valid!\r
+        //\r
+        if (Count != 0) {\r
+          if (HexInput) {\r
+            EditValue = LShiftU64 (EditValue, 4) + Digital;\r
+          } else {\r
+            EditValue = MultU64x32 (EditValue, 10) + (Key.UnicodeChar - L'0');\r
+          }\r
+        } else {\r
+          if (HexInput) {\r
+            EditValue = Digital;\r
+          } else {\r
+            EditValue = Key.UnicodeChar - L'0';\r
+          }\r
+        }\r
+\r
+        if (EditValue > Maximum) {\r
+          UpdateStatusBar (Selection, INPUT_ERROR, Question->QuestionFlags, TRUE);\r
+          ASSERT (Count < sizeof (PreviousNumber) / sizeof (PreviousNumber[0]));\r
+          EditValue = PreviousNumber[Count];\r
+          break;\r
+        } else {\r
+          UpdateStatusBar (Selection, INPUT_ERROR, Question->QuestionFlags, FALSE);\r
+        }\r
+\r
+        Count++;\r
+        ASSERT (Count < (sizeof (PreviousNumber) / sizeof (PreviousNumber[0])));\r
+        PreviousNumber[Count] = EditValue;\r
+\r
+        PrintCharAt (Column, Row, Key.UnicodeChar);\r
+        Column++;\r
+      }\r
+      break;\r
+    }\r
+  } while (TRUE);\r
+\r
+}\r
+\r
+\r
+/**\r
+  Get selection for OneOf and OrderedList (Left/Right will be ignored).\r
+\r
+  @param  Selection         Pointer to current selection.\r
+  @param  MenuOption        Pointer to the current input menu.\r
+\r
+  @retval EFI_SUCCESS       If Option input is processed successfully\r
+  @retval EFI_DEVICE_ERROR  If operation fails\r
+\r
+**/\r
+EFI_STATUS\r
+GetSelectionInputPopUp (\r
+  IN  UI_MENU_SELECTION           *Selection,\r
+  IN  UI_MENU_OPTION              *MenuOption\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EFI_INPUT_KEY           Key;\r
+  UINTN                   Index;\r
+  CHAR16                  *StringPtr;\r
+  CHAR16                  *TempStringPtr;\r
+  UINTN                   Index2;\r
+  UINTN                   TopOptionIndex;\r
+  UINTN                   HighlightOptionIndex;\r
+  UINTN                   Start;\r
+  UINTN                   End;\r
+  UINTN                   Top;\r
+  UINTN                   Bottom;\r
+  UINTN                   PopUpMenuLines;\r
+  UINTN                   MenuLinesInView;\r
+  UINTN                   PopUpWidth;\r
+  CHAR16                  Character;\r
+  INT32                   SavedAttribute;\r
+  BOOLEAN                 ShowDownArrow;\r
+  BOOLEAN                 ShowUpArrow;\r
+  UINTN                   DimensionsWidth;\r
+  LIST_ENTRY              *Link;\r
+  BOOLEAN                 OrderedList;\r
+  UINT8                   *ValueArray;\r
+  UINT8                   ValueType;\r
+  EFI_HII_VALUE           HiiValue;\r
+  EFI_HII_VALUE           *HiiValueArray;\r
+  UINTN                   OptionCount;\r
+  QUESTION_OPTION         *OneOfOption;\r
+  QUESTION_OPTION         *CurrentOption;\r
+  FORM_BROWSER_STATEMENT  *Question;\r
+  INTN                    Result;\r
+\r
+  DimensionsWidth   = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;\r
+\r
+  ValueArray        = NULL;\r
+  ValueType         = 0;\r
+  CurrentOption     = NULL;\r
+  ShowDownArrow     = FALSE;\r
+  ShowUpArrow       = FALSE;\r
+\r
+  StringPtr = AllocateZeroPool ((gOptionBlockWidth + 1) * 2);\r
+  ASSERT (StringPtr);\r
+\r
+  Question = MenuOption->ThisTag;\r
+  if (Question->Operand == EFI_IFR_ORDERED_LIST_OP) {\r
+    ValueArray = Question->BufferValue;\r
+    ValueType = Question->ValueType;\r
+    OrderedList = TRUE;\r
+  } else {\r
+    OrderedList = FALSE;\r
+  }\r
+\r
+  //\r
+  // Calculate Option count\r
+  //\r
+  if (OrderedList) {\r
+    for (Index = 0; Index < Question->MaxContainers; Index++) {\r
+      if (GetArrayData (ValueArray, ValueType, Index) == 0) {\r
+        break;\r
+      }\r
+    }\r
+\r
+    OptionCount = Index;\r
+  } else {\r
+    OptionCount = 0;\r
+    Link = GetFirstNode (&Question->OptionListHead);\r
+    while (!IsNull (&Question->OptionListHead, Link)) {\r
+      OneOfOption = QUESTION_OPTION_FROM_LINK (Link);\r
+\r
+      OptionCount++;\r
+\r
+      Link = GetNextNode (&Question->OptionListHead, Link);\r
+    }\r
+  }\r
+\r
+  //\r
+  // Move valid Option to list head.\r
+  //\r
+  PopUpMenuLines = 0;\r
+  if (OrderedList) {\r
+    //\r
+    // Prepare HiiValue array\r
+    //  \r
+    HiiValueArray = AllocateZeroPool (OptionCount * sizeof (EFI_HII_VALUE));\r
+    ASSERT (HiiValueArray != NULL);\r
+    for (Index = 0; Index < OptionCount; Index++) {\r
+      HiiValueArray[Index].Type = ValueType;\r
+      HiiValueArray[Index].Value.u64 = GetArrayData (ValueArray, ValueType, Index);\r
+    }\r
+\r
+    for (Index = 0; Index < OptionCount; Index++) {\r
+      OneOfOption = ValueToOption (Question, &HiiValueArray[OptionCount - Index - 1]);\r
+      if (OneOfOption == NULL) {\r
+        return EFI_NOT_FOUND;\r
+      }\r
+\r
+      RemoveEntryList (&OneOfOption->Link);\r
+\r
+      //\r
+      // Insert to head.\r
+      //\r
+      InsertHeadList (&Question->OptionListHead, &OneOfOption->Link);\r
+\r
+      PopUpMenuLines++;\r
+    }\r
+\r
+    FreePool (HiiValueArray);\r
+  } else {\r
+    Link = GetFirstNode (&Question->OptionListHead);\r
+    for (Index = 0; Index < OptionCount; Index++) {\r
+      OneOfOption = QUESTION_OPTION_FROM_LINK (Link);\r
+      Link = GetNextNode (&Question->OptionListHead, Link);\r
+      if ((OneOfOption->SuppressExpression != NULL) &&\r
+          EvaluateExpressionList(OneOfOption->SuppressExpression, FALSE, NULL, NULL) > ExpressFalse) {\r
+        continue;\r
+      } else {\r
+        PopUpMenuLines++;\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // Get the number of one of options present and its size\r
+  //\r
+  PopUpWidth = 0;\r
+  HighlightOptionIndex = 0;\r
+  Link = GetFirstNode (&Question->OptionListHead);\r
+  for (Index = 0; Index < PopUpMenuLines; Index++) {\r
+    OneOfOption = QUESTION_OPTION_FROM_LINK (Link);\r
+    Link = GetNextNode (&Question->OptionListHead, Link);\r
+\r
+    if (!OrderedList && (OneOfOption->SuppressExpression != NULL) &&\r
+        EvaluateExpressionList(OneOfOption->SuppressExpression, FALSE, NULL, NULL) > ExpressFalse) {\r
+      Index--;\r
+      continue;\r
+    }\r
+\r
+    StringPtr = GetToken (OneOfOption->Text, MenuOption->Handle);\r
+    if (StrLen (StringPtr) > PopUpWidth) {\r
+      PopUpWidth = StrLen (StringPtr);\r
+    }\r
+    FreePool (StringPtr);\r
+\r
+    if (!OrderedList && (CompareHiiValue (&Question->HiiValue, &OneOfOption->Value, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {\r
+      //\r
+      // Find current selected Option for OneOf\r
+      //\r
+      HighlightOptionIndex = Index;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Perform popup menu initialization.\r
+  //\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 - gFooterHeight - 1;\r
+\r
+  MenuLinesInView = Bottom - Top - 1;\r
+  if (MenuLinesInView >= PopUpMenuLines) {\r
+    Top     = Top + (MenuLinesInView - PopUpMenuLines) / 2;\r
+    Bottom  = Top + PopUpMenuLines + 1;\r
+  } else {\r
+    ShowDownArrow = TRUE;\r
+  }\r
+\r
+  if (HighlightOptionIndex > (MenuLinesInView - 1)) {\r
+    TopOptionIndex = HighlightOptionIndex - MenuLinesInView + 1;\r
+  } else {\r
+    TopOptionIndex = 0;\r
+  }\r
+\r
+  do {\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 = 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 = GEOMETRICSHAPE_UP_TRIANGLE;\r
+      } else {\r
+        Character = BOXDRAW_HORIZONTAL;\r
+      }\r
+\r
+      PrintChar (Character);\r
+    }\r
+\r
+    Character = BOXDRAW_DOWN_LEFT;\r
+    PrintChar (Character);\r
+    Character = BOXDRAW_VERTICAL;\r
+    for (Index = Top + 1; Index < Bottom; Index++) {\r
+      PrintCharAt (Start, Index, Character);\r
+      PrintCharAt (End - 1, Index, Character);\r
+    }\r
+\r
+    //\r
+    // Move to top Option\r
+    //\r
+    Link = GetFirstNode (&Question->OptionListHead);\r
+    for (Index = 0; Index < TopOptionIndex; Index++) {\r
+      Link = GetNextNode (&Question->OptionListHead, Link);\r
+\r
+      OneOfOption = QUESTION_OPTION_FROM_LINK (Link);\r
+      if (!OrderedList && (OneOfOption->SuppressExpression != NULL) &&\r
+          EvaluateExpressionList(OneOfOption->SuppressExpression, FALSE, NULL, NULL) > ExpressFalse) {\r
+        Index--;\r
+        continue;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Display the One of options\r
+    //\r
+    Index2 = Top + 1;\r
+    for (Index = TopOptionIndex; (Index < PopUpMenuLines) && (Index2 < Bottom); Index++) {\r
+      OneOfOption = QUESTION_OPTION_FROM_LINK (Link);\r
+      Link = GetNextNode (&Question->OptionListHead, Link);\r
+\r
+      if (!OrderedList && (OneOfOption->SuppressExpression != NULL) &&\r
+          EvaluateExpressionList(OneOfOption->SuppressExpression, FALSE, NULL, NULL) > ExpressFalse) {\r
+        Index--;\r
+        continue;\r
+      }\r
+\r
+      StringPtr = GetToken (OneOfOption->Text, MenuOption->Handle);\r
+      ASSERT (StringPtr != NULL);\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, L"...");\r
+      }\r
+\r
+      if (Index == HighlightOptionIndex) {\r
+          //\r
+          // Highlight the selected one\r
+          //\r
+          CurrentOption = OneOfOption;\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
+        } else {\r
+          gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);\r
+          PrintStringAt (Start + 2, Index2, StringPtr);\r
+        }\r
+\r
+      Index2++;\r
+      FreePool (StringPtr);\r
+    }\r
+\r
+    Character = 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 = GEOMETRICSHAPE_DOWN_TRIANGLE;\r
+      } else {\r
+        Character = BOXDRAW_HORIZONTAL;\r
+      }\r
+\r
+      PrintChar (Character);\r
+    }\r
+\r
+    Character = BOXDRAW_UP_LEFT;\r
+    PrintChar (Character);\r
+\r
+    //\r
+    // Get User selection\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
+    Status = WaitForKeyStroke (&Key);\r
+\r
+TheKey:\r
+    switch (Key.UnicodeChar) {\r
+    case '+':\r
+      if (OrderedList) {\r
+        if ((TopOptionIndex > 0) && (TopOptionIndex == HighlightOptionIndex)) {\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 == 0) {\r
+          ShowUpArrow = FALSE;\r
+        }\r
+\r
+        if (HighlightOptionIndex > 0) {\r
+          HighlightOptionIndex--;\r
+\r
+          ASSERT (CurrentOption != NULL);\r
+          SwapListEntries (CurrentOption->Link.BackLink, &CurrentOption->Link);\r
+        }\r
+      }\r
+      break;\r
+\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 (OrderedList) {\r
+        if (((TopOptionIndex + MenuLinesInView) < PopUpMenuLines) &&\r
+            (HighlightOptionIndex == (TopOptionIndex + MenuLinesInView - 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) {\r
+          ShowDownArrow = FALSE;\r
+        }\r
+\r
+        if (HighlightOptionIndex < (PopUpMenuLines - 1)) {\r
+          HighlightOptionIndex++;\r
+\r
+          ASSERT (CurrentOption != NULL);\r
+          SwapListEntries (&CurrentOption->Link, CurrentOption->Link.ForwardLink);\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 > 0) && (TopOptionIndex == HighlightOptionIndex)) {\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 == 0) {\r
+            ShowUpArrow = FALSE;\r
+          }\r
+\r
+          if (HighlightOptionIndex > 0) {\r
+            HighlightOptionIndex--;\r
+          }\r
+        } else {\r
+          if (((TopOptionIndex + MenuLinesInView) < PopUpMenuLines) &&\r
+              (HighlightOptionIndex == (TopOptionIndex + MenuLinesInView - 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) {\r
+            ShowDownArrow = FALSE;\r
+          }\r
+\r
+          if (HighlightOptionIndex < (PopUpMenuLines - 1)) {\r
+            HighlightOptionIndex++;\r
+          }\r
+        }\r
+        break;\r
+\r
+      case SCAN_ESC:\r
+        gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);\r
+\r
+        //\r
+        // Restore link list order for orderedlist\r
+        //\r
+        if (OrderedList) {\r
+          HiiValue.Type = ValueType;\r
+          HiiValue.Value.u64 = 0;\r
+          for (Index = 0; Index < Question->MaxContainers; Index++) {\r
+            HiiValue.Value.u64 = GetArrayData (ValueArray, ValueType, Index);\r
+            if (HiiValue.Value.u64 == 0) {\r
+              break;\r
+            }\r
+\r
+            OneOfOption = ValueToOption (Question, &HiiValue);\r
+            if (OneOfOption == NULL) {\r
+              return EFI_NOT_FOUND;\r
+            }\r
+\r
+            RemoveEntryList (&OneOfOption->Link);\r
+            InsertTailList (&Question->OptionListHead, &OneOfOption->Link);\r
+          }\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 (OrderedList) {\r
+        Index = 0;\r
+        Link = GetFirstNode (&Question->OptionListHead);\r
+        while (!IsNull (&Question->OptionListHead, Link)) {\r
+          OneOfOption = QUESTION_OPTION_FROM_LINK (Link);\r
+          Link = GetNextNode (&Question->OptionListHead, Link);\r
+\r
+          if ((OneOfOption->SuppressExpression != NULL) &&\r
+              EvaluateExpressionList(OneOfOption->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {\r
+            continue;\r
+          }\r
+\r
+          SetArrayData (ValueArray, ValueType, Index, OneOfOption->Value.Value.u64);\r
+\r
+          Index++;\r
+          if (Index > Question->MaxContainers) {\r
+            break;\r
+          }\r
+        }\r
+      } else {\r
+        ASSERT (CurrentOption != NULL);\r
+        CopyMem (&Question->HiiValue, &CurrentOption->Value, sizeof (EFI_HII_VALUE));\r
+      }\r
+\r
+      gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);\r
+\r
+      Status = ValidateQuestion (Selection->FormSet, Selection->Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF);\r
+      if (EFI_ERROR (Status)) {\r
+        //\r
+        // Input value is not valid, restore Question Value\r
+        //\r
+        GetQuestionValue (Selection->FormSet, Selection->Form, Question, GetSetValueWithEditBuffer);\r
+      } else {\r
+        SetQuestionValue (Selection->FormSet, Selection->Form, Question, GetSetValueWithEditBuffer);\r
+        UpdateStatusBar (Selection, NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);\r
+      }\r
+\r
+      return Status;\r
+\r
+    default:\r
+      break;\r
+    }\r
+  } while (TRUE);\r
+\r
+}\r
+\r
+/**\r
+  Wait for a key to be pressed by user.\r
+\r
+  @param Key         The key which is pressed by user.\r
+\r
+  @retval EFI_SUCCESS The function always completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+WaitForKeyStroke (\r
+  OUT  EFI_INPUT_KEY           *Key\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  while (TRUE) {\r
+    Status = gST->ConIn->ReadKeyStroke (gST->ConIn, Key);\r
+    if (!EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+\r
+    if (Status != EFI_NOT_READY) {\r
+      continue;\r
+    }\r
+\r
+    UiWaitForSingleEvent (gST->ConIn->WaitForKey, 0, 0);\r
+  }\r
+  return Status;\r
+}\r