2 Implementation for handling user input from the User Interfaces.
4 Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include "FormDisplay.h"
12 Get maximum and minimum info from this opcode.
14 @param OpCode Pointer to the current input opcode.
15 @param Minimum The minimum size info for this opcode.
16 @param Maximum The maximum size info for this opcode.
21 IN EFI_IFR_OP_HEADER
*OpCode
,
26 EFI_IFR_STRING
*StringOp
;
27 EFI_IFR_PASSWORD
*PasswordOp
;
29 if (OpCode
->OpCode
== EFI_IFR_STRING_OP
) {
30 StringOp
= (EFI_IFR_STRING
*)OpCode
;
31 *Minimum
= StringOp
->MinSize
;
32 *Maximum
= StringOp
->MaxSize
;
33 } else if (OpCode
->OpCode
== EFI_IFR_PASSWORD_OP
) {
34 PasswordOp
= (EFI_IFR_PASSWORD
*)OpCode
;
35 *Minimum
= PasswordOp
->MinSize
;
36 *Maximum
= PasswordOp
->MaxSize
;
44 Get string or password input from user.
46 @param MenuOption Pointer to the current input menu.
47 @param Prompt The prompt string shown on popup window.
48 @param StringPtr Old user input and destination for use input string.
50 @retval EFI_SUCCESS If string input is read successfully
51 @retval EFI_DEVICE_ERROR If operation fails
56 IN UI_MENU_OPTION
*MenuOption
,
58 IN OUT CHAR16
*StringPtr
68 CHAR16
*BufferedString
;
74 UINTN DimensionsWidth
;
75 UINTN DimensionsHeight
;
77 BOOLEAN CursorVisible
;
80 FORM_DISPLAY_ENGINE_STATEMENT
*Question
;
84 DimensionsWidth
= gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
;
85 DimensionsHeight
= gStatementDimensions
.BottomRow
- gStatementDimensions
.TopRow
;
87 NullCharacter
= CHAR_NULL
;
88 ScreenSize
= GetStringWidth (Prompt
) / sizeof (CHAR16
);
92 Question
= MenuOption
->ThisTag
;
93 GetFieldFromOp (Question
->OpCode
, &Minimum
, &Maximum
);
95 if (Question
->OpCode
->OpCode
== EFI_IFR_PASSWORD_OP
) {
101 MaxLen
= Maximum
+ 1;
102 TempString
= AllocateZeroPool (MaxLen
* sizeof (CHAR16
));
105 if (ScreenSize
< (Maximum
+ 1)) {
106 ScreenSize
= Maximum
+ 1;
109 if ((ScreenSize
+ 2) > DimensionsWidth
) {
110 ScreenSize
= DimensionsWidth
- 2;
113 BufferedString
= AllocateZeroPool (ScreenSize
* 2);
114 ASSERT (BufferedString
);
116 Start
= (DimensionsWidth
- ScreenSize
- 2) / 2 + gStatementDimensions
.LeftColumn
+ 1;
117 Top
= ((DimensionsHeight
- 6) / 2) + gStatementDimensions
.TopRow
- 1;
120 // Display prompt for string
122 // CreateDialog (NULL, "", Prompt, Space, "", NULL);
123 CreateMultiStringPopUp (ScreenSize
, 4, &NullCharacter
, Prompt
, Space
, &NullCharacter
);
124 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_BLACK
, EFI_LIGHTGRAY
));
126 CursorVisible
= gST
->ConOut
->Mode
->CursorVisible
;
127 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
129 CurrentCursor
= GetStringWidth (StringPtr
) / 2 - 1;
130 if (CurrentCursor
!= 0) {
132 // Show the string which has beed saved before.
134 SetUnicodeMem (BufferedString
, ScreenSize
- 1, L
' ');
135 PrintStringAt (Start
+ 1, Top
+ 3, BufferedString
);
137 if ((GetStringWidth (StringPtr
) / 2) > (DimensionsWidth
- 2)) {
138 Index
= (GetStringWidth (StringPtr
) / 2) - DimensionsWidth
+ 2;
144 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, Start
+ 1, Top
+ 3);
147 for (Count
= 0; Index
+ 1 < GetStringWidth (StringPtr
) / 2; Index
++, Count
++) {
148 BufferedString
[Count
] = StringPtr
[Index
];
151 PrintCharAt ((UINTN
)-1, (UINTN
)-1, L
'*');
156 PrintStringAt (Start
+ 1, Top
+ 3, BufferedString
);
159 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
160 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, Start
+ GetStringWidth (StringPtr
) / 2, Top
+ 3);
164 Status
= WaitForKeyStroke (&Key
);
165 ASSERT_EFI_ERROR (Status
);
167 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_BLACK
, EFI_LIGHTGRAY
));
168 switch (Key
.UnicodeChar
) {
170 switch (Key
.ScanCode
) {
172 if (CurrentCursor
> 0) {
179 if (CurrentCursor
< (GetStringWidth (StringPtr
) / 2 - 1)) {
186 FreePool (TempString
);
187 FreePool (BufferedString
);
188 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
189 gST
->ConOut
->EnableCursor (gST
->ConOut
, CursorVisible
);
190 return EFI_DEVICE_ERROR
;
193 for (Index
= CurrentCursor
; StringPtr
[Index
] != CHAR_NULL
; Index
++) {
194 StringPtr
[Index
] = StringPtr
[Index
+ 1];
195 PrintCharAt (Start
+ Index
+ 1, Top
+ 3, IsPassword
&& StringPtr
[Index
] != CHAR_NULL
? L
'*' : StringPtr
[Index
]);
206 case CHAR_CARRIAGE_RETURN
:
207 if (GetStringWidth (StringPtr
) >= ((Minimum
+ 1) * sizeof (CHAR16
))) {
208 FreePool (TempString
);
209 FreePool (BufferedString
);
210 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
211 gST
->ConOut
->EnableCursor (gST
->ConOut
, CursorVisible
);
215 // Simply create a popup to tell the user that they had typed in too few characters.
216 // To save code space, we can then treat this as an error and return back to the menu.
219 CreateDialog (&Key
, &NullCharacter
, gMiniString
, gPressEnter
, &NullCharacter
, NULL
);
220 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
222 FreePool (TempString
);
223 FreePool (BufferedString
);
224 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
225 gST
->ConOut
->EnableCursor (gST
->ConOut
, CursorVisible
);
226 return EFI_DEVICE_ERROR
;
230 if ((StringPtr
[0] != CHAR_NULL
) && (CurrentCursor
!= 0)) {
231 for (Index
= 0; Index
< CurrentCursor
- 1; Index
++) {
232 TempString
[Index
] = StringPtr
[Index
];
235 Count
= GetStringWidth (StringPtr
) / 2 - 1;
236 if (Count
>= CurrentCursor
) {
237 for (Index
= CurrentCursor
- 1, Index2
= CurrentCursor
; Index2
< Count
; Index
++, Index2
++) {
238 TempString
[Index
] = StringPtr
[Index2
];
241 TempString
[Index
] = CHAR_NULL
;
245 // Effectively truncate string by 1 character
247 StrCpyS (StringPtr
, MaxLen
, TempString
);
253 // If it is the beginning of the string, don't worry about checking maximum limits
255 if ((StringPtr
[0] == CHAR_NULL
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
256 StrnCpyS (StringPtr
, MaxLen
, &Key
.UnicodeChar
, 1);
258 } else if ((GetStringWidth (StringPtr
) < ((Maximum
+ 1) * sizeof (CHAR16
))) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
259 KeyPad
[0] = Key
.UnicodeChar
;
260 KeyPad
[1] = CHAR_NULL
;
261 Count
= GetStringWidth (StringPtr
) / 2 - 1;
262 if (CurrentCursor
< Count
) {
263 for (Index
= 0; Index
< CurrentCursor
; Index
++) {
264 TempString
[Index
] = StringPtr
[Index
];
267 TempString
[Index
] = CHAR_NULL
;
268 StrCatS (TempString
, MaxLen
, KeyPad
);
269 StrCatS (TempString
, MaxLen
, StringPtr
+ CurrentCursor
);
270 StrCpyS (StringPtr
, MaxLen
, TempString
);
272 StrCatS (StringPtr
, MaxLen
, KeyPad
);
279 // If the width of the input string is now larger than the screen, we nee to
280 // adjust the index to start printing portions of the string
282 SetUnicodeMem (BufferedString
, ScreenSize
- 1, L
' ');
283 PrintStringAt (Start
+ 1, Top
+ 3, BufferedString
);
285 if ((GetStringWidth (StringPtr
) / 2) > (DimensionsWidth
- 2)) {
286 Index
= (GetStringWidth (StringPtr
) / 2) - DimensionsWidth
+ 2;
292 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, Start
+ 1, Top
+ 3);
295 for (Count
= 0; Index
+ 1 < GetStringWidth (StringPtr
) / 2; Index
++, Count
++) {
296 BufferedString
[Count
] = StringPtr
[Index
];
299 PrintCharAt ((UINTN
)-1, (UINTN
)-1, L
'*');
304 PrintStringAt (Start
+ 1, Top
+ 3, BufferedString
);
310 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
311 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, Start
+ CurrentCursor
+ 1, Top
+ 3);
316 Adjust the value to the correct one. Rules follow the sample:
317 like: Year change: 2012.02.29 -> 2013.02.29 -> 2013.02.01
318 Month change: 2013.03.29 -> 2013.02.29 -> 2013.02.28
320 @param QuestionValue Pointer to current question.
321 @param Sequence The sequence of the field in the question.
324 AdjustQuestionValue (
325 IN EFI_HII_VALUE
*QuestionValue
,
334 Month
= QuestionValue
->Value
.date
.Month
;
335 Year
= QuestionValue
->Value
.date
.Year
;
340 if (((Year
% 4) == 0) && (((Year
% 100) != 0) || ((Year
% 400) == 0))) {
359 // Change the month area.
362 if (QuestionValue
->Value
.date
.Day
> Maximum
) {
363 QuestionValue
->Value
.date
.Day
= Maximum
;
368 // Change the Year area.
371 if (QuestionValue
->Value
.date
.Day
> Maximum
) {
372 QuestionValue
->Value
.date
.Day
= Minimum
;
378 Get field info from numeric opcode.
380 @param OpCode Pointer to the current input opcode.
381 @param IntInput Whether question shows with EFI_IFR_DISPLAY_INT_DEC type.
382 @param QuestionValue Input question value, with EFI_HII_VALUE type.
383 @param Value Return question value, always return UINT64 type.
384 @param Minimum The minimum size info for this opcode.
385 @param Maximum The maximum size info for this opcode.
386 @param Step The step size info for this opcode.
387 @param StorageWidth The storage width info for this opcode.
392 IN EFI_IFR_OP_HEADER
*OpCode
,
394 IN EFI_HII_VALUE
*QuestionValue
,
399 OUT UINT16
*StorageWidth
402 EFI_IFR_NUMERIC
*NumericOp
;
404 NumericOp
= (EFI_IFR_NUMERIC
*)OpCode
;
406 switch (NumericOp
->Flags
& EFI_IFR_NUMERIC_SIZE
) {
407 case EFI_IFR_NUMERIC_SIZE_1
:
409 *Minimum
= (INT64
)(INT8
)NumericOp
->data
.u8
.MinValue
;
410 *Maximum
= (INT64
)(INT8
)NumericOp
->data
.u8
.MaxValue
;
411 *Value
= (INT64
)(INT8
)QuestionValue
->Value
.u8
;
413 *Minimum
= NumericOp
->data
.u8
.MinValue
;
414 *Maximum
= NumericOp
->data
.u8
.MaxValue
;
415 *Value
= QuestionValue
->Value
.u8
;
418 *Step
= NumericOp
->data
.u8
.Step
;
419 *StorageWidth
= (UINT16
)sizeof (UINT8
);
422 case EFI_IFR_NUMERIC_SIZE_2
:
424 *Minimum
= (INT64
)(INT16
)NumericOp
->data
.u16
.MinValue
;
425 *Maximum
= (INT64
)(INT16
)NumericOp
->data
.u16
.MaxValue
;
426 *Value
= (INT64
)(INT16
)QuestionValue
->Value
.u16
;
428 *Minimum
= NumericOp
->data
.u16
.MinValue
;
429 *Maximum
= NumericOp
->data
.u16
.MaxValue
;
430 *Value
= QuestionValue
->Value
.u16
;
433 *Step
= NumericOp
->data
.u16
.Step
;
434 *StorageWidth
= (UINT16
)sizeof (UINT16
);
437 case EFI_IFR_NUMERIC_SIZE_4
:
439 *Minimum
= (INT64
)(INT32
)NumericOp
->data
.u32
.MinValue
;
440 *Maximum
= (INT64
)(INT32
)NumericOp
->data
.u32
.MaxValue
;
441 *Value
= (INT64
)(INT32
)QuestionValue
->Value
.u32
;
443 *Minimum
= NumericOp
->data
.u32
.MinValue
;
444 *Maximum
= NumericOp
->data
.u32
.MaxValue
;
445 *Value
= QuestionValue
->Value
.u32
;
448 *Step
= NumericOp
->data
.u32
.Step
;
449 *StorageWidth
= (UINT16
)sizeof (UINT32
);
452 case EFI_IFR_NUMERIC_SIZE_8
:
454 *Minimum
= (INT64
)NumericOp
->data
.u64
.MinValue
;
455 *Maximum
= (INT64
)NumericOp
->data
.u64
.MaxValue
;
456 *Value
= (INT64
)QuestionValue
->Value
.u64
;
458 *Minimum
= NumericOp
->data
.u64
.MinValue
;
459 *Maximum
= NumericOp
->data
.u64
.MaxValue
;
460 *Value
= QuestionValue
->Value
.u64
;
463 *Step
= NumericOp
->data
.u64
.Step
;
464 *StorageWidth
= (UINT16
)sizeof (UINT64
);
472 *Maximum
= (UINT64
)-1;
477 This routine reads a numeric value from the user input.
479 @param MenuOption Pointer to the current input menu.
481 @retval EFI_SUCCESS If numerical input is read successfully
482 @retval EFI_DEVICE_ERROR If operation fails
487 IN UI_MENU_OPTION
*MenuOption
492 CHAR16 InputText
[MAX_NUMERIC_INPUT_WIDTH
];
493 CHAR16 FormattedNumber
[MAX_NUMERIC_INPUT_WIDTH
- 1];
494 UINT64 PreviousNumber
[MAX_NUMERIC_INPUT_WIDTH
- 3];
501 BOOLEAN ValidateFail
;
511 EFI_HII_VALUE
*QuestionValue
;
512 FORM_DISPLAY_ENGINE_STATEMENT
*Question
;
513 EFI_IFR_NUMERIC
*NumericOp
;
516 Column
= MenuOption
->OptCol
;
517 Row
= MenuOption
->Row
;
518 PreviousNumber
[0] = 0;
529 ValidateFail
= FALSE
;
531 Question
= MenuOption
->ThisTag
;
532 QuestionValue
= &Question
->CurrentValue
;
533 ZeroMem (InputText
, MAX_NUMERIC_INPUT_WIDTH
* sizeof (CHAR16
));
536 // Only two case, user can enter to this function: Enter and +/- case.
537 // In Enter case, gDirection = 0; in +/- case, gDirection = SCAN_LEFT/SCAN_WRIGHT
539 ManualInput
= (BOOLEAN
)(gDirection
== 0 ? TRUE
: FALSE
);
541 if ((Question
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) || (Question
->OpCode
->OpCode
== EFI_IFR_TIME_OP
)) {
548 // Prepare Value to be edit
552 if (Question
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) {
556 switch (MenuOption
->Sequence
) {
560 EditValue
= QuestionValue
->Value
.date
.Month
;
564 switch (QuestionValue
->Value
.date
.Month
) {
566 if (((QuestionValue
->Value
.date
.Year
% 4) == 0) &&
567 (((QuestionValue
->Value
.date
.Year
% 100) != 0) ||
568 ((QuestionValue
->Value
.date
.Year
% 400) == 0)))
588 EditValue
= QuestionValue
->Value
.date
.Day
;
594 EditValue
= QuestionValue
->Value
.date
.Year
;
600 } else if (Question
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
604 switch (MenuOption
->Sequence
) {
608 EditValue
= QuestionValue
->Value
.time
.Hour
;
614 EditValue
= QuestionValue
->Value
.time
.Minute
;
620 EditValue
= QuestionValue
->Value
.time
.Second
;
627 ASSERT (Question
->OpCode
->OpCode
== EFI_IFR_NUMERIC_OP
);
628 NumericOp
= (EFI_IFR_NUMERIC
*)Question
->OpCode
;
629 GetValueFromNum (Question
->OpCode
, (NumericOp
->Flags
& EFI_IFR_DISPLAY
) == 0, QuestionValue
, &EditValue
, &Minimum
, &Maximum
, &Step
, &StorageWidth
);
630 EraseLen
= gOptionBlockWidth
;
633 if ((Question
->OpCode
->OpCode
== EFI_IFR_NUMERIC_OP
) && (NumericOp
!= NULL
)) {
634 if ((NumericOp
->Flags
& EFI_IFR_DISPLAY
) == EFI_IFR_DISPLAY_UINT_HEX
) {
636 } else if ((NumericOp
->Flags
& EFI_IFR_DISPLAY
) == 0) {
638 // Display with EFI_IFR_DISPLAY_INT_DEC type. Support negative number.
645 // Enter from "Enter" input, clear the old word showing.
648 if (Question
->OpCode
->OpCode
== EFI_IFR_NUMERIC_OP
) {
650 InputWidth
= StorageWidth
* 2;
652 switch (StorageWidth
) {
676 // Support an extra '-' for negative number.
682 InputText
[0] = LEFT_NUMERIC_DELIMITER
;
683 SetUnicodeMem (InputText
+ 1, InputWidth
, L
' ');
684 ASSERT (InputWidth
+ 2 < MAX_NUMERIC_INPUT_WIDTH
);
685 InputText
[InputWidth
+ 1] = RIGHT_NUMERIC_DELIMITER
;
686 InputText
[InputWidth
+ 2] = L
'\0';
688 PrintStringAt (Column
, Row
, InputText
);
692 if (Question
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) {
693 if (MenuOption
->Sequence
== 2) {
699 if (MenuOption
->Sequence
== 0) {
700 InputText
[0] = LEFT_NUMERIC_DELIMITER
;
701 SetUnicodeMem (InputText
+ 1, InputWidth
, L
' ');
702 InputText
[InputWidth
+ 1] = DATE_SEPARATOR
;
703 InputText
[InputWidth
+ 2] = L
'\0';
704 } else if (MenuOption
->Sequence
== 1) {
705 SetUnicodeMem (InputText
, InputWidth
, L
' ');
706 InputText
[InputWidth
] = DATE_SEPARATOR
;
707 InputText
[InputWidth
+ 1] = L
'\0';
709 SetUnicodeMem (InputText
, InputWidth
, L
' ');
710 InputText
[InputWidth
] = RIGHT_NUMERIC_DELIMITER
;
711 InputText
[InputWidth
+ 1] = L
'\0';
714 PrintStringAt (Column
, Row
, InputText
);
715 if (MenuOption
->Sequence
== 0) {
720 if (Question
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
723 if (MenuOption
->Sequence
== 0) {
724 InputText
[0] = LEFT_NUMERIC_DELIMITER
;
725 SetUnicodeMem (InputText
+ 1, InputWidth
, L
' ');
726 InputText
[InputWidth
+ 1] = TIME_SEPARATOR
;
727 InputText
[InputWidth
+ 2] = L
'\0';
728 } else if (MenuOption
->Sequence
== 1) {
729 SetUnicodeMem (InputText
, InputWidth
, L
' ');
730 InputText
[InputWidth
] = TIME_SEPARATOR
;
731 InputText
[InputWidth
+ 1] = L
'\0';
733 SetUnicodeMem (InputText
, InputWidth
, L
' ');
734 InputText
[InputWidth
] = RIGHT_NUMERIC_DELIMITER
;
735 InputText
[InputWidth
+ 1] = L
'\0';
738 PrintStringAt (Column
, Row
, InputText
);
739 if (MenuOption
->Sequence
== 0) {
746 // First time we enter this handler, we need to check to see if
747 // we were passed an increment or decrement directive
750 Key
.UnicodeChar
= CHAR_NULL
;
751 if (gDirection
!= 0) {
752 Key
.ScanCode
= gDirection
;
757 WaitForKeyStroke (&Key
);
760 switch (Key
.UnicodeChar
) {
763 if (ManualInput
&& IntInput
) {
765 // In Manual input mode, check whether input the negative flag.
767 if (Key
.UnicodeChar
== '-') {
773 PrintCharAt (Column
++, Row
, Key
.UnicodeChar
);
776 if (Key
.UnicodeChar
== '+') {
777 Key
.ScanCode
= SCAN_RIGHT
;
779 Key
.ScanCode
= SCAN_LEFT
;
782 Key
.UnicodeChar
= CHAR_NULL
;
789 switch (Key
.ScanCode
) {
792 if (DateOrTime
&& !ManualInput
) {
794 // By setting this value, we will return back to the caller.
795 // We need to do this since an auto-refresh will destroy the adjustment
796 // based on what the real-time-clock is showing. So we always commit
797 // upon changing the value.
799 gDirection
= SCAN_DOWN
;
802 if ((Step
!= 0) && !ManualInput
) {
803 if (Key
.ScanCode
== SCAN_LEFT
) {
805 if ((INT64
)EditValue
>= (INT64
)Minimum
+ (INT64
)Step
) {
806 EditValue
= EditValue
- Step
;
807 } else if ((INT64
)EditValue
> (INT64
)Minimum
) {
813 if (EditValue
>= Minimum
+ Step
) {
814 EditValue
= EditValue
- Step
;
815 } else if (EditValue
> Minimum
) {
821 } else if (Key
.ScanCode
== SCAN_RIGHT
) {
823 if ((INT64
)EditValue
+ (INT64
)Step
<= (INT64
)Maximum
) {
824 EditValue
= EditValue
+ Step
;
825 } else if ((INT64
)EditValue
< (INT64
)Maximum
) {
831 if (EditValue
+ Step
<= Maximum
) {
832 EditValue
= EditValue
+ Step
;
833 } else if (EditValue
< Maximum
) {
841 ZeroMem (FormattedNumber
, 21 * sizeof (CHAR16
));
842 if (Question
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) {
843 if (MenuOption
->Sequence
== 2) {
847 UnicodeSPrint (FormattedNumber
, 21 * sizeof (CHAR16
), L
"%04d", (UINT16
)EditValue
);
852 UnicodeSPrint (FormattedNumber
, 21 * sizeof (CHAR16
), L
"%02d", (UINT8
)EditValue
);
855 if (MenuOption
->Sequence
== 0) {
856 ASSERT (EraseLen
>= 2);
857 FormattedNumber
[EraseLen
- 2] = DATE_SEPARATOR
;
858 } else if (MenuOption
->Sequence
== 1) {
859 ASSERT (EraseLen
>= 1);
860 FormattedNumber
[EraseLen
- 1] = DATE_SEPARATOR
;
862 } else if (Question
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
863 UnicodeSPrint (FormattedNumber
, 21 * sizeof (CHAR16
), L
"%02d", (UINT8
)EditValue
);
865 if (MenuOption
->Sequence
== 0) {
866 ASSERT (EraseLen
>= 2);
867 FormattedNumber
[EraseLen
- 2] = TIME_SEPARATOR
;
868 } else if (MenuOption
->Sequence
== 1) {
869 ASSERT (EraseLen
>= 1);
870 FormattedNumber
[EraseLen
- 1] = TIME_SEPARATOR
;
873 QuestionValue
->Value
.u64
= EditValue
;
874 PrintFormattedNumber (Question
, FormattedNumber
, 21 * sizeof (CHAR16
));
877 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
878 for (Loop
= 0; Loop
< EraseLen
; Loop
++) {
879 PrintStringAt (MenuOption
->OptCol
+ Loop
, MenuOption
->Row
, L
" ");
882 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetHighlightTextColor ());
884 if (MenuOption
->Sequence
== 0) {
885 PrintCharAt (MenuOption
->OptCol
, Row
, LEFT_NUMERIC_DELIMITER
);
886 Column
= MenuOption
->OptCol
+ 1;
889 PrintStringAt (Column
, Row
, FormattedNumber
);
891 if (!DateOrTime
|| (MenuOption
->Sequence
== 2)) {
892 PrintCharAt ((UINTN
)-1, (UINTN
)-1, RIGHT_NUMERIC_DELIMITER
);
896 goto EnterCarriageReturn
;
900 goto EnterCarriageReturn
;
903 return EFI_DEVICE_ERROR
;
913 case CHAR_CARRIAGE_RETURN
:
915 // Validate input value with Minimum value.
917 ValidateFail
= FALSE
;
920 // After user input Enter, need to check whether the input value.
921 // If input a negative value, should compare with maximum value.
922 // else compare with the minimum value.
925 ValidateFail
= (INT64
)EditValue
> (INT64
)Maximum
? TRUE
: FALSE
;
927 ValidateFail
= (INT64
)EditValue
< (INT64
)Minimum
? TRUE
: FALSE
;
931 UpdateStatusBar (INPUT_ERROR
, TRUE
);
934 } else if (EditValue
< Minimum
) {
935 UpdateStatusBar (INPUT_ERROR
, TRUE
);
939 UpdateStatusBar (INPUT_ERROR
, FALSE
);
940 CopyMem (&gUserInput
->InputValue
, &Question
->CurrentValue
, sizeof (EFI_HII_VALUE
));
941 QuestionValue
= &gUserInput
->InputValue
;
943 // Store Edit value back to Question
945 if (Question
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) {
946 switch (MenuOption
->Sequence
) {
948 QuestionValue
->Value
.date
.Month
= (UINT8
)EditValue
;
952 QuestionValue
->Value
.date
.Day
= (UINT8
)EditValue
;
956 QuestionValue
->Value
.date
.Year
= (UINT16
)EditValue
;
962 } else if (Question
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
963 switch (MenuOption
->Sequence
) {
965 QuestionValue
->Value
.time
.Hour
= (UINT8
)EditValue
;
969 QuestionValue
->Value
.time
.Minute
= (UINT8
)EditValue
;
973 QuestionValue
->Value
.time
.Second
= (UINT8
)EditValue
;
983 QuestionValue
->Value
.u64
= EditValue
;
987 // Adjust the value to the correct one.
988 // Sample like: 2012.02.29 -> 2013.02.29 -> 2013.02.01
989 // 2013.03.29 -> 2013.02.29 -> 2013.02.28
991 if ((Question
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) &&
992 ((MenuOption
->Sequence
== 0) || (MenuOption
->Sequence
== 2)))
994 AdjustQuestionValue (QuestionValue
, (UINT8
)MenuOption
->Sequence
);
1005 PrintStringAt (Column
, Row
, L
" ");
1012 // Remove a character
1014 EditValue
= PreviousNumber
[Count
- 1];
1015 UpdateStatusBar (INPUT_ERROR
, FALSE
);
1018 PrintStringAt (Column
, Row
, L
" ");
1026 if ((Key
.UnicodeChar
>= L
'0') && (Key
.UnicodeChar
<= L
'9')) {
1027 Digital
= (UINT8
)(Key
.UnicodeChar
- L
'0');
1028 } else if ((Key
.UnicodeChar
>= L
'A') && (Key
.UnicodeChar
<= L
'F')) {
1029 Digital
= (UINT8
)(Key
.UnicodeChar
- L
'A' + 0x0A);
1030 } else if ((Key
.UnicodeChar
>= L
'a') && (Key
.UnicodeChar
<= L
'f')) {
1031 Digital
= (UINT8
)(Key
.UnicodeChar
- L
'a' + 0x0A);
1033 UpdateStatusBar (INPUT_ERROR
, TRUE
);
1037 if ((Key
.UnicodeChar
> L
'9') || (Key
.UnicodeChar
< L
'0')) {
1038 UpdateStatusBar (INPUT_ERROR
, TRUE
);
1044 // If Count exceed input width, there is no way more is valid
1046 if (Count
>= InputWidth
) {
1051 // Someone typed something valid!
1055 EditValue
= LShiftU64 (EditValue
, 4) + Digital
;
1056 } else if (IntInput
&& Negative
) {
1058 // Save the negative number.
1060 EditValue
= ~(MultU64x32 (~(EditValue
- 1), 10) + (Key
.UnicodeChar
- L
'0')) + 1;
1062 EditValue
= MultU64x32 (EditValue
, 10) + (Key
.UnicodeChar
- L
'0');
1066 EditValue
= Digital
;
1067 } else if (IntInput
&& Negative
) {
1069 // Save the negative number.
1071 EditValue
= ~(Key
.UnicodeChar
- L
'0') + 1;
1073 EditValue
= Key
.UnicodeChar
- L
'0';
1078 ValidateFail
= FALSE
;
1080 // When user input a new value, should check the current value.
1081 // If user input a negative value, should compare it with minimum
1082 // value, else compare it with maximum value.
1085 ValidateFail
= (INT64
)EditValue
< (INT64
)Minimum
? TRUE
: FALSE
;
1087 ValidateFail
= (INT64
)EditValue
> (INT64
)Maximum
? TRUE
: FALSE
;
1091 UpdateStatusBar (INPUT_ERROR
, TRUE
);
1092 ASSERT (Count
< ARRAY_SIZE (PreviousNumber
));
1093 EditValue
= PreviousNumber
[Count
];
1097 if (EditValue
> Maximum
) {
1098 UpdateStatusBar (INPUT_ERROR
, TRUE
);
1099 ASSERT (Count
< ARRAY_SIZE (PreviousNumber
));
1100 EditValue
= PreviousNumber
[Count
];
1105 UpdateStatusBar (INPUT_ERROR
, FALSE
);
1108 ASSERT (Count
< (ARRAY_SIZE (PreviousNumber
)));
1109 PreviousNumber
[Count
] = EditValue
;
1111 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetHighlightTextColor ());
1112 PrintCharAt (Column
, Row
, Key
.UnicodeChar
);
1122 Adjust option order base on the question value.
1124 @param Question Pointer to current question.
1125 @param PopUpMenuLines The line number of the pop up menu.
1127 @retval EFI_SUCCESS If Option input is processed successfully
1128 @retval EFI_DEVICE_ERROR If operation fails
1133 IN FORM_DISPLAY_ENGINE_STATEMENT
*Question
,
1134 OUT UINTN
*PopUpMenuLines
1138 EFI_IFR_ORDERED_LIST
*OrderList
;
1142 DISPLAY_QUESTION_OPTION
*OneOfOption
;
1143 EFI_HII_VALUE
*HiiValueArray
;
1145 Link
= GetFirstNode (&Question
->OptionListHead
);
1146 OneOfOption
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1147 ValueArray
= Question
->CurrentValue
.Buffer
;
1148 ValueType
= OneOfOption
->OptionOpCode
->Type
;
1149 OrderList
= (EFI_IFR_ORDERED_LIST
*)Question
->OpCode
;
1151 for (Index
= 0; Index
< OrderList
->MaxContainers
; Index
++) {
1152 if (GetArrayData (ValueArray
, ValueType
, Index
) == 0) {
1157 *PopUpMenuLines
= Index
;
1160 // Prepare HiiValue array
1162 HiiValueArray
= AllocateZeroPool (*PopUpMenuLines
* sizeof (EFI_HII_VALUE
));
1163 ASSERT (HiiValueArray
!= NULL
);
1165 for (Index
= 0; Index
< *PopUpMenuLines
; Index
++) {
1166 HiiValueArray
[Index
].Type
= ValueType
;
1167 HiiValueArray
[Index
].Value
.u64
= GetArrayData (ValueArray
, ValueType
, Index
);
1170 for (Index
= 0; Index
< *PopUpMenuLines
; Index
++) {
1171 OneOfOption
= ValueToOption (Question
, &HiiValueArray
[*PopUpMenuLines
- Index
- 1]);
1172 if (OneOfOption
== NULL
) {
1173 return EFI_NOT_FOUND
;
1176 RemoveEntryList (&OneOfOption
->Link
);
1181 InsertHeadList (&Question
->OptionListHead
, &OneOfOption
->Link
);
1184 FreePool (HiiValueArray
);
1190 Base on the type to compare the value.
1192 @param Value1 The first value need to compare.
1193 @param Value2 The second value need to compare.
1194 @param Type The value type for above two values.
1196 @retval TRUE The two value are same.
1197 @retval FALSE The two value are different.
1202 IN EFI_IFR_TYPE_VALUE
*Value1
,
1203 IN EFI_IFR_TYPE_VALUE
*Value2
,
1208 case EFI_IFR_TYPE_BOOLEAN
:
1209 case EFI_IFR_TYPE_NUM_SIZE_8
:
1210 return (BOOLEAN
)(Value1
->u8
== Value2
->u8
);
1212 case EFI_IFR_TYPE_NUM_SIZE_16
:
1213 return (BOOLEAN
)(Value1
->u16
== Value2
->u16
);
1215 case EFI_IFR_TYPE_NUM_SIZE_32
:
1216 return (BOOLEAN
)(Value1
->u32
== Value2
->u32
);
1218 case EFI_IFR_TYPE_NUM_SIZE_64
:
1219 return (BOOLEAN
)(Value1
->u64
== Value2
->u64
);
1228 Base on the type to set the value.
1230 @param Dest The dest value.
1231 @param Source The source value.
1232 @param Type The value type for above two values.
1237 OUT EFI_IFR_TYPE_VALUE
*Dest
,
1238 IN EFI_IFR_TYPE_VALUE
*Source
,
1243 case EFI_IFR_TYPE_BOOLEAN
:
1244 Dest
->b
= Source
->b
;
1247 case EFI_IFR_TYPE_NUM_SIZE_8
:
1248 Dest
->u8
= Source
->u8
;
1251 case EFI_IFR_TYPE_NUM_SIZE_16
:
1252 Dest
->u16
= Source
->u16
;
1255 case EFI_IFR_TYPE_NUM_SIZE_32
:
1256 Dest
->u32
= Source
->u32
;
1259 case EFI_IFR_TYPE_NUM_SIZE_64
:
1260 Dest
->u64
= Source
->u64
;
1270 Get selection for OneOf and OrderedList (Left/Right will be ignored).
1272 @param MenuOption Pointer to the current input menu.
1274 @retval EFI_SUCCESS If Option input is processed successfully
1275 @retval EFI_DEVICE_ERROR If operation fails
1279 GetSelectionInputPopUp (
1280 IN UI_MENU_OPTION
*MenuOption
1286 CHAR16
*TempStringPtr
;
1288 UINTN TopOptionIndex
;
1289 UINTN HighlightOptionIndex
;
1294 UINTN PopUpMenuLines
;
1295 UINTN MenuLinesInView
;
1298 INT32 SavedAttribute
;
1299 BOOLEAN ShowDownArrow
;
1300 BOOLEAN ShowUpArrow
;
1301 UINTN DimensionsWidth
;
1303 BOOLEAN OrderedList
;
1307 EFI_HII_VALUE HiiValue
;
1308 DISPLAY_QUESTION_OPTION
*OneOfOption
;
1309 DISPLAY_QUESTION_OPTION
*CurrentOption
;
1310 FORM_DISPLAY_ENGINE_STATEMENT
*Question
;
1312 EFI_IFR_ORDERED_LIST
*OrderList
;
1314 DimensionsWidth
= gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
;
1318 CurrentOption
= NULL
;
1319 ShowDownArrow
= FALSE
;
1320 ShowUpArrow
= FALSE
;
1322 ZeroMem (&HiiValue
, sizeof (EFI_HII_VALUE
));
1324 Question
= MenuOption
->ThisTag
;
1325 if (Question
->OpCode
->OpCode
== EFI_IFR_ORDERED_LIST_OP
) {
1326 Link
= GetFirstNode (&Question
->OptionListHead
);
1327 OneOfOption
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1328 ValueArray
= Question
->CurrentValue
.Buffer
;
1329 ValueType
= OneOfOption
->OptionOpCode
->Type
;
1331 OrderList
= (EFI_IFR_ORDERED_LIST
*)Question
->OpCode
;
1333 OrderedList
= FALSE
;
1338 // Calculate Option count
1342 AdjustOptionOrder (Question
, &PopUpMenuLines
);
1344 Link
= GetFirstNode (&Question
->OptionListHead
);
1345 while (!IsNull (&Question
->OptionListHead
, Link
)) {
1346 OneOfOption
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1348 Link
= GetNextNode (&Question
->OptionListHead
, Link
);
1353 // Get the number of one of options present and its size
1356 HighlightOptionIndex
= 0;
1357 Link
= GetFirstNode (&Question
->OptionListHead
);
1358 for (Index
= 0; Index
< PopUpMenuLines
; Index
++) {
1359 OneOfOption
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1361 StringPtr
= GetToken (OneOfOption
->OptionOpCode
->Option
, gFormData
->HiiHandle
);
1362 if (StrLen (StringPtr
) > PopUpWidth
) {
1363 PopUpWidth
= StrLen (StringPtr
);
1366 FreePool (StringPtr
);
1367 HiiValue
.Type
= OneOfOption
->OptionOpCode
->Type
;
1368 SetValuesByType (&HiiValue
.Value
, &OneOfOption
->OptionOpCode
->Value
, HiiValue
.Type
);
1369 if (!OrderedList
&& (CompareHiiValue (&Question
->CurrentValue
, &HiiValue
, &Result
, NULL
) == EFI_SUCCESS
) && (Result
== 0)) {
1371 // Find current selected Option for OneOf
1373 HighlightOptionIndex
= Index
;
1376 Link
= GetNextNode (&Question
->OptionListHead
, Link
);
1380 // Perform popup menu initialization.
1382 PopUpWidth
= PopUpWidth
+ POPUP_PAD_SPACE_COUNT
;
1384 SavedAttribute
= gST
->ConOut
->Mode
->Attribute
;
1385 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetPopupColor ());
1387 if ((PopUpWidth
+ POPUP_FRAME_WIDTH
) > DimensionsWidth
) {
1388 PopUpWidth
= DimensionsWidth
- POPUP_FRAME_WIDTH
;
1391 Start
= (DimensionsWidth
- PopUpWidth
- POPUP_FRAME_WIDTH
) / 2 + gStatementDimensions
.LeftColumn
;
1392 End
= Start
+ PopUpWidth
+ POPUP_FRAME_WIDTH
;
1393 Top
= gStatementDimensions
.TopRow
;
1394 Bottom
= gStatementDimensions
.BottomRow
- 1;
1396 MenuLinesInView
= Bottom
- Top
- 1;
1397 if (MenuLinesInView
>= PopUpMenuLines
) {
1398 Top
= Top
+ (MenuLinesInView
- PopUpMenuLines
) / 2;
1399 Bottom
= Top
+ PopUpMenuLines
+ 1;
1401 ShowDownArrow
= TRUE
;
1404 if (HighlightOptionIndex
> (MenuLinesInView
- 1)) {
1405 TopOptionIndex
= HighlightOptionIndex
- MenuLinesInView
+ 1;
1412 // Clear that portion of the screen
1414 ClearLines (Start
, End
, Top
, Bottom
, GetPopupColor ());
1417 // Draw "One of" pop-up menu
1419 Character
= BOXDRAW_DOWN_RIGHT
;
1420 PrintCharAt (Start
, Top
, Character
);
1421 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
1422 if ((ShowUpArrow
) && ((Index
+ 1) == (Start
+ End
) / 2)) {
1423 Character
= GEOMETRICSHAPE_UP_TRIANGLE
;
1425 Character
= BOXDRAW_HORIZONTAL
;
1428 PrintCharAt ((UINTN
)-1, (UINTN
)-1, Character
);
1431 Character
= BOXDRAW_DOWN_LEFT
;
1432 PrintCharAt ((UINTN
)-1, (UINTN
)-1, Character
);
1433 Character
= BOXDRAW_VERTICAL
;
1434 for (Index
= Top
+ 1; Index
< Bottom
; Index
++) {
1435 PrintCharAt (Start
, Index
, Character
);
1436 PrintCharAt (End
- 1, Index
, Character
);
1440 // Move to top Option
1442 Link
= GetFirstNode (&Question
->OptionListHead
);
1443 for (Index
= 0; Index
< TopOptionIndex
; Index
++) {
1444 Link
= GetNextNode (&Question
->OptionListHead
, Link
);
1448 // Display the One of options
1451 for (Index
= TopOptionIndex
; (Index
< PopUpMenuLines
) && (Index2
< Bottom
); Index
++) {
1452 OneOfOption
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1453 Link
= GetNextNode (&Question
->OptionListHead
, Link
);
1455 StringPtr
= GetToken (OneOfOption
->OptionOpCode
->Option
, gFormData
->HiiHandle
);
1456 ASSERT (StringPtr
!= NULL
);
1458 // If the string occupies multiple lines, truncate it to fit in one line,
1459 // and append a "..." for indication.
1461 if (StrLen (StringPtr
) > (PopUpWidth
- 1)) {
1462 TempStringPtr
= AllocateZeroPool (sizeof (CHAR16
) * (PopUpWidth
- 1));
1463 ASSERT (TempStringPtr
!= NULL
);
1464 CopyMem (TempStringPtr
, StringPtr
, (sizeof (CHAR16
) * (PopUpWidth
- 5)));
1465 FreePool (StringPtr
);
1466 StringPtr
= TempStringPtr
;
1467 StrCatS (StringPtr
, PopUpWidth
- 1, L
"...");
1470 if (Index
== HighlightOptionIndex
) {
1472 // Highlight the selected one
1474 CurrentOption
= OneOfOption
;
1476 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetPickListColor ());
1477 PrintStringAt (Start
+ 2, Index2
, StringPtr
);
1478 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetPopupColor ());
1480 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetPopupColor ());
1481 PrintStringAt (Start
+ 2, Index2
, StringPtr
);
1485 FreePool (StringPtr
);
1488 Character
= BOXDRAW_UP_RIGHT
;
1489 PrintCharAt (Start
, Bottom
, Character
);
1490 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
1491 if ((ShowDownArrow
) && ((Index
+ 1) == (Start
+ End
) / 2)) {
1492 Character
= GEOMETRICSHAPE_DOWN_TRIANGLE
;
1494 Character
= BOXDRAW_HORIZONTAL
;
1497 PrintCharAt ((UINTN
)-1, (UINTN
)-1, Character
);
1500 Character
= BOXDRAW_UP_LEFT
;
1501 PrintCharAt ((UINTN
)-1, (UINTN
)-1, Character
);
1504 // Get User selection
1506 Key
.UnicodeChar
= CHAR_NULL
;
1507 if ((gDirection
== SCAN_UP
) || (gDirection
== SCAN_DOWN
)) {
1508 Key
.ScanCode
= gDirection
;
1513 WaitForKeyStroke (&Key
);
1516 switch (Key
.UnicodeChar
) {
1519 if ((TopOptionIndex
> 0) && (TopOptionIndex
== HighlightOptionIndex
)) {
1521 // Highlight reaches the top of the popup window, scroll one menu item.
1524 ShowDownArrow
= TRUE
;
1527 if (TopOptionIndex
== 0) {
1528 ShowUpArrow
= FALSE
;
1531 if (HighlightOptionIndex
> 0) {
1532 HighlightOptionIndex
--;
1534 ASSERT (CurrentOption
!= NULL
);
1535 SwapListEntries (CurrentOption
->Link
.BackLink
, &CurrentOption
->Link
);
1543 // If an ordered list op-code, we will allow for a popup of +/- keys
1544 // to create an ordered list of items
1547 if (((TopOptionIndex
+ MenuLinesInView
) < PopUpMenuLines
) &&
1548 (HighlightOptionIndex
== (TopOptionIndex
+ MenuLinesInView
- 1)))
1551 // Highlight reaches the bottom of the popup window, scroll one menu item.
1557 if ((TopOptionIndex
+ MenuLinesInView
) == PopUpMenuLines
) {
1558 ShowDownArrow
= FALSE
;
1561 if (HighlightOptionIndex
< (PopUpMenuLines
- 1)) {
1562 HighlightOptionIndex
++;
1564 ASSERT (CurrentOption
!= NULL
);
1565 SwapListEntries (&CurrentOption
->Link
, CurrentOption
->Link
.ForwardLink
);
1572 switch (Key
.ScanCode
) {
1575 if (Key
.ScanCode
== SCAN_UP
) {
1576 if ((TopOptionIndex
> 0) && (TopOptionIndex
== HighlightOptionIndex
)) {
1578 // Highlight reaches the top of the popup window, scroll one menu item.
1581 ShowDownArrow
= TRUE
;
1584 if (TopOptionIndex
== 0) {
1585 ShowUpArrow
= FALSE
;
1588 if (HighlightOptionIndex
> 0) {
1589 HighlightOptionIndex
--;
1592 if (((TopOptionIndex
+ MenuLinesInView
) < PopUpMenuLines
) &&
1593 (HighlightOptionIndex
== (TopOptionIndex
+ MenuLinesInView
- 1)))
1596 // Highlight reaches the bottom of the popup window, scroll one menu item.
1602 if ((TopOptionIndex
+ MenuLinesInView
) == PopUpMenuLines
) {
1603 ShowDownArrow
= FALSE
;
1606 if (HighlightOptionIndex
< (PopUpMenuLines
- 1)) {
1607 HighlightOptionIndex
++;
1614 gST
->ConOut
->SetAttribute (gST
->ConOut
, SavedAttribute
);
1617 // Restore link list order for orderedlist
1620 HiiValue
.Type
= ValueType
;
1621 HiiValue
.Value
.u64
= 0;
1622 for (Index
= 0; Index
< OrderList
->MaxContainers
; Index
++) {
1623 HiiValue
.Value
.u64
= GetArrayData (ValueArray
, ValueType
, Index
);
1624 if (HiiValue
.Value
.u64
== 0) {
1628 OneOfOption
= ValueToOption (Question
, &HiiValue
);
1629 if (OneOfOption
== NULL
) {
1630 return EFI_NOT_FOUND
;
1633 RemoveEntryList (&OneOfOption
->Link
);
1634 InsertTailList (&Question
->OptionListHead
, &OneOfOption
->Link
);
1638 return EFI_DEVICE_ERROR
;
1646 case CHAR_CARRIAGE_RETURN
:
1648 // return the current selection
1651 ReturnValue
= AllocateZeroPool (Question
->CurrentValue
.BufferLen
);
1652 ASSERT (ReturnValue
!= NULL
);
1654 Link
= GetFirstNode (&Question
->OptionListHead
);
1655 while (!IsNull (&Question
->OptionListHead
, Link
)) {
1656 OneOfOption
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1657 Link
= GetNextNode (&Question
->OptionListHead
, Link
);
1659 SetArrayData (ReturnValue
, ValueType
, Index
, OneOfOption
->OptionOpCode
->Value
.u64
);
1662 if (Index
> OrderList
->MaxContainers
) {
1667 if (CompareMem (ReturnValue
, ValueArray
, Question
->CurrentValue
.BufferLen
) == 0) {
1668 FreePool (ReturnValue
);
1669 return EFI_DEVICE_ERROR
;
1671 gUserInput
->InputValue
.Buffer
= ReturnValue
;
1672 gUserInput
->InputValue
.BufferLen
= Question
->CurrentValue
.BufferLen
;
1675 ASSERT (CurrentOption
!= NULL
);
1676 gUserInput
->InputValue
.Type
= CurrentOption
->OptionOpCode
->Type
;
1677 if (IsValuesEqual (&Question
->CurrentValue
.Value
, &CurrentOption
->OptionOpCode
->Value
, gUserInput
->InputValue
.Type
)) {
1678 return EFI_DEVICE_ERROR
;
1680 SetValuesByType (&gUserInput
->InputValue
.Value
, &CurrentOption
->OptionOpCode
->Value
, gUserInput
->InputValue
.Type
);
1684 gST
->ConOut
->SetAttribute (gST
->ConOut
, SavedAttribute
);