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
;
28 if (OpCode
->OpCode
== EFI_IFR_STRING_OP
) {
29 StringOp
= (EFI_IFR_STRING
*) OpCode
;
30 *Minimum
= StringOp
->MinSize
;
31 *Maximum
= StringOp
->MaxSize
;
32 } else if (OpCode
->OpCode
== EFI_IFR_PASSWORD_OP
) {
33 PasswordOp
= (EFI_IFR_PASSWORD
*) OpCode
;
34 *Minimum
= PasswordOp
->MinSize
;
35 *Maximum
= PasswordOp
->MaxSize
;
43 Get string or password input from user.
45 @param MenuOption Pointer to the current input menu.
46 @param Prompt The prompt string shown on popup window.
47 @param StringPtr Old user input and destination for use input string.
49 @retval EFI_SUCCESS If string input is read successfully
50 @retval EFI_DEVICE_ERROR If operation fails
55 IN UI_MENU_OPTION
*MenuOption
,
57 IN OUT CHAR16
*StringPtr
67 CHAR16
*BufferedString
;
73 UINTN DimensionsWidth
;
74 UINTN DimensionsHeight
;
76 BOOLEAN CursorVisible
;
79 FORM_DISPLAY_ENGINE_STATEMENT
*Question
;
83 DimensionsWidth
= gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
;
84 DimensionsHeight
= gStatementDimensions
.BottomRow
- gStatementDimensions
.TopRow
;
86 NullCharacter
= CHAR_NULL
;
87 ScreenSize
= GetStringWidth (Prompt
) / sizeof (CHAR16
);
91 Question
= MenuOption
->ThisTag
;
92 GetFieldFromOp(Question
->OpCode
, &Minimum
, &Maximum
);
94 if (Question
->OpCode
->OpCode
== EFI_IFR_PASSWORD_OP
) {
100 MaxLen
= Maximum
+ 1;
101 TempString
= AllocateZeroPool (MaxLen
* sizeof (CHAR16
));
104 if (ScreenSize
< (Maximum
+ 1)) {
105 ScreenSize
= Maximum
+ 1;
108 if ((ScreenSize
+ 2) > DimensionsWidth
) {
109 ScreenSize
= DimensionsWidth
- 2;
112 BufferedString
= AllocateZeroPool (ScreenSize
* 2);
113 ASSERT (BufferedString
);
115 Start
= (DimensionsWidth
- ScreenSize
- 2) / 2 + gStatementDimensions
.LeftColumn
+ 1;
116 Top
= ((DimensionsHeight
- 6) / 2) + gStatementDimensions
.TopRow
- 1;
119 // Display prompt for string
121 // CreateDialog (NULL, "", Prompt, Space, "", NULL);
122 CreateMultiStringPopUp (ScreenSize
, 4, &NullCharacter
, Prompt
, Space
, &NullCharacter
);
123 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_BLACK
, EFI_LIGHTGRAY
));
125 CursorVisible
= gST
->ConOut
->Mode
->CursorVisible
;
126 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
128 CurrentCursor
= GetStringWidth (StringPtr
) / 2 - 1;
129 if (CurrentCursor
!= 0) {
131 // Show the string which has beed saved before.
133 SetUnicodeMem (BufferedString
, ScreenSize
- 1, L
' ');
134 PrintStringAt (Start
+ 1, Top
+ 3, BufferedString
);
136 if ((GetStringWidth (StringPtr
) / 2) > (DimensionsWidth
- 2)) {
137 Index
= (GetStringWidth (StringPtr
) / 2) - DimensionsWidth
+ 2;
143 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, Start
+ 1, Top
+ 3);
146 for (Count
= 0; Index
+ 1 < GetStringWidth (StringPtr
) / 2; Index
++, Count
++) {
147 BufferedString
[Count
] = StringPtr
[Index
];
150 PrintCharAt ((UINTN
)-1, (UINTN
)-1, L
'*');
155 PrintStringAt (Start
+ 1, Top
+ 3, BufferedString
);
158 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
159 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, Start
+ GetStringWidth (StringPtr
) / 2, Top
+ 3);
163 Status
= WaitForKeyStroke (&Key
);
164 ASSERT_EFI_ERROR (Status
);
166 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_BLACK
, EFI_LIGHTGRAY
));
167 switch (Key
.UnicodeChar
) {
169 switch (Key
.ScanCode
) {
171 if (CurrentCursor
> 0) {
177 if (CurrentCursor
< (GetStringWidth (StringPtr
) / 2 - 1)) {
183 FreePool (TempString
);
184 FreePool (BufferedString
);
185 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
186 gST
->ConOut
->EnableCursor (gST
->ConOut
, CursorVisible
);
187 return EFI_DEVICE_ERROR
;
190 for (Index
= CurrentCursor
; StringPtr
[Index
] != CHAR_NULL
; Index
++) {
191 StringPtr
[Index
] = StringPtr
[Index
+ 1];
192 PrintCharAt (Start
+ Index
+ 1, Top
+ 3, IsPassword
&& StringPtr
[Index
] != CHAR_NULL
? L
'*' : StringPtr
[Index
]);
202 case CHAR_CARRIAGE_RETURN
:
203 if (GetStringWidth (StringPtr
) >= ((Minimum
+ 1) * sizeof (CHAR16
))) {
205 FreePool (TempString
);
206 FreePool (BufferedString
);
207 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
208 gST
->ConOut
->EnableCursor (gST
->ConOut
, CursorVisible
);
212 // Simply create a popup to tell the user that they had typed in too few characters.
213 // To save code space, we can then treat this as an error and return back to the menu.
216 CreateDialog (&Key
, &NullCharacter
, gMiniString
, gPressEnter
, &NullCharacter
, NULL
);
217 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
219 FreePool (TempString
);
220 FreePool (BufferedString
);
221 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
222 gST
->ConOut
->EnableCursor (gST
->ConOut
, CursorVisible
);
223 return EFI_DEVICE_ERROR
;
228 if (StringPtr
[0] != CHAR_NULL
&& CurrentCursor
!= 0) {
229 for (Index
= 0; Index
< CurrentCursor
- 1; Index
++) {
230 TempString
[Index
] = StringPtr
[Index
];
232 Count
= GetStringWidth (StringPtr
) / 2 - 1;
233 if (Count
>= CurrentCursor
) {
234 for (Index
= CurrentCursor
- 1, Index2
= CurrentCursor
; Index2
< Count
; Index
++, Index2
++) {
235 TempString
[Index
] = StringPtr
[Index2
];
237 TempString
[Index
] = CHAR_NULL
;
240 // Effectively truncate string by 1 character
242 StrCpyS (StringPtr
, MaxLen
, TempString
);
248 // If it is the beginning of the string, don't worry about checking maximum limits
250 if ((StringPtr
[0] == CHAR_NULL
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
251 StrnCpyS (StringPtr
, MaxLen
, &Key
.UnicodeChar
, 1);
253 } else if ((GetStringWidth (StringPtr
) < ((Maximum
+ 1) * sizeof (CHAR16
))) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
254 KeyPad
[0] = Key
.UnicodeChar
;
255 KeyPad
[1] = CHAR_NULL
;
256 Count
= GetStringWidth (StringPtr
) / 2 - 1;
257 if (CurrentCursor
< Count
) {
258 for (Index
= 0; Index
< CurrentCursor
; Index
++) {
259 TempString
[Index
] = StringPtr
[Index
];
261 TempString
[Index
] = CHAR_NULL
;
262 StrCatS (TempString
, MaxLen
, KeyPad
);
263 StrCatS (TempString
, MaxLen
, StringPtr
+ CurrentCursor
);
264 StrCpyS (StringPtr
, MaxLen
, TempString
);
266 StrCatS (StringPtr
, MaxLen
, KeyPad
);
272 // If the width of the input string is now larger than the screen, we nee to
273 // adjust the index to start printing portions of the string
275 SetUnicodeMem (BufferedString
, ScreenSize
- 1, L
' ');
276 PrintStringAt (Start
+ 1, Top
+ 3, BufferedString
);
278 if ((GetStringWidth (StringPtr
) / 2) > (DimensionsWidth
- 2)) {
279 Index
= (GetStringWidth (StringPtr
) / 2) - DimensionsWidth
+ 2;
285 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, Start
+ 1, Top
+ 3);
288 for (Count
= 0; Index
+ 1 < GetStringWidth (StringPtr
) / 2; Index
++, Count
++) {
289 BufferedString
[Count
] = StringPtr
[Index
];
292 PrintCharAt ((UINTN
)-1, (UINTN
)-1, L
'*');
297 PrintStringAt (Start
+ 1, Top
+ 3, BufferedString
);
302 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
303 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, Start
+ CurrentCursor
+ 1, Top
+ 3);
309 Adjust the value to the correct one. Rules follow the sample:
310 like: Year change: 2012.02.29 -> 2013.02.29 -> 2013.02.01
311 Month change: 2013.03.29 -> 2013.02.29 -> 2013.02.28
313 @param QuestionValue Pointer to current question.
314 @param Sequence The sequence of the field in the question.
317 AdjustQuestionValue (
318 IN EFI_HII_VALUE
*QuestionValue
,
327 Month
= QuestionValue
->Value
.date
.Month
;
328 Year
= QuestionValue
->Value
.date
.Year
;
333 if ((Year
% 4) == 0 && ((Year
% 100) != 0 || (Year
% 400) == 0)) {
351 // Change the month area.
354 if (QuestionValue
->Value
.date
.Day
> Maximum
) {
355 QuestionValue
->Value
.date
.Day
= Maximum
;
360 // Change the Year area.
363 if (QuestionValue
->Value
.date
.Day
> Maximum
) {
364 QuestionValue
->Value
.date
.Day
= Minimum
;
370 Get field info from numeric opcode.
372 @param OpCode Pointer to the current input opcode.
373 @param IntInput Whether question shows with EFI_IFR_DISPLAY_INT_DEC type.
374 @param QuestionValue Input question value, with EFI_HII_VALUE type.
375 @param Value Return question value, always return UINT64 type.
376 @param Minimum The minimum size info for this opcode.
377 @param Maximum The maximum size info for this opcode.
378 @param Step The step size info for this opcode.
379 @param StorageWidth The storage width info for this opcode.
384 IN EFI_IFR_OP_HEADER
*OpCode
,
386 IN EFI_HII_VALUE
*QuestionValue
,
391 OUT UINT16
*StorageWidth
394 EFI_IFR_NUMERIC
*NumericOp
;
396 NumericOp
= (EFI_IFR_NUMERIC
*) OpCode
;
398 switch (NumericOp
->Flags
& EFI_IFR_NUMERIC_SIZE
) {
399 case EFI_IFR_NUMERIC_SIZE_1
:
401 *Minimum
= (INT64
) (INT8
) NumericOp
->data
.u8
.MinValue
;
402 *Maximum
= (INT64
) (INT8
) NumericOp
->data
.u8
.MaxValue
;
403 *Value
= (INT64
) (INT8
) QuestionValue
->Value
.u8
;
405 *Minimum
= NumericOp
->data
.u8
.MinValue
;
406 *Maximum
= NumericOp
->data
.u8
.MaxValue
;
407 *Value
= QuestionValue
->Value
.u8
;
409 *Step
= NumericOp
->data
.u8
.Step
;
410 *StorageWidth
= (UINT16
) sizeof (UINT8
);
413 case EFI_IFR_NUMERIC_SIZE_2
:
415 *Minimum
= (INT64
) (INT16
) NumericOp
->data
.u16
.MinValue
;
416 *Maximum
= (INT64
) (INT16
) NumericOp
->data
.u16
.MaxValue
;
417 *Value
= (INT64
) (INT16
) QuestionValue
->Value
.u16
;
419 *Minimum
= NumericOp
->data
.u16
.MinValue
;
420 *Maximum
= NumericOp
->data
.u16
.MaxValue
;
421 *Value
= QuestionValue
->Value
.u16
;
423 *Step
= NumericOp
->data
.u16
.Step
;
424 *StorageWidth
= (UINT16
) sizeof (UINT16
);
427 case EFI_IFR_NUMERIC_SIZE_4
:
429 *Minimum
= (INT64
) (INT32
) NumericOp
->data
.u32
.MinValue
;
430 *Maximum
= (INT64
) (INT32
) NumericOp
->data
.u32
.MaxValue
;
431 *Value
= (INT64
) (INT32
) QuestionValue
->Value
.u32
;
433 *Minimum
= NumericOp
->data
.u32
.MinValue
;
434 *Maximum
= NumericOp
->data
.u32
.MaxValue
;
435 *Value
= QuestionValue
->Value
.u32
;
437 *Step
= NumericOp
->data
.u32
.Step
;
438 *StorageWidth
= (UINT16
) sizeof (UINT32
);
441 case EFI_IFR_NUMERIC_SIZE_8
:
443 *Minimum
= (INT64
) NumericOp
->data
.u64
.MinValue
;
444 *Maximum
= (INT64
) NumericOp
->data
.u64
.MaxValue
;
445 *Value
= (INT64
) QuestionValue
->Value
.u64
;
447 *Minimum
= NumericOp
->data
.u64
.MinValue
;
448 *Maximum
= NumericOp
->data
.u64
.MaxValue
;
449 *Value
= QuestionValue
->Value
.u64
;
451 *Step
= NumericOp
->data
.u64
.Step
;
452 *StorageWidth
= (UINT16
) sizeof (UINT64
);
460 *Maximum
= (UINT64
) -1;
465 This routine reads a numeric value from the user input.
467 @param MenuOption Pointer to the current input menu.
469 @retval EFI_SUCCESS If numerical input is read successfully
470 @retval EFI_DEVICE_ERROR If operation fails
475 IN UI_MENU_OPTION
*MenuOption
480 CHAR16 InputText
[MAX_NUMERIC_INPUT_WIDTH
];
481 CHAR16 FormattedNumber
[MAX_NUMERIC_INPUT_WIDTH
- 1];
482 UINT64 PreviousNumber
[MAX_NUMERIC_INPUT_WIDTH
- 3];
489 BOOLEAN ValidateFail
;
499 EFI_HII_VALUE
*QuestionValue
;
500 FORM_DISPLAY_ENGINE_STATEMENT
*Question
;
501 EFI_IFR_NUMERIC
*NumericOp
;
504 Column
= MenuOption
->OptCol
;
505 Row
= MenuOption
->Row
;
506 PreviousNumber
[0] = 0;
517 ValidateFail
= FALSE
;
519 Question
= MenuOption
->ThisTag
;
520 QuestionValue
= &Question
->CurrentValue
;
521 ZeroMem (InputText
, MAX_NUMERIC_INPUT_WIDTH
* sizeof (CHAR16
));
524 // Only two case, user can enter to this function: Enter and +/- case.
525 // In Enter case, gDirection = 0; in +/- case, gDirection = SCAN_LEFT/SCAN_WRIGHT
527 ManualInput
= (BOOLEAN
)(gDirection
== 0 ? TRUE
: FALSE
);
529 if ((Question
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) || (Question
->OpCode
->OpCode
== EFI_IFR_TIME_OP
)) {
536 // Prepare Value to be edit
540 if (Question
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) {
544 switch (MenuOption
->Sequence
) {
548 EditValue
= QuestionValue
->Value
.date
.Month
;
552 switch (QuestionValue
->Value
.date
.Month
) {
554 if ((QuestionValue
->Value
.date
.Year
% 4) == 0 &&
555 ((QuestionValue
->Value
.date
.Year
% 100) != 0 ||
556 (QuestionValue
->Value
.date
.Year
% 400) == 0)) {
574 EditValue
= QuestionValue
->Value
.date
.Day
;
580 EditValue
= QuestionValue
->Value
.date
.Year
;
586 } else if (Question
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
590 switch (MenuOption
->Sequence
) {
594 EditValue
= QuestionValue
->Value
.time
.Hour
;
600 EditValue
= QuestionValue
->Value
.time
.Minute
;
606 EditValue
= QuestionValue
->Value
.time
.Second
;
613 ASSERT (Question
->OpCode
->OpCode
== EFI_IFR_NUMERIC_OP
);
614 NumericOp
= (EFI_IFR_NUMERIC
*) Question
->OpCode
;
615 GetValueFromNum(Question
->OpCode
, (NumericOp
->Flags
& EFI_IFR_DISPLAY
) == 0, QuestionValue
, &EditValue
, &Minimum
, &Maximum
, &Step
, &StorageWidth
);
616 EraseLen
= gOptionBlockWidth
;
619 if ((Question
->OpCode
->OpCode
== EFI_IFR_NUMERIC_OP
) && (NumericOp
!= NULL
)) {
620 if ((NumericOp
->Flags
& EFI_IFR_DISPLAY
) == EFI_IFR_DISPLAY_UINT_HEX
){
622 } else if ((NumericOp
->Flags
& EFI_IFR_DISPLAY
) == 0){
624 // Display with EFI_IFR_DISPLAY_INT_DEC type. Support negative number.
631 // Enter from "Enter" input, clear the old word showing.
634 if (Question
->OpCode
->OpCode
== EFI_IFR_NUMERIC_OP
) {
636 InputWidth
= StorageWidth
* 2;
638 switch (StorageWidth
) {
662 // Support an extra '-' for negative number.
668 InputText
[0] = LEFT_NUMERIC_DELIMITER
;
669 SetUnicodeMem (InputText
+ 1, InputWidth
, L
' ');
670 ASSERT (InputWidth
+ 2 < MAX_NUMERIC_INPUT_WIDTH
);
671 InputText
[InputWidth
+ 1] = RIGHT_NUMERIC_DELIMITER
;
672 InputText
[InputWidth
+ 2] = L
'\0';
674 PrintStringAt (Column
, Row
, InputText
);
678 if (Question
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) {
679 if (MenuOption
->Sequence
== 2) {
685 if (MenuOption
->Sequence
== 0) {
686 InputText
[0] = LEFT_NUMERIC_DELIMITER
;
687 SetUnicodeMem (InputText
+ 1, InputWidth
, L
' ');
688 InputText
[InputWidth
+ 1] = DATE_SEPARATOR
;
689 InputText
[InputWidth
+ 2] = L
'\0';
690 } else if (MenuOption
->Sequence
== 1){
691 SetUnicodeMem (InputText
, InputWidth
, L
' ');
692 InputText
[InputWidth
] = DATE_SEPARATOR
;
693 InputText
[InputWidth
+ 1] = L
'\0';
695 SetUnicodeMem (InputText
, InputWidth
, L
' ');
696 InputText
[InputWidth
] = RIGHT_NUMERIC_DELIMITER
;
697 InputText
[InputWidth
+ 1] = L
'\0';
700 PrintStringAt (Column
, Row
, InputText
);
701 if (MenuOption
->Sequence
== 0) {
706 if (Question
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
709 if (MenuOption
->Sequence
== 0) {
710 InputText
[0] = LEFT_NUMERIC_DELIMITER
;
711 SetUnicodeMem (InputText
+ 1, InputWidth
, L
' ');
712 InputText
[InputWidth
+ 1] = TIME_SEPARATOR
;
713 InputText
[InputWidth
+ 2] = L
'\0';
714 } else if (MenuOption
->Sequence
== 1){
715 SetUnicodeMem (InputText
, InputWidth
, L
' ');
716 InputText
[InputWidth
] = TIME_SEPARATOR
;
717 InputText
[InputWidth
+ 1] = L
'\0';
719 SetUnicodeMem (InputText
, InputWidth
, L
' ');
720 InputText
[InputWidth
] = RIGHT_NUMERIC_DELIMITER
;
721 InputText
[InputWidth
+ 1] = L
'\0';
724 PrintStringAt (Column
, Row
, InputText
);
725 if (MenuOption
->Sequence
== 0) {
732 // First time we enter this handler, we need to check to see if
733 // we were passed an increment or decrement directive
736 Key
.UnicodeChar
= CHAR_NULL
;
737 if (gDirection
!= 0) {
738 Key
.ScanCode
= gDirection
;
743 WaitForKeyStroke (&Key
);
746 switch (Key
.UnicodeChar
) {
750 if (ManualInput
&& IntInput
) {
752 // In Manual input mode, check whether input the negative flag.
754 if (Key
.UnicodeChar
== '-') {
759 PrintCharAt (Column
++, Row
, Key
.UnicodeChar
);
762 if (Key
.UnicodeChar
== '+') {
763 Key
.ScanCode
= SCAN_RIGHT
;
765 Key
.ScanCode
= SCAN_LEFT
;
767 Key
.UnicodeChar
= CHAR_NULL
;
773 switch (Key
.ScanCode
) {
776 if (DateOrTime
&& !ManualInput
) {
778 // By setting this value, we will return back to the caller.
779 // We need to do this since an auto-refresh will destroy the adjustment
780 // based on what the real-time-clock is showing. So we always commit
781 // upon changing the value.
783 gDirection
= SCAN_DOWN
;
786 if ((Step
!= 0) && !ManualInput
) {
787 if (Key
.ScanCode
== SCAN_LEFT
) {
789 if ((INT64
) EditValue
>= (INT64
) Minimum
+ (INT64
) Step
) {
790 EditValue
= EditValue
- Step
;
791 } else if ((INT64
) EditValue
> (INT64
) Minimum
){
797 if (EditValue
>= Minimum
+ Step
) {
798 EditValue
= EditValue
- Step
;
799 } else if (EditValue
> Minimum
){
805 } else if (Key
.ScanCode
== SCAN_RIGHT
) {
807 if ((INT64
) EditValue
+ (INT64
) Step
<= (INT64
) Maximum
) {
808 EditValue
= EditValue
+ Step
;
809 } else if ((INT64
) EditValue
< (INT64
) Maximum
) {
815 if (EditValue
+ Step
<= Maximum
) {
816 EditValue
= EditValue
+ Step
;
817 } else if (EditValue
< Maximum
) {
825 ZeroMem (FormattedNumber
, 21 * sizeof (CHAR16
));
826 if (Question
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) {
827 if (MenuOption
->Sequence
== 2) {
831 UnicodeSPrint (FormattedNumber
, 21 * sizeof (CHAR16
), L
"%04d", (UINT16
) EditValue
);
836 UnicodeSPrint (FormattedNumber
, 21 * sizeof (CHAR16
), L
"%02d", (UINT8
) EditValue
);
839 if (MenuOption
->Sequence
== 0) {
840 ASSERT (EraseLen
>= 2);
841 FormattedNumber
[EraseLen
- 2] = DATE_SEPARATOR
;
842 } else if (MenuOption
->Sequence
== 1) {
843 ASSERT (EraseLen
>= 1);
844 FormattedNumber
[EraseLen
- 1] = DATE_SEPARATOR
;
846 } else if (Question
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
847 UnicodeSPrint (FormattedNumber
, 21 * sizeof (CHAR16
), L
"%02d", (UINT8
) EditValue
);
849 if (MenuOption
->Sequence
== 0) {
850 ASSERT (EraseLen
>= 2);
851 FormattedNumber
[EraseLen
- 2] = TIME_SEPARATOR
;
852 } else if (MenuOption
->Sequence
== 1) {
853 ASSERT (EraseLen
>= 1);
854 FormattedNumber
[EraseLen
- 1] = TIME_SEPARATOR
;
857 QuestionValue
->Value
.u64
= EditValue
;
858 PrintFormattedNumber (Question
, FormattedNumber
, 21 * sizeof (CHAR16
));
861 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
862 for (Loop
= 0; Loop
< EraseLen
; Loop
++) {
863 PrintStringAt (MenuOption
->OptCol
+ Loop
, MenuOption
->Row
, L
" ");
865 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetHighlightTextColor ());
867 if (MenuOption
->Sequence
== 0) {
868 PrintCharAt (MenuOption
->OptCol
, Row
, LEFT_NUMERIC_DELIMITER
);
869 Column
= MenuOption
->OptCol
+ 1;
872 PrintStringAt (Column
, Row
, FormattedNumber
);
874 if (!DateOrTime
|| MenuOption
->Sequence
== 2) {
875 PrintCharAt ((UINTN
)-1, (UINTN
)-1, RIGHT_NUMERIC_DELIMITER
);
879 goto EnterCarriageReturn
;
883 goto EnterCarriageReturn
;
886 return EFI_DEVICE_ERROR
;
896 case CHAR_CARRIAGE_RETURN
:
898 // Validate input value with Minimum value.
900 ValidateFail
= FALSE
;
903 // After user input Enter, need to check whether the input value.
904 // If input a negative value, should compare with maximum value.
905 // else compare with the minimum value.
908 ValidateFail
= (INT64
) EditValue
> (INT64
) Maximum
? TRUE
: FALSE
;
910 ValidateFail
= (INT64
) EditValue
< (INT64
) Minimum
? TRUE
: FALSE
;
914 UpdateStatusBar (INPUT_ERROR
, TRUE
);
917 } else if (EditValue
< Minimum
) {
918 UpdateStatusBar (INPUT_ERROR
, TRUE
);
922 UpdateStatusBar (INPUT_ERROR
, FALSE
);
923 CopyMem (&gUserInput
->InputValue
, &Question
->CurrentValue
, sizeof (EFI_HII_VALUE
));
924 QuestionValue
= &gUserInput
->InputValue
;
926 // Store Edit value back to Question
928 if (Question
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) {
929 switch (MenuOption
->Sequence
) {
931 QuestionValue
->Value
.date
.Month
= (UINT8
) EditValue
;
935 QuestionValue
->Value
.date
.Day
= (UINT8
) EditValue
;
939 QuestionValue
->Value
.date
.Year
= (UINT16
) EditValue
;
945 } else if (Question
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
946 switch (MenuOption
->Sequence
) {
948 QuestionValue
->Value
.time
.Hour
= (UINT8
) EditValue
;
952 QuestionValue
->Value
.time
.Minute
= (UINT8
) EditValue
;
956 QuestionValue
->Value
.time
.Second
= (UINT8
) EditValue
;
966 QuestionValue
->Value
.u64
= EditValue
;
970 // Adjust the value to the correct one.
971 // Sample like: 2012.02.29 -> 2013.02.29 -> 2013.02.01
972 // 2013.03.29 -> 2013.02.29 -> 2013.02.28
974 if (Question
->OpCode
->OpCode
== EFI_IFR_DATE_OP
&&
975 (MenuOption
->Sequence
== 0 || MenuOption
->Sequence
== 2)) {
976 AdjustQuestionValue (QuestionValue
, (UINT8
)MenuOption
->Sequence
);
987 PrintStringAt (Column
, Row
, L
" ");
992 // Remove a character
994 EditValue
= PreviousNumber
[Count
- 1];
995 UpdateStatusBar (INPUT_ERROR
, FALSE
);
998 PrintStringAt (Column
, Row
, L
" ");
1005 if ((Key
.UnicodeChar
>= L
'0') && (Key
.UnicodeChar
<= L
'9')) {
1006 Digital
= (UINT8
) (Key
.UnicodeChar
- L
'0');
1007 } else if ((Key
.UnicodeChar
>= L
'A') && (Key
.UnicodeChar
<= L
'F')) {
1008 Digital
= (UINT8
) (Key
.UnicodeChar
- L
'A' + 0x0A);
1009 } else if ((Key
.UnicodeChar
>= L
'a') && (Key
.UnicodeChar
<= L
'f')) {
1010 Digital
= (UINT8
) (Key
.UnicodeChar
- L
'a' + 0x0A);
1012 UpdateStatusBar (INPUT_ERROR
, TRUE
);
1016 if (Key
.UnicodeChar
> L
'9' || Key
.UnicodeChar
< L
'0') {
1017 UpdateStatusBar (INPUT_ERROR
, TRUE
);
1023 // If Count exceed input width, there is no way more is valid
1025 if (Count
>= InputWidth
) {
1029 // Someone typed something valid!
1033 EditValue
= LShiftU64 (EditValue
, 4) + Digital
;
1034 } else if (IntInput
&& Negative
) {
1036 // Save the negative number.
1038 EditValue
= ~(MultU64x32 (~(EditValue
- 1), 10) + (Key
.UnicodeChar
- L
'0')) + 1;
1040 EditValue
= MultU64x32 (EditValue
, 10) + (Key
.UnicodeChar
- L
'0');
1044 EditValue
= Digital
;
1045 } else if (IntInput
&& Negative
) {
1047 // Save the negative number.
1049 EditValue
= ~(Key
.UnicodeChar
- L
'0') + 1;
1051 EditValue
= Key
.UnicodeChar
- L
'0';
1056 ValidateFail
= FALSE
;
1058 // When user input a new value, should check the current value.
1059 // If user input a negative value, should compare it with minimum
1060 // value, else compare it with maximum value.
1063 ValidateFail
= (INT64
) EditValue
< (INT64
) Minimum
? TRUE
: FALSE
;
1065 ValidateFail
= (INT64
) EditValue
> (INT64
) Maximum
? TRUE
: FALSE
;
1069 UpdateStatusBar (INPUT_ERROR
, TRUE
);
1070 ASSERT (Count
< ARRAY_SIZE (PreviousNumber
));
1071 EditValue
= PreviousNumber
[Count
];
1075 if (EditValue
> Maximum
) {
1076 UpdateStatusBar (INPUT_ERROR
, TRUE
);
1077 ASSERT (Count
< ARRAY_SIZE (PreviousNumber
));
1078 EditValue
= PreviousNumber
[Count
];
1083 UpdateStatusBar (INPUT_ERROR
, FALSE
);
1086 ASSERT (Count
< (ARRAY_SIZE (PreviousNumber
)));
1087 PreviousNumber
[Count
] = EditValue
;
1089 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetHighlightTextColor ());
1090 PrintCharAt (Column
, Row
, Key
.UnicodeChar
);
1099 Adjust option order base on the question value.
1101 @param Question Pointer to current question.
1102 @param PopUpMenuLines The line number of the pop up menu.
1104 @retval EFI_SUCCESS If Option input is processed successfully
1105 @retval EFI_DEVICE_ERROR If operation fails
1110 IN FORM_DISPLAY_ENGINE_STATEMENT
*Question
,
1111 OUT UINTN
*PopUpMenuLines
1115 EFI_IFR_ORDERED_LIST
*OrderList
;
1119 DISPLAY_QUESTION_OPTION
*OneOfOption
;
1120 EFI_HII_VALUE
*HiiValueArray
;
1122 Link
= GetFirstNode (&Question
->OptionListHead
);
1123 OneOfOption
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1124 ValueArray
= Question
->CurrentValue
.Buffer
;
1125 ValueType
= OneOfOption
->OptionOpCode
->Type
;
1126 OrderList
= (EFI_IFR_ORDERED_LIST
*) Question
->OpCode
;
1128 for (Index
= 0; Index
< OrderList
->MaxContainers
; Index
++) {
1129 if (GetArrayData (ValueArray
, ValueType
, Index
) == 0) {
1134 *PopUpMenuLines
= Index
;
1137 // Prepare HiiValue array
1139 HiiValueArray
= AllocateZeroPool (*PopUpMenuLines
* sizeof (EFI_HII_VALUE
));
1140 ASSERT (HiiValueArray
!= NULL
);
1142 for (Index
= 0; Index
< *PopUpMenuLines
; Index
++) {
1143 HiiValueArray
[Index
].Type
= ValueType
;
1144 HiiValueArray
[Index
].Value
.u64
= GetArrayData (ValueArray
, ValueType
, Index
);
1147 for (Index
= 0; Index
< *PopUpMenuLines
; Index
++) {
1148 OneOfOption
= ValueToOption (Question
, &HiiValueArray
[*PopUpMenuLines
- Index
- 1]);
1149 if (OneOfOption
== NULL
) {
1150 return EFI_NOT_FOUND
;
1153 RemoveEntryList (&OneOfOption
->Link
);
1158 InsertHeadList (&Question
->OptionListHead
, &OneOfOption
->Link
);
1161 FreePool (HiiValueArray
);
1167 Base on the type to compare the value.
1169 @param Value1 The first value need to compare.
1170 @param Value2 The second value need to compare.
1171 @param Type The value type for above two values.
1173 @retval TRUE The two value are same.
1174 @retval FALSE The two value are different.
1179 IN EFI_IFR_TYPE_VALUE
*Value1
,
1180 IN EFI_IFR_TYPE_VALUE
*Value2
,
1185 case EFI_IFR_TYPE_BOOLEAN
:
1186 case EFI_IFR_TYPE_NUM_SIZE_8
:
1187 return (BOOLEAN
) (Value1
->u8
== Value2
->u8
);
1189 case EFI_IFR_TYPE_NUM_SIZE_16
:
1190 return (BOOLEAN
) (Value1
->u16
== Value2
->u16
);
1192 case EFI_IFR_TYPE_NUM_SIZE_32
:
1193 return (BOOLEAN
) (Value1
->u32
== Value2
->u32
);
1195 case EFI_IFR_TYPE_NUM_SIZE_64
:
1196 return (BOOLEAN
) (Value1
->u64
== Value2
->u64
);
1205 Base on the type to set the value.
1207 @param Dest The dest value.
1208 @param Source The source value.
1209 @param Type The value type for above two values.
1214 OUT EFI_IFR_TYPE_VALUE
*Dest
,
1215 IN EFI_IFR_TYPE_VALUE
*Source
,
1220 case EFI_IFR_TYPE_BOOLEAN
:
1221 Dest
->b
= Source
->b
;
1224 case EFI_IFR_TYPE_NUM_SIZE_8
:
1225 Dest
->u8
= Source
->u8
;
1228 case EFI_IFR_TYPE_NUM_SIZE_16
:
1229 Dest
->u16
= Source
->u16
;
1232 case EFI_IFR_TYPE_NUM_SIZE_32
:
1233 Dest
->u32
= Source
->u32
;
1236 case EFI_IFR_TYPE_NUM_SIZE_64
:
1237 Dest
->u64
= Source
->u64
;
1247 Get selection for OneOf and OrderedList (Left/Right will be ignored).
1249 @param MenuOption Pointer to the current input menu.
1251 @retval EFI_SUCCESS If Option input is processed successfully
1252 @retval EFI_DEVICE_ERROR If operation fails
1256 GetSelectionInputPopUp (
1257 IN UI_MENU_OPTION
*MenuOption
1263 CHAR16
*TempStringPtr
;
1265 UINTN TopOptionIndex
;
1266 UINTN HighlightOptionIndex
;
1271 UINTN PopUpMenuLines
;
1272 UINTN MenuLinesInView
;
1275 INT32 SavedAttribute
;
1276 BOOLEAN ShowDownArrow
;
1277 BOOLEAN ShowUpArrow
;
1278 UINTN DimensionsWidth
;
1280 BOOLEAN OrderedList
;
1284 EFI_HII_VALUE HiiValue
;
1285 DISPLAY_QUESTION_OPTION
*OneOfOption
;
1286 DISPLAY_QUESTION_OPTION
*CurrentOption
;
1287 FORM_DISPLAY_ENGINE_STATEMENT
*Question
;
1289 EFI_IFR_ORDERED_LIST
*OrderList
;
1291 DimensionsWidth
= gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
;
1295 CurrentOption
= NULL
;
1296 ShowDownArrow
= FALSE
;
1297 ShowUpArrow
= FALSE
;
1299 ZeroMem (&HiiValue
, sizeof (EFI_HII_VALUE
));
1301 Question
= MenuOption
->ThisTag
;
1302 if (Question
->OpCode
->OpCode
== EFI_IFR_ORDERED_LIST_OP
) {
1303 Link
= GetFirstNode (&Question
->OptionListHead
);
1304 OneOfOption
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1305 ValueArray
= Question
->CurrentValue
.Buffer
;
1306 ValueType
= OneOfOption
->OptionOpCode
->Type
;
1308 OrderList
= (EFI_IFR_ORDERED_LIST
*) Question
->OpCode
;
1310 OrderedList
= FALSE
;
1315 // Calculate Option count
1319 AdjustOptionOrder(Question
, &PopUpMenuLines
);
1321 Link
= GetFirstNode (&Question
->OptionListHead
);
1322 while (!IsNull (&Question
->OptionListHead
, Link
)) {
1323 OneOfOption
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1325 Link
= GetNextNode (&Question
->OptionListHead
, Link
);
1330 // Get the number of one of options present and its size
1333 HighlightOptionIndex
= 0;
1334 Link
= GetFirstNode (&Question
->OptionListHead
);
1335 for (Index
= 0; Index
< PopUpMenuLines
; Index
++) {
1336 OneOfOption
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1338 StringPtr
= GetToken (OneOfOption
->OptionOpCode
->Option
, gFormData
->HiiHandle
);
1339 if (StrLen (StringPtr
) > PopUpWidth
) {
1340 PopUpWidth
= StrLen (StringPtr
);
1342 FreePool (StringPtr
);
1343 HiiValue
.Type
= OneOfOption
->OptionOpCode
->Type
;
1344 SetValuesByType (&HiiValue
.Value
, &OneOfOption
->OptionOpCode
->Value
, HiiValue
.Type
);
1345 if (!OrderedList
&& (CompareHiiValue (&Question
->CurrentValue
, &HiiValue
, &Result
, NULL
) == EFI_SUCCESS
) && (Result
== 0)) {
1347 // Find current selected Option for OneOf
1349 HighlightOptionIndex
= Index
;
1352 Link
= GetNextNode (&Question
->OptionListHead
, Link
);
1356 // Perform popup menu initialization.
1358 PopUpWidth
= PopUpWidth
+ POPUP_PAD_SPACE_COUNT
;
1360 SavedAttribute
= gST
->ConOut
->Mode
->Attribute
;
1361 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetPopupColor ());
1363 if ((PopUpWidth
+ POPUP_FRAME_WIDTH
) > DimensionsWidth
) {
1364 PopUpWidth
= DimensionsWidth
- POPUP_FRAME_WIDTH
;
1367 Start
= (DimensionsWidth
- PopUpWidth
- POPUP_FRAME_WIDTH
) / 2 + gStatementDimensions
.LeftColumn
;
1368 End
= Start
+ PopUpWidth
+ POPUP_FRAME_WIDTH
;
1369 Top
= gStatementDimensions
.TopRow
;
1370 Bottom
= gStatementDimensions
.BottomRow
- 1;
1372 MenuLinesInView
= Bottom
- Top
- 1;
1373 if (MenuLinesInView
>= PopUpMenuLines
) {
1374 Top
= Top
+ (MenuLinesInView
- PopUpMenuLines
) / 2;
1375 Bottom
= Top
+ PopUpMenuLines
+ 1;
1377 ShowDownArrow
= TRUE
;
1380 if (HighlightOptionIndex
> (MenuLinesInView
- 1)) {
1381 TopOptionIndex
= HighlightOptionIndex
- MenuLinesInView
+ 1;
1388 // Clear that portion of the screen
1390 ClearLines (Start
, End
, Top
, Bottom
, GetPopupColor ());
1393 // Draw "One of" pop-up menu
1395 Character
= BOXDRAW_DOWN_RIGHT
;
1396 PrintCharAt (Start
, Top
, Character
);
1397 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
1398 if ((ShowUpArrow
) && ((Index
+ 1) == (Start
+ End
) / 2)) {
1399 Character
= GEOMETRICSHAPE_UP_TRIANGLE
;
1401 Character
= BOXDRAW_HORIZONTAL
;
1404 PrintCharAt ((UINTN
)-1, (UINTN
)-1, Character
);
1407 Character
= BOXDRAW_DOWN_LEFT
;
1408 PrintCharAt ((UINTN
)-1, (UINTN
)-1, Character
);
1409 Character
= BOXDRAW_VERTICAL
;
1410 for (Index
= Top
+ 1; Index
< Bottom
; Index
++) {
1411 PrintCharAt (Start
, Index
, Character
);
1412 PrintCharAt (End
- 1, Index
, Character
);
1416 // Move to top Option
1418 Link
= GetFirstNode (&Question
->OptionListHead
);
1419 for (Index
= 0; Index
< TopOptionIndex
; Index
++) {
1420 Link
= GetNextNode (&Question
->OptionListHead
, Link
);
1424 // Display the One of options
1427 for (Index
= TopOptionIndex
; (Index
< PopUpMenuLines
) && (Index2
< Bottom
); Index
++) {
1428 OneOfOption
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1429 Link
= GetNextNode (&Question
->OptionListHead
, Link
);
1431 StringPtr
= GetToken (OneOfOption
->OptionOpCode
->Option
, gFormData
->HiiHandle
);
1432 ASSERT (StringPtr
!= NULL
);
1434 // If the string occupies multiple lines, truncate it to fit in one line,
1435 // and append a "..." for indication.
1437 if (StrLen (StringPtr
) > (PopUpWidth
- 1)) {
1438 TempStringPtr
= AllocateZeroPool (sizeof (CHAR16
) * (PopUpWidth
- 1));
1439 ASSERT ( TempStringPtr
!= NULL
);
1440 CopyMem (TempStringPtr
, StringPtr
, (sizeof (CHAR16
) * (PopUpWidth
- 5)));
1441 FreePool (StringPtr
);
1442 StringPtr
= TempStringPtr
;
1443 StrCatS (StringPtr
, PopUpWidth
- 1, L
"...");
1446 if (Index
== HighlightOptionIndex
) {
1448 // Highlight the selected one
1450 CurrentOption
= OneOfOption
;
1452 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetPickListColor ());
1453 PrintStringAt (Start
+ 2, Index2
, StringPtr
);
1454 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetPopupColor ());
1456 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetPopupColor ());
1457 PrintStringAt (Start
+ 2, Index2
, StringPtr
);
1461 FreePool (StringPtr
);
1464 Character
= BOXDRAW_UP_RIGHT
;
1465 PrintCharAt (Start
, Bottom
, Character
);
1466 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
1467 if ((ShowDownArrow
) && ((Index
+ 1) == (Start
+ End
) / 2)) {
1468 Character
= GEOMETRICSHAPE_DOWN_TRIANGLE
;
1470 Character
= BOXDRAW_HORIZONTAL
;
1473 PrintCharAt ((UINTN
)-1, (UINTN
)-1, Character
);
1476 Character
= BOXDRAW_UP_LEFT
;
1477 PrintCharAt ((UINTN
)-1, (UINTN
)-1, Character
);
1480 // Get User selection
1482 Key
.UnicodeChar
= CHAR_NULL
;
1483 if ((gDirection
== SCAN_UP
) || (gDirection
== SCAN_DOWN
)) {
1484 Key
.ScanCode
= gDirection
;
1489 WaitForKeyStroke (&Key
);
1492 switch (Key
.UnicodeChar
) {
1495 if ((TopOptionIndex
> 0) && (TopOptionIndex
== HighlightOptionIndex
)) {
1497 // Highlight reaches the top of the popup window, scroll one menu item.
1500 ShowDownArrow
= TRUE
;
1503 if (TopOptionIndex
== 0) {
1504 ShowUpArrow
= FALSE
;
1507 if (HighlightOptionIndex
> 0) {
1508 HighlightOptionIndex
--;
1510 ASSERT (CurrentOption
!= NULL
);
1511 SwapListEntries (CurrentOption
->Link
.BackLink
, &CurrentOption
->Link
);
1518 // If an ordered list op-code, we will allow for a popup of +/- keys
1519 // to create an ordered list of items
1522 if (((TopOptionIndex
+ MenuLinesInView
) < PopUpMenuLines
) &&
1523 (HighlightOptionIndex
== (TopOptionIndex
+ MenuLinesInView
- 1))) {
1525 // Highlight reaches the bottom of the popup window, scroll one menu item.
1531 if ((TopOptionIndex
+ MenuLinesInView
) == PopUpMenuLines
) {
1532 ShowDownArrow
= FALSE
;
1535 if (HighlightOptionIndex
< (PopUpMenuLines
- 1)) {
1536 HighlightOptionIndex
++;
1538 ASSERT (CurrentOption
!= NULL
);
1539 SwapListEntries (&CurrentOption
->Link
, CurrentOption
->Link
.ForwardLink
);
1545 switch (Key
.ScanCode
) {
1548 if (Key
.ScanCode
== SCAN_UP
) {
1549 if ((TopOptionIndex
> 0) && (TopOptionIndex
== HighlightOptionIndex
)) {
1551 // Highlight reaches the top of the popup window, scroll one menu item.
1554 ShowDownArrow
= TRUE
;
1557 if (TopOptionIndex
== 0) {
1558 ShowUpArrow
= FALSE
;
1561 if (HighlightOptionIndex
> 0) {
1562 HighlightOptionIndex
--;
1565 if (((TopOptionIndex
+ MenuLinesInView
) < PopUpMenuLines
) &&
1566 (HighlightOptionIndex
== (TopOptionIndex
+ MenuLinesInView
- 1))) {
1568 // Highlight reaches the bottom of the popup window, scroll one menu item.
1574 if ((TopOptionIndex
+ MenuLinesInView
) == PopUpMenuLines
) {
1575 ShowDownArrow
= FALSE
;
1578 if (HighlightOptionIndex
< (PopUpMenuLines
- 1)) {
1579 HighlightOptionIndex
++;
1585 gST
->ConOut
->SetAttribute (gST
->ConOut
, SavedAttribute
);
1588 // Restore link list order for orderedlist
1591 HiiValue
.Type
= ValueType
;
1592 HiiValue
.Value
.u64
= 0;
1593 for (Index
= 0; Index
< OrderList
->MaxContainers
; Index
++) {
1594 HiiValue
.Value
.u64
= GetArrayData (ValueArray
, ValueType
, Index
);
1595 if (HiiValue
.Value
.u64
== 0) {
1599 OneOfOption
= ValueToOption (Question
, &HiiValue
);
1600 if (OneOfOption
== NULL
) {
1601 return EFI_NOT_FOUND
;
1604 RemoveEntryList (&OneOfOption
->Link
);
1605 InsertTailList (&Question
->OptionListHead
, &OneOfOption
->Link
);
1609 return EFI_DEVICE_ERROR
;
1617 case CHAR_CARRIAGE_RETURN
:
1619 // return the current selection
1622 ReturnValue
= AllocateZeroPool (Question
->CurrentValue
.BufferLen
);
1623 ASSERT (ReturnValue
!= NULL
);
1625 Link
= GetFirstNode (&Question
->OptionListHead
);
1626 while (!IsNull (&Question
->OptionListHead
, Link
)) {
1627 OneOfOption
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1628 Link
= GetNextNode (&Question
->OptionListHead
, Link
);
1630 SetArrayData (ReturnValue
, ValueType
, Index
, OneOfOption
->OptionOpCode
->Value
.u64
);
1633 if (Index
> OrderList
->MaxContainers
) {
1637 if (CompareMem (ReturnValue
, ValueArray
, Question
->CurrentValue
.BufferLen
) == 0) {
1638 FreePool (ReturnValue
);
1639 return EFI_DEVICE_ERROR
;
1641 gUserInput
->InputValue
.Buffer
= ReturnValue
;
1642 gUserInput
->InputValue
.BufferLen
= Question
->CurrentValue
.BufferLen
;
1645 ASSERT (CurrentOption
!= NULL
);
1646 gUserInput
->InputValue
.Type
= CurrentOption
->OptionOpCode
->Type
;
1647 if (IsValuesEqual (&Question
->CurrentValue
.Value
, &CurrentOption
->OptionOpCode
->Value
, gUserInput
->InputValue
.Type
)) {
1648 return EFI_DEVICE_ERROR
;
1650 SetValuesByType (&gUserInput
->InputValue
.Value
, &CurrentOption
->OptionOpCode
->Value
, gUserInput
->InputValue
.Type
);
1654 gST
->ConOut
->SetAttribute (gST
->ConOut
, SavedAttribute
);