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