3 Copyright (c) 2006 - 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 Implementation for handling user input from the User Interface
25 // Include common header file for this module.
27 #include "CommonHeader.h"
33 #define EFI_MAX(_a, _b) ((_a) > (_b) ? (_a) : (_b))
37 IN UI_MENU_OPTION
*MenuOption
,
48 BOOLEAN SelectionComplete
;
50 CHAR16
*BufferedString
;
55 CHAR16
*PromptForDataString
;
56 UINTN DimensionsWidth
;
57 UINTN DimensionsHeight
;
58 BOOLEAN CursorVisible
;
60 DimensionsWidth
= gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
;
61 DimensionsHeight
= gScreenDimensions
.BottomRow
- gScreenDimensions
.TopRow
;
63 PromptForDataString
= GetToken (STRING_TOKEN (PROMPT_FOR_DATA
), gHiiHandle
);
65 NullCharacter
= CHAR_NULL
;
66 ScreenSize
= GetStringWidth (PromptForDataString
) / 2;
67 Tag
= MenuOption
->ThisTag
;
70 SelectionComplete
= FALSE
;
72 TempString
= AllocateZeroPool (MenuOption
->ThisTag
->Maximum
* 2);
75 if (ScreenSize
< (Tag
->Maximum
/ (UINTN
) 2)) {
76 ScreenSize
= Tag
->Maximum
/ 2;
79 if ((ScreenSize
+ 2) > DimensionsWidth
) {
80 ScreenSize
= DimensionsWidth
- 2;
83 BufferedString
= AllocateZeroPool (ScreenSize
* 2);
84 ASSERT (BufferedString
);
86 Start
= (DimensionsWidth
- ScreenSize
- 2) / 2 + gScreenDimensions
.LeftColumn
+ 1;
87 Top
= ((DimensionsHeight
- 6) / 2) + gScreenDimensions
.TopRow
- 1;
90 // Display prompt for string
92 CreatePopUp (ScreenSize
, 4, &NullCharacter
, PromptForDataString
, Space
, &NullCharacter
);
94 FreePool (PromptForDataString
);
96 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_BLACK
, EFI_LIGHTGRAY
));
98 CursorVisible
= gST
->ConOut
->Mode
->CursorVisible
;
99 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
102 Status
= WaitForKeyStroke (&Key
);
104 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_BLACK
, EFI_LIGHTGRAY
));
105 switch (Key
.UnicodeChar
) {
107 switch (Key
.ScanCode
) {
115 FreePool (TempString
);
116 FreePool (BufferedString
);
117 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
118 gST
->ConOut
->EnableCursor (gST
->ConOut
, CursorVisible
);
119 return EFI_DEVICE_ERROR
;
127 case CHAR_CARRIAGE_RETURN
:
128 if (GetStringWidth (StringPtr
) >= MenuOption
->ThisTag
->Minimum
) {
129 SelectionComplete
= TRUE
;
130 FreePool (TempString
);
131 FreePool (BufferedString
);
132 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
133 gST
->ConOut
->EnableCursor (gST
->ConOut
, CursorVisible
);
136 ScreenSize
= GetStringWidth (gMiniString
) / 2;
137 CreatePopUp (ScreenSize
, 4, &NullCharacter
, gMiniString
, gPressEnter
, &NullCharacter
);
139 // Simply create a popup to tell the user that they had typed in too few characters.
140 // To save code space, we can then treat this as an error and return back to the menu.
143 Status
= WaitForKeyStroke (&Key
);
144 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
145 FreePool (TempString
);
146 FreePool (BufferedString
);
147 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
148 gST
->ConOut
->EnableCursor (gST
->ConOut
, CursorVisible
);
149 return EFI_DEVICE_ERROR
;
155 if (StringPtr
[0] != CHAR_NULL
) {
156 for (Index
= 0; StringPtr
[Index
] != CHAR_NULL
; Index
++) {
157 TempString
[Index
] = StringPtr
[Index
];
160 // Effectively truncate string by 1 character
162 TempString
[Index
- 1] = CHAR_NULL
;
163 StrCpy (StringPtr
, TempString
);
168 // If it is the beginning of the string, don't worry about checking maximum limits
170 if ((StringPtr
[0] == CHAR_NULL
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
171 StrnCpy (StringPtr
, &Key
.UnicodeChar
, 1);
172 StrnCpy (TempString
, &Key
.UnicodeChar
, 1);
173 } else if ((GetStringWidth (StringPtr
) < MenuOption
->ThisTag
->Maximum
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
174 KeyPad
[0] = Key
.UnicodeChar
;
175 KeyPad
[1] = CHAR_NULL
;
176 StrCat (StringPtr
, KeyPad
);
177 StrCat (TempString
, KeyPad
);
180 // If the width of the input string is now larger than the screen, we nee to
181 // adjust the index to start printing portions of the string
183 SetUnicodeMem (BufferedString
, ScreenSize
- 1, L
' ');
185 PrintStringAt (Start
+ 1, Top
+ 3, BufferedString
);
187 if ((GetStringWidth (StringPtr
) / 2) > (DimensionsWidth
- 2)) {
188 Index
= (GetStringWidth (StringPtr
) / 2) - DimensionsWidth
+ 2;
193 for (Count
= 0; Index
+ 1 < GetStringWidth (StringPtr
) / 2; Index
++, Count
++) {
194 BufferedString
[Count
] = StringPtr
[Index
];
197 PrintStringAt (Start
+ 1, Top
+ 3, BufferedString
);
201 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
202 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, Start
+ GetStringWidth (StringPtr
) / 2, Top
+ 3);
203 } while (!SelectionComplete
);
204 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
205 gST
->ConOut
->EnableCursor (gST
->ConOut
, CursorVisible
);
211 IN UI_MENU_OPTION
*MenuOption
,
212 IN BOOLEAN PromptForPassword
,
214 IN EFI_IFR_DATA_ARRAY
*PageData
,
215 IN BOOLEAN SecondEntry
,
216 IN EFI_FILE_FORM_TAGS
*FileFormTags
,
217 OUT CHAR16
*StringPtr
222 CHAR16 NullCharacter
;
231 BOOLEAN Confirmation
;
232 BOOLEAN ConfirmationComplete
;
233 EFI_HII_CALLBACK_PACKET
*Packet
;
234 EFI_FORM_CALLBACK_PROTOCOL
*FormCallback
;
235 EFI_VARIABLE_DEFINITION
*VariableDefinition
;
236 UINTN DimensionsWidth
;
237 UINTN DimensionsHeight
;
238 EFI_IFR_DATA_ENTRY
*DataEntry
;
241 DimensionsWidth
= gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
;
242 DimensionsHeight
= gScreenDimensions
.BottomRow
- gScreenDimensions
.TopRow
;
244 VariableDefinition
= NULL
;
245 NullCharacter
= CHAR_NULL
;
247 Space
[1] = CHAR_NULL
;
248 Confirmation
= FALSE
;
249 ConfirmationComplete
= FALSE
;
250 Status
= EFI_SUCCESS
;
255 // Remember that dynamic pages in an environment where all pages are not
256 // dynamic require us to call back to the user to give them an opportunity
257 // to register fresh information in the HII database so that we can extract it.
259 Status
= gBS
->HandleProtocol (
260 (VOID
*) (UINTN
) MenuOption
->Tags
[0].CallbackHandle
,
261 &gEfiFormCallbackProtocolGuid
,
262 (VOID
**) &FormCallback
265 TempString
= AllocateZeroPool (MenuOption
->ThisTag
->Maximum
* 2);
266 TempString2
= AllocateZeroPool (MenuOption
->ThisTag
->Maximum
* 2);
269 ASSERT (TempString2
);
271 if (Tag
->Flags
& EFI_IFR_FLAG_INTERACTIVE
) {
273 // Password requires a callback to determine if a password exists
275 DataEntry
= (EFI_IFR_DATA_ENTRY
*) (PageData
+ 1);
276 DataEntry
->OpCode
= EFI_IFR_PASSWORD_OP
;
277 DataEntry
->Length
= 3;
279 ExtractRequestedNvMap (FileFormTags
, Tag
->VariableNumber
, &VariableDefinition
);
282 // The user is about to be prompted with a password field, Data = 0 (Return Status determines the type of prompt)
284 DataEntry
->Data
= (VOID
*) (UINTN
) (UINT8
) (0 + SecondEntry
* 2);
285 PageData
->NvRamMap
= VariableDefinition
->NvRamMap
;
287 if ((FormCallback
!= NULL
) && (FormCallback
->Callback
!= NULL
)) {
288 Status
= FormCallback
->Callback (
296 // If error on return, continue with the reading of a typed in password to verify user knows password
297 // If no error, there is no password set, so prompt for new password
298 // if the previous callback was to verify the user knew password, and user typed it correctly - should return no error
300 if (!EFI_ERROR (Status
)) {
301 PromptForPassword
= FALSE
;
304 // Simulate this as the second entry into this routine for an interactive behavior
307 } else if (Status
== EFI_NOT_READY
) {
309 if (Packet
!= NULL
) {
311 // Upon error, we will likely receive a string to print out
312 // Display error popup
314 WidthOfString
= GetStringWidth (Packet
->String
);
315 ScreenSize
= EFI_MAX(WidthOfString
, GetStringWidth (gPressEnter
)) / 2;
316 CreatePopUp (ScreenSize
, 4, &NullCharacter
, Packet
->String
, gPressEnter
, &NullCharacter
);
320 Status
= WaitForKeyStroke (&Key
);
321 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
324 Status
= EFI_NOT_READY
;
331 // Display PopUp Screen
333 ScreenSize
= GetStringWidth (gPromptForNewPassword
) / 2;
334 if (GetStringWidth (gConfirmPassword
) / 2 > ScreenSize
) {
335 ScreenSize
= GetStringWidth (gConfirmPassword
) / 2;
338 Start
= (DimensionsWidth
- ScreenSize
- 4) / 2 + gScreenDimensions
.LeftColumn
+ 2;
339 Top
= ((DimensionsHeight
- 6) / 2) + gScreenDimensions
.TopRow
- 1;
342 if (PromptForPassword
) {
343 CreatePopUp (ScreenSize
, 4, &NullCharacter
, gPromptForPassword
, Space
, &NullCharacter
);
345 CreatePopUp (ScreenSize
, 4, &NullCharacter
, gPromptForNewPassword
, Space
, &NullCharacter
);
348 CreatePopUp (ScreenSize
, 4, &NullCharacter
, gConfirmPassword
, Space
, &NullCharacter
);
349 StringPtr
[0] = CHAR_NULL
;
353 Status
= WaitForKeyStroke (&Key
);
355 switch (Key
.UnicodeChar
) {
357 if (Key
.ScanCode
== SCAN_ESC
) {
358 return EFI_NOT_READY
;
361 ConfirmationComplete
= FALSE
;
364 case CHAR_CARRIAGE_RETURN
:
365 if (Tag
->Flags
& EFI_IFR_FLAG_INTERACTIVE
) {
367 // User just typed a string in
369 DataEntry
= (EFI_IFR_DATA_ENTRY
*) (PageData
+ 1);
370 DataEntry
->OpCode
= EFI_IFR_PASSWORD_OP
;
373 // If the user just typed in a password, Data = 1
374 // If the user just typed in a password to confirm the previous password, Data = 2
377 DataEntry
->Length
= 3;
378 DataEntry
->Data
= (VOID
*) (UINTN
) (UINT8
) (1 + SecondEntry
* 2);
380 if ((FormCallback
!= NULL
) && (FormCallback
->Callback
!= NULL
)) {
381 Status
= FormCallback
->Callback (
389 DataEntry
->Length
= sizeof (EFI_IFR_DATA_ENTRY
);
390 DataEntry
->Data
= (VOID
*) TempString
;
392 DataEntry
->Length
= 3;
393 DataEntry
->Data
= (VOID
*) (UINTN
) (UINT8
) (2 + SecondEntry
* 2);
395 if ((FormCallback
!= NULL
) && (FormCallback
->Callback
!= NULL
)) {
396 Status
= FormCallback
->Callback (
404 DataEntry
->Length
= sizeof (EFI_IFR_DATA_ENTRY
);
405 DataEntry
->Data
= (VOID
*) TempString2
;
408 if ((FormCallback
!= NULL
) && (FormCallback
->Callback
!= NULL
)) {
409 Status
= FormCallback
->Callback (
417 // If this was the confirmation round of callbacks
418 // and an error comes back, display an error
421 if (EFI_ERROR (Status
)) {
422 if (Packet
->String
== NULL
) {
423 WidthOfString
= GetStringWidth (gConfirmError
);
424 ScreenSize
= EFI_MAX (WidthOfString
, GetStringWidth (gPressEnter
)) / 2;
425 CreatePopUp (ScreenSize
, 4, &NullCharacter
, gConfirmError
, gPressEnter
, &NullCharacter
);
427 WidthOfString
= GetStringWidth (Packet
->String
);
428 ScreenSize
= EFI_MAX (WidthOfString
, GetStringWidth (gPressEnter
)) / 2;
429 CreatePopUp (ScreenSize
, 4, &NullCharacter
, Packet
->String
, gPressEnter
, &NullCharacter
);
433 StringPtr
[0] = CHAR_NULL
;
435 Status
= WaitForKeyStroke (&Key
);
437 if (Key
.UnicodeChar
== CHAR_CARRIAGE_RETURN
) {
438 Status
= EFI_NOT_READY
;
443 Status
= EFI_NOT_READY
;
448 // User typed a string in and it wasn't valid somehow from the callback
449 // For instance, callback may have said that some invalid characters were contained in the string
451 if (Status
== EFI_NOT_READY
) {
455 if (PromptForPassword
&& EFI_ERROR (Status
)) {
456 Status
= EFI_DEVICE_ERROR
;
464 // Compare tempstring and tempstring2, if the same, return with StringPtr success
465 // Otherwise, kick and error box, and return an error
467 if (StrCmp (TempString
, TempString2
) == 0) {
468 Status
= EFI_SUCCESS
;
471 WidthOfString
= GetStringWidth (gConfirmError
);
472 ScreenSize
= EFI_MAX (WidthOfString
, GetStringWidth (gPressEnter
)) / 2;
473 CreatePopUp (ScreenSize
, 4, &NullCharacter
, gConfirmError
, gPressEnter
, &NullCharacter
);
474 StringPtr
[0] = CHAR_NULL
;
476 Status
= WaitForKeyStroke (&Key
);
477 if (Key
.UnicodeChar
== CHAR_CARRIAGE_RETURN
) {
478 Status
= EFI_DEVICE_ERROR
;
485 if (PromptForPassword
) {
487 // I was asked for a password, return it back in StringPtr
489 Status
= EFI_SUCCESS
;
493 // If the two passwords were not the same kick an error popup
496 ConfirmationComplete
= TRUE
;
501 if (StringPtr
[0] != CHAR_NULL
) {
503 for (Index
= 0; StringPtr
[Index
] != CHAR_NULL
; Index
++) {
504 TempString
[Index
] = StringPtr
[Index
];
507 // Effectively truncate string by 1 character
509 TempString
[Index
- 1] = CHAR_NULL
;
510 StrCpy (StringPtr
, TempString
);
512 for (Index
= 0; StringPtr
[Index
] != CHAR_NULL
; Index
++) {
513 TempString2
[Index
] = StringPtr
[Index
];
516 // Effectively truncate string by 1 character
518 TempString2
[Index
- 1] = CHAR_NULL
;
519 StrCpy (StringPtr
, TempString2
);
522 ConfirmationComplete
= FALSE
;
524 ConfirmationComplete
= FALSE
;
528 // Must be a character we are interested in!
531 if ((StringPtr
[0] == CHAR_NULL
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
533 StrnCpy (StringPtr
, &Key
.UnicodeChar
, 1);
534 StrnCpy (TempString
, &Key
.UnicodeChar
, 1);
536 StrnCpy (StringPtr
, &Key
.UnicodeChar
, 1);
537 StrnCpy (TempString2
, &Key
.UnicodeChar
, 1);
538 ConfirmationComplete
= FALSE
;
540 } else if ((GetStringWidth (StringPtr
) / 2 <= (UINTN
) (MenuOption
->ThisTag
->Maximum
- 1) / 2) &&
541 (Key
.UnicodeChar
!= CHAR_BACKSPACE
)
543 KeyPad
[0] = Key
.UnicodeChar
;
544 KeyPad
[1] = CHAR_NULL
;
546 StrCat (StringPtr
, KeyPad
);
547 StrCat (TempString
, KeyPad
);
549 StrCat (StringPtr
, KeyPad
);
550 StrCat (TempString2
, KeyPad
);
554 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_BLACK
, EFI_LIGHTGRAY
));
555 for (Index
= 1; Index
< ScreenSize
; Index
++) {
556 PrintCharAt (Start
+ Index
, Top
+ 3, L
' ');
559 gST
->ConOut
->SetCursorPosition (
561 (DimensionsWidth
- GetStringWidth (StringPtr
) / 2) / 2 + gScreenDimensions
.LeftColumn
,
564 for (Index
= 0; Index
+ 1 < GetStringWidth (StringPtr
) / 2; Index
++) {
568 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
574 } while (!ConfirmationComplete
);
579 FreePool (TempString
);
580 FreePool (TempString2
);
595 Key
= (CHAR16
*) L
"MAR10648567";
596 Buffer
= AllocateZeroPool (MaxSize
);
600 for (Index
= 0; Key
[Index
] != 0; Index
++) {
601 for (Loop
= 0; Loop
< (UINT8
) (MaxSize
/ 2); Loop
++) {
602 Buffer
[Loop
] = (CHAR16
) (Password
[Loop
] ^ Key
[Index
]);
606 CopyMem (Password
, Buffer
, MaxSize
);
614 IN UI_MENU_OPTION
*MenuOption
,
615 IN EFI_FILE_FORM_TAGS
*FileFormTagsHead
,
616 IN BOOLEAN ManualInput
,
618 IN UINTN NumericType
,
625 This routine reads a numeric value from the user input.
629 MenuOption - Pointer to the current input menu.
631 FileFormTagsHead - Pointer to the root of formset.
633 ManualInput - If the input is manual or not.
635 Tag - Pointer to all the attributes and values associated with a tag.
637 Value - Pointer to the numeric value that is going to be read.
641 EFI_SUCCESS - If numerical input is read successfully
642 EFI_DEVICE_ERROR - If operation fails
647 BOOLEAN SelectionComplete
;
650 CHAR16 FormattedNumber
[6];
651 UINTN PreviousNumber
[6];
656 CHAR16 NullCharacter
;
658 EFI_FILE_FORM_TAGS
*FileFormTags
;
659 EFI_VARIABLE_DEFINITION
*VariableDefinition
;
662 NullCharacter
= CHAR_NULL
;
664 Column
= MenuOption
->OptCol
;
665 Row
= MenuOption
->Row
;
667 PreviousNumber
[0] = 0;
669 SelectionComplete
= FALSE
;
670 BackupValue
= Tag
->Value
;
671 FileFormTags
= FileFormTagsHead
;
674 PrintAt (Column
, Row
, (CHAR16
*) L
"[ ]");
676 if (Tag
->Operand
!= EFI_IFR_TIME_OP
) {
677 *Value
= BackupValue
;
681 // First time we enter this handler, we need to check to see if
682 // we were passed an increment or decrement directive
685 Key
.UnicodeChar
= CHAR_NULL
;
686 if (gDirection
!= 0) {
687 Key
.ScanCode
= gDirection
;
692 WaitForKeyStroke (&Key
);
695 switch (Key
.UnicodeChar
) {
698 if ((Tag
->Operand
== EFI_IFR_DATE_OP
) || (Tag
->Operand
== EFI_IFR_TIME_OP
)) {
699 Key
.UnicodeChar
= CHAR_NULL
;
700 if (Key
.UnicodeChar
== '+') {
701 Key
.ScanCode
= SCAN_RIGHT
;
703 Key
.ScanCode
= SCAN_LEFT
;
711 switch (Key
.ScanCode
) {
714 if ((Tag
->Operand
== EFI_IFR_DATE_OP
) || (Tag
->Operand
== EFI_IFR_TIME_OP
)) {
716 // By setting this value, we will return back to the caller.
717 // We need to do this since an auto-refresh will destroy the adjustment
718 // based on what the real-time-clock is showing. So we always commit
719 // upon changing the value.
721 gDirection
= SCAN_DOWN
;
726 if (Key
.ScanCode
== SCAN_LEFT
) {
727 Number
= *Value
- Tag
->Step
;
728 if (Number
< Tag
->Minimum
) {
729 Number
= Tag
->Minimum
;
731 } else if (Key
.ScanCode
== SCAN_RIGHT
) {
732 Number
= *Value
+ Tag
->Step
;
733 if (Number
> Tag
->Maximum
) {
734 Number
= Tag
->Maximum
;
738 Tag
->Value
= (UINT16
) Number
;
739 *Value
= (UINT16
) Number
;
740 UnicodeValueToString (
744 (sizeof (FormattedNumber
) / sizeof (FormattedNumber
[0]))
746 Number
= (UINT16
) GetStringWidth (FormattedNumber
);
748 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT
| FIELD_BACKGROUND
);
749 if ((Tag
->Operand
== EFI_IFR_DATE_OP
) || (Tag
->Operand
== EFI_IFR_TIME_OP
)) {
750 for (Loop
= 0; Loop
< (UINTN
) ((Number
>= 8) ? 4 : 2); Loop
++) {
751 PrintAt (MenuOption
->OptCol
+ Loop
, MenuOption
->Row
, (CHAR16
*) L
" ");
754 for (Loop
= 0; Loop
< gOptionBlockWidth
; Loop
++) {
755 PrintAt (MenuOption
->OptCol
+ Loop
, MenuOption
->Row
, (CHAR16
*) L
" ");
759 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_HIGHLIGHT
| FIELD_BACKGROUND_HIGHLIGHT
);
761 if ((MenuOption
->Col
+ gPromptBlockWidth
+ 1) == MenuOption
->OptCol
) {
762 PrintCharAt (MenuOption
->OptCol
, Row
, LEFT_NUMERIC_DELIMITER
);
763 Column
= MenuOption
->OptCol
+ 1;
766 // If Number looks like "3", convert it to "03/"
768 if (Number
== 4 && (NumericType
== DATE_NUMERIC
)) {
769 FormattedNumber
[3] = FormattedNumber
[1];
770 FormattedNumber
[2] = DATE_SEPARATOR
;
771 FormattedNumber
[1] = FormattedNumber
[0];
772 FormattedNumber
[0] = L
'0';
776 // If Number looks like "13", convert it to "13/"
778 if (Number
== 6 && (NumericType
== DATE_NUMERIC
)) {
779 FormattedNumber
[3] = FormattedNumber
[2];
780 FormattedNumber
[2] = DATE_SEPARATOR
;
785 (NumericType
== TIME_NUMERIC
) &&
786 (MenuOption
->Col
+ gPromptBlockWidth
+ 8) != MenuOption
->OptCol
788 FormattedNumber
[3] = FormattedNumber
[1];
789 FormattedNumber
[2] = TIME_SEPARATOR
;
790 FormattedNumber
[1] = FormattedNumber
[0];
791 FormattedNumber
[0] = L
'0';
796 (NumericType
== TIME_NUMERIC
) &&
797 (MenuOption
->Col
+ gPromptBlockWidth
+ 8) == MenuOption
->OptCol
799 FormattedNumber
[3] = FormattedNumber
[1];
800 FormattedNumber
[2] = RIGHT_NUMERIC_DELIMITER
;
801 FormattedNumber
[1] = FormattedNumber
[0];
802 FormattedNumber
[0] = L
'0';
806 PrintStringAt (Column
, Row
, FormattedNumber
);
807 if (Number
== 10 && (NumericType
== DATE_NUMERIC
)) {
808 PrintChar (RIGHT_NUMERIC_DELIMITER
);
811 if (NumericType
== REGULAR_NUMERIC
) {
812 PrintChar (RIGHT_NUMERIC_DELIMITER
);
819 goto EnterCarriageReturn
;
822 return EFI_DEVICE_ERROR
;
832 case CHAR_CARRIAGE_RETURN
:
834 // Check to see if the Value is something reasonable against consistency limitations.
835 // If not, let's kick the error specified.
838 // This gives us visibility to the FileFormTags->NvRamMap to check things
839 // ActiveIfr is a global maintained by the menuing code to ensure that we
840 // are pointing to the correct formset's file data.
842 for (Count
= 0; Count
< gActiveIfr
; Count
++) {
843 FileFormTags
= FileFormTags
->NextFile
;
846 ExtractRequestedNvMap (FileFormTags
, Tag
->VariableNumber
, &VariableDefinition
);
848 CopyMem (&VariableDefinition
->NvRamMap
[Tag
->StorageStart
], &Tag
->Value
, Tag
->StorageWidth
);
851 // Data associated with a NULL device (in the fake NV storage)
853 if (Tag
->StorageWidth
== (UINT16
) 0) {
854 CopyMem (&VariableDefinition
->FakeNvRamMap
[Tag
->StorageStart
], &Tag
->Value
, 2);
857 // If a late check is required save off the information. This is used when consistency checks
858 // are required, but certain values might be bound by an impossible consistency check such as
859 // if two questions are bound by consistency checks and each only has two possible choices, there
860 // would be no way for a user to switch the values. Thus we require late checking.
862 if (Tag
->Flags
& EFI_IFR_FLAG_LATE_CHECK
) {
863 CopyMem (&Tag
->OldValue
, &BackupValue
, Tag
->StorageWidth
);
866 // In theory, passing the value and the Id are sufficient to determine what needs
867 // to be done. The Id is the key to look for the entry needed in the Inconsistency
868 // database. That will yields operand and ID data - and since the ID's correspond
869 // to the NV storage, we can determine the values for other IDs there.
871 if (ValueIsNotValid (TRUE
, 0, Tag
, FileFormTags
, &PopUp
)) {
872 if (PopUp
== 0x0000) {
873 SelectionComplete
= TRUE
;
877 StringPtr
= GetToken (PopUp
, MenuOption
->Handle
);
879 CreatePopUp (GetStringWidth (StringPtr
) / 2, 3, &NullCharacter
, StringPtr
, &NullCharacter
);
882 WaitForKeyStroke (&Key
);
884 switch (Key
.UnicodeChar
) {
886 case CHAR_CARRIAGE_RETURN
:
887 SelectionComplete
= TRUE
;
888 FreePool (StringPtr
);
894 } while (!SelectionComplete
);
896 Tag
->Value
= BackupValue
;
897 *Value
= BackupValue
;
899 CopyMem (&VariableDefinition
->NvRamMap
[Tag
->StorageStart
], &Tag
->Value
, Tag
->StorageWidth
);
902 // Data associated with a NULL device (in the fake NV storage)
904 if (Tag
->StorageWidth
== (UINT16
) 0) {
905 CopyMem (&VariableDefinition
->FakeNvRamMap
[Tag
->StorageStart
], &Tag
->Value
, 2);
908 return EFI_DEVICE_ERROR
;
921 // Remove a character
923 Number
= PreviousNumber
[Count
- 1];
924 *Value
= (UINT16
) Number
;
925 UpdateStatusBar (INPUT_ERROR
, Tag
->Flags
, FALSE
);
928 PrintAt (Column
, Row
, (CHAR16
*) L
" ");
934 if (Key
.UnicodeChar
> L
'9' || Key
.UnicodeChar
< L
'0') {
935 UpdateStatusBar (INPUT_ERROR
, Tag
->Flags
, TRUE
);
939 // If Count 0-4 is complete, there is no way more is valid
945 // Someone typed something valid!
948 Number
= Number
* 10 + (Key
.UnicodeChar
- L
'0');
950 Number
= Key
.UnicodeChar
- L
'0';
953 if (Number
> Tag
->Maximum
) {
954 UpdateStatusBar (INPUT_ERROR
, Tag
->Flags
, TRUE
);
955 Number
= PreviousNumber
[Count
];
958 UpdateStatusBar (INPUT_ERROR
, Tag
->Flags
, FALSE
);
963 PreviousNumber
[Count
] = Number
;
964 *Value
= (UINT16
) Number
;
965 Tag
->Value
= (UINT16
) Number
;
967 PrintCharAt (Column
, Row
, Key
.UnicodeChar
);
972 } while (!SelectionComplete
);
976 // Notice that this is at least needed for the ordered list manipulation.
977 // Left/Right doesn't make sense for this op-code
980 GetSelectionInputPopUp (
981 IN UI_MENU_OPTION
*MenuOption
,
992 CHAR16
*TempStringPtr
;
995 UINTN TopOptionIndex
;
996 UINTN HighlightPosition
;
1003 UINTN PopUpMenuLines
;
1004 UINTN MenuLinesInView
;
1007 BOOLEAN FirstOptionFoundFlag
;
1008 INT32 SavedAttribute
;
1011 UINT8
*ValueArrayBackup
;
1013 BOOLEAN Initialized
;
1014 BOOLEAN KeyInitialized
;
1015 BOOLEAN ShowDownArrow
;
1016 BOOLEAN ShowUpArrow
;
1017 UINTN DimensionsWidth
;
1019 DimensionsWidth
= gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
;
1023 ValueArray
= (UINT8
*) Value
;
1024 ValueArrayBackup
= NULL
;
1025 Initialized
= FALSE
;
1026 KeyInitialized
= FALSE
;
1027 ShowDownArrow
= FALSE
;
1028 ShowUpArrow
= FALSE
;
1030 if (Tag
->Operand
== EFI_IFR_ORDERED_LIST_OP
) {
1031 ValueArrayBackup
= AllocateZeroPool (Tag
->StorageWidth
);
1032 ASSERT (ValueArrayBackup
!= NULL
);
1033 CopyMem (ValueArrayBackup
, ValueArray
, ValueCount
);
1034 TempValue
= *(UINT8
*) (ValueArray
);
1035 if (ValueArray
[0] != 0x00) {
1039 for (Index
= 0; ValueArray
[Index
] != 0x00; Index
++)
1049 FirstOptionFoundFlag
= FALSE
;
1051 StringPtr
= AllocateZeroPool ((gOptionBlockWidth
+ 1) * 2);
1055 // Initialization for "One of" pop-up menu
1058 // Get the number of one of options present and its size
1060 for (Index
= MenuOption
->TagIndex
; MenuOption
->Tags
[Index
].Operand
!= EFI_IFR_END_ONE_OF_OP
; Index
++) {
1061 if (MenuOption
->Tags
[Index
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
&&
1062 !MenuOption
->Tags
[Index
].Suppress
) {
1063 if (!FirstOptionFoundFlag
) {
1064 FirstOptionFoundFlag
= TRUE
;
1068 Token
= MenuOption
->Tags
[Index
].Text
;
1071 // If this is an ordered list that is initialized
1074 for (ValueBackup
= (UINT8
) MenuOption
->TagIndex
;
1075 MenuOption
->Tags
[ValueBackup
].Operand
!= EFI_IFR_END_OP
;
1078 if (MenuOption
->Tags
[ValueBackup
].Value
== ((UINT8
*) ValueArrayBackup
)[Index
- MenuOption
->TagIndex
- 1]) {
1079 StringPtr
= GetToken (MenuOption
->Tags
[ValueBackup
].Text
, MenuOption
->Handle
);
1084 StringPtr
= GetToken (Token
, MenuOption
->Handle
);
1087 if (StrLen (StringPtr
) > PopUpWidth
) {
1088 PopUpWidth
= StrLen (StringPtr
);
1091 FreePool (StringPtr
);
1095 // Perform popup menu initialization.
1097 PopUpMenuLines
= Count
;
1098 PopUpWidth
= PopUpWidth
+ POPUP_PAD_SPACE_COUNT
;
1100 SavedAttribute
= gST
->ConOut
->Mode
->Attribute
;
1101 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
1103 if ((PopUpWidth
+ POPUP_FRAME_WIDTH
) > DimensionsWidth
) {
1104 PopUpWidth
= DimensionsWidth
- POPUP_FRAME_WIDTH
;
1107 Start
= (DimensionsWidth
- PopUpWidth
- POPUP_FRAME_WIDTH
) / 2 + gScreenDimensions
.LeftColumn
;
1108 End
= Start
+ PopUpWidth
+ POPUP_FRAME_WIDTH
;
1109 Top
= gScreenDimensions
.TopRow
+ NONE_FRONT_PAGE_HEADER_HEIGHT
;
1110 Bottom
= gScreenDimensions
.BottomRow
- STATUS_BAR_HEIGHT
- FOOTER_HEIGHT
;
1112 MenuLinesInView
= Bottom
- Top
- 1;
1113 if (MenuLinesInView
>= PopUpMenuLines
) {
1114 Top
= Top
+ (MenuLinesInView
- PopUpMenuLines
) / 2;
1115 Bottom
= Top
+ PopUpMenuLines
+ 1;
1117 TempValue
= MenuOption
->Tags
[MenuOption
->TagIndex
+ 1].Value
;
1118 ShowDownArrow
= TRUE
;
1122 HighlightPosition
= 0;
1125 for (Index
= MenuOption
->TagIndex
, Index2
= 0; Index2
< ValueCount
; Index
++, Index2
++) {
1127 // Set the value for the item we are looking for
1129 Count
= ValueArrayBackup
[Index2
];
1132 // If we hit the end of the Array, we are complete
1138 if (MenuOption
->Tags
[Index
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
) {
1139 for (ValueBackup
= (UINT8
) MenuOption
->TagIndex
;
1140 MenuOption
->Tags
[ValueBackup
].Operand
!= EFI_IFR_END_ONE_OF_OP
;
1144 // We just found what we are looking for
1146 if (MenuOption
->Tags
[ValueBackup
].Value
== Count
) {
1148 // As long as the two indexes aren't the same, we have
1149 // two different op-codes we need to swap internally
1151 if (Index
!= ValueBackup
) {
1153 // Backup destination tag, then copy source to destination, then copy backup to source location
1155 CopyMem (&TagBackup
, &MenuOption
->Tags
[Index
], sizeof (EFI_TAG
));
1156 CopyMem (&MenuOption
->Tags
[Index
], &MenuOption
->Tags
[ValueBackup
], sizeof (EFI_TAG
));
1157 CopyMem (&MenuOption
->Tags
[ValueBackup
], &TagBackup
, sizeof (EFI_TAG
));
1160 // If the indexes are the same, then the op-code is where he belongs
1167 // Since this wasn't an option op-code (likely the ordered list op-code) decerement Index2
1174 // Clear that portion of the screen
1176 ClearLines (Start
, End
, Top
, Bottom
, POPUP_TEXT
| POPUP_BACKGROUND
);
1179 // Draw "One of" pop-up menu
1181 Character
= (CHAR16
) BOXDRAW_DOWN_RIGHT
;
1182 PrintCharAt (Start
, Top
, Character
);
1183 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
1184 if ((ShowUpArrow
) && ((Index
+ 1) == (Start
+ End
) / 2)) {
1185 Character
= (CHAR16
) GEOMETRICSHAPE_UP_TRIANGLE
;
1187 Character
= (CHAR16
) BOXDRAW_HORIZONTAL
;
1190 PrintChar (Character
);
1193 Character
= (CHAR16
) BOXDRAW_DOWN_LEFT
;
1194 PrintChar (Character
);
1195 Character
= (CHAR16
) BOXDRAW_VERTICAL
;
1196 for (Index
= Top
+ 1; Index
< Bottom
; Index
++) {
1197 PrintCharAt (Start
, Index
, Character
);
1198 PrintCharAt (End
- 1, Index
, Character
);
1201 // Display the One of options
1204 for (Index
= MenuOption
->TagIndex
+ TopOptionIndex
;
1205 (MenuOption
->Tags
[Index
].Operand
!= EFI_IFR_END_ONE_OF_OP
) && (Index2
< Bottom
);
1208 if (MenuOption
->Tags
[Index
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
) {
1209 Token
= MenuOption
->Tags
[Index
].Text
;
1211 for (ValueBackup
= (UINT8
) MenuOption
->TagIndex
;
1212 MenuOption
->Tags
[ValueBackup
].Operand
!= EFI_IFR_END_ONE_OF_OP
;
1215 if (MenuOption
->Tags
[ValueBackup
].Value
== ((UINT8
*) ValueArrayBackup
)[Index
- MenuOption
->TagIndex
- 1]) {
1216 StringPtr
= GetToken (MenuOption
->Tags
[ValueBackup
].Text
, MenuOption
->Handle
);
1221 ValueBackup
= (UINT8
) Index
;
1222 StringPtr
= GetToken (Token
, MenuOption
->Handle
);
1225 // If the string occupies multiple lines, truncate it to fit in one line,
1226 // and append a "..." for indication.
1228 if (StrLen (StringPtr
) > (PopUpWidth
- 1)) {
1229 TempStringPtr
= AllocateZeroPool (sizeof (CHAR16
) * (PopUpWidth
- 1));
1230 ASSERT (TempStringPtr
!= NULL
);
1231 CopyMem (TempStringPtr
, StringPtr
, (sizeof (CHAR16
) * (PopUpWidth
- 5)));
1232 FreePool (StringPtr
);
1233 StringPtr
= TempStringPtr
;
1234 StrCat (StringPtr
, (CHAR16
*) L
"...");
1237 // Code to display the text should go here. Follwed by the [*]
1239 if (MenuOption
->Tags
[ValueBackup
].Suppress
== TRUE
) {
1241 // Don't show the one, so decrease the Index2 for balance
1244 } else if (MenuOption
->Tags
[ValueBackup
].GrayOut
== TRUE
) {
1248 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_GRAYED
| POPUP_BACKGROUND
);
1249 PrintStringAt (Start
+ 2, Index2
, StringPtr
);
1250 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
1251 } else if (MenuOption
->Tags
[ValueBackup
].Value
== TempValue
) {
1253 // Highlight the selected one
1255 gST
->ConOut
->SetAttribute (gST
->ConOut
, PICKLIST_HIGHLIGHT_TEXT
| PICKLIST_HIGHLIGHT_BACKGROUND
);
1256 PrintStringAt (Start
+ 2, Index2
, StringPtr
);
1257 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
1258 HighlightPosition
= Index2
;
1260 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
1261 PrintStringAt (Start
+ 2, Index2
, StringPtr
);
1264 FreePool (StringPtr
);
1265 Index2
= Index2
+ 1;
1269 Character
= (CHAR16
) BOXDRAW_UP_RIGHT
;
1270 PrintCharAt (Start
, Bottom
, Character
);
1271 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
1272 if ((ShowDownArrow
) && ((Index
+ 1) == (Start
+ End
) / 2)) {
1273 Character
= (CHAR16
) GEOMETRICSHAPE_DOWN_TRIANGLE
;
1275 Character
= (CHAR16
) BOXDRAW_HORIZONTAL
;
1278 PrintChar (Character
);
1281 Character
= (CHAR16
) BOXDRAW_UP_LEFT
;
1282 PrintChar (Character
);
1284 // Get User selection and change TempValue if necessary
1287 // Stop: One of pop-up menu
1289 Key
.UnicodeChar
= CHAR_NULL
;
1290 if ((gDirection
== SCAN_UP
) || (gDirection
== SCAN_DOWN
)) {
1291 Key
.ScanCode
= gDirection
;
1296 if (!KeyInitialized
) {
1297 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_ONE_OF_OP
) {
1298 *KeyValue
= MenuOption
->Tags
[MenuOption
->TagIndex
+ 1].Key
;
1300 *KeyValue
= MenuOption
->ThisTag
->Key
;
1303 KeyInitialized
= TRUE
;
1306 WaitForKeyStroke (&Key
);
1309 switch (Key
.UnicodeChar
) {
1313 // If an ordered list op-code, we will allow for a popup of +/- keys
1314 // to create an ordered list of items
1316 if (Tag
->Operand
== EFI_IFR_ORDERED_LIST_OP
) {
1317 if (Key
.UnicodeChar
== '+') {
1318 if ((TopOptionIndex
> 1) && (HighlightPosition
== (Top
+ 1))) {
1320 // Highlight reaches the top of the popup window, scroll one menu item.
1323 ShowDownArrow
= TRUE
;
1326 if (TopOptionIndex
== 1) {
1327 ShowUpArrow
= FALSE
;
1330 if (((TopOptionIndex
+ MenuLinesInView
) <= PopUpMenuLines
) && (HighlightPosition
== (Bottom
- 1))) {
1332 // Highlight reaches the bottom of the popup window, scroll one menu item.
1338 if ((TopOptionIndex
+ MenuLinesInView
) == (PopUpMenuLines
+ 1)) {
1339 ShowDownArrow
= FALSE
;
1343 for (Index
= MenuOption
->TagIndex
+ TopOptionIndex
;
1344 MenuOption
->Tags
[Index
].Operand
!= EFI_IFR_END_ONE_OF_OP
;
1347 if (MenuOption
->Tags
[Index
].Operand
== EFI_IFR_ORDERED_LIST_OP
) {
1351 if (Key
.UnicodeChar
== '+') {
1352 TempIndex
= Index
- 1;
1354 TempIndex
= Index
+ 1;
1357 // Is this the current tag we are on?
1359 if (MenuOption
->Tags
[Index
].Value
== TempValue
) {
1361 // Is this prior tag a valid choice? If not, bail out
1363 if (MenuOption
->Tags
[TempIndex
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
) {
1365 // Copy the destination tag to the local variable
1367 CopyMem (&TagBackup
, &MenuOption
->Tags
[TempIndex
], sizeof (EFI_TAG
));
1369 // Copy the current tag to the tag location before us
1371 CopyMem (&MenuOption
->Tags
[TempIndex
], &MenuOption
->Tags
[Index
], sizeof (EFI_TAG
));
1373 // Copy the backed up tag to the current location
1375 CopyMem (&MenuOption
->Tags
[Index
], &TagBackup
, sizeof (EFI_TAG
));
1378 // Adjust the array of values
1380 for (Index
= 0; Index
< ValueCount
; Index
++) {
1381 if (ValueArrayBackup
[Index
] == (UINT8
) TempValue
) {
1382 if (Key
.UnicodeChar
== '+') {
1385 // It is the top of the array already
1390 TempIndex
= Index
- 1;
1392 if ((Index
+ 1) == ValueCount
) {
1394 // It is the bottom of the array already
1399 TempIndex
= Index
+ 1;
1402 ValueBackup
= ValueArrayBackup
[TempIndex
];
1403 ValueArrayBackup
[TempIndex
] = ValueArrayBackup
[Index
];
1404 ValueArrayBackup
[Index
] = ValueBackup
;
1419 switch (Key
.ScanCode
) {
1422 if (Key
.ScanCode
== SCAN_UP
) {
1423 if ((TopOptionIndex
> 1) && (HighlightPosition
== (Top
+ 1))) {
1425 // Highlight reaches the top of the popup window, scroll one menu item.
1428 ShowDownArrow
= TRUE
;
1431 if (TopOptionIndex
== 1) {
1432 ShowUpArrow
= FALSE
;
1435 if (((TopOptionIndex
+ MenuLinesInView
) <= PopUpMenuLines
) && (HighlightPosition
== (Bottom
- 1))) {
1437 // Highlight reaches the bottom of the popup window, scroll one menu item.
1443 if ((TopOptionIndex
+ MenuLinesInView
) == (PopUpMenuLines
+ 1)) {
1444 ShowDownArrow
= FALSE
;
1448 for (Index
= MenuOption
->TagIndex
+ TopOptionIndex
;
1449 MenuOption
->Tags
[Index
].Operand
!= EFI_IFR_END_ONE_OF_OP
;
1452 if (MenuOption
->Tags
[Index
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
) {
1454 for (Index
= 0; (ValueArrayBackup
[Index
] != TempValue
) && (Index
< ValueCount
); Index
++)
1458 // Did we hit the end of the array? Either get the first TempValue or the next one
1460 if (Key
.ScanCode
== SCAN_UP
) {
1462 TempValue
= ValueArrayBackup
[0];
1464 TempValue
= ValueArrayBackup
[Index
- 1];
1467 if ((Index
+ 1) == ValueCount
) {
1468 TempValue
= ValueArrayBackup
[Index
];
1470 TempValue
= ValueArrayBackup
[Index
+ 1];
1475 if (Key
.ScanCode
== SCAN_UP
) {
1476 TempIndex
= Index
- 1;
1479 // Keep going until meets meaningful tag.
1481 while ((MenuOption
->Tags
[TempIndex
].Operand
!= EFI_IFR_ONE_OF_OPTION_OP
&&
1482 MenuOption
->Tags
[TempIndex
].Operand
!= EFI_IFR_ONE_OF_OP
&&
1483 MenuOption
->Tags
[TempIndex
].Operand
!= EFI_IFR_END_ONE_OF_OP
)
1485 (MenuOption
->Tags
[TempIndex
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
&&
1486 (MenuOption
->Tags
[TempIndex
].Suppress
|| MenuOption
->Tags
[TempIndex
].GrayOut
))) {
1490 TempIndex
= Index
+ 1;
1493 // Keep going until meets meaningful tag.
1495 while ((MenuOption
->Tags
[TempIndex
].Operand
!= EFI_IFR_ONE_OF_OPTION_OP
&&
1496 MenuOption
->Tags
[TempIndex
].Operand
!= EFI_IFR_ONE_OF_OP
&&
1497 MenuOption
->Tags
[TempIndex
].Operand
!= EFI_IFR_END_ONE_OF_OP
)
1499 (MenuOption
->Tags
[TempIndex
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
&&
1500 (MenuOption
->Tags
[TempIndex
].Suppress
|| MenuOption
->Tags
[TempIndex
].GrayOut
))) {
1505 // The option value is the same as what is stored in NV store. This is where we take action
1507 if (MenuOption
->Tags
[Index
].Value
== TempValue
) {
1509 // Only if the previous op-code is an option can we select it, otherwise we are at the left-most option
1511 if (MenuOption
->Tags
[TempIndex
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
) {
1512 TempValue
= MenuOption
->Tags
[TempIndex
].Value
;
1513 *KeyValue
= MenuOption
->Tags
[TempIndex
].Key
;
1515 TempValue
= MenuOption
->Tags
[Index
].Value
;
1516 *KeyValue
= MenuOption
->Tags
[Index
].Key
;
1526 gST
->ConOut
->SetAttribute (gST
->ConOut
, SavedAttribute
);
1527 if (ValueArrayBackup
!= NULL
) {
1528 FreePool (ValueArrayBackup
);
1531 return EFI_DEVICE_ERROR
;
1539 case CHAR_CARRIAGE_RETURN
:
1541 // return the current selection
1543 if (Tag
->Operand
== EFI_IFR_ORDERED_LIST_OP
) {
1544 CopyMem (ValueArray
, ValueArrayBackup
, ValueCount
);
1545 FreePool (ValueArrayBackup
);
1558 gST
->ConOut
->SetAttribute (gST
->ConOut
, SavedAttribute
);
1564 OUT EFI_INPUT_KEY
*Key
1570 UiWaitForSingleEvent (gST
->ConIn
->WaitForKey
, 0);
1571 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, Key
);
1572 } while (EFI_ERROR(Status
));