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
220 CHAR16 NullCharacter
;
229 BOOLEAN Confirmation
;
230 BOOLEAN ConfirmationComplete
;
231 EFI_HII_CALLBACK_PACKET
*Packet
;
232 EFI_FORM_CALLBACK_PROTOCOL
*FormCallback
;
233 EFI_VARIABLE_DEFINITION
*VariableDefinition
;
234 UINTN DimensionsWidth
;
235 UINTN DimensionsHeight
;
236 EFI_IFR_DATA_ENTRY
*DataEntry
;
238 DimensionsWidth
= gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
;
239 DimensionsHeight
= gScreenDimensions
.BottomRow
- gScreenDimensions
.TopRow
;
241 VariableDefinition
= NULL
;
243 NullCharacter
= CHAR_NULL
;
245 Space
[1] = CHAR_NULL
;
246 Confirmation
= FALSE
;
247 ConfirmationComplete
= FALSE
;
248 Status
= EFI_SUCCESS
;
253 // Remember that dynamic pages in an environment where all pages are not
254 // dynamic require us to call back to the user to give them an opportunity
255 // to register fresh information in the HII database so that we can extract it.
257 Status
= gBS
->HandleProtocol (
258 (VOID
*) (UINTN
) MenuOption
->Tags
[0].CallbackHandle
,
259 &gEfiFormCallbackProtocolGuid
,
260 (VOID
**) &FormCallback
263 TempString
= AllocateZeroPool (MenuOption
->ThisTag
->Maximum
* 2);
264 TempString2
= AllocateZeroPool (MenuOption
->ThisTag
->Maximum
* 2);
267 ASSERT (TempString2
);
269 if (Tag
->Flags
& EFI_IFR_FLAG_INTERACTIVE
) {
271 // Password requires a callback to determine if a password exists
273 DataEntry
= (EFI_IFR_DATA_ENTRY
*) (PageData
+ 1);
274 DataEntry
->OpCode
= EFI_IFR_PASSWORD_OP
;
275 DataEntry
->Length
= 3;
277 ExtractRequestedNvMap (FileFormTags
, Tag
->VariableNumber
, &VariableDefinition
);
280 // The user is about to be prompted with a password field, Data = 0 (Return Status determines the type of prompt)
282 DataEntry
->Data
= (VOID
*) (UINTN
) (UINT8
) (0 + SecondEntry
* 2);
283 PageData
->NvRamMap
= VariableDefinition
->NvRamMap
;
285 if ((FormCallback
!= NULL
) && (FormCallback
->Callback
!= NULL
)) {
286 Status
= FormCallback
->Callback (
294 // If error on return, continue with the reading of a typed in password to verify user knows password
295 // If no error, there is no password set, so prompt for new password
296 // if the previous callback was to verify the user knew password, and user typed it correctly - should return no error
298 if (!EFI_ERROR (Status
)) {
299 PromptForPassword
= FALSE
;
302 // Simulate this as the second entry into this routine for an interactive behavior
305 } else if (Status
== EFI_NOT_READY
) {
307 if (Packet
!= NULL
) {
309 // Upon error, we will likely receive a string to print out
310 // Display error popup
312 ScreenSize
= EFI_MAX(GetStringWidth (Packet
->String
), 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 gBS
->FreePool (TempString
);
322 gBS
->FreePool (TempString2
);
323 return EFI_NOT_READY
;
329 // Display PopUp Screen
331 ScreenSize
= GetStringWidth (gPromptForNewPassword
) / 2;
332 if (GetStringWidth (gConfirmPassword
) / 2 > ScreenSize
) {
333 ScreenSize
= GetStringWidth (gConfirmPassword
) / 2;
336 Start
= (DimensionsWidth
- ScreenSize
- 4) / 2 + gScreenDimensions
.LeftColumn
+ 2;
337 Top
= ((DimensionsHeight
- 6) / 2) + gScreenDimensions
.TopRow
- 1;
340 if (PromptForPassword
) {
341 CreatePopUp (ScreenSize
, 4, &NullCharacter
, gPromptForPassword
, Space
, &NullCharacter
);
343 CreatePopUp (ScreenSize
, 4, &NullCharacter
, gPromptForNewPassword
, Space
, &NullCharacter
);
346 CreatePopUp (ScreenSize
, 4, &NullCharacter
, gConfirmPassword
, Space
, &NullCharacter
);
347 StringPtr
[0] = CHAR_NULL
;
351 Status
= WaitForKeyStroke (&Key
);
353 switch (Key
.UnicodeChar
) {
355 if (Key
.ScanCode
== SCAN_ESC
) {
356 return EFI_NOT_READY
;
359 ConfirmationComplete
= FALSE
;
362 case CHAR_CARRIAGE_RETURN
:
363 if (Tag
->Flags
& EFI_IFR_FLAG_INTERACTIVE
) {
365 // User just typed a string in
367 DataEntry
= (EFI_IFR_DATA_ENTRY
*) (PageData
+ 1);
368 DataEntry
->OpCode
= EFI_IFR_PASSWORD_OP
;
371 // If the user just typed in a password, Data = 1
372 // If the user just typed in a password to confirm the previous password, Data = 2
375 DataEntry
->Length
= 3;
376 DataEntry
->Data
= (VOID
*) (UINTN
) (UINT8
) (1 + SecondEntry
* 2);
378 if ((FormCallback
!= NULL
) && (FormCallback
->Callback
!= NULL
)) {
379 Status
= FormCallback
->Callback (
387 DataEntry
->Length
= sizeof (EFI_IFR_DATA_ENTRY
);
388 DataEntry
->Data
= (VOID
*) TempString
;
390 DataEntry
->Length
= 3;
391 DataEntry
->Data
= (VOID
*) (UINTN
) (UINT8
) (2 + SecondEntry
* 2);
393 if ((FormCallback
!= NULL
) && (FormCallback
->Callback
!= NULL
)) {
394 Status
= FormCallback
->Callback (
402 DataEntry
->Length
= sizeof (EFI_IFR_DATA_ENTRY
);
403 DataEntry
->Data
= (VOID
*) TempString2
;
406 if ((FormCallback
!= NULL
) && (FormCallback
->Callback
!= NULL
)) {
407 Status
= FormCallback
->Callback (
415 // If this was the confirmation round of callbacks
416 // and an error comes back, display an error
419 if (EFI_ERROR (Status
)) {
420 if (Packet
->String
== NULL
) {
421 ScreenSize
= EFI_MAX (GetStringWidth (gConfirmError
), GetStringWidth (gPressEnter
)) / 2;
422 CreatePopUp (ScreenSize
, 4, &NullCharacter
, gConfirmError
, gPressEnter
, &NullCharacter
);
424 ScreenSize
= EFI_MAX (GetStringWidth (Packet
->String
), GetStringWidth (gPressEnter
)) / 2;
425 CreatePopUp (ScreenSize
, 4, &NullCharacter
, Packet
->String
, gPressEnter
, &NullCharacter
);
426 gBS
->FreePool (Packet
);
429 StringPtr
[0] = CHAR_NULL
;
431 Status
= WaitForKeyStroke (&Key
);
433 if (Key
.UnicodeChar
== CHAR_CARRIAGE_RETURN
) {
434 gBS
->FreePool (TempString
);
435 gBS
->FreePool (TempString2
);
436 return EFI_NOT_READY
;
440 gBS
->FreePool (TempString
);
441 gBS
->FreePool (TempString2
);
442 return EFI_NOT_READY
;
446 // User typed a string in and it wasn't valid somehow from the callback
447 // For instance, callback may have said that some invalid characters were contained in the string
449 if (Status
== EFI_NOT_READY
) {
453 if (PromptForPassword
&& EFI_ERROR (Status
)) {
454 gBS
->FreePool (TempString
);
455 gBS
->FreePool (TempString2
);
456 return EFI_DEVICE_ERROR
;
463 // Compare tempstring and tempstring2, if the same, return with StringPtr success
464 // Otherwise, kick and error box, and return an error
466 if (StrCmp (TempString
, TempString2
) == 0) {
467 gBS
->FreePool (TempString
);
468 gBS
->FreePool (TempString2
);
471 ScreenSize
= EFI_MAX (GetStringWidth (gConfirmError
), GetStringWidth (gPressEnter
)) / 2;
472 CreatePopUp (ScreenSize
, 4, &NullCharacter
, gConfirmError
, gPressEnter
, &NullCharacter
);
473 StringPtr
[0] = CHAR_NULL
;
475 Status
= WaitForKeyStroke (&Key
);
476 if (Key
.UnicodeChar
== CHAR_CARRIAGE_RETURN
) {
477 gBS
->FreePool (TempString
);
478 gBS
->FreePool (TempString2
);
479 return EFI_DEVICE_ERROR
;
485 if (PromptForPassword
) {
487 // I was asked for a password, return it back in StringPtr
489 gBS
->FreePool (TempString
);
490 gBS
->FreePool (TempString2
);
494 // If the two passwords were not the same kick an error popup
497 ConfirmationComplete
= TRUE
;
502 if (StringPtr
[0] != CHAR_NULL
) {
504 for (Index
= 0; StringPtr
[Index
] != CHAR_NULL
; Index
++) {
505 TempString
[Index
] = StringPtr
[Index
];
508 // Effectively truncate string by 1 character
510 TempString
[Index
- 1] = CHAR_NULL
;
511 StrCpy (StringPtr
, TempString
);
513 for (Index
= 0; StringPtr
[Index
] != CHAR_NULL
; Index
++) {
514 TempString2
[Index
] = StringPtr
[Index
];
517 // Effectively truncate string by 1 character
519 TempString2
[Index
- 1] = CHAR_NULL
;
520 StrCpy (StringPtr
, TempString2
);
523 ConfirmationComplete
= FALSE
;
525 ConfirmationComplete
= FALSE
;
529 // Must be a character we are interested in!
532 if ((StringPtr
[0] == CHAR_NULL
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
534 StrnCpy (StringPtr
, &Key
.UnicodeChar
, 1);
535 StrnCpy (TempString
, &Key
.UnicodeChar
, 1);
537 StrnCpy (StringPtr
, &Key
.UnicodeChar
, 1);
538 StrnCpy (TempString2
, &Key
.UnicodeChar
, 1);
539 ConfirmationComplete
= FALSE
;
541 } else if ((GetStringWidth (StringPtr
) / 2 <= (UINTN
) (MenuOption
->ThisTag
->Maximum
- 1) / 2) &&
542 (Key
.UnicodeChar
!= CHAR_BACKSPACE
)
544 KeyPad
[0] = Key
.UnicodeChar
;
545 KeyPad
[1] = CHAR_NULL
;
547 StrCat (StringPtr
, KeyPad
);
548 StrCat (TempString
, KeyPad
);
550 StrCat (StringPtr
, KeyPad
);
551 StrCat (TempString2
, KeyPad
);
555 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_BLACK
, EFI_LIGHTGRAY
));
556 for (Index
= 1; Index
< ScreenSize
; Index
++) {
557 PrintCharAt (Start
+ Index
, Top
+ 3, L
' ');
560 gST
->ConOut
->SetCursorPosition (
562 (DimensionsWidth
- GetStringWidth (StringPtr
) / 2) / 2 + gScreenDimensions
.LeftColumn
,
565 for (Index
= 0; Index
+ 1 < GetStringWidth (StringPtr
) / 2; Index
++) {
569 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
575 } while (!ConfirmationComplete
);
578 gBS
->FreePool (TempString
);
579 gBS
->FreePool (TempString2
);
594 Key
= (CHAR16
*) L
"MAR10648567";
595 Buffer
= AllocateZeroPool (MaxSize
);
599 for (Index
= 0; Key
[Index
] != 0; Index
++) {
600 for (Loop
= 0; Loop
< (UINT8
) (MaxSize
/ 2); Loop
++) {
601 Buffer
[Loop
] = (CHAR16
) (Password
[Loop
] ^ Key
[Index
]);
605 CopyMem (Password
, Buffer
, MaxSize
);
607 gBS
->FreePool (Buffer
);
613 IN UI_MENU_OPTION
*MenuOption
,
614 IN EFI_FILE_FORM_TAGS
*FileFormTagsHead
,
615 IN BOOLEAN ManualInput
,
617 IN UINTN NumericType
,
624 This routine reads a numeric value from the user input.
628 MenuOption - Pointer to the current input menu.
630 FileFormTagsHead - Pointer to the root of formset.
632 ManualInput - If the input is manual or not.
634 Tag - Pointer to all the attributes and values associated with a tag.
636 Value - Pointer to the numeric value that is going to be read.
640 EFI_SUCCESS - If numerical input is read successfully
641 EFI_DEVICE_ERROR - If operation fails
646 BOOLEAN SelectionComplete
;
649 CHAR16 FormattedNumber
[6];
650 UINTN PreviousNumber
[6];
655 CHAR16 NullCharacter
;
657 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 Status
= 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 Status
= WaitForKeyStroke (&Key
);
884 switch (Key
.UnicodeChar
) {
886 case CHAR_CARRIAGE_RETURN
:
887 SelectionComplete
= TRUE
;
888 gBS
->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
,
993 CHAR16
*TempStringPtr
;
996 UINTN TopOptionIndex
;
997 UINTN HighlightPosition
;
1004 UINTN PopUpMenuLines
;
1005 UINTN MenuLinesInView
;
1009 BOOLEAN FirstOptionFoundFlag
;
1010 INT32 SavedAttribute
;
1013 UINT8
*ValueArrayBackup
;
1015 BOOLEAN Initialized
;
1016 BOOLEAN KeyInitialized
;
1017 BOOLEAN ShowDownArrow
;
1018 BOOLEAN ShowUpArrow
;
1019 UINTN DimensionsWidth
;
1020 UINTN DimensionsHeight
;
1022 DimensionsWidth
= gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
;
1023 DimensionsHeight
= gScreenDimensions
.BottomRow
- gScreenDimensions
.TopRow
;
1027 ValueArray
= (UINT8
*) Value
;
1028 ValueArrayBackup
= NULL
;
1029 Initialized
= FALSE
;
1030 KeyInitialized
= FALSE
;
1031 ShowDownArrow
= FALSE
;
1032 ShowUpArrow
= FALSE
;
1034 if (Tag
->Operand
== EFI_IFR_ORDERED_LIST_OP
) {
1035 ValueArrayBackup
= AllocateZeroPool (Tag
->StorageWidth
);
1036 ASSERT (ValueArrayBackup
!= NULL
);
1037 CopyMem (ValueArrayBackup
, ValueArray
, ValueCount
);
1038 TempValue
= *(UINT8
*) (ValueArray
);
1039 if (ValueArray
[0] != 0x00) {
1043 for (Index
= 0; ValueArray
[Index
] != 0x00; Index
++)
1053 FirstOption
= MenuOption
->TagIndex
;
1054 FirstOptionFoundFlag
= FALSE
;
1056 StringPtr
= AllocateZeroPool ((gOptionBlockWidth
+ 1) * 2);
1060 // Initialization for "One of" pop-up menu
1063 // Get the number of one of options present and its size
1065 for (Index
= MenuOption
->TagIndex
; MenuOption
->Tags
[Index
].Operand
!= EFI_IFR_END_ONE_OF_OP
; Index
++) {
1066 if (MenuOption
->Tags
[Index
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
&&
1067 !MenuOption
->Tags
[Index
].Suppress
) {
1068 if (!FirstOptionFoundFlag
) {
1069 FirstOption
= Index
;
1070 FirstOptionFoundFlag
= TRUE
;
1074 Token
= MenuOption
->Tags
[Index
].Text
;
1077 // If this is an ordered list that is initialized
1080 for (ValueBackup
= (UINT8
) MenuOption
->TagIndex
;
1081 MenuOption
->Tags
[ValueBackup
].Operand
!= EFI_IFR_END_OP
;
1084 if (MenuOption
->Tags
[ValueBackup
].Value
== ((UINT8
*) ValueArrayBackup
)[Index
- MenuOption
->TagIndex
- 1]) {
1085 StringPtr
= GetToken (MenuOption
->Tags
[ValueBackup
].Text
, MenuOption
->Handle
);
1090 StringPtr
= GetToken (Token
, MenuOption
->Handle
);
1093 if (StrLen (StringPtr
) > PopUpWidth
) {
1094 PopUpWidth
= StrLen (StringPtr
);
1097 gBS
->FreePool (StringPtr
);
1101 // Perform popup menu initialization.
1103 PopUpMenuLines
= Count
;
1104 PopUpWidth
= PopUpWidth
+ POPUP_PAD_SPACE_COUNT
;
1106 SavedAttribute
= gST
->ConOut
->Mode
->Attribute
;
1107 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
1109 if ((PopUpWidth
+ POPUP_FRAME_WIDTH
) > DimensionsWidth
) {
1110 PopUpWidth
= DimensionsWidth
- POPUP_FRAME_WIDTH
;
1113 Start
= (DimensionsWidth
- PopUpWidth
- POPUP_FRAME_WIDTH
) / 2 + gScreenDimensions
.LeftColumn
;
1114 End
= Start
+ PopUpWidth
+ POPUP_FRAME_WIDTH
;
1115 Top
= gScreenDimensions
.TopRow
+ NONE_FRONT_PAGE_HEADER_HEIGHT
;
1116 Bottom
= gScreenDimensions
.BottomRow
- STATUS_BAR_HEIGHT
- FOOTER_HEIGHT
;
1118 MenuLinesInView
= Bottom
- Top
- 1;
1119 if (MenuLinesInView
>= PopUpMenuLines
) {
1120 Top
= Top
+ (MenuLinesInView
- PopUpMenuLines
) / 2;
1121 Bottom
= Top
+ PopUpMenuLines
+ 1;
1123 TempValue
= MenuOption
->Tags
[MenuOption
->TagIndex
+ 1].Value
;
1124 ShowDownArrow
= TRUE
;
1128 HighlightPosition
= 0;
1131 for (Index
= MenuOption
->TagIndex
, Index2
= 0; Index2
< ValueCount
; Index
++, Index2
++) {
1133 // Set the value for the item we are looking for
1135 Count
= ValueArrayBackup
[Index2
];
1138 // If we hit the end of the Array, we are complete
1144 if (MenuOption
->Tags
[Index
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
) {
1145 for (ValueBackup
= (UINT8
) MenuOption
->TagIndex
;
1146 MenuOption
->Tags
[ValueBackup
].Operand
!= EFI_IFR_END_ONE_OF_OP
;
1150 // We just found what we are looking for
1152 if (MenuOption
->Tags
[ValueBackup
].Value
== Count
) {
1154 // As long as the two indexes aren't the same, we have
1155 // two different op-codes we need to swap internally
1157 if (Index
!= ValueBackup
) {
1159 // Backup destination tag, then copy source to destination, then copy backup to source location
1161 CopyMem (&TagBackup
, &MenuOption
->Tags
[Index
], sizeof (EFI_TAG
));
1162 CopyMem (&MenuOption
->Tags
[Index
], &MenuOption
->Tags
[ValueBackup
], sizeof (EFI_TAG
));
1163 CopyMem (&MenuOption
->Tags
[ValueBackup
], &TagBackup
, sizeof (EFI_TAG
));
1166 // If the indexes are the same, then the op-code is where he belongs
1173 // Since this wasn't an option op-code (likely the ordered list op-code) decerement Index2
1180 // Clear that portion of the screen
1182 ClearLines (Start
, End
, Top
, Bottom
, POPUP_TEXT
| POPUP_BACKGROUND
);
1185 // Draw "One of" pop-up menu
1187 Character
= (CHAR16
) BOXDRAW_DOWN_RIGHT
;
1188 PrintCharAt (Start
, Top
, Character
);
1189 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
1190 if ((ShowUpArrow
) && ((Index
+ 1) == (Start
+ End
) / 2)) {
1191 Character
= (CHAR16
) GEOMETRICSHAPE_UP_TRIANGLE
;
1193 Character
= (CHAR16
) BOXDRAW_HORIZONTAL
;
1196 PrintChar (Character
);
1199 Character
= (CHAR16
) BOXDRAW_DOWN_LEFT
;
1200 PrintChar (Character
);
1201 Character
= (CHAR16
) BOXDRAW_VERTICAL
;
1202 for (Index
= Top
+ 1; Index
< Bottom
; Index
++) {
1203 PrintCharAt (Start
, Index
, Character
);
1204 PrintCharAt (End
- 1, Index
, Character
);
1207 // Display the One of options
1210 for (Index
= MenuOption
->TagIndex
+ TopOptionIndex
;
1211 (MenuOption
->Tags
[Index
].Operand
!= EFI_IFR_END_ONE_OF_OP
) && (Index2
< Bottom
);
1214 if (MenuOption
->Tags
[Index
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
) {
1215 Token
= MenuOption
->Tags
[Index
].Text
;
1217 for (ValueBackup
= (UINT8
) MenuOption
->TagIndex
;
1218 MenuOption
->Tags
[ValueBackup
].Operand
!= EFI_IFR_END_ONE_OF_OP
;
1221 if (MenuOption
->Tags
[ValueBackup
].Value
== ((UINT8
*) ValueArrayBackup
)[Index
- MenuOption
->TagIndex
- 1]) {
1222 StringPtr
= GetToken (MenuOption
->Tags
[ValueBackup
].Text
, MenuOption
->Handle
);
1227 ValueBackup
= (UINT8
) Index
;
1228 StringPtr
= GetToken (Token
, MenuOption
->Handle
);
1231 // If the string occupies multiple lines, truncate it to fit in one line,
1232 // and append a "..." for indication.
1234 if (StrLen (StringPtr
) > (PopUpWidth
- 1)) {
1235 TempStringPtr
= AllocateZeroPool (sizeof (CHAR16
) * (PopUpWidth
- 1));
1236 ASSERT (TempStringPtr
!= NULL
);
1237 CopyMem (TempStringPtr
, StringPtr
, (sizeof (CHAR16
) * (PopUpWidth
- 5)));
1238 gBS
->FreePool (StringPtr
);
1239 StringPtr
= TempStringPtr
;
1240 StrCat (StringPtr
, (CHAR16
*) L
"...");
1243 // Code to display the text should go here. Follwed by the [*]
1245 if (MenuOption
->Tags
[ValueBackup
].Suppress
== TRUE
) {
1247 // Don't show the one, so decrease the Index2 for balance
1250 } else if (MenuOption
->Tags
[ValueBackup
].GrayOut
== TRUE
) {
1254 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_GRAYED
| POPUP_BACKGROUND
);
1255 PrintStringAt (Start
+ 2, Index2
, StringPtr
);
1256 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
1257 } else if (MenuOption
->Tags
[ValueBackup
].Value
== TempValue
) {
1259 // Highlight the selected one
1261 gST
->ConOut
->SetAttribute (gST
->ConOut
, PICKLIST_HIGHLIGHT_TEXT
| PICKLIST_HIGHLIGHT_BACKGROUND
);
1262 PrintStringAt (Start
+ 2, Index2
, StringPtr
);
1263 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
1264 HighlightPosition
= Index2
;
1266 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
1267 PrintStringAt (Start
+ 2, Index2
, StringPtr
);
1270 gBS
->FreePool (StringPtr
);
1271 Index2
= Index2
+ 1;
1275 Character
= (CHAR16
) BOXDRAW_UP_RIGHT
;
1276 PrintCharAt (Start
, Bottom
, Character
);
1277 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
1278 if ((ShowDownArrow
) && ((Index
+ 1) == (Start
+ End
) / 2)) {
1279 Character
= (CHAR16
) GEOMETRICSHAPE_DOWN_TRIANGLE
;
1281 Character
= (CHAR16
) BOXDRAW_HORIZONTAL
;
1284 PrintChar (Character
);
1287 Character
= (CHAR16
) BOXDRAW_UP_LEFT
;
1288 PrintChar (Character
);
1290 // Get User selection and change TempValue if necessary
1293 // Stop: One of pop-up menu
1295 Key
.UnicodeChar
= CHAR_NULL
;
1296 if ((gDirection
== SCAN_UP
) || (gDirection
== SCAN_DOWN
)) {
1297 Key
.ScanCode
= gDirection
;
1302 if (!KeyInitialized
) {
1303 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_ONE_OF_OP
) {
1304 *KeyValue
= MenuOption
->Tags
[MenuOption
->TagIndex
+ 1].Key
;
1306 *KeyValue
= MenuOption
->ThisTag
->Key
;
1309 KeyInitialized
= TRUE
;
1312 Status
= WaitForKeyStroke (&Key
);
1315 switch (Key
.UnicodeChar
) {
1319 // If an ordered list op-code, we will allow for a popup of +/- keys
1320 // to create an ordered list of items
1322 if (Tag
->Operand
== EFI_IFR_ORDERED_LIST_OP
) {
1323 if (Key
.UnicodeChar
== '+') {
1324 if ((TopOptionIndex
> 1) && (HighlightPosition
== (Top
+ 1))) {
1326 // Highlight reaches the top of the popup window, scroll one menu item.
1329 ShowDownArrow
= TRUE
;
1332 if (TopOptionIndex
== 1) {
1333 ShowUpArrow
= FALSE
;
1336 if (((TopOptionIndex
+ MenuLinesInView
) <= PopUpMenuLines
) && (HighlightPosition
== (Bottom
- 1))) {
1338 // Highlight reaches the bottom of the popup window, scroll one menu item.
1344 if ((TopOptionIndex
+ MenuLinesInView
) == (PopUpMenuLines
+ 1)) {
1345 ShowDownArrow
= FALSE
;
1349 for (Index
= MenuOption
->TagIndex
+ TopOptionIndex
;
1350 MenuOption
->Tags
[Index
].Operand
!= EFI_IFR_END_ONE_OF_OP
;
1353 if (MenuOption
->Tags
[Index
].Operand
== EFI_IFR_ORDERED_LIST_OP
) {
1357 if (Key
.UnicodeChar
== '+') {
1358 TempIndex
= Index
- 1;
1360 TempIndex
= Index
+ 1;
1363 // Is this the current tag we are on?
1365 if (MenuOption
->Tags
[Index
].Value
== TempValue
) {
1367 // Is this prior tag a valid choice? If not, bail out
1369 if (MenuOption
->Tags
[TempIndex
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
) {
1371 // Copy the destination tag to the local variable
1373 CopyMem (&TagBackup
, &MenuOption
->Tags
[TempIndex
], sizeof (EFI_TAG
));
1375 // Copy the current tag to the tag location before us
1377 CopyMem (&MenuOption
->Tags
[TempIndex
], &MenuOption
->Tags
[Index
], sizeof (EFI_TAG
));
1379 // Copy the backed up tag to the current location
1381 CopyMem (&MenuOption
->Tags
[Index
], &TagBackup
, sizeof (EFI_TAG
));
1384 // Adjust the array of values
1386 for (Index
= 0; Index
< ValueCount
; Index
++) {
1387 if (ValueArrayBackup
[Index
] == (UINT8
) TempValue
) {
1388 if (Key
.UnicodeChar
== '+') {
1391 // It is the top of the array already
1396 TempIndex
= Index
- 1;
1398 if ((Index
+ 1) == ValueCount
) {
1400 // It is the bottom of the array already
1405 TempIndex
= Index
+ 1;
1408 ValueBackup
= ValueArrayBackup
[TempIndex
];
1409 ValueArrayBackup
[TempIndex
] = ValueArrayBackup
[Index
];
1410 ValueArrayBackup
[Index
] = ValueBackup
;
1425 switch (Key
.ScanCode
) {
1428 if (Key
.ScanCode
== SCAN_UP
) {
1429 if ((TopOptionIndex
> 1) && (HighlightPosition
== (Top
+ 1))) {
1431 // Highlight reaches the top of the popup window, scroll one menu item.
1434 ShowDownArrow
= TRUE
;
1437 if (TopOptionIndex
== 1) {
1438 ShowUpArrow
= FALSE
;
1441 if (((TopOptionIndex
+ MenuLinesInView
) <= PopUpMenuLines
) && (HighlightPosition
== (Bottom
- 1))) {
1443 // Highlight reaches the bottom of the popup window, scroll one menu item.
1449 if ((TopOptionIndex
+ MenuLinesInView
) == (PopUpMenuLines
+ 1)) {
1450 ShowDownArrow
= FALSE
;
1454 for (Index
= MenuOption
->TagIndex
+ TopOptionIndex
;
1455 MenuOption
->Tags
[Index
].Operand
!= EFI_IFR_END_ONE_OF_OP
;
1458 if (MenuOption
->Tags
[Index
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
) {
1460 for (Index
= 0; (ValueArrayBackup
[Index
] != TempValue
) && (Index
< ValueCount
); Index
++)
1464 // Did we hit the end of the array? Either get the first TempValue or the next one
1466 if (Key
.ScanCode
== SCAN_UP
) {
1468 TempValue
= ValueArrayBackup
[0];
1470 TempValue
= ValueArrayBackup
[Index
- 1];
1473 if ((Index
+ 1) == ValueCount
) {
1474 TempValue
= ValueArrayBackup
[Index
];
1476 TempValue
= ValueArrayBackup
[Index
+ 1];
1481 if (Key
.ScanCode
== SCAN_UP
) {
1482 TempIndex
= Index
- 1;
1485 // Keep going until meets meaningful tag.
1487 while ((MenuOption
->Tags
[TempIndex
].Operand
!= EFI_IFR_ONE_OF_OPTION_OP
&&
1488 MenuOption
->Tags
[TempIndex
].Operand
!= EFI_IFR_ONE_OF_OP
&&
1489 MenuOption
->Tags
[TempIndex
].Operand
!= EFI_IFR_END_ONE_OF_OP
)
1491 (MenuOption
->Tags
[TempIndex
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
&&
1492 (MenuOption
->Tags
[TempIndex
].Suppress
|| MenuOption
->Tags
[TempIndex
].GrayOut
))) {
1496 TempIndex
= Index
+ 1;
1499 // Keep going until meets meaningful tag.
1501 while ((MenuOption
->Tags
[TempIndex
].Operand
!= EFI_IFR_ONE_OF_OPTION_OP
&&
1502 MenuOption
->Tags
[TempIndex
].Operand
!= EFI_IFR_ONE_OF_OP
&&
1503 MenuOption
->Tags
[TempIndex
].Operand
!= EFI_IFR_END_ONE_OF_OP
)
1505 (MenuOption
->Tags
[TempIndex
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
&&
1506 (MenuOption
->Tags
[TempIndex
].Suppress
|| MenuOption
->Tags
[TempIndex
].GrayOut
))) {
1511 // The option value is the same as what is stored in NV store. This is where we take action
1513 if (MenuOption
->Tags
[Index
].Value
== TempValue
) {
1515 // Only if the previous op-code is an option can we select it, otherwise we are at the left-most option
1517 if (MenuOption
->Tags
[TempIndex
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
) {
1518 TempValue
= MenuOption
->Tags
[TempIndex
].Value
;
1519 *KeyValue
= MenuOption
->Tags
[TempIndex
].Key
;
1521 TempValue
= MenuOption
->Tags
[Index
].Value
;
1522 *KeyValue
= MenuOption
->Tags
[Index
].Key
;
1532 gST
->ConOut
->SetAttribute (gST
->ConOut
, SavedAttribute
);
1533 if (ValueArrayBackup
!= NULL
) {
1534 gBS
->FreePool (ValueArrayBackup
);
1537 return EFI_DEVICE_ERROR
;
1545 case CHAR_CARRIAGE_RETURN
:
1547 // return the current selection
1549 if (Tag
->Operand
== EFI_IFR_ORDERED_LIST_OP
) {
1550 CopyMem (ValueArray
, ValueArrayBackup
, ValueCount
);
1551 gBS
->FreePool (ValueArrayBackup
);
1556 gST
->ConOut
->SetAttribute (gST
->ConOut
, SavedAttribute
);
1564 gST
->ConOut
->SetAttribute (gST
->ConOut
, SavedAttribute
);
1570 OUT EFI_INPUT_KEY
*Key
1576 UiWaitForSingleEvent (gST
->ConIn
->WaitForKey
, 0);
1577 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, Key
);
1578 } while (EFI_ERROR(Status
));