3 Copyright (c) 2006, 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
29 #define EFI_MAX(_a, _b) ((_a) > (_b) ? (_a) : (_b))
34 IN UI_MENU_OPTION
*MenuOption
,
45 BOOLEAN SelectionComplete
;
47 CHAR16
*BufferedString
;
52 CHAR16
*PromptForDataString
;
53 UINTN DimensionsWidth
;
54 UINTN DimensionsHeight
;
55 BOOLEAN CursorVisible
;
57 DimensionsWidth
= gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
;
58 DimensionsHeight
= gScreenDimensions
.BottomRow
- gScreenDimensions
.TopRow
;
60 PromptForDataString
= GetToken (STRING_TOKEN (PROMPT_FOR_DATA
), gHiiHandle
);
62 NullCharacter
= CHAR_NULL
;
63 ScreenSize
= GetStringWidth (PromptForDataString
) / 2;
64 Tag
= MenuOption
->ThisTag
;
67 SelectionComplete
= FALSE
;
69 TempString
= AllocateZeroPool (MenuOption
->ThisTag
->Maximum
* 2);
72 if (ScreenSize
< (Tag
->Maximum
/ (UINTN
) 2)) {
73 ScreenSize
= Tag
->Maximum
/ 2;
76 if ((ScreenSize
+ 2) > DimensionsWidth
) {
77 ScreenSize
= DimensionsWidth
- 2;
80 BufferedString
= AllocateZeroPool (ScreenSize
* 2);
81 ASSERT (BufferedString
);
83 Start
= (DimensionsWidth
- ScreenSize
- 2) / 2 + gScreenDimensions
.LeftColumn
+ 1;
84 Top
= ((DimensionsHeight
- 6) / 2) + gScreenDimensions
.TopRow
- 1;
87 // Display prompt for string
89 CreatePopUp (ScreenSize
, 4, &NullCharacter
, PromptForDataString
, Space
, &NullCharacter
);
91 gBS
->FreePool (PromptForDataString
);
93 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_BLACK
, EFI_LIGHTGRAY
));
95 CursorVisible
= gST
->ConOut
->Mode
->CursorVisible
;
96 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
99 Status
= WaitForKeyStroke (&Key
);
101 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_BLACK
, EFI_LIGHTGRAY
));
102 switch (Key
.UnicodeChar
) {
104 switch (Key
.ScanCode
) {
112 gBS
->FreePool (TempString
);
113 gBS
->FreePool (BufferedString
);
114 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
115 gST
->ConOut
->EnableCursor (gST
->ConOut
, CursorVisible
);
116 return EFI_DEVICE_ERROR
;
124 case CHAR_CARRIAGE_RETURN
:
125 if (GetStringWidth (StringPtr
) >= MenuOption
->ThisTag
->Minimum
) {
126 SelectionComplete
= TRUE
;
127 gBS
->FreePool (TempString
);
128 gBS
->FreePool (BufferedString
);
129 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
130 gST
->ConOut
->EnableCursor (gST
->ConOut
, CursorVisible
);
133 ScreenSize
= GetStringWidth (gMiniString
) / 2;
134 CreatePopUp (ScreenSize
, 4, &NullCharacter
, gMiniString
, gPressEnter
, &NullCharacter
);
136 // Simply create a popup to tell the user that they had typed in too few characters.
137 // To save code space, we can then treat this as an error and return back to the menu.
140 Status
= WaitForKeyStroke (&Key
);
141 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
142 gBS
->FreePool (TempString
);
143 gBS
->FreePool (BufferedString
);
144 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
145 gST
->ConOut
->EnableCursor (gST
->ConOut
, CursorVisible
);
146 return EFI_DEVICE_ERROR
;
152 if (StringPtr
[0] != CHAR_NULL
) {
153 for (Index
= 0; StringPtr
[Index
] != CHAR_NULL
; Index
++) {
154 TempString
[Index
] = StringPtr
[Index
];
157 // Effectively truncate string by 1 character
159 TempString
[Index
- 1] = CHAR_NULL
;
160 StrCpy (StringPtr
, TempString
);
165 // If it is the beginning of the string, don't worry about checking maximum limits
167 if ((StringPtr
[0] == CHAR_NULL
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
168 StrnCpy (StringPtr
, &Key
.UnicodeChar
, 1);
169 StrnCpy (TempString
, &Key
.UnicodeChar
, 1);
170 } else if ((GetStringWidth (StringPtr
) < MenuOption
->ThisTag
->Maximum
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
171 KeyPad
[0] = Key
.UnicodeChar
;
172 KeyPad
[1] = CHAR_NULL
;
173 StrCat (StringPtr
, KeyPad
);
174 StrCat (TempString
, KeyPad
);
177 // If the width of the input string is now larger than the screen, we nee to
178 // adjust the index to start printing portions of the string
180 SetUnicodeMem (BufferedString
, ScreenSize
- 1, L
' ');
182 PrintStringAt (Start
+ 1, Top
+ 3, BufferedString
);
184 if ((GetStringWidth (StringPtr
) / 2) > (DimensionsWidth
- 2)) {
185 Index
= (GetStringWidth (StringPtr
) / 2) - DimensionsWidth
+ 2;
190 for (Count
= 0; Index
+ 1 < GetStringWidth (StringPtr
) / 2; Index
++, Count
++) {
191 BufferedString
[Count
] = StringPtr
[Index
];
194 PrintStringAt (Start
+ 1, Top
+ 3, BufferedString
);
198 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
199 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, Start
+ GetStringWidth (StringPtr
) / 2, Top
+ 3);
200 } while (!SelectionComplete
);
201 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
202 gST
->ConOut
->EnableCursor (gST
->ConOut
, CursorVisible
);
208 IN UI_MENU_OPTION
*MenuOption
,
209 IN BOOLEAN PromptForPassword
,
211 IN EFI_IFR_DATA_ARRAY
*PageData
,
212 IN BOOLEAN SecondEntry
,
213 IN EFI_FILE_FORM_TAGS
*FileFormTags
,
214 OUT CHAR16
*StringPtr
219 CHAR16 NullCharacter
;
228 BOOLEAN Confirmation
;
229 BOOLEAN ConfirmationComplete
;
230 EFI_HII_CALLBACK_PACKET
*Packet
;
231 EFI_FORM_CALLBACK_PROTOCOL
*FormCallback
;
232 EFI_VARIABLE_DEFINITION
*VariableDefinition
;
233 UINTN DimensionsWidth
;
234 UINTN DimensionsHeight
;
235 EFI_IFR_DATA_ENTRY
*DataEntry
;
238 DimensionsWidth
= gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
;
239 DimensionsHeight
= gScreenDimensions
.BottomRow
- gScreenDimensions
.TopRow
;
241 VariableDefinition
= NULL
;
242 NullCharacter
= CHAR_NULL
;
244 Space
[1] = CHAR_NULL
;
245 Confirmation
= FALSE
;
246 ConfirmationComplete
= FALSE
;
247 Status
= EFI_SUCCESS
;
252 // Remember that dynamic pages in an environment where all pages are not
253 // dynamic require us to call back to the user to give them an opportunity
254 // to register fresh information in the HII database so that we can extract it.
256 Status
= gBS
->HandleProtocol (
257 (VOID
*) (UINTN
) MenuOption
->Tags
[0].CallbackHandle
,
258 &gEfiFormCallbackProtocolGuid
,
259 (VOID
**) &FormCallback
262 TempString
= AllocateZeroPool (MenuOption
->ThisTag
->Maximum
* 2);
263 TempString2
= AllocateZeroPool (MenuOption
->ThisTag
->Maximum
* 2);
266 ASSERT (TempString2
);
268 if (Tag
->Flags
& EFI_IFR_FLAG_INTERACTIVE
) {
270 // Password requires a callback to determine if a password exists
272 DataEntry
= (EFI_IFR_DATA_ENTRY
*) (PageData
+ 1);
273 DataEntry
->OpCode
= EFI_IFR_PASSWORD_OP
;
274 DataEntry
->Length
= 3;
276 ExtractRequestedNvMap (FileFormTags
, Tag
->VariableNumber
, &VariableDefinition
);
279 // The user is about to be prompted with a password field, Data = 0 (Return Status determines the type of prompt)
281 DataEntry
->Data
= (VOID
*) (UINTN
) (UINT8
) (0 + SecondEntry
* 2);
282 PageData
->NvRamMap
= VariableDefinition
->NvRamMap
;
284 if ((FormCallback
!= NULL
) && (FormCallback
->Callback
!= NULL
)) {
285 Status
= FormCallback
->Callback (
293 // If error on return, continue with the reading of a typed in password to verify user knows password
294 // If no error, there is no password set, so prompt for new password
295 // if the previous callback was to verify the user knew password, and user typed it correctly - should return no error
297 if (!EFI_ERROR (Status
)) {
298 PromptForPassword
= FALSE
;
301 // Simulate this as the second entry into this routine for an interactive behavior
304 } else if (Status
== EFI_NOT_READY
) {
306 if (Packet
!= NULL
) {
308 // Upon error, we will likely receive a string to print out
309 // Display error popup
311 WidthOfString
= GetStringWidth (Packet
->String
);
312 ScreenSize
= EFI_MAX(WidthOfString
, GetStringWidth (gPressEnter
)) / 2;
313 CreatePopUp (ScreenSize
, 4, &NullCharacter
, Packet
->String
, gPressEnter
, &NullCharacter
);
314 gBS
->FreePool (Packet
);
317 Status
= WaitForKeyStroke (&Key
);
318 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
321 Status
= EFI_NOT_READY
;
328 // Display PopUp Screen
330 ScreenSize
= GetStringWidth (gPromptForNewPassword
) / 2;
331 if (GetStringWidth (gConfirmPassword
) / 2 > ScreenSize
) {
332 ScreenSize
= GetStringWidth (gConfirmPassword
) / 2;
335 Start
= (DimensionsWidth
- ScreenSize
- 4) / 2 + gScreenDimensions
.LeftColumn
+ 2;
336 Top
= ((DimensionsHeight
- 6) / 2) + gScreenDimensions
.TopRow
- 1;
339 if (PromptForPassword
) {
340 CreatePopUp (ScreenSize
, 4, &NullCharacter
, gPromptForPassword
, Space
, &NullCharacter
);
342 CreatePopUp (ScreenSize
, 4, &NullCharacter
, gPromptForNewPassword
, Space
, &NullCharacter
);
345 CreatePopUp (ScreenSize
, 4, &NullCharacter
, gConfirmPassword
, Space
, &NullCharacter
);
346 StringPtr
[0] = CHAR_NULL
;
350 Status
= WaitForKeyStroke (&Key
);
352 switch (Key
.UnicodeChar
) {
354 if (Key
.ScanCode
== SCAN_ESC
) {
355 return EFI_NOT_READY
;
358 ConfirmationComplete
= FALSE
;
361 case CHAR_CARRIAGE_RETURN
:
362 if (Tag
->Flags
& EFI_IFR_FLAG_INTERACTIVE
) {
364 // User just typed a string in
366 DataEntry
= (EFI_IFR_DATA_ENTRY
*) (PageData
+ 1);
367 DataEntry
->OpCode
= EFI_IFR_PASSWORD_OP
;
370 // If the user just typed in a password, Data = 1
371 // If the user just typed in a password to confirm the previous password, Data = 2
374 DataEntry
->Length
= 3;
375 DataEntry
->Data
= (VOID
*) (UINTN
) (UINT8
) (1 + SecondEntry
* 2);
377 if ((FormCallback
!= NULL
) && (FormCallback
->Callback
!= NULL
)) {
378 Status
= FormCallback
->Callback (
386 DataEntry
->Length
= sizeof (EFI_IFR_DATA_ENTRY
);
387 DataEntry
->Data
= (VOID
*) TempString
;
389 DataEntry
->Length
= 3;
390 DataEntry
->Data
= (VOID
*) (UINTN
) (UINT8
) (2 + SecondEntry
* 2);
392 if ((FormCallback
!= NULL
) && (FormCallback
->Callback
!= NULL
)) {
393 Status
= FormCallback
->Callback (
401 DataEntry
->Length
= sizeof (EFI_IFR_DATA_ENTRY
);
402 DataEntry
->Data
= (VOID
*) TempString2
;
405 if ((FormCallback
!= NULL
) && (FormCallback
->Callback
!= NULL
)) {
406 Status
= FormCallback
->Callback (
414 // If this was the confirmation round of callbacks
415 // and an error comes back, display an error
418 if (EFI_ERROR (Status
)) {
419 if (Packet
->String
== NULL
) {
420 WidthOfString
= GetStringWidth (gConfirmError
);
421 ScreenSize
= EFI_MAX (WidthOfString
, GetStringWidth (gPressEnter
)) / 2;
422 CreatePopUp (ScreenSize
, 4, &NullCharacter
, gConfirmError
, gPressEnter
, &NullCharacter
);
424 WidthOfString
= GetStringWidth (Packet
->String
);
425 ScreenSize
= EFI_MAX (WidthOfString
, GetStringWidth (gPressEnter
)) / 2;
426 CreatePopUp (ScreenSize
, 4, &NullCharacter
, Packet
->String
, gPressEnter
, &NullCharacter
);
427 gBS
->FreePool (Packet
);
430 StringPtr
[0] = CHAR_NULL
;
432 Status
= WaitForKeyStroke (&Key
);
434 if (Key
.UnicodeChar
== CHAR_CARRIAGE_RETURN
) {
435 Status
= EFI_NOT_READY
;
440 Status
= EFI_NOT_READY
;
445 // User typed a string in and it wasn't valid somehow from the callback
446 // For instance, callback may have said that some invalid characters were contained in the string
448 if (Status
== EFI_NOT_READY
) {
452 if (PromptForPassword
&& EFI_ERROR (Status
)) {
453 Status
= EFI_DEVICE_ERROR
;
461 // Compare tempstring and tempstring2, if the same, return with StringPtr success
462 // Otherwise, kick and error box, and return an error
464 if (StrCmp (TempString
, TempString2
) == 0) {
465 Status
= EFI_SUCCESS
;
468 WidthOfString
= GetStringWidth (gConfirmError
);
469 ScreenSize
= EFI_MAX (WidthOfString
, GetStringWidth (gPressEnter
)) / 2;
470 CreatePopUp (ScreenSize
, 4, &NullCharacter
, gConfirmError
, gPressEnter
, &NullCharacter
);
471 StringPtr
[0] = CHAR_NULL
;
473 Status
= WaitForKeyStroke (&Key
);
474 if (Key
.UnicodeChar
== CHAR_CARRIAGE_RETURN
) {
475 Status
= EFI_DEVICE_ERROR
;
482 if (PromptForPassword
) {
484 // I was asked for a password, return it back in StringPtr
486 Status
= EFI_SUCCESS
;
490 // If the two passwords were not the same kick an error popup
493 ConfirmationComplete
= TRUE
;
498 if (StringPtr
[0] != CHAR_NULL
) {
500 for (Index
= 0; StringPtr
[Index
] != CHAR_NULL
; Index
++) {
501 TempString
[Index
] = StringPtr
[Index
];
504 // Effectively truncate string by 1 character
506 TempString
[Index
- 1] = CHAR_NULL
;
507 StrCpy (StringPtr
, TempString
);
509 for (Index
= 0; StringPtr
[Index
] != CHAR_NULL
; Index
++) {
510 TempString2
[Index
] = StringPtr
[Index
];
513 // Effectively truncate string by 1 character
515 TempString2
[Index
- 1] = CHAR_NULL
;
516 StrCpy (StringPtr
, TempString2
);
519 ConfirmationComplete
= FALSE
;
521 ConfirmationComplete
= FALSE
;
525 // Must be a character we are interested in!
528 if ((StringPtr
[0] == CHAR_NULL
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
530 StrnCpy (StringPtr
, &Key
.UnicodeChar
, 1);
531 StrnCpy (TempString
, &Key
.UnicodeChar
, 1);
533 StrnCpy (StringPtr
, &Key
.UnicodeChar
, 1);
534 StrnCpy (TempString2
, &Key
.UnicodeChar
, 1);
535 ConfirmationComplete
= FALSE
;
537 } else if ((GetStringWidth (StringPtr
) / 2 <= (UINTN
) (MenuOption
->ThisTag
->Maximum
- 1) / 2) &&
538 (Key
.UnicodeChar
!= CHAR_BACKSPACE
)
540 KeyPad
[0] = Key
.UnicodeChar
;
541 KeyPad
[1] = CHAR_NULL
;
543 StrCat (StringPtr
, KeyPad
);
544 StrCat (TempString
, KeyPad
);
546 StrCat (StringPtr
, KeyPad
);
547 StrCat (TempString2
, KeyPad
);
551 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_BLACK
, EFI_LIGHTGRAY
));
552 for (Index
= 1; Index
< ScreenSize
; Index
++) {
553 PrintCharAt (Start
+ Index
, Top
+ 3, L
' ');
556 gST
->ConOut
->SetCursorPosition (
558 (DimensionsWidth
- GetStringWidth (StringPtr
) / 2) / 2 + gScreenDimensions
.LeftColumn
,
561 for (Index
= 0; Index
+ 1 < GetStringWidth (StringPtr
) / 2; Index
++) {
565 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
571 } while (!ConfirmationComplete
);
576 gBS
->FreePool (TempString
);
577 gBS
->FreePool (TempString2
);
592 Key
= (CHAR16
*) L
"MAR10648567";
593 Buffer
= AllocateZeroPool (MaxSize
);
597 for (Index
= 0; Key
[Index
] != 0; Index
++) {
598 for (Loop
= 0; Loop
< (UINT8
) (MaxSize
/ 2); Loop
++) {
599 Buffer
[Loop
] = (CHAR16
) (Password
[Loop
] ^ Key
[Index
]);
603 CopyMem (Password
, Buffer
, MaxSize
);
605 gBS
->FreePool (Buffer
);
611 IN UI_MENU_OPTION
*MenuOption
,
612 IN EFI_FILE_FORM_TAGS
*FileFormTagsHead
,
613 IN BOOLEAN ManualInput
,
615 IN UINTN NumericType
,
622 This routine reads a numeric value from the user input.
626 MenuOption - Pointer to the current input menu.
628 FileFormTagsHead - Pointer to the root of formset.
630 ManualInput - If the input is manual or not.
632 Tag - Pointer to all the attributes and values associated with a tag.
634 Value - Pointer to the numeric value that is going to be read.
638 EFI_SUCCESS - If numerical input is read successfully
639 EFI_DEVICE_ERROR - If operation fails
644 BOOLEAN SelectionComplete
;
647 CHAR16 FormattedNumber
[6];
648 UINTN PreviousNumber
[6];
653 CHAR16 NullCharacter
;
655 EFI_FILE_FORM_TAGS
*FileFormTags
;
656 EFI_VARIABLE_DEFINITION
*VariableDefinition
;
659 NullCharacter
= CHAR_NULL
;
661 Column
= MenuOption
->OptCol
;
662 Row
= MenuOption
->Row
;
664 PreviousNumber
[0] = 0;
666 SelectionComplete
= FALSE
;
667 BackupValue
= Tag
->Value
;
668 FileFormTags
= FileFormTagsHead
;
671 PrintAt (Column
, Row
, (CHAR16
*) L
"[ ]");
673 if (Tag
->Operand
!= EFI_IFR_TIME_OP
) {
674 *Value
= BackupValue
;
678 // First time we enter this handler, we need to check to see if
679 // we were passed an increment or decrement directive
682 Key
.UnicodeChar
= CHAR_NULL
;
683 if (gDirection
!= 0) {
684 Key
.ScanCode
= gDirection
;
689 WaitForKeyStroke (&Key
);
692 switch (Key
.UnicodeChar
) {
695 if ((Tag
->Operand
== EFI_IFR_DATE_OP
) || (Tag
->Operand
== EFI_IFR_TIME_OP
)) {
696 Key
.UnicodeChar
= CHAR_NULL
;
697 if (Key
.UnicodeChar
== '+') {
698 Key
.ScanCode
= SCAN_RIGHT
;
700 Key
.ScanCode
= SCAN_LEFT
;
708 switch (Key
.ScanCode
) {
711 if ((Tag
->Operand
== EFI_IFR_DATE_OP
) || (Tag
->Operand
== EFI_IFR_TIME_OP
)) {
713 // By setting this value, we will return back to the caller.
714 // We need to do this since an auto-refresh will destroy the adjustment
715 // based on what the real-time-clock is showing. So we always commit
716 // upon changing the value.
718 gDirection
= SCAN_DOWN
;
723 if (Key
.ScanCode
== SCAN_LEFT
) {
724 Number
= *Value
- Tag
->Step
;
725 if (Number
< Tag
->Minimum
) {
726 Number
= Tag
->Minimum
;
728 } else if (Key
.ScanCode
== SCAN_RIGHT
) {
729 Number
= *Value
+ Tag
->Step
;
730 if (Number
> Tag
->Maximum
) {
731 Number
= Tag
->Maximum
;
735 Tag
->Value
= (UINT16
) Number
;
736 *Value
= (UINT16
) Number
;
737 UnicodeValueToString (
741 (sizeof (FormattedNumber
) / sizeof (FormattedNumber
[0]))
743 Number
= (UINT16
) GetStringWidth (FormattedNumber
);
745 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT
| FIELD_BACKGROUND
);
746 if ((Tag
->Operand
== EFI_IFR_DATE_OP
) || (Tag
->Operand
== EFI_IFR_TIME_OP
)) {
747 for (Loop
= 0; Loop
< (UINTN
) ((Number
>= 8) ? 4 : 2); Loop
++) {
748 PrintAt (MenuOption
->OptCol
+ Loop
, MenuOption
->Row
, (CHAR16
*) L
" ");
751 for (Loop
= 0; Loop
< gOptionBlockWidth
; Loop
++) {
752 PrintAt (MenuOption
->OptCol
+ Loop
, MenuOption
->Row
, (CHAR16
*) L
" ");
756 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_HIGHLIGHT
| FIELD_BACKGROUND_HIGHLIGHT
);
758 if ((MenuOption
->Col
+ gPromptBlockWidth
+ 1) == MenuOption
->OptCol
) {
759 PrintCharAt (MenuOption
->OptCol
, Row
, LEFT_NUMERIC_DELIMITER
);
760 Column
= MenuOption
->OptCol
+ 1;
763 // If Number looks like "3", convert it to "03/"
765 if (Number
== 4 && (NumericType
== DATE_NUMERIC
)) {
766 FormattedNumber
[3] = FormattedNumber
[1];
767 FormattedNumber
[2] = DATE_SEPARATOR
;
768 FormattedNumber
[1] = FormattedNumber
[0];
769 FormattedNumber
[0] = L
'0';
773 // If Number looks like "13", convert it to "13/"
775 if (Number
== 6 && (NumericType
== DATE_NUMERIC
)) {
776 FormattedNumber
[3] = FormattedNumber
[2];
777 FormattedNumber
[2] = DATE_SEPARATOR
;
782 (NumericType
== TIME_NUMERIC
) &&
783 (MenuOption
->Col
+ gPromptBlockWidth
+ 8) != MenuOption
->OptCol
785 FormattedNumber
[3] = FormattedNumber
[1];
786 FormattedNumber
[2] = TIME_SEPARATOR
;
787 FormattedNumber
[1] = FormattedNumber
[0];
788 FormattedNumber
[0] = L
'0';
793 (NumericType
== TIME_NUMERIC
) &&
794 (MenuOption
->Col
+ gPromptBlockWidth
+ 8) == MenuOption
->OptCol
796 FormattedNumber
[3] = FormattedNumber
[1];
797 FormattedNumber
[2] = RIGHT_NUMERIC_DELIMITER
;
798 FormattedNumber
[1] = FormattedNumber
[0];
799 FormattedNumber
[0] = L
'0';
803 PrintStringAt (Column
, Row
, FormattedNumber
);
804 if (Number
== 10 && (NumericType
== DATE_NUMERIC
)) {
805 PrintChar (RIGHT_NUMERIC_DELIMITER
);
808 if (NumericType
== REGULAR_NUMERIC
) {
809 PrintChar (RIGHT_NUMERIC_DELIMITER
);
816 goto EnterCarriageReturn
;
819 return EFI_DEVICE_ERROR
;
829 case CHAR_CARRIAGE_RETURN
:
831 // Check to see if the Value is something reasonable against consistency limitations.
832 // If not, let's kick the error specified.
835 // This gives us visibility to the FileFormTags->NvRamMap to check things
836 // ActiveIfr is a global maintained by the menuing code to ensure that we
837 // are pointing to the correct formset's file data.
839 for (Count
= 0; Count
< gActiveIfr
; Count
++) {
840 FileFormTags
= FileFormTags
->NextFile
;
843 ExtractRequestedNvMap (FileFormTags
, Tag
->VariableNumber
, &VariableDefinition
);
845 CopyMem (&VariableDefinition
->NvRamMap
[Tag
->StorageStart
], &Tag
->Value
, Tag
->StorageWidth
);
848 // Data associated with a NULL device (in the fake NV storage)
850 if (Tag
->StorageWidth
== (UINT16
) 0) {
851 CopyMem (&VariableDefinition
->FakeNvRamMap
[Tag
->StorageStart
], &Tag
->Value
, 2);
854 // If a late check is required save off the information. This is used when consistency checks
855 // are required, but certain values might be bound by an impossible consistency check such as
856 // if two questions are bound by consistency checks and each only has two possible choices, there
857 // would be no way for a user to switch the values. Thus we require late checking.
859 if (Tag
->Flags
& EFI_IFR_FLAG_LATE_CHECK
) {
860 CopyMem (&Tag
->OldValue
, &BackupValue
, Tag
->StorageWidth
);
863 // In theory, passing the value and the Id are sufficient to determine what needs
864 // to be done. The Id is the key to look for the entry needed in the Inconsistency
865 // database. That will yields operand and ID data - and since the ID's correspond
866 // to the NV storage, we can determine the values for other IDs there.
868 if (ValueIsNotValid (TRUE
, 0, Tag
, FileFormTags
, &PopUp
)) {
869 if (PopUp
== 0x0000) {
870 SelectionComplete
= TRUE
;
874 StringPtr
= GetToken (PopUp
, MenuOption
->Handle
);
876 CreatePopUp (GetStringWidth (StringPtr
) / 2, 3, &NullCharacter
, StringPtr
, &NullCharacter
);
879 WaitForKeyStroke (&Key
);
881 switch (Key
.UnicodeChar
) {
883 case CHAR_CARRIAGE_RETURN
:
884 SelectionComplete
= TRUE
;
885 gBS
->FreePool (StringPtr
);
891 } while (!SelectionComplete
);
893 Tag
->Value
= BackupValue
;
894 *Value
= BackupValue
;
896 CopyMem (&VariableDefinition
->NvRamMap
[Tag
->StorageStart
], &Tag
->Value
, Tag
->StorageWidth
);
899 // Data associated with a NULL device (in the fake NV storage)
901 if (Tag
->StorageWidth
== (UINT16
) 0) {
902 CopyMem (&VariableDefinition
->FakeNvRamMap
[Tag
->StorageStart
], &Tag
->Value
, 2);
905 return EFI_DEVICE_ERROR
;
918 // Remove a character
920 Number
= PreviousNumber
[Count
- 1];
921 *Value
= (UINT16
) Number
;
922 UpdateStatusBar (INPUT_ERROR
, Tag
->Flags
, FALSE
);
925 PrintAt (Column
, Row
, (CHAR16
*) L
" ");
931 if (Key
.UnicodeChar
> L
'9' || Key
.UnicodeChar
< L
'0') {
932 UpdateStatusBar (INPUT_ERROR
, Tag
->Flags
, TRUE
);
936 // If Count 0-4 is complete, there is no way more is valid
942 // Someone typed something valid!
945 Number
= Number
* 10 + (Key
.UnicodeChar
- L
'0');
947 Number
= Key
.UnicodeChar
- L
'0';
950 if (Number
> Tag
->Maximum
) {
951 UpdateStatusBar (INPUT_ERROR
, Tag
->Flags
, TRUE
);
952 Number
= PreviousNumber
[Count
];
955 UpdateStatusBar (INPUT_ERROR
, Tag
->Flags
, FALSE
);
960 PreviousNumber
[Count
] = Number
;
961 *Value
= (UINT16
) Number
;
962 Tag
->Value
= (UINT16
) Number
;
964 PrintCharAt (Column
, Row
, Key
.UnicodeChar
);
969 } while (!SelectionComplete
);
973 // Notice that this is at least needed for the ordered list manipulation.
974 // Left/Right doesn't make sense for this op-code
977 GetSelectionInputPopUp (
978 IN UI_MENU_OPTION
*MenuOption
,
989 CHAR16
*TempStringPtr
;
992 UINTN TopOptionIndex
;
993 UINTN HighlightPosition
;
1000 UINTN PopUpMenuLines
;
1001 UINTN MenuLinesInView
;
1004 BOOLEAN FirstOptionFoundFlag
;
1005 INT32 SavedAttribute
;
1008 UINT8
*ValueArrayBackup
;
1010 BOOLEAN Initialized
;
1011 BOOLEAN KeyInitialized
;
1012 BOOLEAN ShowDownArrow
;
1013 BOOLEAN ShowUpArrow
;
1014 UINTN DimensionsWidth
;
1016 DimensionsWidth
= gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
;
1020 ValueArray
= (UINT8
*) Value
;
1021 ValueArrayBackup
= NULL
;
1022 Initialized
= FALSE
;
1023 KeyInitialized
= FALSE
;
1024 ShowDownArrow
= FALSE
;
1025 ShowUpArrow
= FALSE
;
1027 if (Tag
->Operand
== EFI_IFR_ORDERED_LIST_OP
) {
1028 ValueArrayBackup
= AllocateZeroPool (Tag
->StorageWidth
);
1029 ASSERT (ValueArrayBackup
!= NULL
);
1030 CopyMem (ValueArrayBackup
, ValueArray
, ValueCount
);
1031 TempValue
= *(UINT8
*) (ValueArray
);
1032 if (ValueArray
[0] != 0x00) {
1036 for (Index
= 0; ValueArray
[Index
] != 0x00; Index
++)
1046 FirstOptionFoundFlag
= FALSE
;
1048 StringPtr
= AllocateZeroPool ((gOptionBlockWidth
+ 1) * 2);
1052 // Initialization for "One of" pop-up menu
1055 // Get the number of one of options present and its size
1057 for (Index
= MenuOption
->TagIndex
; MenuOption
->Tags
[Index
].Operand
!= EFI_IFR_END_ONE_OF_OP
; Index
++) {
1058 if (MenuOption
->Tags
[Index
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
&&
1059 !MenuOption
->Tags
[Index
].Suppress
) {
1060 if (!FirstOptionFoundFlag
) {
1061 FirstOptionFoundFlag
= TRUE
;
1065 Token
= MenuOption
->Tags
[Index
].Text
;
1068 // If this is an ordered list that is initialized
1071 for (ValueBackup
= (UINT8
) MenuOption
->TagIndex
;
1072 MenuOption
->Tags
[ValueBackup
].Operand
!= EFI_IFR_END_OP
;
1075 if (MenuOption
->Tags
[ValueBackup
].Value
== ((UINT8
*) ValueArrayBackup
)[Index
- MenuOption
->TagIndex
- 1]) {
1076 StringPtr
= GetToken (MenuOption
->Tags
[ValueBackup
].Text
, MenuOption
->Handle
);
1081 StringPtr
= GetToken (Token
, MenuOption
->Handle
);
1084 if (StrLen (StringPtr
) > PopUpWidth
) {
1085 PopUpWidth
= StrLen (StringPtr
);
1088 gBS
->FreePool (StringPtr
);
1092 // Perform popup menu initialization.
1094 PopUpMenuLines
= Count
;
1095 PopUpWidth
= PopUpWidth
+ POPUP_PAD_SPACE_COUNT
;
1097 SavedAttribute
= gST
->ConOut
->Mode
->Attribute
;
1098 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
1100 if ((PopUpWidth
+ POPUP_FRAME_WIDTH
) > DimensionsWidth
) {
1101 PopUpWidth
= DimensionsWidth
- POPUP_FRAME_WIDTH
;
1104 Start
= (DimensionsWidth
- PopUpWidth
- POPUP_FRAME_WIDTH
) / 2 + gScreenDimensions
.LeftColumn
;
1105 End
= Start
+ PopUpWidth
+ POPUP_FRAME_WIDTH
;
1106 Top
= gScreenDimensions
.TopRow
+ NONE_FRONT_PAGE_HEADER_HEIGHT
;
1107 Bottom
= gScreenDimensions
.BottomRow
- STATUS_BAR_HEIGHT
- FOOTER_HEIGHT
;
1109 MenuLinesInView
= Bottom
- Top
- 1;
1110 if (MenuLinesInView
>= PopUpMenuLines
) {
1111 Top
= Top
+ (MenuLinesInView
- PopUpMenuLines
) / 2;
1112 Bottom
= Top
+ PopUpMenuLines
+ 1;
1114 TempValue
= MenuOption
->Tags
[MenuOption
->TagIndex
+ 1].Value
;
1115 ShowDownArrow
= TRUE
;
1119 HighlightPosition
= 0;
1122 for (Index
= MenuOption
->TagIndex
, Index2
= 0; Index2
< ValueCount
; Index
++, Index2
++) {
1124 // Set the value for the item we are looking for
1126 Count
= ValueArrayBackup
[Index2
];
1129 // If we hit the end of the Array, we are complete
1135 if (MenuOption
->Tags
[Index
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
) {
1136 for (ValueBackup
= (UINT8
) MenuOption
->TagIndex
;
1137 MenuOption
->Tags
[ValueBackup
].Operand
!= EFI_IFR_END_ONE_OF_OP
;
1141 // We just found what we are looking for
1143 if (MenuOption
->Tags
[ValueBackup
].Value
== Count
) {
1145 // As long as the two indexes aren't the same, we have
1146 // two different op-codes we need to swap internally
1148 if (Index
!= ValueBackup
) {
1150 // Backup destination tag, then copy source to destination, then copy backup to source location
1152 CopyMem (&TagBackup
, &MenuOption
->Tags
[Index
], sizeof (EFI_TAG
));
1153 CopyMem (&MenuOption
->Tags
[Index
], &MenuOption
->Tags
[ValueBackup
], sizeof (EFI_TAG
));
1154 CopyMem (&MenuOption
->Tags
[ValueBackup
], &TagBackup
, sizeof (EFI_TAG
));
1157 // If the indexes are the same, then the op-code is where he belongs
1164 // Since this wasn't an option op-code (likely the ordered list op-code) decerement Index2
1171 // Clear that portion of the screen
1173 ClearLines (Start
, End
, Top
, Bottom
, POPUP_TEXT
| POPUP_BACKGROUND
);
1176 // Draw "One of" pop-up menu
1178 Character
= (CHAR16
) BOXDRAW_DOWN_RIGHT
;
1179 PrintCharAt (Start
, Top
, Character
);
1180 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
1181 if ((ShowUpArrow
) && ((Index
+ 1) == (Start
+ End
) / 2)) {
1182 Character
= (CHAR16
) GEOMETRICSHAPE_UP_TRIANGLE
;
1184 Character
= (CHAR16
) BOXDRAW_HORIZONTAL
;
1187 PrintChar (Character
);
1190 Character
= (CHAR16
) BOXDRAW_DOWN_LEFT
;
1191 PrintChar (Character
);
1192 Character
= (CHAR16
) BOXDRAW_VERTICAL
;
1193 for (Index
= Top
+ 1; Index
< Bottom
; Index
++) {
1194 PrintCharAt (Start
, Index
, Character
);
1195 PrintCharAt (End
- 1, Index
, Character
);
1198 // Display the One of options
1201 for (Index
= MenuOption
->TagIndex
+ TopOptionIndex
;
1202 (MenuOption
->Tags
[Index
].Operand
!= EFI_IFR_END_ONE_OF_OP
) && (Index2
< Bottom
);
1205 if (MenuOption
->Tags
[Index
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
) {
1206 Token
= MenuOption
->Tags
[Index
].Text
;
1208 for (ValueBackup
= (UINT8
) MenuOption
->TagIndex
;
1209 MenuOption
->Tags
[ValueBackup
].Operand
!= EFI_IFR_END_ONE_OF_OP
;
1212 if (MenuOption
->Tags
[ValueBackup
].Value
== ((UINT8
*) ValueArrayBackup
)[Index
- MenuOption
->TagIndex
- 1]) {
1213 StringPtr
= GetToken (MenuOption
->Tags
[ValueBackup
].Text
, MenuOption
->Handle
);
1218 ValueBackup
= (UINT8
) Index
;
1219 StringPtr
= GetToken (Token
, MenuOption
->Handle
);
1222 // If the string occupies multiple lines, truncate it to fit in one line,
1223 // and append a "..." for indication.
1225 if (StrLen (StringPtr
) > (PopUpWidth
- 1)) {
1226 TempStringPtr
= AllocateZeroPool (sizeof (CHAR16
) * (PopUpWidth
- 1));
1227 ASSERT (TempStringPtr
!= NULL
);
1228 CopyMem (TempStringPtr
, StringPtr
, (sizeof (CHAR16
) * (PopUpWidth
- 5)));
1229 gBS
->FreePool (StringPtr
);
1230 StringPtr
= TempStringPtr
;
1231 StrCat (StringPtr
, (CHAR16
*) L
"...");
1234 // Code to display the text should go here. Follwed by the [*]
1236 if (MenuOption
->Tags
[ValueBackup
].Suppress
== TRUE
) {
1238 // Don't show the one, so decrease the Index2 for balance
1241 } else if (MenuOption
->Tags
[ValueBackup
].GrayOut
== TRUE
) {
1245 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_GRAYED
| POPUP_BACKGROUND
);
1246 PrintStringAt (Start
+ 2, Index2
, StringPtr
);
1247 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
1248 } else if (MenuOption
->Tags
[ValueBackup
].Value
== TempValue
) {
1250 // Highlight the selected one
1252 gST
->ConOut
->SetAttribute (gST
->ConOut
, PICKLIST_HIGHLIGHT_TEXT
| PICKLIST_HIGHLIGHT_BACKGROUND
);
1253 PrintStringAt (Start
+ 2, Index2
, StringPtr
);
1254 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
1255 HighlightPosition
= Index2
;
1257 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
1258 PrintStringAt (Start
+ 2, Index2
, StringPtr
);
1261 gBS
->FreePool (StringPtr
);
1262 Index2
= Index2
+ 1;
1266 Character
= (CHAR16
) BOXDRAW_UP_RIGHT
;
1267 PrintCharAt (Start
, Bottom
, Character
);
1268 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
1269 if ((ShowDownArrow
) && ((Index
+ 1) == (Start
+ End
) / 2)) {
1270 Character
= (CHAR16
) GEOMETRICSHAPE_DOWN_TRIANGLE
;
1272 Character
= (CHAR16
) BOXDRAW_HORIZONTAL
;
1275 PrintChar (Character
);
1278 Character
= (CHAR16
) BOXDRAW_UP_LEFT
;
1279 PrintChar (Character
);
1281 // Get User selection and change TempValue if necessary
1284 // Stop: One of pop-up menu
1286 Key
.UnicodeChar
= CHAR_NULL
;
1287 if ((gDirection
== SCAN_UP
) || (gDirection
== SCAN_DOWN
)) {
1288 Key
.ScanCode
= gDirection
;
1293 if (!KeyInitialized
) {
1294 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_ONE_OF_OP
) {
1295 *KeyValue
= MenuOption
->Tags
[MenuOption
->TagIndex
+ 1].Key
;
1297 *KeyValue
= MenuOption
->ThisTag
->Key
;
1300 KeyInitialized
= TRUE
;
1303 WaitForKeyStroke (&Key
);
1306 switch (Key
.UnicodeChar
) {
1310 // If an ordered list op-code, we will allow for a popup of +/- keys
1311 // to create an ordered list of items
1313 if (Tag
->Operand
== EFI_IFR_ORDERED_LIST_OP
) {
1314 if (Key
.UnicodeChar
== '+') {
1315 if ((TopOptionIndex
> 1) && (HighlightPosition
== (Top
+ 1))) {
1317 // Highlight reaches the top of the popup window, scroll one menu item.
1320 ShowDownArrow
= TRUE
;
1323 if (TopOptionIndex
== 1) {
1324 ShowUpArrow
= FALSE
;
1327 if (((TopOptionIndex
+ MenuLinesInView
) <= PopUpMenuLines
) && (HighlightPosition
== (Bottom
- 1))) {
1329 // Highlight reaches the bottom of the popup window, scroll one menu item.
1335 if ((TopOptionIndex
+ MenuLinesInView
) == (PopUpMenuLines
+ 1)) {
1336 ShowDownArrow
= FALSE
;
1340 for (Index
= MenuOption
->TagIndex
+ TopOptionIndex
;
1341 MenuOption
->Tags
[Index
].Operand
!= EFI_IFR_END_ONE_OF_OP
;
1344 if (MenuOption
->Tags
[Index
].Operand
== EFI_IFR_ORDERED_LIST_OP
) {
1348 if (Key
.UnicodeChar
== '+') {
1349 TempIndex
= Index
- 1;
1351 TempIndex
= Index
+ 1;
1354 // Is this the current tag we are on?
1356 if (MenuOption
->Tags
[Index
].Value
== TempValue
) {
1358 // Is this prior tag a valid choice? If not, bail out
1360 if (MenuOption
->Tags
[TempIndex
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
) {
1362 // Copy the destination tag to the local variable
1364 CopyMem (&TagBackup
, &MenuOption
->Tags
[TempIndex
], sizeof (EFI_TAG
));
1366 // Copy the current tag to the tag location before us
1368 CopyMem (&MenuOption
->Tags
[TempIndex
], &MenuOption
->Tags
[Index
], sizeof (EFI_TAG
));
1370 // Copy the backed up tag to the current location
1372 CopyMem (&MenuOption
->Tags
[Index
], &TagBackup
, sizeof (EFI_TAG
));
1375 // Adjust the array of values
1377 for (Index
= 0; Index
< ValueCount
; Index
++) {
1378 if (ValueArrayBackup
[Index
] == (UINT8
) TempValue
) {
1379 if (Key
.UnicodeChar
== '+') {
1382 // It is the top of the array already
1387 TempIndex
= Index
- 1;
1389 if ((Index
+ 1) == ValueCount
) {
1391 // It is the bottom of the array already
1396 TempIndex
= Index
+ 1;
1399 ValueBackup
= ValueArrayBackup
[TempIndex
];
1400 ValueArrayBackup
[TempIndex
] = ValueArrayBackup
[Index
];
1401 ValueArrayBackup
[Index
] = ValueBackup
;
1416 switch (Key
.ScanCode
) {
1419 if (Key
.ScanCode
== SCAN_UP
) {
1420 if ((TopOptionIndex
> 1) && (HighlightPosition
== (Top
+ 1))) {
1422 // Highlight reaches the top of the popup window, scroll one menu item.
1425 ShowDownArrow
= TRUE
;
1428 if (TopOptionIndex
== 1) {
1429 ShowUpArrow
= FALSE
;
1432 if (((TopOptionIndex
+ MenuLinesInView
) <= PopUpMenuLines
) && (HighlightPosition
== (Bottom
- 1))) {
1434 // Highlight reaches the bottom of the popup window, scroll one menu item.
1440 if ((TopOptionIndex
+ MenuLinesInView
) == (PopUpMenuLines
+ 1)) {
1441 ShowDownArrow
= FALSE
;
1445 for (Index
= MenuOption
->TagIndex
+ TopOptionIndex
;
1446 MenuOption
->Tags
[Index
].Operand
!= EFI_IFR_END_ONE_OF_OP
;
1449 if (MenuOption
->Tags
[Index
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
) {
1451 for (Index
= 0; (ValueArrayBackup
[Index
] != TempValue
) && (Index
< ValueCount
); Index
++)
1455 // Did we hit the end of the array? Either get the first TempValue or the next one
1457 if (Key
.ScanCode
== SCAN_UP
) {
1459 TempValue
= ValueArrayBackup
[0];
1461 TempValue
= ValueArrayBackup
[Index
- 1];
1464 if ((Index
+ 1) == ValueCount
) {
1465 TempValue
= ValueArrayBackup
[Index
];
1467 TempValue
= ValueArrayBackup
[Index
+ 1];
1472 if (Key
.ScanCode
== SCAN_UP
) {
1473 TempIndex
= Index
- 1;
1476 // Keep going until meets meaningful tag.
1478 while ((MenuOption
->Tags
[TempIndex
].Operand
!= EFI_IFR_ONE_OF_OPTION_OP
&&
1479 MenuOption
->Tags
[TempIndex
].Operand
!= EFI_IFR_ONE_OF_OP
&&
1480 MenuOption
->Tags
[TempIndex
].Operand
!= EFI_IFR_END_ONE_OF_OP
)
1482 (MenuOption
->Tags
[TempIndex
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
&&
1483 (MenuOption
->Tags
[TempIndex
].Suppress
|| MenuOption
->Tags
[TempIndex
].GrayOut
))) {
1487 TempIndex
= Index
+ 1;
1490 // Keep going until meets meaningful tag.
1492 while ((MenuOption
->Tags
[TempIndex
].Operand
!= EFI_IFR_ONE_OF_OPTION_OP
&&
1493 MenuOption
->Tags
[TempIndex
].Operand
!= EFI_IFR_ONE_OF_OP
&&
1494 MenuOption
->Tags
[TempIndex
].Operand
!= EFI_IFR_END_ONE_OF_OP
)
1496 (MenuOption
->Tags
[TempIndex
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
&&
1497 (MenuOption
->Tags
[TempIndex
].Suppress
|| MenuOption
->Tags
[TempIndex
].GrayOut
))) {
1502 // The option value is the same as what is stored in NV store. This is where we take action
1504 if (MenuOption
->Tags
[Index
].Value
== TempValue
) {
1506 // Only if the previous op-code is an option can we select it, otherwise we are at the left-most option
1508 if (MenuOption
->Tags
[TempIndex
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
) {
1509 TempValue
= MenuOption
->Tags
[TempIndex
].Value
;
1510 *KeyValue
= MenuOption
->Tags
[TempIndex
].Key
;
1512 TempValue
= MenuOption
->Tags
[Index
].Value
;
1513 *KeyValue
= MenuOption
->Tags
[Index
].Key
;
1523 gST
->ConOut
->SetAttribute (gST
->ConOut
, SavedAttribute
);
1524 if (ValueArrayBackup
!= NULL
) {
1525 gBS
->FreePool (ValueArrayBackup
);
1528 return EFI_DEVICE_ERROR
;
1536 case CHAR_CARRIAGE_RETURN
:
1538 // return the current selection
1540 if (Tag
->Operand
== EFI_IFR_ORDERED_LIST_OP
) {
1541 CopyMem (ValueArray
, ValueArrayBackup
, ValueCount
);
1542 gBS
->FreePool (ValueArrayBackup
);
1555 gST
->ConOut
->SetAttribute (gST
->ConOut
, SavedAttribute
);
1561 OUT EFI_INPUT_KEY
*Key
1567 UiWaitForSingleEvent (gST
->ConIn
->WaitForKey
, 0);
1568 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, Key
);
1569 } while (EFI_ERROR(Status
));