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
28 #define EFI_MAX(_a, _b) ((_a) > (_b) ? (_a) : (_b))
32 IN UI_MENU_OPTION
*MenuOption
,
43 BOOLEAN SelectionComplete
;
45 CHAR16
*BufferedString
;
50 CHAR16
*PromptForDataString
;
51 UINTN DimensionsWidth
;
52 UINTN DimensionsHeight
;
53 BOOLEAN CursorVisible
;
55 DimensionsWidth
= gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
;
56 DimensionsHeight
= gScreenDimensions
.BottomRow
- gScreenDimensions
.TopRow
;
58 PromptForDataString
= GetToken (STRING_TOKEN (PROMPT_FOR_DATA
), gHiiHandle
);
60 NullCharacter
= CHAR_NULL
;
61 ScreenSize
= GetStringWidth (PromptForDataString
) / 2;
62 Tag
= MenuOption
->ThisTag
;
65 SelectionComplete
= FALSE
;
67 TempString
= AllocateZeroPool (MenuOption
->ThisTag
->Maximum
* 2);
70 if (ScreenSize
< (Tag
->Maximum
/ (UINTN
) 2)) {
71 ScreenSize
= Tag
->Maximum
/ 2;
74 if ((ScreenSize
+ 2) > DimensionsWidth
) {
75 ScreenSize
= DimensionsWidth
- 2;
78 BufferedString
= AllocateZeroPool (ScreenSize
* 2);
79 ASSERT (BufferedString
);
81 Start
= (DimensionsWidth
- ScreenSize
- 2) / 2 + gScreenDimensions
.LeftColumn
+ 1;
82 Top
= ((DimensionsHeight
- 6) / 2) + gScreenDimensions
.TopRow
- 1;
85 // Display prompt for string
87 CreatePopUp (ScreenSize
, 4, &NullCharacter
, PromptForDataString
, Space
, &NullCharacter
);
89 FreePool (PromptForDataString
);
91 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_BLACK
, EFI_LIGHTGRAY
));
93 CursorVisible
= gST
->ConOut
->Mode
->CursorVisible
;
94 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
97 Status
= WaitForKeyStroke (&Key
);
99 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_BLACK
, EFI_LIGHTGRAY
));
100 switch (Key
.UnicodeChar
) {
102 switch (Key
.ScanCode
) {
110 FreePool (TempString
);
111 FreePool (BufferedString
);
112 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
113 gST
->ConOut
->EnableCursor (gST
->ConOut
, CursorVisible
);
114 return EFI_DEVICE_ERROR
;
122 case CHAR_CARRIAGE_RETURN
:
123 if (GetStringWidth (StringPtr
) >= MenuOption
->ThisTag
->Minimum
) {
124 SelectionComplete
= TRUE
;
125 FreePool (TempString
);
126 FreePool (BufferedString
);
127 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
128 gST
->ConOut
->EnableCursor (gST
->ConOut
, CursorVisible
);
131 ScreenSize
= GetStringWidth (gMiniString
) / 2;
132 CreatePopUp (ScreenSize
, 4, &NullCharacter
, gMiniString
, gPressEnter
, &NullCharacter
);
134 // Simply create a popup to tell the user that they had typed in too few characters.
135 // To save code space, we can then treat this as an error and return back to the menu.
138 Status
= WaitForKeyStroke (&Key
);
139 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
140 FreePool (TempString
);
141 FreePool (BufferedString
);
142 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
143 gST
->ConOut
->EnableCursor (gST
->ConOut
, CursorVisible
);
144 return EFI_DEVICE_ERROR
;
150 if (StringPtr
[0] != CHAR_NULL
) {
151 for (Index
= 0; StringPtr
[Index
] != CHAR_NULL
; Index
++) {
152 TempString
[Index
] = StringPtr
[Index
];
155 // Effectively truncate string by 1 character
157 TempString
[Index
- 1] = CHAR_NULL
;
158 StrCpy (StringPtr
, TempString
);
163 // If it is the beginning of the string, don't worry about checking maximum limits
165 if ((StringPtr
[0] == CHAR_NULL
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
166 StrnCpy (StringPtr
, &Key
.UnicodeChar
, 1);
167 StrnCpy (TempString
, &Key
.UnicodeChar
, 1);
168 } else if ((GetStringWidth (StringPtr
) < MenuOption
->ThisTag
->Maximum
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
169 KeyPad
[0] = Key
.UnicodeChar
;
170 KeyPad
[1] = CHAR_NULL
;
171 StrCat (StringPtr
, KeyPad
);
172 StrCat (TempString
, KeyPad
);
175 // If the width of the input string is now larger than the screen, we nee to
176 // adjust the index to start printing portions of the string
178 SetUnicodeMem (BufferedString
, ScreenSize
- 1, L
' ');
180 PrintStringAt (Start
+ 1, Top
+ 3, BufferedString
);
182 if ((GetStringWidth (StringPtr
) / 2) > (DimensionsWidth
- 2)) {
183 Index
= (GetStringWidth (StringPtr
) / 2) - DimensionsWidth
+ 2;
188 for (Count
= 0; Index
+ 1 < GetStringWidth (StringPtr
) / 2; Index
++, Count
++) {
189 BufferedString
[Count
] = StringPtr
[Index
];
192 PrintStringAt (Start
+ 1, Top
+ 3, BufferedString
);
196 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
197 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, Start
+ GetStringWidth (StringPtr
) / 2, Top
+ 3);
198 } while (!SelectionComplete
);
199 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
200 gST
->ConOut
->EnableCursor (gST
->ConOut
, CursorVisible
);
206 IN UI_MENU_OPTION
*MenuOption
,
207 IN BOOLEAN PromptForPassword
,
209 IN EFI_IFR_DATA_ARRAY
*PageData
,
210 IN BOOLEAN SecondEntry
,
211 IN EFI_FILE_FORM_TAGS
*FileFormTags
,
212 OUT CHAR16
*StringPtr
217 CHAR16 NullCharacter
;
226 BOOLEAN Confirmation
;
227 BOOLEAN ConfirmationComplete
;
228 EFI_HII_CALLBACK_PACKET
*Packet
;
229 EFI_FORM_CALLBACK_PROTOCOL
*FormCallback
;
230 EFI_VARIABLE_DEFINITION
*VariableDefinition
;
231 UINTN DimensionsWidth
;
232 UINTN DimensionsHeight
;
233 EFI_IFR_DATA_ENTRY
*DataEntry
;
236 DimensionsWidth
= gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
;
237 DimensionsHeight
= gScreenDimensions
.BottomRow
- gScreenDimensions
.TopRow
;
239 VariableDefinition
= NULL
;
240 NullCharacter
= CHAR_NULL
;
242 Space
[1] = CHAR_NULL
;
243 Confirmation
= FALSE
;
244 ConfirmationComplete
= FALSE
;
245 Status
= EFI_SUCCESS
;
250 // Remember that dynamic pages in an environment where all pages are not
251 // dynamic require us to call back to the user to give them an opportunity
252 // to register fresh information in the HII database so that we can extract it.
254 Status
= gBS
->HandleProtocol (
255 (VOID
*) (UINTN
) MenuOption
->Tags
[0].CallbackHandle
,
256 &gEfiFormCallbackProtocolGuid
,
257 (VOID
**) &FormCallback
260 TempString
= AllocateZeroPool (MenuOption
->ThisTag
->Maximum
* 2);
261 TempString2
= AllocateZeroPool (MenuOption
->ThisTag
->Maximum
* 2);
264 ASSERT (TempString2
);
266 if (Tag
->Flags
& EFI_IFR_FLAG_INTERACTIVE
) {
268 // Password requires a callback to determine if a password exists
270 DataEntry
= (EFI_IFR_DATA_ENTRY
*) (PageData
+ 1);
271 DataEntry
->OpCode
= EFI_IFR_PASSWORD_OP
;
272 DataEntry
->Length
= 3;
274 ExtractRequestedNvMap (FileFormTags
, Tag
->VariableNumber
, &VariableDefinition
);
277 // The user is about to be prompted with a password field, Data = 0 (Return Status determines the type of prompt)
279 DataEntry
->Data
= (VOID
*) (UINTN
) (UINT8
) (0 + SecondEntry
* 2);
280 PageData
->NvRamMap
= VariableDefinition
->NvRamMap
;
282 if ((FormCallback
!= NULL
) && (FormCallback
->Callback
!= NULL
)) {
283 Status
= FormCallback
->Callback (
291 // If error on return, continue with the reading of a typed in password to verify user knows password
292 // If no error, there is no password set, so prompt for new password
293 // if the previous callback was to verify the user knew password, and user typed it correctly - should return no error
295 if (!EFI_ERROR (Status
)) {
296 PromptForPassword
= FALSE
;
299 // Simulate this as the second entry into this routine for an interactive behavior
302 } else if (Status
== EFI_NOT_READY
) {
304 if (Packet
!= NULL
) {
306 // Upon error, we will likely receive a string to print out
307 // Display error popup
309 WidthOfString
= GetStringWidth (Packet
->String
);
310 ScreenSize
= EFI_MAX(WidthOfString
, GetStringWidth (gPressEnter
)) / 2;
311 CreatePopUp (ScreenSize
, 4, &NullCharacter
, Packet
->String
, gPressEnter
, &NullCharacter
);
315 Status
= WaitForKeyStroke (&Key
);
316 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
319 Status
= EFI_NOT_READY
;
326 // Display PopUp Screen
328 ScreenSize
= GetStringWidth (gPromptForNewPassword
) / 2;
329 if (GetStringWidth (gConfirmPassword
) / 2 > ScreenSize
) {
330 ScreenSize
= GetStringWidth (gConfirmPassword
) / 2;
333 Start
= (DimensionsWidth
- ScreenSize
- 4) / 2 + gScreenDimensions
.LeftColumn
+ 2;
334 Top
= ((DimensionsHeight
- 6) / 2) + gScreenDimensions
.TopRow
- 1;
337 if (PromptForPassword
) {
338 CreatePopUp (ScreenSize
, 4, &NullCharacter
, gPromptForPassword
, Space
, &NullCharacter
);
340 CreatePopUp (ScreenSize
, 4, &NullCharacter
, gPromptForNewPassword
, Space
, &NullCharacter
);
343 CreatePopUp (ScreenSize
, 4, &NullCharacter
, gConfirmPassword
, Space
, &NullCharacter
);
344 StringPtr
[0] = CHAR_NULL
;
348 Status
= WaitForKeyStroke (&Key
);
350 switch (Key
.UnicodeChar
) {
352 if (Key
.ScanCode
== SCAN_ESC
) {
353 return EFI_NOT_READY
;
356 ConfirmationComplete
= FALSE
;
359 case CHAR_CARRIAGE_RETURN
:
360 if (Tag
->Flags
& EFI_IFR_FLAG_INTERACTIVE
) {
362 // User just typed a string in
364 DataEntry
= (EFI_IFR_DATA_ENTRY
*) (PageData
+ 1);
365 DataEntry
->OpCode
= EFI_IFR_PASSWORD_OP
;
368 // If the user just typed in a password, Data = 1
369 // If the user just typed in a password to confirm the previous password, Data = 2
372 DataEntry
->Length
= 3;
373 DataEntry
->Data
= (VOID
*) (UINTN
) (UINT8
) (1 + SecondEntry
* 2);
375 if ((FormCallback
!= NULL
) && (FormCallback
->Callback
!= NULL
)) {
376 Status
= FormCallback
->Callback (
384 DataEntry
->Length
= sizeof (EFI_IFR_DATA_ENTRY
);
385 DataEntry
->Data
= (VOID
*) TempString
;
387 DataEntry
->Length
= 3;
388 DataEntry
->Data
= (VOID
*) (UINTN
) (UINT8
) (2 + SecondEntry
* 2);
390 if ((FormCallback
!= NULL
) && (FormCallback
->Callback
!= NULL
)) {
391 Status
= FormCallback
->Callback (
399 DataEntry
->Length
= sizeof (EFI_IFR_DATA_ENTRY
);
400 DataEntry
->Data
= (VOID
*) TempString2
;
403 if ((FormCallback
!= NULL
) && (FormCallback
->Callback
!= NULL
)) {
404 Status
= FormCallback
->Callback (
412 // If this was the confirmation round of callbacks
413 // and an error comes back, display an error
416 if (EFI_ERROR (Status
)) {
417 if (Packet
->String
== NULL
) {
418 WidthOfString
= GetStringWidth (gConfirmError
);
419 ScreenSize
= EFI_MAX (WidthOfString
, GetStringWidth (gPressEnter
)) / 2;
420 CreatePopUp (ScreenSize
, 4, &NullCharacter
, gConfirmError
, gPressEnter
, &NullCharacter
);
422 WidthOfString
= GetStringWidth (Packet
->String
);
423 ScreenSize
= EFI_MAX (WidthOfString
, GetStringWidth (gPressEnter
)) / 2;
424 CreatePopUp (ScreenSize
, 4, &NullCharacter
, Packet
->String
, gPressEnter
, &NullCharacter
);
428 StringPtr
[0] = CHAR_NULL
;
430 Status
= WaitForKeyStroke (&Key
);
432 if (Key
.UnicodeChar
== CHAR_CARRIAGE_RETURN
) {
433 Status
= EFI_NOT_READY
;
438 Status
= EFI_NOT_READY
;
443 // User typed a string in and it wasn't valid somehow from the callback
444 // For instance, callback may have said that some invalid characters were contained in the string
446 if (Status
== EFI_NOT_READY
) {
450 if (PromptForPassword
&& EFI_ERROR (Status
)) {
451 Status
= EFI_DEVICE_ERROR
;
459 // Compare tempstring and tempstring2, if the same, return with StringPtr success
460 // Otherwise, kick and error box, and return an error
462 if (StrCmp (TempString
, TempString2
) == 0) {
463 Status
= EFI_SUCCESS
;
466 WidthOfString
= GetStringWidth (gConfirmError
);
467 ScreenSize
= EFI_MAX (WidthOfString
, GetStringWidth (gPressEnter
)) / 2;
468 CreatePopUp (ScreenSize
, 4, &NullCharacter
, gConfirmError
, gPressEnter
, &NullCharacter
);
469 StringPtr
[0] = CHAR_NULL
;
471 Status
= WaitForKeyStroke (&Key
);
472 if (Key
.UnicodeChar
== CHAR_CARRIAGE_RETURN
) {
473 Status
= EFI_DEVICE_ERROR
;
480 if (PromptForPassword
) {
482 // I was asked for a password, return it back in StringPtr
484 Status
= EFI_SUCCESS
;
488 // If the two passwords were not the same kick an error popup
491 ConfirmationComplete
= TRUE
;
496 if (StringPtr
[0] != CHAR_NULL
) {
498 for (Index
= 0; StringPtr
[Index
] != CHAR_NULL
; Index
++) {
499 TempString
[Index
] = StringPtr
[Index
];
502 // Effectively truncate string by 1 character
504 TempString
[Index
- 1] = CHAR_NULL
;
505 StrCpy (StringPtr
, TempString
);
507 for (Index
= 0; StringPtr
[Index
] != CHAR_NULL
; Index
++) {
508 TempString2
[Index
] = StringPtr
[Index
];
511 // Effectively truncate string by 1 character
513 TempString2
[Index
- 1] = CHAR_NULL
;
514 StrCpy (StringPtr
, TempString2
);
517 ConfirmationComplete
= FALSE
;
519 ConfirmationComplete
= FALSE
;
523 // Must be a character we are interested in!
526 if ((StringPtr
[0] == CHAR_NULL
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
528 StrnCpy (StringPtr
, &Key
.UnicodeChar
, 1);
529 StrnCpy (TempString
, &Key
.UnicodeChar
, 1);
531 StrnCpy (StringPtr
, &Key
.UnicodeChar
, 1);
532 StrnCpy (TempString2
, &Key
.UnicodeChar
, 1);
533 ConfirmationComplete
= FALSE
;
535 } else if ((GetStringWidth (StringPtr
) / 2 <= (UINTN
) (MenuOption
->ThisTag
->Maximum
- 1) / 2) &&
536 (Key
.UnicodeChar
!= CHAR_BACKSPACE
)
538 KeyPad
[0] = Key
.UnicodeChar
;
539 KeyPad
[1] = CHAR_NULL
;
541 StrCat (StringPtr
, KeyPad
);
542 StrCat (TempString
, KeyPad
);
544 StrCat (StringPtr
, KeyPad
);
545 StrCat (TempString2
, KeyPad
);
549 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_BLACK
, EFI_LIGHTGRAY
));
550 for (Index
= 1; Index
< ScreenSize
; Index
++) {
551 PrintCharAt (Start
+ Index
, Top
+ 3, L
' ');
554 gST
->ConOut
->SetCursorPosition (
556 (DimensionsWidth
- GetStringWidth (StringPtr
) / 2) / 2 + gScreenDimensions
.LeftColumn
,
559 for (Index
= 0; Index
+ 1 < GetStringWidth (StringPtr
) / 2; Index
++) {
563 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
569 } while (!ConfirmationComplete
);
574 FreePool (TempString
);
575 FreePool (TempString2
);
590 Key
= (CHAR16
*) L
"MAR10648567";
591 Buffer
= AllocateZeroPool (MaxSize
);
595 for (Index
= 0; Key
[Index
] != 0; Index
++) {
596 for (Loop
= 0; Loop
< (UINT8
) (MaxSize
/ 2); Loop
++) {
597 Buffer
[Loop
] = (CHAR16
) (Password
[Loop
] ^ Key
[Index
]);
601 CopyMem (Password
, Buffer
, MaxSize
);
609 IN UI_MENU_OPTION
*MenuOption
,
610 IN EFI_FILE_FORM_TAGS
*FileFormTagsHead
,
611 IN BOOLEAN ManualInput
,
613 IN UINTN NumericType
,
620 This routine reads a numeric value from the user input.
624 MenuOption - Pointer to the current input menu.
626 FileFormTagsHead - Pointer to the root of formset.
628 ManualInput - If the input is manual or not.
630 Tag - Pointer to all the attributes and values associated with a tag.
632 Value - Pointer to the numeric value that is going to be read.
636 EFI_SUCCESS - If numerical input is read successfully
637 EFI_DEVICE_ERROR - If operation fails
642 BOOLEAN SelectionComplete
;
645 CHAR16 FormattedNumber
[6];
646 UINTN PreviousNumber
[6];
651 CHAR16 NullCharacter
;
653 EFI_FILE_FORM_TAGS
*FileFormTags
;
654 EFI_VARIABLE_DEFINITION
*VariableDefinition
;
657 NullCharacter
= CHAR_NULL
;
659 Column
= MenuOption
->OptCol
;
660 Row
= MenuOption
->Row
;
662 PreviousNumber
[0] = 0;
664 SelectionComplete
= FALSE
;
665 BackupValue
= Tag
->Value
;
666 FileFormTags
= FileFormTagsHead
;
669 PrintAt (Column
, Row
, (CHAR16
*) L
"[ ]");
671 if (Tag
->Operand
!= EFI_IFR_TIME_OP
) {
672 *Value
= BackupValue
;
676 // First time we enter this handler, we need to check to see if
677 // we were passed an increment or decrement directive
680 Key
.UnicodeChar
= CHAR_NULL
;
681 if (gDirection
!= 0) {
682 Key
.ScanCode
= gDirection
;
687 WaitForKeyStroke (&Key
);
690 switch (Key
.UnicodeChar
) {
693 if ((Tag
->Operand
== EFI_IFR_DATE_OP
) || (Tag
->Operand
== EFI_IFR_TIME_OP
)) {
694 Key
.UnicodeChar
= CHAR_NULL
;
695 if (Key
.UnicodeChar
== '+') {
696 Key
.ScanCode
= SCAN_RIGHT
;
698 Key
.ScanCode
= SCAN_LEFT
;
706 switch (Key
.ScanCode
) {
709 if ((Tag
->Operand
== EFI_IFR_DATE_OP
) || (Tag
->Operand
== EFI_IFR_TIME_OP
)) {
711 // By setting this value, we will return back to the caller.
712 // We need to do this since an auto-refresh will destroy the adjustment
713 // based on what the real-time-clock is showing. So we always commit
714 // upon changing the value.
716 gDirection
= SCAN_DOWN
;
721 if (Key
.ScanCode
== SCAN_LEFT
) {
722 Number
= *Value
- Tag
->Step
;
723 if (Number
< Tag
->Minimum
) {
724 Number
= Tag
->Minimum
;
726 } else if (Key
.ScanCode
== SCAN_RIGHT
) {
727 Number
= *Value
+ Tag
->Step
;
728 if (Number
> Tag
->Maximum
) {
729 Number
= Tag
->Maximum
;
733 Tag
->Value
= (UINT16
) Number
;
734 *Value
= (UINT16
) Number
;
735 UnicodeValueToString (
739 (sizeof (FormattedNumber
) / sizeof (FormattedNumber
[0]))
741 Number
= (UINT16
) GetStringWidth (FormattedNumber
);
743 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT
| FIELD_BACKGROUND
);
744 if ((Tag
->Operand
== EFI_IFR_DATE_OP
) || (Tag
->Operand
== EFI_IFR_TIME_OP
)) {
745 for (Loop
= 0; Loop
< (UINTN
) ((Number
>= 8) ? 4 : 2); Loop
++) {
746 PrintAt (MenuOption
->OptCol
+ Loop
, MenuOption
->Row
, (CHAR16
*) L
" ");
749 for (Loop
= 0; Loop
< gOptionBlockWidth
; Loop
++) {
750 PrintAt (MenuOption
->OptCol
+ Loop
, MenuOption
->Row
, (CHAR16
*) L
" ");
754 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_HIGHLIGHT
| FIELD_BACKGROUND_HIGHLIGHT
);
756 if ((MenuOption
->Col
+ gPromptBlockWidth
+ 1) == MenuOption
->OptCol
) {
757 PrintCharAt (MenuOption
->OptCol
, Row
, LEFT_NUMERIC_DELIMITER
);
758 Column
= MenuOption
->OptCol
+ 1;
761 // If Number looks like "3", convert it to "03/"
763 if (Number
== 4 && (NumericType
== DATE_NUMERIC
)) {
764 FormattedNumber
[3] = FormattedNumber
[1];
765 FormattedNumber
[2] = DATE_SEPARATOR
;
766 FormattedNumber
[1] = FormattedNumber
[0];
767 FormattedNumber
[0] = L
'0';
771 // If Number looks like "13", convert it to "13/"
773 if (Number
== 6 && (NumericType
== DATE_NUMERIC
)) {
774 FormattedNumber
[3] = FormattedNumber
[2];
775 FormattedNumber
[2] = DATE_SEPARATOR
;
780 (NumericType
== TIME_NUMERIC
) &&
781 (MenuOption
->Col
+ gPromptBlockWidth
+ 8) != MenuOption
->OptCol
783 FormattedNumber
[3] = FormattedNumber
[1];
784 FormattedNumber
[2] = TIME_SEPARATOR
;
785 FormattedNumber
[1] = FormattedNumber
[0];
786 FormattedNumber
[0] = L
'0';
791 (NumericType
== TIME_NUMERIC
) &&
792 (MenuOption
->Col
+ gPromptBlockWidth
+ 8) == MenuOption
->OptCol
794 FormattedNumber
[3] = FormattedNumber
[1];
795 FormattedNumber
[2] = RIGHT_NUMERIC_DELIMITER
;
796 FormattedNumber
[1] = FormattedNumber
[0];
797 FormattedNumber
[0] = L
'0';
801 PrintStringAt (Column
, Row
, FormattedNumber
);
802 if (Number
== 10 && (NumericType
== DATE_NUMERIC
)) {
803 PrintChar (RIGHT_NUMERIC_DELIMITER
);
806 if (NumericType
== REGULAR_NUMERIC
) {
807 PrintChar (RIGHT_NUMERIC_DELIMITER
);
814 goto EnterCarriageReturn
;
817 return EFI_DEVICE_ERROR
;
827 case CHAR_CARRIAGE_RETURN
:
829 // Check to see if the Value is something reasonable against consistency limitations.
830 // If not, let's kick the error specified.
833 // This gives us visibility to the FileFormTags->NvRamMap to check things
834 // ActiveIfr is a global maintained by the menuing code to ensure that we
835 // are pointing to the correct formset's file data.
837 for (Count
= 0; Count
< gActiveIfr
; Count
++) {
838 FileFormTags
= FileFormTags
->NextFile
;
841 ExtractRequestedNvMap (FileFormTags
, Tag
->VariableNumber
, &VariableDefinition
);
843 CopyMem (&VariableDefinition
->NvRamMap
[Tag
->StorageStart
], &Tag
->Value
, Tag
->StorageWidth
);
846 // Data associated with a NULL device (in the fake NV storage)
848 if (Tag
->StorageWidth
== (UINT16
) 0) {
849 CopyMem (&VariableDefinition
->FakeNvRamMap
[Tag
->StorageStart
], &Tag
->Value
, 2);
852 // If a late check is required save off the information. This is used when consistency checks
853 // are required, but certain values might be bound by an impossible consistency check such as
854 // if two questions are bound by consistency checks and each only has two possible choices, there
855 // would be no way for a user to switch the values. Thus we require late checking.
857 if (Tag
->Flags
& EFI_IFR_FLAG_LATE_CHECK
) {
858 CopyMem (&Tag
->OldValue
, &BackupValue
, Tag
->StorageWidth
);
861 // In theory, passing the value and the Id are sufficient to determine what needs
862 // to be done. The Id is the key to look for the entry needed in the Inconsistency
863 // database. That will yields operand and ID data - and since the ID's correspond
864 // to the NV storage, we can determine the values for other IDs there.
866 if (ValueIsNotValid (TRUE
, 0, Tag
, FileFormTags
, &PopUp
)) {
867 if (PopUp
== 0x0000) {
868 SelectionComplete
= TRUE
;
872 StringPtr
= GetToken (PopUp
, MenuOption
->Handle
);
874 CreatePopUp (GetStringWidth (StringPtr
) / 2, 3, &NullCharacter
, StringPtr
, &NullCharacter
);
877 WaitForKeyStroke (&Key
);
879 switch (Key
.UnicodeChar
) {
881 case CHAR_CARRIAGE_RETURN
:
882 SelectionComplete
= TRUE
;
883 FreePool (StringPtr
);
889 } while (!SelectionComplete
);
891 Tag
->Value
= BackupValue
;
892 *Value
= BackupValue
;
894 CopyMem (&VariableDefinition
->NvRamMap
[Tag
->StorageStart
], &Tag
->Value
, Tag
->StorageWidth
);
897 // Data associated with a NULL device (in the fake NV storage)
899 if (Tag
->StorageWidth
== (UINT16
) 0) {
900 CopyMem (&VariableDefinition
->FakeNvRamMap
[Tag
->StorageStart
], &Tag
->Value
, 2);
903 return EFI_DEVICE_ERROR
;
916 // Remove a character
918 Number
= PreviousNumber
[Count
- 1];
919 *Value
= (UINT16
) Number
;
920 UpdateStatusBar (INPUT_ERROR
, Tag
->Flags
, FALSE
);
923 PrintAt (Column
, Row
, (CHAR16
*) L
" ");
929 if (Key
.UnicodeChar
> L
'9' || Key
.UnicodeChar
< L
'0') {
930 UpdateStatusBar (INPUT_ERROR
, Tag
->Flags
, TRUE
);
934 // If Count 0-4 is complete, there is no way more is valid
940 // Someone typed something valid!
943 Number
= Number
* 10 + (Key
.UnicodeChar
- L
'0');
945 Number
= Key
.UnicodeChar
- L
'0';
948 if (Number
> Tag
->Maximum
) {
949 UpdateStatusBar (INPUT_ERROR
, Tag
->Flags
, TRUE
);
950 Number
= PreviousNumber
[Count
];
953 UpdateStatusBar (INPUT_ERROR
, Tag
->Flags
, FALSE
);
958 PreviousNumber
[Count
] = Number
;
959 *Value
= (UINT16
) Number
;
960 Tag
->Value
= (UINT16
) Number
;
962 PrintCharAt (Column
, Row
, Key
.UnicodeChar
);
967 } while (!SelectionComplete
);
971 // Notice that this is at least needed for the ordered list manipulation.
972 // Left/Right doesn't make sense for this op-code
975 GetSelectionInputPopUp (
976 IN UI_MENU_OPTION
*MenuOption
,
987 CHAR16
*TempStringPtr
;
990 UINTN TopOptionIndex
;
991 UINTN HighlightPosition
;
998 UINTN PopUpMenuLines
;
999 UINTN MenuLinesInView
;
1002 BOOLEAN FirstOptionFoundFlag
;
1003 INT32 SavedAttribute
;
1006 UINT8
*ValueArrayBackup
;
1008 BOOLEAN Initialized
;
1009 BOOLEAN KeyInitialized
;
1010 BOOLEAN ShowDownArrow
;
1011 BOOLEAN ShowUpArrow
;
1012 UINTN DimensionsWidth
;
1014 DimensionsWidth
= gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
;
1018 ValueArray
= (UINT8
*) Value
;
1019 ValueArrayBackup
= NULL
;
1020 Initialized
= FALSE
;
1021 KeyInitialized
= FALSE
;
1022 ShowDownArrow
= FALSE
;
1023 ShowUpArrow
= FALSE
;
1025 if (Tag
->Operand
== EFI_IFR_ORDERED_LIST_OP
) {
1026 ValueArrayBackup
= AllocateZeroPool (Tag
->StorageWidth
);
1027 ASSERT (ValueArrayBackup
!= NULL
);
1028 CopyMem (ValueArrayBackup
, ValueArray
, ValueCount
);
1029 TempValue
= *(UINT8
*) (ValueArray
);
1030 if (ValueArray
[0] != 0x00) {
1034 for (Index
= 0; ValueArray
[Index
] != 0x00; Index
++)
1044 FirstOptionFoundFlag
= FALSE
;
1046 StringPtr
= AllocateZeroPool ((gOptionBlockWidth
+ 1) * 2);
1050 // Initialization for "One of" pop-up menu
1053 // Get the number of one of options present and its size
1055 for (Index
= MenuOption
->TagIndex
; MenuOption
->Tags
[Index
].Operand
!= EFI_IFR_END_ONE_OF_OP
; Index
++) {
1056 if (MenuOption
->Tags
[Index
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
&&
1057 !MenuOption
->Tags
[Index
].Suppress
) {
1058 if (!FirstOptionFoundFlag
) {
1059 FirstOptionFoundFlag
= TRUE
;
1063 Token
= MenuOption
->Tags
[Index
].Text
;
1066 // If this is an ordered list that is initialized
1069 for (ValueBackup
= (UINT8
) MenuOption
->TagIndex
;
1070 MenuOption
->Tags
[ValueBackup
].Operand
!= EFI_IFR_END_OP
;
1073 if (MenuOption
->Tags
[ValueBackup
].Value
== ((UINT8
*) ValueArrayBackup
)[Index
- MenuOption
->TagIndex
- 1]) {
1074 StringPtr
= GetToken (MenuOption
->Tags
[ValueBackup
].Text
, MenuOption
->Handle
);
1079 StringPtr
= GetToken (Token
, MenuOption
->Handle
);
1082 if (StrLen (StringPtr
) > PopUpWidth
) {
1083 PopUpWidth
= StrLen (StringPtr
);
1086 FreePool (StringPtr
);
1090 // Perform popup menu initialization.
1092 PopUpMenuLines
= Count
;
1093 PopUpWidth
= PopUpWidth
+ POPUP_PAD_SPACE_COUNT
;
1095 SavedAttribute
= gST
->ConOut
->Mode
->Attribute
;
1096 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
1098 if ((PopUpWidth
+ POPUP_FRAME_WIDTH
) > DimensionsWidth
) {
1099 PopUpWidth
= DimensionsWidth
- POPUP_FRAME_WIDTH
;
1102 Start
= (DimensionsWidth
- PopUpWidth
- POPUP_FRAME_WIDTH
) / 2 + gScreenDimensions
.LeftColumn
;
1103 End
= Start
+ PopUpWidth
+ POPUP_FRAME_WIDTH
;
1104 Top
= gScreenDimensions
.TopRow
+ NONE_FRONT_PAGE_HEADER_HEIGHT
;
1105 Bottom
= gScreenDimensions
.BottomRow
- STATUS_BAR_HEIGHT
- FOOTER_HEIGHT
;
1107 MenuLinesInView
= Bottom
- Top
- 1;
1108 if (MenuLinesInView
>= PopUpMenuLines
) {
1109 Top
= Top
+ (MenuLinesInView
- PopUpMenuLines
) / 2;
1110 Bottom
= Top
+ PopUpMenuLines
+ 1;
1112 TempValue
= MenuOption
->Tags
[MenuOption
->TagIndex
+ 1].Value
;
1113 ShowDownArrow
= TRUE
;
1117 HighlightPosition
= 0;
1120 for (Index
= MenuOption
->TagIndex
, Index2
= 0; Index2
< ValueCount
; Index
++, Index2
++) {
1122 // Set the value for the item we are looking for
1124 Count
= ValueArrayBackup
[Index2
];
1127 // If we hit the end of the Array, we are complete
1133 if (MenuOption
->Tags
[Index
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
) {
1134 for (ValueBackup
= (UINT8
) MenuOption
->TagIndex
;
1135 MenuOption
->Tags
[ValueBackup
].Operand
!= EFI_IFR_END_ONE_OF_OP
;
1139 // We just found what we are looking for
1141 if (MenuOption
->Tags
[ValueBackup
].Value
== Count
) {
1143 // As long as the two indexes aren't the same, we have
1144 // two different op-codes we need to swap internally
1146 if (Index
!= ValueBackup
) {
1148 // Backup destination tag, then copy source to destination, then copy backup to source location
1150 CopyMem (&TagBackup
, &MenuOption
->Tags
[Index
], sizeof (EFI_TAG
));
1151 CopyMem (&MenuOption
->Tags
[Index
], &MenuOption
->Tags
[ValueBackup
], sizeof (EFI_TAG
));
1152 CopyMem (&MenuOption
->Tags
[ValueBackup
], &TagBackup
, sizeof (EFI_TAG
));
1155 // If the indexes are the same, then the op-code is where he belongs
1162 // Since this wasn't an option op-code (likely the ordered list op-code) decerement Index2
1169 // Clear that portion of the screen
1171 ClearLines (Start
, End
, Top
, Bottom
, POPUP_TEXT
| POPUP_BACKGROUND
);
1174 // Draw "One of" pop-up menu
1176 Character
= (CHAR16
) BOXDRAW_DOWN_RIGHT
;
1177 PrintCharAt (Start
, Top
, Character
);
1178 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
1179 if ((ShowUpArrow
) && ((Index
+ 1) == (Start
+ End
) / 2)) {
1180 Character
= (CHAR16
) GEOMETRICSHAPE_UP_TRIANGLE
;
1182 Character
= (CHAR16
) BOXDRAW_HORIZONTAL
;
1185 PrintChar (Character
);
1188 Character
= (CHAR16
) BOXDRAW_DOWN_LEFT
;
1189 PrintChar (Character
);
1190 Character
= (CHAR16
) BOXDRAW_VERTICAL
;
1191 for (Index
= Top
+ 1; Index
< Bottom
; Index
++) {
1192 PrintCharAt (Start
, Index
, Character
);
1193 PrintCharAt (End
- 1, Index
, Character
);
1196 // Display the One of options
1199 for (Index
= MenuOption
->TagIndex
+ TopOptionIndex
;
1200 (MenuOption
->Tags
[Index
].Operand
!= EFI_IFR_END_ONE_OF_OP
) && (Index2
< Bottom
);
1203 if (MenuOption
->Tags
[Index
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
) {
1204 Token
= MenuOption
->Tags
[Index
].Text
;
1206 for (ValueBackup
= (UINT8
) MenuOption
->TagIndex
;
1207 MenuOption
->Tags
[ValueBackup
].Operand
!= EFI_IFR_END_ONE_OF_OP
;
1210 if (MenuOption
->Tags
[ValueBackup
].Value
== ((UINT8
*) ValueArrayBackup
)[Index
- MenuOption
->TagIndex
- 1]) {
1211 StringPtr
= GetToken (MenuOption
->Tags
[ValueBackup
].Text
, MenuOption
->Handle
);
1216 ValueBackup
= (UINT8
) Index
;
1217 StringPtr
= GetToken (Token
, MenuOption
->Handle
);
1220 // If the string occupies multiple lines, truncate it to fit in one line,
1221 // and append a "..." for indication.
1223 if (StrLen (StringPtr
) > (PopUpWidth
- 1)) {
1224 TempStringPtr
= AllocateZeroPool (sizeof (CHAR16
) * (PopUpWidth
- 1));
1225 ASSERT (TempStringPtr
!= NULL
);
1226 CopyMem (TempStringPtr
, StringPtr
, (sizeof (CHAR16
) * (PopUpWidth
- 5)));
1227 FreePool (StringPtr
);
1228 StringPtr
= TempStringPtr
;
1229 StrCat (StringPtr
, (CHAR16
*) L
"...");
1232 // Code to display the text should go here. Follwed by the [*]
1234 if (MenuOption
->Tags
[ValueBackup
].Suppress
== TRUE
) {
1236 // Don't show the one, so decrease the Index2 for balance
1239 } else if (MenuOption
->Tags
[ValueBackup
].GrayOut
== TRUE
) {
1243 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_GRAYED
| POPUP_BACKGROUND
);
1244 PrintStringAt (Start
+ 2, Index2
, StringPtr
);
1245 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
1246 } else if (MenuOption
->Tags
[ValueBackup
].Value
== TempValue
) {
1248 // Highlight the selected one
1250 gST
->ConOut
->SetAttribute (gST
->ConOut
, PICKLIST_HIGHLIGHT_TEXT
| PICKLIST_HIGHLIGHT_BACKGROUND
);
1251 PrintStringAt (Start
+ 2, Index2
, StringPtr
);
1252 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
1253 HighlightPosition
= Index2
;
1255 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
1256 PrintStringAt (Start
+ 2, Index2
, StringPtr
);
1259 FreePool (StringPtr
);
1260 Index2
= Index2
+ 1;
1264 Character
= (CHAR16
) BOXDRAW_UP_RIGHT
;
1265 PrintCharAt (Start
, Bottom
, Character
);
1266 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
1267 if ((ShowDownArrow
) && ((Index
+ 1) == (Start
+ End
) / 2)) {
1268 Character
= (CHAR16
) GEOMETRICSHAPE_DOWN_TRIANGLE
;
1270 Character
= (CHAR16
) BOXDRAW_HORIZONTAL
;
1273 PrintChar (Character
);
1276 Character
= (CHAR16
) BOXDRAW_UP_LEFT
;
1277 PrintChar (Character
);
1279 // Get User selection and change TempValue if necessary
1282 // Stop: One of pop-up menu
1284 Key
.UnicodeChar
= CHAR_NULL
;
1285 if ((gDirection
== SCAN_UP
) || (gDirection
== SCAN_DOWN
)) {
1286 Key
.ScanCode
= gDirection
;
1291 if (!KeyInitialized
) {
1292 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_ONE_OF_OP
) {
1293 *KeyValue
= MenuOption
->Tags
[MenuOption
->TagIndex
+ 1].Key
;
1295 *KeyValue
= MenuOption
->ThisTag
->Key
;
1298 KeyInitialized
= TRUE
;
1301 WaitForKeyStroke (&Key
);
1304 switch (Key
.UnicodeChar
) {
1308 // If an ordered list op-code, we will allow for a popup of +/- keys
1309 // to create an ordered list of items
1311 if (Tag
->Operand
== EFI_IFR_ORDERED_LIST_OP
) {
1312 if (Key
.UnicodeChar
== '+') {
1313 if ((TopOptionIndex
> 1) && (HighlightPosition
== (Top
+ 1))) {
1315 // Highlight reaches the top of the popup window, scroll one menu item.
1318 ShowDownArrow
= TRUE
;
1321 if (TopOptionIndex
== 1) {
1322 ShowUpArrow
= FALSE
;
1325 if (((TopOptionIndex
+ MenuLinesInView
) <= PopUpMenuLines
) && (HighlightPosition
== (Bottom
- 1))) {
1327 // Highlight reaches the bottom of the popup window, scroll one menu item.
1333 if ((TopOptionIndex
+ MenuLinesInView
) == (PopUpMenuLines
+ 1)) {
1334 ShowDownArrow
= FALSE
;
1338 for (Index
= MenuOption
->TagIndex
+ TopOptionIndex
;
1339 MenuOption
->Tags
[Index
].Operand
!= EFI_IFR_END_ONE_OF_OP
;
1342 if (MenuOption
->Tags
[Index
].Operand
== EFI_IFR_ORDERED_LIST_OP
) {
1346 if (Key
.UnicodeChar
== '+') {
1347 TempIndex
= Index
- 1;
1349 TempIndex
= Index
+ 1;
1352 // Is this the current tag we are on?
1354 if (MenuOption
->Tags
[Index
].Value
== TempValue
) {
1356 // Is this prior tag a valid choice? If not, bail out
1358 if (MenuOption
->Tags
[TempIndex
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
) {
1360 // Copy the destination tag to the local variable
1362 CopyMem (&TagBackup
, &MenuOption
->Tags
[TempIndex
], sizeof (EFI_TAG
));
1364 // Copy the current tag to the tag location before us
1366 CopyMem (&MenuOption
->Tags
[TempIndex
], &MenuOption
->Tags
[Index
], sizeof (EFI_TAG
));
1368 // Copy the backed up tag to the current location
1370 CopyMem (&MenuOption
->Tags
[Index
], &TagBackup
, sizeof (EFI_TAG
));
1373 // Adjust the array of values
1375 for (Index
= 0; Index
< ValueCount
; Index
++) {
1376 if (ValueArrayBackup
[Index
] == (UINT8
) TempValue
) {
1377 if (Key
.UnicodeChar
== '+') {
1380 // It is the top of the array already
1385 TempIndex
= Index
- 1;
1387 if ((Index
+ 1) == ValueCount
) {
1389 // It is the bottom of the array already
1394 TempIndex
= Index
+ 1;
1397 ValueBackup
= ValueArrayBackup
[TempIndex
];
1398 ValueArrayBackup
[TempIndex
] = ValueArrayBackup
[Index
];
1399 ValueArrayBackup
[Index
] = ValueBackup
;
1414 switch (Key
.ScanCode
) {
1417 if (Key
.ScanCode
== SCAN_UP
) {
1418 if ((TopOptionIndex
> 1) && (HighlightPosition
== (Top
+ 1))) {
1420 // Highlight reaches the top of the popup window, scroll one menu item.
1423 ShowDownArrow
= TRUE
;
1426 if (TopOptionIndex
== 1) {
1427 ShowUpArrow
= FALSE
;
1430 if (((TopOptionIndex
+ MenuLinesInView
) <= PopUpMenuLines
) && (HighlightPosition
== (Bottom
- 1))) {
1432 // Highlight reaches the bottom of the popup window, scroll one menu item.
1438 if ((TopOptionIndex
+ MenuLinesInView
) == (PopUpMenuLines
+ 1)) {
1439 ShowDownArrow
= FALSE
;
1443 for (Index
= MenuOption
->TagIndex
+ TopOptionIndex
;
1444 MenuOption
->Tags
[Index
].Operand
!= EFI_IFR_END_ONE_OF_OP
;
1447 if (MenuOption
->Tags
[Index
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
) {
1449 for (Index
= 0; (ValueArrayBackup
[Index
] != TempValue
) && (Index
< ValueCount
); Index
++)
1453 // Did we hit the end of the array? Either get the first TempValue or the next one
1455 if (Key
.ScanCode
== SCAN_UP
) {
1457 TempValue
= ValueArrayBackup
[0];
1459 TempValue
= ValueArrayBackup
[Index
- 1];
1462 if ((Index
+ 1) == ValueCount
) {
1463 TempValue
= ValueArrayBackup
[Index
];
1465 TempValue
= ValueArrayBackup
[Index
+ 1];
1470 if (Key
.ScanCode
== SCAN_UP
) {
1471 TempIndex
= Index
- 1;
1474 // Keep going until meets meaningful tag.
1476 while ((MenuOption
->Tags
[TempIndex
].Operand
!= EFI_IFR_ONE_OF_OPTION_OP
&&
1477 MenuOption
->Tags
[TempIndex
].Operand
!= EFI_IFR_ONE_OF_OP
&&
1478 MenuOption
->Tags
[TempIndex
].Operand
!= EFI_IFR_END_ONE_OF_OP
)
1480 (MenuOption
->Tags
[TempIndex
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
&&
1481 (MenuOption
->Tags
[TempIndex
].Suppress
|| MenuOption
->Tags
[TempIndex
].GrayOut
))) {
1485 TempIndex
= Index
+ 1;
1488 // Keep going until meets meaningful tag.
1490 while ((MenuOption
->Tags
[TempIndex
].Operand
!= EFI_IFR_ONE_OF_OPTION_OP
&&
1491 MenuOption
->Tags
[TempIndex
].Operand
!= EFI_IFR_ONE_OF_OP
&&
1492 MenuOption
->Tags
[TempIndex
].Operand
!= EFI_IFR_END_ONE_OF_OP
)
1494 (MenuOption
->Tags
[TempIndex
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
&&
1495 (MenuOption
->Tags
[TempIndex
].Suppress
|| MenuOption
->Tags
[TempIndex
].GrayOut
))) {
1500 // The option value is the same as what is stored in NV store. This is where we take action
1502 if (MenuOption
->Tags
[Index
].Value
== TempValue
) {
1504 // Only if the previous op-code is an option can we select it, otherwise we are at the left-most option
1506 if (MenuOption
->Tags
[TempIndex
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
) {
1507 TempValue
= MenuOption
->Tags
[TempIndex
].Value
;
1508 *KeyValue
= MenuOption
->Tags
[TempIndex
].Key
;
1510 TempValue
= MenuOption
->Tags
[Index
].Value
;
1511 *KeyValue
= MenuOption
->Tags
[Index
].Key
;
1521 gST
->ConOut
->SetAttribute (gST
->ConOut
, SavedAttribute
);
1522 if (ValueArrayBackup
!= NULL
) {
1523 FreePool (ValueArrayBackup
);
1526 return EFI_DEVICE_ERROR
;
1534 case CHAR_CARRIAGE_RETURN
:
1536 // return the current selection
1538 if (Tag
->Operand
== EFI_IFR_ORDERED_LIST_OP
) {
1539 CopyMem (ValueArray
, ValueArrayBackup
, ValueCount
);
1540 FreePool (ValueArrayBackup
);
1553 gST
->ConOut
->SetAttribute (gST
->ConOut
, SavedAttribute
);
1559 OUT EFI_INPUT_KEY
*Key
1565 UiWaitForSingleEvent (gST
->ConIn
->WaitForKey
, 0);
1566 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, Key
);
1567 } while (EFI_ERROR(Status
));