2 Implementation for handling user input from the User Interfaces.
4 Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "FormDisplay.h"
18 Get maximum and minimum info from this opcode.
20 @param OpCode Pointer to the current input opcode.
21 @param Minimum The minimum size info for this opcode.
22 @param Maximum The maximum size info for this opcode.
27 IN EFI_IFR_OP_HEADER
*OpCode
,
32 EFI_IFR_STRING
*StringOp
;
33 EFI_IFR_PASSWORD
*PasswordOp
;
34 if (OpCode
->OpCode
== EFI_IFR_STRING_OP
) {
35 StringOp
= (EFI_IFR_STRING
*) OpCode
;
36 *Minimum
= StringOp
->MinSize
;
37 *Maximum
= StringOp
->MaxSize
;
38 } else if (OpCode
->OpCode
== EFI_IFR_PASSWORD_OP
) {
39 PasswordOp
= (EFI_IFR_PASSWORD
*) OpCode
;
40 *Minimum
= PasswordOp
->MinSize
;
41 *Maximum
= PasswordOp
->MaxSize
;
49 Get string or password input from user.
51 @param MenuOption Pointer to the current input menu.
52 @param Prompt The prompt string shown on popup window.
53 @param StringPtr Old user input and destination for use input string.
55 @retval EFI_SUCCESS If string input is read successfully
56 @retval EFI_DEVICE_ERROR If operation fails
61 IN UI_MENU_OPTION
*MenuOption
,
63 IN OUT CHAR16
*StringPtr
73 CHAR16
*BufferedString
;
79 UINTN DimensionsWidth
;
80 UINTN DimensionsHeight
;
82 BOOLEAN CursorVisible
;
85 FORM_DISPLAY_ENGINE_STATEMENT
*Question
;
89 DimensionsWidth
= gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
;
90 DimensionsHeight
= gStatementDimensions
.BottomRow
- gStatementDimensions
.TopRow
;
92 NullCharacter
= CHAR_NULL
;
93 ScreenSize
= GetStringWidth (Prompt
) / sizeof (CHAR16
);
97 Question
= MenuOption
->ThisTag
;
98 GetFieldFromOp(Question
->OpCode
, &Minimum
, &Maximum
);
100 if (Question
->OpCode
->OpCode
== EFI_IFR_PASSWORD_OP
) {
106 MaxLen
= Maximum
+ 1;
107 TempString
= AllocateZeroPool (MaxLen
* sizeof (CHAR16
));
110 if (ScreenSize
< (Maximum
+ 1)) {
111 ScreenSize
= Maximum
+ 1;
114 if ((ScreenSize
+ 2) > DimensionsWidth
) {
115 ScreenSize
= DimensionsWidth
- 2;
118 BufferedString
= AllocateZeroPool (ScreenSize
* 2);
119 ASSERT (BufferedString
);
121 Start
= (DimensionsWidth
- ScreenSize
- 2) / 2 + gStatementDimensions
.LeftColumn
+ 1;
122 Top
= ((DimensionsHeight
- 6) / 2) + gStatementDimensions
.TopRow
- 1;
125 // Display prompt for string
127 // CreateDialog (NULL, "", Prompt, Space, "", NULL);
128 CreateMultiStringPopUp (ScreenSize
, 4, &NullCharacter
, Prompt
, Space
, &NullCharacter
);
129 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_BLACK
, EFI_LIGHTGRAY
));
131 CursorVisible
= gST
->ConOut
->Mode
->CursorVisible
;
132 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
134 CurrentCursor
= GetStringWidth (StringPtr
) / 2 - 1;
135 if (CurrentCursor
!= 0) {
137 // Show the string which has beed saved before.
139 SetUnicodeMem (BufferedString
, ScreenSize
- 1, L
' ');
140 PrintStringAt (Start
+ 1, Top
+ 3, BufferedString
);
142 if ((GetStringWidth (StringPtr
) / 2) > (DimensionsWidth
- 2)) {
143 Index
= (GetStringWidth (StringPtr
) / 2) - DimensionsWidth
+ 2;
149 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, Start
+ 1, Top
+ 3);
152 for (Count
= 0; Index
+ 1 < GetStringWidth (StringPtr
) / 2; Index
++, Count
++) {
153 BufferedString
[Count
] = StringPtr
[Index
];
156 PrintCharAt ((UINTN
)-1, (UINTN
)-1, L
'*');
161 PrintStringAt (Start
+ 1, Top
+ 3, BufferedString
);
164 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
165 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, Start
+ GetStringWidth (StringPtr
) / 2, Top
+ 3);
169 Status
= WaitForKeyStroke (&Key
);
170 ASSERT_EFI_ERROR (Status
);
172 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_BLACK
, EFI_LIGHTGRAY
));
173 switch (Key
.UnicodeChar
) {
175 switch (Key
.ScanCode
) {
177 if (CurrentCursor
> 0) {
183 if (CurrentCursor
< (GetStringWidth (StringPtr
) / 2 - 1)) {
189 FreePool (TempString
);
190 FreePool (BufferedString
);
191 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
192 gST
->ConOut
->EnableCursor (gST
->ConOut
, CursorVisible
);
193 return EFI_DEVICE_ERROR
;
196 for (Index
= CurrentCursor
; StringPtr
[Index
] != CHAR_NULL
; Index
++) {
197 StringPtr
[Index
] = StringPtr
[Index
+ 1];
198 PrintCharAt (Start
+ Index
+ 1, Top
+ 3, IsPassword
&& StringPtr
[Index
] != CHAR_NULL
? L
'*' : StringPtr
[Index
]);
208 case CHAR_CARRIAGE_RETURN
:
209 if (GetStringWidth (StringPtr
) >= ((Minimum
+ 1) * sizeof (CHAR16
))) {
211 FreePool (TempString
);
212 FreePool (BufferedString
);
213 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
214 gST
->ConOut
->EnableCursor (gST
->ConOut
, CursorVisible
);
218 // Simply create a popup to tell the user that they had typed in too few characters.
219 // To save code space, we can then treat this as an error and return back to the menu.
222 CreateDialog (&Key
, &NullCharacter
, gMiniString
, gPressEnter
, &NullCharacter
, NULL
);
223 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
225 FreePool (TempString
);
226 FreePool (BufferedString
);
227 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
228 gST
->ConOut
->EnableCursor (gST
->ConOut
, CursorVisible
);
229 return EFI_DEVICE_ERROR
;
234 if (StringPtr
[0] != CHAR_NULL
&& CurrentCursor
!= 0) {
235 for (Index
= 0; Index
< CurrentCursor
- 1; Index
++) {
236 TempString
[Index
] = StringPtr
[Index
];
238 Count
= GetStringWidth (StringPtr
) / 2 - 1;
239 if (Count
>= CurrentCursor
) {
240 for (Index
= CurrentCursor
- 1, Index2
= CurrentCursor
; Index2
< Count
; Index
++, Index2
++) {
241 TempString
[Index
] = StringPtr
[Index2
];
243 TempString
[Index
] = CHAR_NULL
;
246 // Effectively truncate string by 1 character
248 StrCpyS (StringPtr
, MaxLen
, TempString
);
254 // If it is the beginning of the string, don't worry about checking maximum limits
256 if ((StringPtr
[0] == CHAR_NULL
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
257 StrnCpyS (StringPtr
, MaxLen
, &Key
.UnicodeChar
, 1);
259 } else if ((GetStringWidth (StringPtr
) < ((Maximum
+ 1) * sizeof (CHAR16
))) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
260 KeyPad
[0] = Key
.UnicodeChar
;
261 KeyPad
[1] = CHAR_NULL
;
262 Count
= GetStringWidth (StringPtr
) / 2 - 1;
263 if (CurrentCursor
< Count
) {
264 for (Index
= 0; Index
< CurrentCursor
; Index
++) {
265 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
);
278 // If the width of the input string is now larger than the screen, we nee to
279 // adjust the index to start printing portions of the string
281 SetUnicodeMem (BufferedString
, ScreenSize
- 1, L
' ');
282 PrintStringAt (Start
+ 1, Top
+ 3, BufferedString
);
284 if ((GetStringWidth (StringPtr
) / 2) > (DimensionsWidth
- 2)) {
285 Index
= (GetStringWidth (StringPtr
) / 2) - DimensionsWidth
+ 2;
291 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, Start
+ 1, Top
+ 3);
294 for (Count
= 0; Index
+ 1 < GetStringWidth (StringPtr
) / 2; Index
++, Count
++) {
295 BufferedString
[Count
] = StringPtr
[Index
];
298 PrintCharAt ((UINTN
)-1, (UINTN
)-1, L
'*');
303 PrintStringAt (Start
+ 1, Top
+ 3, BufferedString
);
308 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
309 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, Start
+ CurrentCursor
+ 1, Top
+ 3);
315 Adjust the value to the correct one. Rules follow the sample:
316 like: Year change: 2012.02.29 -> 2013.02.29 -> 2013.02.01
317 Month change: 2013.03.29 -> 2013.02.29 -> 2013.02.28
319 @param QuestionValue Pointer to current question.
320 @param Sequence The sequence of the field in the question.
323 AdjustQuestionValue (
324 IN EFI_HII_VALUE
*QuestionValue
,
333 Month
= QuestionValue
->Value
.date
.Month
;
334 Year
= QuestionValue
->Value
.date
.Year
;
339 if ((Year
% 4) == 0 && ((Year
% 100) != 0 || (Year
% 400) == 0)) {
357 // Change the month area.
360 if (QuestionValue
->Value
.date
.Day
> Maximum
) {
361 QuestionValue
->Value
.date
.Day
= Maximum
;
366 // Change the Year area.
369 if (QuestionValue
->Value
.date
.Day
> Maximum
) {
370 QuestionValue
->Value
.date
.Day
= Minimum
;
376 Get field info from numeric opcode.
378 @param OpCode Pointer to the current input opcode.
379 @param IntInput Whether question shows with EFI_IFR_DISPLAY_INT_DEC type.
380 @param QuestionValue Input question value, with EFI_HII_VALUE type.
381 @param Value Return question value, always return UINT64 type.
382 @param Minimum The minimum size info for this opcode.
383 @param Maximum The maximum size info for this opcode.
384 @param Step The step size info for this opcode.
385 @param StorageWidth The storage width info for this opcode.
390 IN EFI_IFR_OP_HEADER
*OpCode
,
392 IN EFI_HII_VALUE
*QuestionValue
,
397 OUT UINT16
*StorageWidth
400 EFI_IFR_NUMERIC
*NumericOp
;
402 NumericOp
= (EFI_IFR_NUMERIC
*) OpCode
;
404 switch (NumericOp
->Flags
& EFI_IFR_NUMERIC_SIZE
) {
405 case EFI_IFR_NUMERIC_SIZE_1
:
407 *Minimum
= (INT64
) (INT8
) NumericOp
->data
.u8
.MinValue
;
408 *Maximum
= (INT64
) (INT8
) NumericOp
->data
.u8
.MaxValue
;
409 *Value
= (INT64
) (INT8
) QuestionValue
->Value
.u8
;
411 *Minimum
= NumericOp
->data
.u8
.MinValue
;
412 *Maximum
= NumericOp
->data
.u8
.MaxValue
;
413 *Value
= QuestionValue
->Value
.u8
;
415 *Step
= NumericOp
->data
.u8
.Step
;
416 *StorageWidth
= (UINT16
) sizeof (UINT8
);
419 case EFI_IFR_NUMERIC_SIZE_2
:
421 *Minimum
= (INT64
) (INT16
) NumericOp
->data
.u16
.MinValue
;
422 *Maximum
= (INT64
) (INT16
) NumericOp
->data
.u16
.MaxValue
;
423 *Value
= (INT64
) (INT16
) QuestionValue
->Value
.u16
;
425 *Minimum
= NumericOp
->data
.u16
.MinValue
;
426 *Maximum
= NumericOp
->data
.u16
.MaxValue
;
427 *Value
= QuestionValue
->Value
.u16
;
429 *Step
= NumericOp
->data
.u16
.Step
;
430 *StorageWidth
= (UINT16
) sizeof (UINT16
);
433 case EFI_IFR_NUMERIC_SIZE_4
:
435 *Minimum
= (INT64
) (INT32
) NumericOp
->data
.u32
.MinValue
;
436 *Maximum
= (INT64
) (INT32
) NumericOp
->data
.u32
.MaxValue
;
437 *Value
= (INT64
) (INT32
) QuestionValue
->Value
.u32
;
439 *Minimum
= NumericOp
->data
.u32
.MinValue
;
440 *Maximum
= NumericOp
->data
.u32
.MaxValue
;
441 *Value
= QuestionValue
->Value
.u32
;
443 *Step
= NumericOp
->data
.u32
.Step
;
444 *StorageWidth
= (UINT16
) sizeof (UINT32
);
447 case EFI_IFR_NUMERIC_SIZE_8
:
449 *Minimum
= (INT64
) NumericOp
->data
.u64
.MinValue
;
450 *Maximum
= (INT64
) NumericOp
->data
.u64
.MaxValue
;
451 *Value
= (INT64
) QuestionValue
->Value
.u64
;
453 *Minimum
= NumericOp
->data
.u64
.MinValue
;
454 *Maximum
= NumericOp
->data
.u64
.MaxValue
;
455 *Value
= QuestionValue
->Value
.u64
;
457 *Step
= NumericOp
->data
.u64
.Step
;
458 *StorageWidth
= (UINT16
) sizeof (UINT64
);
466 *Maximum
= (UINT64
) -1;
471 This routine reads a numeric value from the user input.
473 @param MenuOption Pointer to the current input menu.
475 @retval EFI_SUCCESS If numerical input is read successfully
476 @retval EFI_DEVICE_ERROR If operation fails
481 IN UI_MENU_OPTION
*MenuOption
486 CHAR16 InputText
[MAX_NUMERIC_INPUT_WIDTH
];
487 CHAR16 FormattedNumber
[MAX_NUMERIC_INPUT_WIDTH
- 1];
488 UINT64 PreviousNumber
[MAX_NUMERIC_INPUT_WIDTH
- 3];
495 BOOLEAN ValidateFail
;
505 EFI_HII_VALUE
*QuestionValue
;
506 FORM_DISPLAY_ENGINE_STATEMENT
*Question
;
507 EFI_IFR_NUMERIC
*NumericOp
;
510 Column
= MenuOption
->OptCol
;
511 Row
= MenuOption
->Row
;
512 PreviousNumber
[0] = 0;
523 ValidateFail
= FALSE
;
525 Question
= MenuOption
->ThisTag
;
526 QuestionValue
= &Question
->CurrentValue
;
527 ZeroMem (InputText
, MAX_NUMERIC_INPUT_WIDTH
* sizeof (CHAR16
));
530 // Only two case, user can enter to this function: Enter and +/- case.
531 // In Enter case, gDirection = 0; in +/- case, gDirection = SCAN_LEFT/SCAN_WRIGHT
533 ManualInput
= (BOOLEAN
)(gDirection
== 0 ? TRUE
: FALSE
);
535 if ((Question
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) || (Question
->OpCode
->OpCode
== EFI_IFR_TIME_OP
)) {
542 // Prepare Value to be edit
546 if (Question
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) {
550 switch (MenuOption
->Sequence
) {
554 EditValue
= QuestionValue
->Value
.date
.Month
;
558 switch (QuestionValue
->Value
.date
.Month
) {
560 if ((QuestionValue
->Value
.date
.Year
% 4) == 0 &&
561 ((QuestionValue
->Value
.date
.Year
% 100) != 0 ||
562 (QuestionValue
->Value
.date
.Year
% 400) == 0)) {
580 EditValue
= QuestionValue
->Value
.date
.Day
;
586 EditValue
= QuestionValue
->Value
.date
.Year
;
592 } else if (Question
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
596 switch (MenuOption
->Sequence
) {
600 EditValue
= QuestionValue
->Value
.time
.Hour
;
606 EditValue
= QuestionValue
->Value
.time
.Minute
;
612 EditValue
= QuestionValue
->Value
.time
.Second
;
619 ASSERT (Question
->OpCode
->OpCode
== EFI_IFR_NUMERIC_OP
);
620 NumericOp
= (EFI_IFR_NUMERIC
*) Question
->OpCode
;
621 GetValueFromNum(Question
->OpCode
, (NumericOp
->Flags
& EFI_IFR_DISPLAY
) == 0, QuestionValue
, &EditValue
, &Minimum
, &Maximum
, &Step
, &StorageWidth
);
622 EraseLen
= gOptionBlockWidth
;
625 if ((Question
->OpCode
->OpCode
== EFI_IFR_NUMERIC_OP
) && (NumericOp
!= NULL
)) {
626 if ((NumericOp
->Flags
& EFI_IFR_DISPLAY
) == EFI_IFR_DISPLAY_UINT_HEX
){
628 } else if ((NumericOp
->Flags
& EFI_IFR_DISPLAY
) == 0){
630 // Display with EFI_IFR_DISPLAY_INT_DEC type. Support negative number.
637 // Enter from "Enter" input, clear the old word showing.
640 if (Question
->OpCode
->OpCode
== EFI_IFR_NUMERIC_OP
) {
642 InputWidth
= StorageWidth
* 2;
644 switch (StorageWidth
) {
668 // Support an extra '-' for negative number.
674 InputText
[0] = LEFT_NUMERIC_DELIMITER
;
675 SetUnicodeMem (InputText
+ 1, InputWidth
, L
' ');
676 ASSERT (InputWidth
+ 2 < MAX_NUMERIC_INPUT_WIDTH
);
677 InputText
[InputWidth
+ 1] = RIGHT_NUMERIC_DELIMITER
;
678 InputText
[InputWidth
+ 2] = L
'\0';
680 PrintStringAt (Column
, Row
, InputText
);
684 if (Question
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) {
685 if (MenuOption
->Sequence
== 2) {
691 if (MenuOption
->Sequence
== 0) {
692 InputText
[0] = LEFT_NUMERIC_DELIMITER
;
693 SetUnicodeMem (InputText
+ 1, InputWidth
, L
' ');
694 InputText
[InputWidth
+ 1] = DATE_SEPARATOR
;
695 InputText
[InputWidth
+ 2] = L
'\0';
696 } else if (MenuOption
->Sequence
== 1){
697 SetUnicodeMem (InputText
, InputWidth
, L
' ');
698 InputText
[InputWidth
] = DATE_SEPARATOR
;
699 InputText
[InputWidth
+ 1] = L
'\0';
701 SetUnicodeMem (InputText
, InputWidth
, L
' ');
702 InputText
[InputWidth
] = RIGHT_NUMERIC_DELIMITER
;
703 InputText
[InputWidth
+ 1] = L
'\0';
706 PrintStringAt (Column
, Row
, InputText
);
707 if (MenuOption
->Sequence
== 0) {
712 if (Question
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
715 if (MenuOption
->Sequence
== 0) {
716 InputText
[0] = LEFT_NUMERIC_DELIMITER
;
717 SetUnicodeMem (InputText
+ 1, InputWidth
, L
' ');
718 InputText
[InputWidth
+ 1] = TIME_SEPARATOR
;
719 InputText
[InputWidth
+ 2] = L
'\0';
720 } else if (MenuOption
->Sequence
== 1){
721 SetUnicodeMem (InputText
, InputWidth
, L
' ');
722 InputText
[InputWidth
] = TIME_SEPARATOR
;
723 InputText
[InputWidth
+ 1] = L
'\0';
725 SetUnicodeMem (InputText
, InputWidth
, L
' ');
726 InputText
[InputWidth
] = RIGHT_NUMERIC_DELIMITER
;
727 InputText
[InputWidth
+ 1] = L
'\0';
730 PrintStringAt (Column
, Row
, InputText
);
731 if (MenuOption
->Sequence
== 0) {
738 // First time we enter this handler, we need to check to see if
739 // we were passed an increment or decrement directive
742 Key
.UnicodeChar
= CHAR_NULL
;
743 if (gDirection
!= 0) {
744 Key
.ScanCode
= gDirection
;
749 WaitForKeyStroke (&Key
);
752 switch (Key
.UnicodeChar
) {
756 if (ManualInput
&& IntInput
) {
758 // In Manual input mode, check whether input the negative flag.
760 if (Key
.UnicodeChar
== '-') {
765 PrintCharAt (Column
++, Row
, Key
.UnicodeChar
);
768 if (Key
.UnicodeChar
== '+') {
769 Key
.ScanCode
= SCAN_RIGHT
;
771 Key
.ScanCode
= SCAN_LEFT
;
773 Key
.UnicodeChar
= CHAR_NULL
;
779 switch (Key
.ScanCode
) {
782 if (DateOrTime
&& !ManualInput
) {
784 // By setting this value, we will return back to the caller.
785 // We need to do this since an auto-refresh will destroy the adjustment
786 // based on what the real-time-clock is showing. So we always commit
787 // upon changing the value.
789 gDirection
= SCAN_DOWN
;
792 if ((Step
!= 0) && !ManualInput
) {
793 if (Key
.ScanCode
== SCAN_LEFT
) {
795 if ((INT64
) EditValue
>= (INT64
) Minimum
+ (INT64
) Step
) {
796 EditValue
= EditValue
- Step
;
797 } else if ((INT64
) EditValue
> (INT64
) Minimum
){
803 if (EditValue
>= Minimum
+ Step
) {
804 EditValue
= EditValue
- Step
;
805 } else if (EditValue
> Minimum
){
811 } else if (Key
.ScanCode
== SCAN_RIGHT
) {
813 if ((INT64
) EditValue
+ (INT64
) Step
<= (INT64
) Maximum
) {
814 EditValue
= EditValue
+ Step
;
815 } else if ((INT64
) EditValue
< (INT64
) Maximum
) {
821 if (EditValue
+ Step
<= Maximum
) {
822 EditValue
= EditValue
+ Step
;
823 } else if (EditValue
< Maximum
) {
831 ZeroMem (FormattedNumber
, 21 * sizeof (CHAR16
));
832 if (Question
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) {
833 if (MenuOption
->Sequence
== 2) {
837 UnicodeSPrint (FormattedNumber
, 21 * sizeof (CHAR16
), L
"%04d", (UINT16
) EditValue
);
842 UnicodeSPrint (FormattedNumber
, 21 * sizeof (CHAR16
), L
"%02d", (UINT8
) EditValue
);
845 if (MenuOption
->Sequence
== 0) {
846 ASSERT (EraseLen
>= 2);
847 FormattedNumber
[EraseLen
- 2] = DATE_SEPARATOR
;
848 } else if (MenuOption
->Sequence
== 1) {
849 ASSERT (EraseLen
>= 1);
850 FormattedNumber
[EraseLen
- 1] = DATE_SEPARATOR
;
852 } else if (Question
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
853 UnicodeSPrint (FormattedNumber
, 21 * sizeof (CHAR16
), L
"%02d", (UINT8
) EditValue
);
855 if (MenuOption
->Sequence
== 0) {
856 ASSERT (EraseLen
>= 2);
857 FormattedNumber
[EraseLen
- 2] = TIME_SEPARATOR
;
858 } else if (MenuOption
->Sequence
== 1) {
859 ASSERT (EraseLen
>= 1);
860 FormattedNumber
[EraseLen
- 1] = TIME_SEPARATOR
;
863 QuestionValue
->Value
.u64
= EditValue
;
864 PrintFormattedNumber (Question
, FormattedNumber
, 21 * sizeof (CHAR16
));
867 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
868 for (Loop
= 0; Loop
< EraseLen
; Loop
++) {
869 PrintStringAt (MenuOption
->OptCol
+ Loop
, MenuOption
->Row
, L
" ");
871 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetHighlightTextColor ());
873 if (MenuOption
->Sequence
== 0) {
874 PrintCharAt (MenuOption
->OptCol
, Row
, LEFT_NUMERIC_DELIMITER
);
875 Column
= MenuOption
->OptCol
+ 1;
878 PrintStringAt (Column
, Row
, FormattedNumber
);
880 if (!DateOrTime
|| MenuOption
->Sequence
== 2) {
881 PrintCharAt ((UINTN
)-1, (UINTN
)-1, RIGHT_NUMERIC_DELIMITER
);
885 goto EnterCarriageReturn
;
889 goto EnterCarriageReturn
;
892 return EFI_DEVICE_ERROR
;
902 case CHAR_CARRIAGE_RETURN
:
904 // Validate input value with Minimum value.
906 ValidateFail
= FALSE
;
909 // After user input Enter, need to check whether the input value.
910 // If input a negative value, should compare with maximum value.
911 // else compare with the minimum value.
914 ValidateFail
= (INT64
) EditValue
> (INT64
) Maximum
? TRUE
: FALSE
;
916 ValidateFail
= (INT64
) EditValue
< (INT64
) Minimum
? TRUE
: FALSE
;
920 UpdateStatusBar (INPUT_ERROR
, TRUE
);
923 } else if (EditValue
< Minimum
) {
924 UpdateStatusBar (INPUT_ERROR
, TRUE
);
928 UpdateStatusBar (INPUT_ERROR
, FALSE
);
929 CopyMem (&gUserInput
->InputValue
, &Question
->CurrentValue
, sizeof (EFI_HII_VALUE
));
930 QuestionValue
= &gUserInput
->InputValue
;
932 // Store Edit value back to Question
934 if (Question
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) {
935 switch (MenuOption
->Sequence
) {
937 QuestionValue
->Value
.date
.Month
= (UINT8
) EditValue
;
941 QuestionValue
->Value
.date
.Day
= (UINT8
) EditValue
;
945 QuestionValue
->Value
.date
.Year
= (UINT16
) EditValue
;
951 } else if (Question
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
952 switch (MenuOption
->Sequence
) {
954 QuestionValue
->Value
.time
.Hour
= (UINT8
) EditValue
;
958 QuestionValue
->Value
.time
.Minute
= (UINT8
) EditValue
;
962 QuestionValue
->Value
.time
.Second
= (UINT8
) EditValue
;
972 QuestionValue
->Value
.u64
= EditValue
;
976 // Adjust the value to the correct one.
977 // Sample like: 2012.02.29 -> 2013.02.29 -> 2013.02.01
978 // 2013.03.29 -> 2013.02.29 -> 2013.02.28
980 if (Question
->OpCode
->OpCode
== EFI_IFR_DATE_OP
&&
981 (MenuOption
->Sequence
== 0 || MenuOption
->Sequence
== 2)) {
982 AdjustQuestionValue (QuestionValue
, (UINT8
)MenuOption
->Sequence
);
993 PrintStringAt (Column
, Row
, L
" ");
998 // Remove a character
1000 EditValue
= PreviousNumber
[Count
- 1];
1001 UpdateStatusBar (INPUT_ERROR
, FALSE
);
1004 PrintStringAt (Column
, Row
, L
" ");
1011 if ((Key
.UnicodeChar
>= L
'0') && (Key
.UnicodeChar
<= L
'9')) {
1012 Digital
= (UINT8
) (Key
.UnicodeChar
- L
'0');
1013 } else if ((Key
.UnicodeChar
>= L
'A') && (Key
.UnicodeChar
<= L
'F')) {
1014 Digital
= (UINT8
) (Key
.UnicodeChar
- L
'A' + 0x0A);
1015 } else if ((Key
.UnicodeChar
>= L
'a') && (Key
.UnicodeChar
<= L
'f')) {
1016 Digital
= (UINT8
) (Key
.UnicodeChar
- L
'a' + 0x0A);
1018 UpdateStatusBar (INPUT_ERROR
, TRUE
);
1022 if (Key
.UnicodeChar
> L
'9' || Key
.UnicodeChar
< L
'0') {
1023 UpdateStatusBar (INPUT_ERROR
, TRUE
);
1029 // If Count exceed input width, there is no way more is valid
1031 if (Count
>= InputWidth
) {
1035 // Someone typed something valid!
1039 EditValue
= LShiftU64 (EditValue
, 4) + Digital
;
1040 } else if (IntInput
&& Negative
) {
1042 // Save the negative number.
1044 EditValue
= ~(MultU64x32 (~(EditValue
- 1), 10) + (Key
.UnicodeChar
- L
'0')) + 1;
1046 EditValue
= MultU64x32 (EditValue
, 10) + (Key
.UnicodeChar
- L
'0');
1050 EditValue
= Digital
;
1051 } else if (IntInput
&& Negative
) {
1053 // Save the negative number.
1055 EditValue
= ~(Key
.UnicodeChar
- L
'0') + 1;
1057 EditValue
= Key
.UnicodeChar
- L
'0';
1062 ValidateFail
= FALSE
;
1064 // When user input a new value, should check the current value.
1065 // If user input a negative value, should compare it with minimum
1066 // value, else compare it with maximum value.
1069 ValidateFail
= (INT64
) EditValue
< (INT64
) Minimum
? TRUE
: FALSE
;
1071 ValidateFail
= (INT64
) EditValue
> (INT64
) Maximum
? TRUE
: FALSE
;
1075 UpdateStatusBar (INPUT_ERROR
, TRUE
);
1076 ASSERT (Count
< ARRAY_SIZE (PreviousNumber
));
1077 EditValue
= PreviousNumber
[Count
];
1081 if (EditValue
> Maximum
) {
1082 UpdateStatusBar (INPUT_ERROR
, TRUE
);
1083 ASSERT (Count
< ARRAY_SIZE (PreviousNumber
));
1084 EditValue
= PreviousNumber
[Count
];
1089 UpdateStatusBar (INPUT_ERROR
, FALSE
);
1092 ASSERT (Count
< (ARRAY_SIZE (PreviousNumber
)));
1093 PreviousNumber
[Count
] = EditValue
;
1095 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetHighlightTextColor ());
1096 PrintCharAt (Column
, Row
, Key
.UnicodeChar
);
1105 Adjust option order base on the question value.
1107 @param Question Pointer to current question.
1108 @param PopUpMenuLines The line number of the pop up menu.
1110 @retval EFI_SUCCESS If Option input is processed successfully
1111 @retval EFI_DEVICE_ERROR If operation fails
1116 IN FORM_DISPLAY_ENGINE_STATEMENT
*Question
,
1117 OUT UINTN
*PopUpMenuLines
1121 EFI_IFR_ORDERED_LIST
*OrderList
;
1125 DISPLAY_QUESTION_OPTION
*OneOfOption
;
1126 EFI_HII_VALUE
*HiiValueArray
;
1128 Link
= GetFirstNode (&Question
->OptionListHead
);
1129 OneOfOption
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1130 ValueArray
= Question
->CurrentValue
.Buffer
;
1131 ValueType
= OneOfOption
->OptionOpCode
->Type
;
1132 OrderList
= (EFI_IFR_ORDERED_LIST
*) Question
->OpCode
;
1134 for (Index
= 0; Index
< OrderList
->MaxContainers
; Index
++) {
1135 if (GetArrayData (ValueArray
, ValueType
, Index
) == 0) {
1140 *PopUpMenuLines
= Index
;
1143 // Prepare HiiValue array
1145 HiiValueArray
= AllocateZeroPool (*PopUpMenuLines
* sizeof (EFI_HII_VALUE
));
1146 ASSERT (HiiValueArray
!= NULL
);
1148 for (Index
= 0; Index
< *PopUpMenuLines
; Index
++) {
1149 HiiValueArray
[Index
].Type
= ValueType
;
1150 HiiValueArray
[Index
].Value
.u64
= GetArrayData (ValueArray
, ValueType
, Index
);
1153 for (Index
= 0; Index
< *PopUpMenuLines
; Index
++) {
1154 OneOfOption
= ValueToOption (Question
, &HiiValueArray
[*PopUpMenuLines
- Index
- 1]);
1155 if (OneOfOption
== NULL
) {
1156 return EFI_NOT_FOUND
;
1159 RemoveEntryList (&OneOfOption
->Link
);
1164 InsertHeadList (&Question
->OptionListHead
, &OneOfOption
->Link
);
1167 FreePool (HiiValueArray
);
1173 Base on the type to compare the value.
1175 @param Value1 The first value need to compare.
1176 @param Value2 The second value need to compare.
1177 @param Type The value type for above two values.
1179 @retval TRUE The two value are same.
1180 @retval FALSE The two value are different.
1185 IN EFI_IFR_TYPE_VALUE
*Value1
,
1186 IN EFI_IFR_TYPE_VALUE
*Value2
,
1191 case EFI_IFR_TYPE_BOOLEAN
:
1192 case EFI_IFR_TYPE_NUM_SIZE_8
:
1193 return (BOOLEAN
) (Value1
->u8
== Value2
->u8
);
1195 case EFI_IFR_TYPE_NUM_SIZE_16
:
1196 return (BOOLEAN
) (Value1
->u16
== Value2
->u16
);
1198 case EFI_IFR_TYPE_NUM_SIZE_32
:
1199 return (BOOLEAN
) (Value1
->u32
== Value2
->u32
);
1201 case EFI_IFR_TYPE_NUM_SIZE_64
:
1202 return (BOOLEAN
) (Value1
->u64
== Value2
->u64
);
1211 Base on the type to set the value.
1213 @param Dest The dest value.
1214 @param Source The source value.
1215 @param Type The value type for above two values.
1220 OUT EFI_IFR_TYPE_VALUE
*Dest
,
1221 IN EFI_IFR_TYPE_VALUE
*Source
,
1226 case EFI_IFR_TYPE_BOOLEAN
:
1227 Dest
->b
= Source
->b
;
1230 case EFI_IFR_TYPE_NUM_SIZE_8
:
1231 Dest
->u8
= Source
->u8
;
1234 case EFI_IFR_TYPE_NUM_SIZE_16
:
1235 Dest
->u16
= Source
->u16
;
1238 case EFI_IFR_TYPE_NUM_SIZE_32
:
1239 Dest
->u32
= Source
->u32
;
1242 case EFI_IFR_TYPE_NUM_SIZE_64
:
1243 Dest
->u64
= Source
->u64
;
1253 Get selection for OneOf and OrderedList (Left/Right will be ignored).
1255 @param MenuOption Pointer to the current input menu.
1257 @retval EFI_SUCCESS If Option input is processed successfully
1258 @retval EFI_DEVICE_ERROR If operation fails
1262 GetSelectionInputPopUp (
1263 IN UI_MENU_OPTION
*MenuOption
1269 CHAR16
*TempStringPtr
;
1271 UINTN TopOptionIndex
;
1272 UINTN HighlightOptionIndex
;
1277 UINTN PopUpMenuLines
;
1278 UINTN MenuLinesInView
;
1281 INT32 SavedAttribute
;
1282 BOOLEAN ShowDownArrow
;
1283 BOOLEAN ShowUpArrow
;
1284 UINTN DimensionsWidth
;
1286 BOOLEAN OrderedList
;
1290 EFI_HII_VALUE HiiValue
;
1291 DISPLAY_QUESTION_OPTION
*OneOfOption
;
1292 DISPLAY_QUESTION_OPTION
*CurrentOption
;
1293 FORM_DISPLAY_ENGINE_STATEMENT
*Question
;
1295 EFI_IFR_ORDERED_LIST
*OrderList
;
1297 DimensionsWidth
= gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
;
1301 CurrentOption
= NULL
;
1302 ShowDownArrow
= FALSE
;
1303 ShowUpArrow
= FALSE
;
1305 ZeroMem (&HiiValue
, sizeof (EFI_HII_VALUE
));
1307 Question
= MenuOption
->ThisTag
;
1308 if (Question
->OpCode
->OpCode
== EFI_IFR_ORDERED_LIST_OP
) {
1309 Link
= GetFirstNode (&Question
->OptionListHead
);
1310 OneOfOption
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1311 ValueArray
= Question
->CurrentValue
.Buffer
;
1312 ValueType
= OneOfOption
->OptionOpCode
->Type
;
1314 OrderList
= (EFI_IFR_ORDERED_LIST
*) Question
->OpCode
;
1316 OrderedList
= FALSE
;
1321 // Calculate Option count
1325 AdjustOptionOrder(Question
, &PopUpMenuLines
);
1327 Link
= GetFirstNode (&Question
->OptionListHead
);
1328 while (!IsNull (&Question
->OptionListHead
, Link
)) {
1329 OneOfOption
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1331 Link
= GetNextNode (&Question
->OptionListHead
, Link
);
1336 // Get the number of one of options present and its size
1339 HighlightOptionIndex
= 0;
1340 Link
= GetFirstNode (&Question
->OptionListHead
);
1341 for (Index
= 0; Index
< PopUpMenuLines
; Index
++) {
1342 OneOfOption
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1344 StringPtr
= GetToken (OneOfOption
->OptionOpCode
->Option
, gFormData
->HiiHandle
);
1345 if (StrLen (StringPtr
) > PopUpWidth
) {
1346 PopUpWidth
= StrLen (StringPtr
);
1348 FreePool (StringPtr
);
1349 HiiValue
.Type
= OneOfOption
->OptionOpCode
->Type
;
1350 SetValuesByType (&HiiValue
.Value
, &OneOfOption
->OptionOpCode
->Value
, HiiValue
.Type
);
1351 if (!OrderedList
&& (CompareHiiValue (&Question
->CurrentValue
, &HiiValue
, &Result
, NULL
) == EFI_SUCCESS
) && (Result
== 0)) {
1353 // Find current selected Option for OneOf
1355 HighlightOptionIndex
= Index
;
1358 Link
= GetNextNode (&Question
->OptionListHead
, Link
);
1362 // Perform popup menu initialization.
1364 PopUpWidth
= PopUpWidth
+ POPUP_PAD_SPACE_COUNT
;
1366 SavedAttribute
= gST
->ConOut
->Mode
->Attribute
;
1367 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetPopupColor ());
1369 if ((PopUpWidth
+ POPUP_FRAME_WIDTH
) > DimensionsWidth
) {
1370 PopUpWidth
= DimensionsWidth
- POPUP_FRAME_WIDTH
;
1373 Start
= (DimensionsWidth
- PopUpWidth
- POPUP_FRAME_WIDTH
) / 2 + gStatementDimensions
.LeftColumn
;
1374 End
= Start
+ PopUpWidth
+ POPUP_FRAME_WIDTH
;
1375 Top
= gStatementDimensions
.TopRow
;
1376 Bottom
= gStatementDimensions
.BottomRow
- 1;
1378 MenuLinesInView
= Bottom
- Top
- 1;
1379 if (MenuLinesInView
>= PopUpMenuLines
) {
1380 Top
= Top
+ (MenuLinesInView
- PopUpMenuLines
) / 2;
1381 Bottom
= Top
+ PopUpMenuLines
+ 1;
1383 ShowDownArrow
= TRUE
;
1386 if (HighlightOptionIndex
> (MenuLinesInView
- 1)) {
1387 TopOptionIndex
= HighlightOptionIndex
- MenuLinesInView
+ 1;
1394 // Clear that portion of the screen
1396 ClearLines (Start
, End
, Top
, Bottom
, GetPopupColor ());
1399 // Draw "One of" pop-up menu
1401 Character
= BOXDRAW_DOWN_RIGHT
;
1402 PrintCharAt (Start
, Top
, Character
);
1403 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
1404 if ((ShowUpArrow
) && ((Index
+ 1) == (Start
+ End
) / 2)) {
1405 Character
= GEOMETRICSHAPE_UP_TRIANGLE
;
1407 Character
= BOXDRAW_HORIZONTAL
;
1410 PrintCharAt ((UINTN
)-1, (UINTN
)-1, Character
);
1413 Character
= BOXDRAW_DOWN_LEFT
;
1414 PrintCharAt ((UINTN
)-1, (UINTN
)-1, Character
);
1415 Character
= BOXDRAW_VERTICAL
;
1416 for (Index
= Top
+ 1; Index
< Bottom
; Index
++) {
1417 PrintCharAt (Start
, Index
, Character
);
1418 PrintCharAt (End
- 1, Index
, Character
);
1422 // Move to top Option
1424 Link
= GetFirstNode (&Question
->OptionListHead
);
1425 for (Index
= 0; Index
< TopOptionIndex
; Index
++) {
1426 Link
= GetNextNode (&Question
->OptionListHead
, Link
);
1430 // Display the One of options
1433 for (Index
= TopOptionIndex
; (Index
< PopUpMenuLines
) && (Index2
< Bottom
); Index
++) {
1434 OneOfOption
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1435 Link
= GetNextNode (&Question
->OptionListHead
, Link
);
1437 StringPtr
= GetToken (OneOfOption
->OptionOpCode
->Option
, gFormData
->HiiHandle
);
1438 ASSERT (StringPtr
!= NULL
);
1440 // If the string occupies multiple lines, truncate it to fit in one line,
1441 // and append a "..." for indication.
1443 if (StrLen (StringPtr
) > (PopUpWidth
- 1)) {
1444 TempStringPtr
= AllocateZeroPool (sizeof (CHAR16
) * (PopUpWidth
- 1));
1445 ASSERT ( TempStringPtr
!= NULL
);
1446 CopyMem (TempStringPtr
, StringPtr
, (sizeof (CHAR16
) * (PopUpWidth
- 5)));
1447 FreePool (StringPtr
);
1448 StringPtr
= TempStringPtr
;
1449 StrCatS (StringPtr
, PopUpWidth
- 1, L
"...");
1452 if (Index
== HighlightOptionIndex
) {
1454 // Highlight the selected one
1456 CurrentOption
= OneOfOption
;
1458 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetPickListColor ());
1459 PrintStringAt (Start
+ 2, Index2
, StringPtr
);
1460 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetPopupColor ());
1462 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetPopupColor ());
1463 PrintStringAt (Start
+ 2, Index2
, StringPtr
);
1467 FreePool (StringPtr
);
1470 Character
= BOXDRAW_UP_RIGHT
;
1471 PrintCharAt (Start
, Bottom
, Character
);
1472 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
1473 if ((ShowDownArrow
) && ((Index
+ 1) == (Start
+ End
) / 2)) {
1474 Character
= GEOMETRICSHAPE_DOWN_TRIANGLE
;
1476 Character
= BOXDRAW_HORIZONTAL
;
1479 PrintCharAt ((UINTN
)-1, (UINTN
)-1, Character
);
1482 Character
= BOXDRAW_UP_LEFT
;
1483 PrintCharAt ((UINTN
)-1, (UINTN
)-1, Character
);
1486 // Get User selection
1488 Key
.UnicodeChar
= CHAR_NULL
;
1489 if ((gDirection
== SCAN_UP
) || (gDirection
== SCAN_DOWN
)) {
1490 Key
.ScanCode
= gDirection
;
1495 WaitForKeyStroke (&Key
);
1498 switch (Key
.UnicodeChar
) {
1501 if ((TopOptionIndex
> 0) && (TopOptionIndex
== HighlightOptionIndex
)) {
1503 // Highlight reaches the top of the popup window, scroll one menu item.
1506 ShowDownArrow
= TRUE
;
1509 if (TopOptionIndex
== 0) {
1510 ShowUpArrow
= FALSE
;
1513 if (HighlightOptionIndex
> 0) {
1514 HighlightOptionIndex
--;
1516 ASSERT (CurrentOption
!= NULL
);
1517 SwapListEntries (CurrentOption
->Link
.BackLink
, &CurrentOption
->Link
);
1524 // If an ordered list op-code, we will allow for a popup of +/- keys
1525 // to create an ordered list of items
1528 if (((TopOptionIndex
+ MenuLinesInView
) < PopUpMenuLines
) &&
1529 (HighlightOptionIndex
== (TopOptionIndex
+ MenuLinesInView
- 1))) {
1531 // Highlight reaches the bottom of the popup window, scroll one menu item.
1537 if ((TopOptionIndex
+ MenuLinesInView
) == PopUpMenuLines
) {
1538 ShowDownArrow
= FALSE
;
1541 if (HighlightOptionIndex
< (PopUpMenuLines
- 1)) {
1542 HighlightOptionIndex
++;
1544 ASSERT (CurrentOption
!= NULL
);
1545 SwapListEntries (&CurrentOption
->Link
, CurrentOption
->Link
.ForwardLink
);
1551 switch (Key
.ScanCode
) {
1554 if (Key
.ScanCode
== SCAN_UP
) {
1555 if ((TopOptionIndex
> 0) && (TopOptionIndex
== HighlightOptionIndex
)) {
1557 // Highlight reaches the top of the popup window, scroll one menu item.
1560 ShowDownArrow
= TRUE
;
1563 if (TopOptionIndex
== 0) {
1564 ShowUpArrow
= FALSE
;
1567 if (HighlightOptionIndex
> 0) {
1568 HighlightOptionIndex
--;
1571 if (((TopOptionIndex
+ MenuLinesInView
) < PopUpMenuLines
) &&
1572 (HighlightOptionIndex
== (TopOptionIndex
+ MenuLinesInView
- 1))) {
1574 // Highlight reaches the bottom of the popup window, scroll one menu item.
1580 if ((TopOptionIndex
+ MenuLinesInView
) == PopUpMenuLines
) {
1581 ShowDownArrow
= FALSE
;
1584 if (HighlightOptionIndex
< (PopUpMenuLines
- 1)) {
1585 HighlightOptionIndex
++;
1591 gST
->ConOut
->SetAttribute (gST
->ConOut
, SavedAttribute
);
1594 // Restore link list order for orderedlist
1597 HiiValue
.Type
= ValueType
;
1598 HiiValue
.Value
.u64
= 0;
1599 for (Index
= 0; Index
< OrderList
->MaxContainers
; Index
++) {
1600 HiiValue
.Value
.u64
= GetArrayData (ValueArray
, ValueType
, Index
);
1601 if (HiiValue
.Value
.u64
== 0) {
1605 OneOfOption
= ValueToOption (Question
, &HiiValue
);
1606 if (OneOfOption
== NULL
) {
1607 return EFI_NOT_FOUND
;
1610 RemoveEntryList (&OneOfOption
->Link
);
1611 InsertTailList (&Question
->OptionListHead
, &OneOfOption
->Link
);
1615 return EFI_DEVICE_ERROR
;
1623 case CHAR_CARRIAGE_RETURN
:
1625 // return the current selection
1628 ReturnValue
= AllocateZeroPool (Question
->CurrentValue
.BufferLen
);
1629 ASSERT (ReturnValue
!= NULL
);
1631 Link
= GetFirstNode (&Question
->OptionListHead
);
1632 while (!IsNull (&Question
->OptionListHead
, Link
)) {
1633 OneOfOption
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1634 Link
= GetNextNode (&Question
->OptionListHead
, Link
);
1636 SetArrayData (ReturnValue
, ValueType
, Index
, OneOfOption
->OptionOpCode
->Value
.u64
);
1639 if (Index
> OrderList
->MaxContainers
) {
1643 if (CompareMem (ReturnValue
, ValueArray
, Question
->CurrentValue
.BufferLen
) == 0) {
1644 FreePool (ReturnValue
);
1645 return EFI_DEVICE_ERROR
;
1647 gUserInput
->InputValue
.Buffer
= ReturnValue
;
1648 gUserInput
->InputValue
.BufferLen
= Question
->CurrentValue
.BufferLen
;
1651 ASSERT (CurrentOption
!= NULL
);
1652 gUserInput
->InputValue
.Type
= CurrentOption
->OptionOpCode
->Type
;
1653 if (IsValuesEqual (&Question
->CurrentValue
.Value
, &CurrentOption
->OptionOpCode
->Value
, gUserInput
->InputValue
.Type
)) {
1654 return EFI_DEVICE_ERROR
;
1656 SetValuesByType (&gUserInput
->InputValue
.Value
, &CurrentOption
->OptionOpCode
->Value
, gUserInput
->InputValue
.Type
);
1660 gST
->ConOut
->SetAttribute (gST
->ConOut
, SavedAttribute
);