Пример #1
0
/**
  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[MAX_NUMERIC_INPUT_WIDTH];
    CHAR16                  FormattedNumber[MAX_NUMERIC_INPUT_WIDTH - 1];
    UINT64                  PreviousNumber[MAX_NUMERIC_INPUT_WIDTH - 3];
    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;

    //
    // Only two case, user can enter to this function: Enter and +/- case.
    // In Enter case, gDirection = 0; in +/- case, gDirection = SCAN_LEFT/SCAN_WRIGHT
    //
    ManualInput        = (BOOLEAN)(gDirection == 0 ? TRUE : FALSE);

    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:
            switch (QuestionValue->Value.date.Month) {
            case 2:
                if ((QuestionValue->Value.date.Year % 4) == 0  &&
                        ((QuestionValue->Value.date.Year % 100) != 0 ||
                         (QuestionValue->Value.date.Year % 400) == 0)) {
                    Maximum = 29;
                } else {
                    Maximum = 28;
                }
                break;
            case 4:
            case 6:
            case 9:
            case 11:
                Maximum = 30;
                break;
            default:
                Maximum = 31;
                break;
            }

            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 ((Question->Operand == EFI_IFR_NUMERIC_OP) &&
            ((Question->Flags & EFI_IFR_DISPLAY) == EFI_IFR_DISPLAY_UINT_HEX)) {
        HexInput = TRUE;
    } else {
        HexInput = FALSE;
    }

    //
    // Enter from "Enter" input, clear the old word showing.
    //
    if (ManualInput) {
        if (Question->Operand == EFI_IFR_NUMERIC_OP) {
            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' ');
            ASSERT (InputWidth + 2 < MAX_NUMERIC_INPUT_WIDTH);
            InputText[InputWidth + 1] = RIGHT_NUMERIC_DELIMITER;
            InputText[InputWidth + 2] = L'\0';

            PrintAt (Column, Row, InputText);
            Column++;
        }

        if (Question->Operand == EFI_IFR_DATE_OP) {
            if (MenuOption->Sequence == 2) {
                InputWidth = 4;
            } else {
                InputWidth = 2;
            }

            if (MenuOption->Sequence == 0) {
                InputText[0] = LEFT_NUMERIC_DELIMITER;
                SetUnicodeMem (InputText + 1, InputWidth, L' ');
            } else {
                SetUnicodeMem (InputText, InputWidth, L' ');
            }

            if (MenuOption->Sequence == 2) {
                InputText[InputWidth + 1] = RIGHT_NUMERIC_DELIMITER;
            } else {
                InputText[InputWidth + 1] = DATE_SEPARATOR;
            }
            InputText[InputWidth + 2] = L'\0';

            PrintAt (Column, Row, InputText);
            if (MenuOption->Sequence == 0) {
                Column++;
            }
        }

        if (Question->Operand == EFI_IFR_TIME_OP) {
            InputWidth = 2;

            if (MenuOption->Sequence == 0) {
                InputText[0] = LEFT_NUMERIC_DELIMITER;
                SetUnicodeMem (InputText + 1, InputWidth, L' ');
            } else {
                SetUnicodeMem (InputText, InputWidth, L' ');
            }

            if (MenuOption->Sequence == 2) {
                InputText[InputWidth + 1] = RIGHT_NUMERIC_DELIMITER;
            } else {
                InputText[InputWidth + 1] = TIME_SEPARATOR;
            }
            InputText[InputWidth + 2] = L'\0';

            PrintAt (Column, Row, InputText);
            if (MenuOption->Sequence == 0) {
                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 && !ManualInput) {
                    //
                    // 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 ((Step != 0) && !ManualInput) {
                    if (Key.ScanCode == SCAN_LEFT) {
                        if (EditValue >= Minimum + Step) {
                            EditValue = EditValue - Step;
                        } else if (EditValue > Minimum) {
                            EditValue = Minimum;
                        } else {
                            EditValue = Maximum;
                        }
                    } else if (Key.ScanCode == SCAN_RIGHT) {
                        if (EditValue + Step <= Maximum) {
                            EditValue = EditValue + Step;
                        } else if (EditValue < Maximum) {
                            EditValue = Maximum;
                        } else {
                            EditValue = Minimum;
                        }
                    }

                    ZeroMem (FormattedNumber, 21 * sizeof (CHAR16));
                    if (Question->Operand == EFI_IFR_DATE_OP) {
                        if (MenuOption->Sequence == 2) {
                            //
                            // Year
                            //
                            UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%04d", (UINT16) EditValue);
                        } else {
                            //
                            // Month/Day
                            //
                            UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%02d", (UINT8) EditValue);
                        }

                        if (MenuOption->Sequence == 0) {
                            ASSERT (EraseLen >= 2);
                            FormattedNumber[EraseLen - 2] = DATE_SEPARATOR;
                        } else if (MenuOption->Sequence == 1) {
                            ASSERT (EraseLen >= 1);
                            FormattedNumber[EraseLen - 1] = DATE_SEPARATOR;
                        }
                    } else if (Question->Operand == EFI_IFR_TIME_OP) {
                        UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%02d", (UINT8) EditValue);

                        if (MenuOption->Sequence == 0) {
                            ASSERT (EraseLen >= 2);
                            FormattedNumber[EraseLen - 2] = TIME_SEPARATOR;
                        } else if (MenuOption->Sequence == 1) {
                            ASSERT (EraseLen >= 1);
                            FormattedNumber[EraseLen - 1] = TIME_SEPARATOR;
                        }
                    } else {
                        QuestionValue->Value.u64 = EditValue;
                        PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16));
                    }

                    gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND);
                    for (Loop = 0; Loop < EraseLen; Loop++) {
                        PrintAt (MenuOption->OptCol + Loop, MenuOption->Row, L" ");
                    }
                    gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextHighlightColor) | PcdGet8 (PcdBrowserFieldBackgroundHighlightColor));

                    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);
                    }
                }

                goto EnterCarriageReturn;
                break;

            case SCAN_UP:
            case SCAN_DOWN:
                goto EnterCarriageReturn;

            case SCAN_ESC:
                return EFI_DEVICE_ERROR;

            default:
                break;
            }

            break;

EnterCarriageReturn:

        case CHAR_CARRIAGE_RETURN:
            //
            // Validate input value with Minimum value.
            //
            if (EditValue < Minimum) {
                UpdateStatusBar (Selection, INPUT_ERROR, Question->QuestionFlags, TRUE);
                break;
            } else {
                UpdateStatusBar (Selection, INPUT_ERROR, Question->QuestionFlags, FALSE);
            }

            //
            // 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;
            }

            //
            // Adjust the value to the correct one.
            // Sample like: 2012.02.29 -> 2013.02.29 -> 2013.02.01
            //              2013.03.29 -> 2013.02.29 -> 2013.02.28
            //
            if (Question->Operand == EFI_IFR_DATE_OP &&
                    (MenuOption->Sequence == 0 || MenuOption->Sequence == 2)) {
                AdjustQuestionValue (Question, (UINT8)MenuOption->Sequence);
            }

            //
            // 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 (Selection, 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 (Selection, INPUT_ERROR, Question->QuestionFlags, FALSE);
                Count--;
                Column--;
                PrintAt (Column, Row, L" ");
            }
            break;

        default:
            if (ManualInput) {
                if (HexInput) {
                    if ((Key.UnicodeChar >= L'0') && (Key.UnicodeChar <= L'9')) {
                        Digital = (UINT8) (Key.UnicodeChar - L'0');
                    } else if ((Key.UnicodeChar >= L'A') && (Key.UnicodeChar <= L'F')) {
                        Digital = (UINT8) (Key.UnicodeChar - L'A' + 0x0A);
                    } else if ((Key.UnicodeChar >= L'a') && (Key.UnicodeChar <= L'f')) {
                        Digital = (UINT8) (Key.UnicodeChar - L'a' + 0x0A);
                    } else {
                        UpdateStatusBar (Selection, INPUT_ERROR, Question->QuestionFlags, TRUE);
                        break;
                    }
                } else {
                    if (Key.UnicodeChar > L'9' || Key.UnicodeChar < L'0') {
                        UpdateStatusBar (Selection, 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 (Selection, INPUT_ERROR, Question->QuestionFlags, TRUE);
                    ASSERT (Count < sizeof (PreviousNumber) / sizeof (PreviousNumber[0]));
                    EditValue = PreviousNumber[Count];
                    break;
                } else {
                    UpdateStatusBar (Selection, INPUT_ERROR, Question->QuestionFlags, FALSE);
                }

                Count++;
                ASSERT (Count < (sizeof (PreviousNumber) / sizeof (PreviousNumber[0])));
                PreviousNumber[Count] = EditValue;

                PrintCharAt (Column, Row, Key.UnicodeChar);
                Column++;
            }
            break;
        }
    } while (TRUE);

}
Пример #2
0
/**
  This routine reads a numeric value from the user input.

  @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_OPTION              *MenuOption
  )
{
  UINTN                   Column;
  UINTN                   Row;
  CHAR16                  InputText[MAX_NUMERIC_INPUT_WIDTH];
  CHAR16                  FormattedNumber[MAX_NUMERIC_INPUT_WIDTH - 1];
  UINT64                  PreviousNumber[MAX_NUMERIC_INPUT_WIDTH - 3];
  UINTN                   Count;
  UINTN                   Loop;
  BOOLEAN                 ManualInput;
  BOOLEAN                 HexInput;
  BOOLEAN                 IntInput;
  BOOLEAN                 Negative;
  BOOLEAN                 ValidateFail;
  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_DISPLAY_ENGINE_STATEMENT  *Question;
  EFI_IFR_NUMERIC                *NumericOp;
  UINT16                         StorageWidth;

  Column            = MenuOption->OptCol;
  Row               = MenuOption->Row;
  PreviousNumber[0] = 0;
  Count             = 0;
  InputWidth        = 0;
  Digital           = 0;
  StorageWidth      = 0;
  Minimum           = 0;
  Maximum           = 0;
  NumericOp         = NULL;
  IntInput          = FALSE;
  HexInput          = FALSE;
  Negative          = FALSE;
  ValidateFail      = FALSE;

  Question      = MenuOption->ThisTag;
  QuestionValue = &Question->CurrentValue;
  ZeroMem (InputText, MAX_NUMERIC_INPUT_WIDTH * sizeof (CHAR16));

  //
  // Only two case, user can enter to this function: Enter and +/- case.
  // In Enter case, gDirection = 0; in +/- case, gDirection = SCAN_LEFT/SCAN_WRIGHT
  //
  ManualInput        = (BOOLEAN)(gDirection == 0 ? TRUE : FALSE);

  if ((Question->OpCode->OpCode == EFI_IFR_DATE_OP) || (Question->OpCode->OpCode == EFI_IFR_TIME_OP)) {
    DateOrTime = TRUE;
  } else {
    DateOrTime = FALSE;
  }

  //
  // Prepare Value to be edit
  //
  EraseLen = 0;
  EditValue = 0;
  if (Question->OpCode->OpCode == 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:
      switch (QuestionValue->Value.date.Month) {
      case 2:
        if ((QuestionValue->Value.date.Year % 4) == 0  &&
            ((QuestionValue->Value.date.Year % 100) != 0 ||
            (QuestionValue->Value.date.Year % 400) == 0)) {
          Maximum = 29;
        } else {
          Maximum = 28;
        }
        break;
      case 4:
      case 6:
      case 9:
      case 11:
        Maximum = 30;
        break;
      default:
        Maximum = 31;
        break;
      }

      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->OpCode->OpCode == 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 {
    ASSERT (Question->OpCode->OpCode == EFI_IFR_NUMERIC_OP);
    NumericOp = (EFI_IFR_NUMERIC *) Question->OpCode;
    GetValueFromNum(Question->OpCode, (NumericOp->Flags & EFI_IFR_DISPLAY) == 0, QuestionValue, &EditValue, &Minimum, &Maximum, &Step, &StorageWidth);
    EraseLen  = gOptionBlockWidth;
  }

  if ((Question->OpCode->OpCode == EFI_IFR_NUMERIC_OP) && (NumericOp != NULL)) {
    if ((NumericOp->Flags & EFI_IFR_DISPLAY) == EFI_IFR_DISPLAY_UINT_HEX){
      HexInput = TRUE;
    } else if ((NumericOp->Flags & EFI_IFR_DISPLAY) == 0){
      //
      // Display with EFI_IFR_DISPLAY_INT_DEC type. Support negative number.
      //
      IntInput = TRUE;
    }
  }

  //
  // Enter from "Enter" input, clear the old word showing.
  //
  if (ManualInput) {
    if (Question->OpCode->OpCode == EFI_IFR_NUMERIC_OP) {
      if (HexInput) {
        InputWidth = StorageWidth * 2;
      } else {
        switch (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;
        }

        if (IntInput) {
          //
          // Support an extra '-' for negative number.
          //
          InputWidth += 1;
        }
      }

      InputText[0] = LEFT_NUMERIC_DELIMITER;
      SetUnicodeMem (InputText + 1, InputWidth, L' ');
      ASSERT (InputWidth + 2 < MAX_NUMERIC_INPUT_WIDTH);
      InputText[InputWidth + 1] = RIGHT_NUMERIC_DELIMITER;
      InputText[InputWidth + 2] = L'\0';

      PrintStringAt (Column, Row, InputText);
      Column++;
    }

    if (Question->OpCode->OpCode == EFI_IFR_DATE_OP) {
      if (MenuOption->Sequence == 2) {
        InputWidth = 4;
      } else {
        InputWidth = 2;
      }

      if (MenuOption->Sequence == 0) {
        InputText[0] = LEFT_NUMERIC_DELIMITER;
        SetUnicodeMem (InputText + 1, InputWidth, L' ');
        InputText[InputWidth + 1] = DATE_SEPARATOR;
        InputText[InputWidth + 2] = L'\0';
      } else  if (MenuOption->Sequence == 1){
        SetUnicodeMem (InputText, InputWidth, L' ');
        InputText[InputWidth] = DATE_SEPARATOR;
        InputText[InputWidth + 1] = L'\0';
      } else {
        SetUnicodeMem (InputText, InputWidth, L' ');
        InputText[InputWidth] = RIGHT_NUMERIC_DELIMITER;
        InputText[InputWidth + 1] = L'\0';
      }

      PrintStringAt (Column, Row, InputText);
      if (MenuOption->Sequence == 0) {
        Column++;
      }
    }

    if (Question->OpCode->OpCode == EFI_IFR_TIME_OP) {
      InputWidth = 2;

      if (MenuOption->Sequence == 0) {
        InputText[0] = LEFT_NUMERIC_DELIMITER;
        SetUnicodeMem (InputText + 1, InputWidth, L' ');
        InputText[InputWidth + 1] = TIME_SEPARATOR;
        InputText[InputWidth + 2] = L'\0';
      } else if (MenuOption->Sequence == 1){
        SetUnicodeMem (InputText, InputWidth, L' ');
        InputText[InputWidth] = TIME_SEPARATOR;
        InputText[InputWidth + 1] = L'\0';
      } else {
        SetUnicodeMem (InputText, InputWidth, L' ');
        InputText[InputWidth] = RIGHT_NUMERIC_DELIMITER;
        InputText[InputWidth + 1] = L'\0';
      }

      PrintStringAt (Column, Row, InputText);
      if (MenuOption->Sequence == 0) {
        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;
    }

    WaitForKeyStroke (&Key);

TheKey2:
    switch (Key.UnicodeChar) {

    case '+':
    case '-':
      if (ManualInput && IntInput) {
        //
        // In Manual input mode, check whether input the negative flag.
        //
        if (Key.UnicodeChar == '-') {
          if (Negative) {
            break;
          }
          Negative = TRUE;
          PrintCharAt (Column++, Row, Key.UnicodeChar);
        }
      } else {
        if (Key.UnicodeChar == '+') {
          Key.ScanCode = SCAN_RIGHT;
        } else {
          Key.ScanCode = SCAN_LEFT;
        }
        Key.UnicodeChar = CHAR_NULL;
        goto TheKey2;
      }
      break;

    case CHAR_NULL:
      switch (Key.ScanCode) {
      case SCAN_LEFT:
      case SCAN_RIGHT:
        if (DateOrTime && !ManualInput) {
          //
          // 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 ((Step != 0) && !ManualInput) {
          if (Key.ScanCode == SCAN_LEFT) {
            if (IntInput) {
              if ((INT64) EditValue >= (INT64) Minimum + (INT64) Step) {
                EditValue = EditValue - Step;
              } else if ((INT64) EditValue > (INT64) Minimum){
                EditValue = Minimum;
              } else {
                EditValue = Maximum;
              }
            } else {
              if (EditValue >= Minimum + Step) {
                EditValue = EditValue - Step;
              } else if (EditValue > Minimum){
                EditValue = Minimum;
              } else {
                EditValue = Maximum;
              }
            }
          } else if (Key.ScanCode == SCAN_RIGHT) {
            if (IntInput) {
              if ((INT64) EditValue + (INT64) Step <= (INT64) Maximum) {
                EditValue = EditValue + Step;
              } else if ((INT64) EditValue < (INT64) Maximum) {
                EditValue = Maximum;
              } else {
                EditValue = Minimum;
              }
            } else {
              if (EditValue + Step <= Maximum) {
                EditValue = EditValue + Step;
              } else if (EditValue < Maximum) {
                EditValue = Maximum;
              } else {
                EditValue = Minimum;
              }
            }
          }

          ZeroMem (FormattedNumber, 21 * sizeof (CHAR16));
          if (Question->OpCode->OpCode == EFI_IFR_DATE_OP) {
            if (MenuOption->Sequence == 2) {
              //
              // Year
              //
              UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%04d", (UINT16) EditValue);
            } else {
              //
              // Month/Day
              //
              UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%02d", (UINT8) EditValue);
            }

            if (MenuOption->Sequence == 0) {
              ASSERT (EraseLen >= 2);
              FormattedNumber[EraseLen - 2] = DATE_SEPARATOR;
            } else if (MenuOption->Sequence == 1) {
              ASSERT (EraseLen >= 1);
              FormattedNumber[EraseLen - 1] = DATE_SEPARATOR;
            }
          } else if (Question->OpCode->OpCode == EFI_IFR_TIME_OP) {
            UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%02d", (UINT8) EditValue);

            if (MenuOption->Sequence == 0) {
              ASSERT (EraseLen >= 2);
              FormattedNumber[EraseLen - 2] = TIME_SEPARATOR;
            } else if (MenuOption->Sequence == 1) {
              ASSERT (EraseLen >= 1);
              FormattedNumber[EraseLen - 1] = TIME_SEPARATOR;
            }
          } else {
            QuestionValue->Value.u64 = EditValue;
            PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16));
          }

          gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());
          for (Loop = 0; Loop < EraseLen; Loop++) {
            PrintStringAt (MenuOption->OptCol + Loop, MenuOption->Row, L" ");
          }
          gST->ConOut->SetAttribute (gST->ConOut, GetHighlightTextColor ());

          if (MenuOption->Sequence == 0) {
            PrintCharAt (MenuOption->OptCol, Row, LEFT_NUMERIC_DELIMITER);
            Column = MenuOption->OptCol + 1;
          }

          PrintStringAt (Column, Row, FormattedNumber);

          if (!DateOrTime || MenuOption->Sequence == 2) {
            PrintCharAt ((UINTN)-1, (UINTN)-1, RIGHT_NUMERIC_DELIMITER);
          }
        }

        goto EnterCarriageReturn;

      case SCAN_UP:
      case SCAN_DOWN:
        goto EnterCarriageReturn;

      case SCAN_ESC:
        return EFI_DEVICE_ERROR;

      default:
        break;
      }

      break;

EnterCarriageReturn:

    case CHAR_CARRIAGE_RETURN:
      //
      // Validate input value with Minimum value.
      //
      ValidateFail = FALSE;
      if (IntInput) {
        //
        // After user input Enter, need to check whether the input value.
        // If input a negative value, should compare with maximum value.
        // else compare with the minimum value.
        //
        if (Negative) {
          ValidateFail = (INT64) EditValue > (INT64) Maximum ? TRUE : FALSE;
        } else {
          ValidateFail = (INT64) EditValue < (INT64) Minimum ? TRUE : FALSE;
        }

        if (ValidateFail) {
          UpdateStatusBar (INPUT_ERROR, TRUE);
          break;
        }
      } else if (EditValue < Minimum) {
        UpdateStatusBar (INPUT_ERROR, TRUE);
        break;
      }

      UpdateStatusBar (INPUT_ERROR, FALSE);
      CopyMem (&gUserInput->InputValue, &Question->CurrentValue, sizeof (EFI_HII_VALUE));
      QuestionValue = &gUserInput->InputValue;
      //
      // Store Edit value back to Question
      //
      if (Question->OpCode->OpCode == 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->OpCode->OpCode  == 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;
      }

      //
      // Adjust the value to the correct one.
      // Sample like: 2012.02.29 -> 2013.02.29 -> 2013.02.01
      //              2013.03.29 -> 2013.02.29 -> 2013.02.28
      //
      if (Question->OpCode->OpCode  == EFI_IFR_DATE_OP &&
        (MenuOption->Sequence == 0 || MenuOption->Sequence == 2)) {
        AdjustQuestionValue (QuestionValue, (UINT8)MenuOption->Sequence);
      }

      return EFI_SUCCESS;

    case CHAR_BACKSPACE:
      if (ManualInput) {
        if (Count == 0) {
          if (Negative) {
            Negative = FALSE;
            Column--;
            PrintStringAt (Column, Row, L" ");
          }
          break;
        }
        //
        // Remove a character
        //
        EditValue = PreviousNumber[Count - 1];
        UpdateStatusBar (INPUT_ERROR,  FALSE);
        Count--;
        Column--;
        PrintStringAt (Column, Row, L" ");
      }
      break;

    default:
      if (ManualInput) {
        if (HexInput) {
          if ((Key.UnicodeChar >= L'0') && (Key.UnicodeChar <= L'9')) {
            Digital = (UINT8) (Key.UnicodeChar - L'0');
          } else if ((Key.UnicodeChar >= L'A') && (Key.UnicodeChar <= L'F')) {
            Digital = (UINT8) (Key.UnicodeChar - L'A' + 0x0A);
          } else if ((Key.UnicodeChar >= L'a') && (Key.UnicodeChar <= L'f')) {
            Digital = (UINT8) (Key.UnicodeChar - L'a' + 0x0A);
          } else {
            UpdateStatusBar (INPUT_ERROR, TRUE);
            break;
          }
        } else {
          if (Key.UnicodeChar > L'9' || Key.UnicodeChar < L'0') {
            UpdateStatusBar (INPUT_ERROR, 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 if (IntInput && Negative) {
            //
            // Save the negative number.
            //
            EditValue = ~(MultU64x32 (~(EditValue - 1), 10) + (Key.UnicodeChar - L'0')) + 1;
          } else {
            EditValue = MultU64x32 (EditValue, 10) + (Key.UnicodeChar - L'0');
          }
        } else {
          if (HexInput) {
            EditValue = Digital;
          } else if (IntInput && Negative) {
            //
            // Save the negative number.
            //
            EditValue = ~(Key.UnicodeChar - L'0') + 1;
          } else {
            EditValue = Key.UnicodeChar - L'0';
          }
        }

        if (IntInput) {
          ValidateFail = FALSE;
          //
          // When user input a new value, should check the current value.
          // If user input a negative value, should compare it with minimum
          // value, else compare it with maximum value.
          //
          if (Negative) {
            ValidateFail = (INT64) EditValue < (INT64) Minimum ? TRUE : FALSE;
          } else {
            ValidateFail = (INT64) EditValue > (INT64) Maximum ? TRUE : FALSE;
          }

          if (ValidateFail) {
            UpdateStatusBar (INPUT_ERROR, TRUE);
            ASSERT (Count < ARRAY_SIZE (PreviousNumber));
            EditValue = PreviousNumber[Count];
            break;
          }
        } else {
          if (EditValue > Maximum) {
            UpdateStatusBar (INPUT_ERROR, TRUE);
            ASSERT (Count < ARRAY_SIZE (PreviousNumber));
            EditValue = PreviousNumber[Count];
            break;
          }
        }

        UpdateStatusBar (INPUT_ERROR, FALSE);

        Count++;
        ASSERT (Count < (ARRAY_SIZE (PreviousNumber)));
        PreviousNumber[Count] = EditValue;

        gST->ConOut->SetAttribute (gST->ConOut, GetHighlightTextColor ());
        PrintCharAt (Column, Row, Key.UnicodeChar);
        Column++;
      }
      break;
    }
  } while (TRUE);
}