2 Implementation for handling user input from the User Interface
4 Copyright (c) 2006, Intel Corporation
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
21 IN UI_MENU_OPTION
*MenuOption
,
32 BOOLEAN SelectionComplete
;
34 CHAR16
*BufferedString
;
39 CHAR16
*PromptForDataString
;
40 UINTN DimensionsWidth
;
41 UINTN DimensionsHeight
;
42 BOOLEAN CursorVisible
;
44 DimensionsWidth
= gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
;
45 DimensionsHeight
= gScreenDimensions
.BottomRow
- gScreenDimensions
.TopRow
;
47 PromptForDataString
= GetToken (STRING_TOKEN (PROMPT_FOR_DATA
), gHiiHandle
);
49 NullCharacter
= CHAR_NULL
;
50 ScreenSize
= GetStringWidth (PromptForDataString
) / 2;
51 Tag
= MenuOption
->ThisTag
;
54 SelectionComplete
= FALSE
;
56 TempString
= AllocateZeroPool (MenuOption
->ThisTag
->Maximum
* 2);
59 if (ScreenSize
< (Tag
->Maximum
/ (UINTN
) 2)) {
60 ScreenSize
= Tag
->Maximum
/ 2;
63 if ((ScreenSize
+ 2) > DimensionsWidth
) {
64 ScreenSize
= DimensionsWidth
- 2;
67 BufferedString
= AllocateZeroPool (ScreenSize
* 2);
68 ASSERT (BufferedString
);
70 Start
= (DimensionsWidth
- ScreenSize
- 2) / 2 + gScreenDimensions
.LeftColumn
+ 1;
71 Top
= ((DimensionsHeight
- 6) / 2) + gScreenDimensions
.TopRow
- 1;
74 // Display prompt for string
76 CreatePopUp (ScreenSize
, 4, &NullCharacter
, PromptForDataString
, Space
, &NullCharacter
);
78 FreePool (PromptForDataString
);
80 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_BLACK
, EFI_LIGHTGRAY
));
82 CursorVisible
= gST
->ConOut
->Mode
->CursorVisible
;
83 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
86 Status
= WaitForKeyStroke (&Key
);
88 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_BLACK
, EFI_LIGHTGRAY
));
89 switch (Key
.UnicodeChar
) {
91 switch (Key
.ScanCode
) {
99 FreePool (TempString
);
100 FreePool (BufferedString
);
101 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
102 gST
->ConOut
->EnableCursor (gST
->ConOut
, CursorVisible
);
103 return EFI_DEVICE_ERROR
;
111 case CHAR_CARRIAGE_RETURN
:
112 if (GetStringWidth (StringPtr
) >= MenuOption
->ThisTag
->Minimum
) {
113 SelectionComplete
= TRUE
;
114 FreePool (TempString
);
115 FreePool (BufferedString
);
116 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
117 gST
->ConOut
->EnableCursor (gST
->ConOut
, CursorVisible
);
120 ScreenSize
= GetStringWidth (gMiniString
) / 2;
121 CreatePopUp (ScreenSize
, 4, &NullCharacter
, gMiniString
, gPressEnter
, &NullCharacter
);
123 // Simply create a popup to tell the user that they had typed in too few characters.
124 // To save code space, we can then treat this as an error and return back to the menu.
127 Status
= WaitForKeyStroke (&Key
);
128 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
129 FreePool (TempString
);
130 FreePool (BufferedString
);
131 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
132 gST
->ConOut
->EnableCursor (gST
->ConOut
, CursorVisible
);
133 return EFI_DEVICE_ERROR
;
139 if (StringPtr
[0] != CHAR_NULL
) {
140 for (Index
= 0; StringPtr
[Index
] != CHAR_NULL
; Index
++) {
141 TempString
[Index
] = StringPtr
[Index
];
144 // Effectively truncate string by 1 character
146 TempString
[Index
- 1] = CHAR_NULL
;
147 StrCpy (StringPtr
, TempString
);
152 // If it is the beginning of the string, don't worry about checking maximum limits
154 if ((StringPtr
[0] == CHAR_NULL
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
155 StrnCpy (StringPtr
, &Key
.UnicodeChar
, 1);
156 StrnCpy (TempString
, &Key
.UnicodeChar
, 1);
157 } else if ((GetStringWidth (StringPtr
) < MenuOption
->ThisTag
->Maximum
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
158 KeyPad
[0] = Key
.UnicodeChar
;
159 KeyPad
[1] = CHAR_NULL
;
160 StrCat (StringPtr
, KeyPad
);
161 StrCat (TempString
, KeyPad
);
164 // If the width of the input string is now larger than the screen, we nee to
165 // adjust the index to start printing portions of the string
167 SetUnicodeMem (BufferedString
, ScreenSize
- 1, L
' ');
169 PrintStringAt (Start
+ 1, Top
+ 3, BufferedString
);
171 if ((GetStringWidth (StringPtr
) / 2) > (DimensionsWidth
- 2)) {
172 Index
= (GetStringWidth (StringPtr
) / 2) - DimensionsWidth
+ 2;
177 for (Count
= 0; Index
+ 1 < GetStringWidth (StringPtr
) / 2; Index
++, Count
++) {
178 BufferedString
[Count
] = StringPtr
[Index
];
181 PrintStringAt (Start
+ 1, Top
+ 3, BufferedString
);
185 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
186 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, Start
+ GetStringWidth (StringPtr
) / 2, Top
+ 3);
187 } while (!SelectionComplete
);
188 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
189 gST
->ConOut
->EnableCursor (gST
->ConOut
, CursorVisible
);
195 IN UI_MENU_OPTION
*MenuOption
,
196 IN BOOLEAN PromptForPassword
,
198 IN EFI_IFR_DATA_ARRAY
*PageData
,
199 IN BOOLEAN SecondEntry
,
200 IN EFI_FILE_FORM_TAGS
*FileFormTags
,
201 OUT CHAR16
*StringPtr
206 CHAR16 NullCharacter
;
215 BOOLEAN Confirmation
;
216 BOOLEAN ConfirmationComplete
;
217 EFI_HII_CALLBACK_PACKET
*Packet
;
218 EFI_FORM_CALLBACK_PROTOCOL
*FormCallback
;
219 EFI_VARIABLE_DEFINITION
*VariableDefinition
;
220 UINTN DimensionsWidth
;
221 UINTN DimensionsHeight
;
222 EFI_IFR_DATA_ENTRY
*DataEntry
;
225 DimensionsWidth
= gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
;
226 DimensionsHeight
= gScreenDimensions
.BottomRow
- gScreenDimensions
.TopRow
;
228 VariableDefinition
= NULL
;
229 NullCharacter
= CHAR_NULL
;
231 Space
[1] = CHAR_NULL
;
232 Confirmation
= FALSE
;
233 ConfirmationComplete
= FALSE
;
234 Status
= EFI_SUCCESS
;
239 // Remember that dynamic pages in an environment where all pages are not
240 // dynamic require us to call back to the user to give them an opportunity
241 // to register fresh information in the HII database so that we can extract it.
243 Status
= gBS
->HandleProtocol (
244 (VOID
*) (UINTN
) MenuOption
->Tags
[0].CallbackHandle
,
245 &gEfiFormCallbackProtocolGuid
,
246 (VOID
**) &FormCallback
249 TempString
= AllocateZeroPool (MenuOption
->ThisTag
->Maximum
* 2);
250 TempString2
= AllocateZeroPool (MenuOption
->ThisTag
->Maximum
* 2);
253 ASSERT (TempString2
);
255 if (Tag
->Flags
& EFI_IFR_FLAG_INTERACTIVE
) {
257 // Password requires a callback to determine if a password exists
259 DataEntry
= (EFI_IFR_DATA_ENTRY
*) (PageData
+ 1);
260 DataEntry
->OpCode
= EFI_IFR_PASSWORD_OP
;
261 DataEntry
->Length
= 3;
263 ExtractRequestedNvMap (FileFormTags
, Tag
->VariableNumber
, &VariableDefinition
);
266 // The user is about to be prompted with a password field, Data = 0 (Return Status determines the type of prompt)
268 DataEntry
->Data
= (VOID
*) (UINTN
) (UINT8
) (0 + SecondEntry
* 2);
269 PageData
->NvRamMap
= VariableDefinition
->NvRamMap
;
271 if ((FormCallback
!= NULL
) && (FormCallback
->Callback
!= NULL
)) {
272 Status
= FormCallback
->Callback (
280 // If error on return, continue with the reading of a typed in password to verify user knows password
281 // If no error, there is no password set, so prompt for new password
282 // if the previous callback was to verify the user knew password, and user typed it correctly - should return no error
284 if (!EFI_ERROR (Status
)) {
285 PromptForPassword
= FALSE
;
288 // Simulate this as the second entry into this routine for an interactive behavior
291 } else if (Status
== EFI_NOT_READY
) {
293 if (Packet
!= NULL
&& Packet
->String
!= NULL
) {
295 // Upon error, we will likely receive a string to print out
296 // Display error popup
298 WidthOfString
= GetStringWidth (Packet
->String
);
299 ScreenSize
= MAX(WidthOfString
, GetStringWidth (gPressEnter
)) / 2;
300 CreatePopUp (ScreenSize
, 4, &NullCharacter
, Packet
->String
, gPressEnter
, &NullCharacter
);
301 FreePool (Packet
->String
);
305 Status
= WaitForKeyStroke (&Key
);
306 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
309 Status
= EFI_NOT_READY
;
316 // Display PopUp Screen
318 ScreenSize
= GetStringWidth (gPromptForNewPassword
) / 2;
319 if (GetStringWidth (gConfirmPassword
) / 2 > ScreenSize
) {
320 ScreenSize
= GetStringWidth (gConfirmPassword
) / 2;
323 Start
= (DimensionsWidth
- ScreenSize
- 4) / 2 + gScreenDimensions
.LeftColumn
+ 2;
324 Top
= ((DimensionsHeight
- 6) / 2) + gScreenDimensions
.TopRow
- 1;
327 if (PromptForPassword
) {
328 CreatePopUp (ScreenSize
, 4, &NullCharacter
, gPromptForPassword
, Space
, &NullCharacter
);
330 CreatePopUp (ScreenSize
, 4, &NullCharacter
, gPromptForNewPassword
, Space
, &NullCharacter
);
333 CreatePopUp (ScreenSize
, 4, &NullCharacter
, gConfirmPassword
, Space
, &NullCharacter
);
334 StringPtr
[0] = CHAR_NULL
;
338 Status
= WaitForKeyStroke (&Key
);
340 switch (Key
.UnicodeChar
) {
342 if (Key
.ScanCode
== SCAN_ESC
) {
343 return EFI_NOT_READY
;
346 ConfirmationComplete
= FALSE
;
349 case CHAR_CARRIAGE_RETURN
:
350 if (Tag
->Flags
& EFI_IFR_FLAG_INTERACTIVE
) {
352 // User just typed a string in
354 DataEntry
= (EFI_IFR_DATA_ENTRY
*) (PageData
+ 1);
355 DataEntry
->OpCode
= EFI_IFR_PASSWORD_OP
;
358 // If the user just typed in a password, Data = 1
359 // If the user just typed in a password to confirm the previous password, Data = 2
362 DataEntry
->Length
= 3;
363 DataEntry
->Data
= (VOID
*) (UINTN
) (UINT8
) (1 + SecondEntry
* 2);
365 if ((FormCallback
!= NULL
) && (FormCallback
->Callback
!= NULL
)) {
366 Status
= FormCallback
->Callback (
374 DataEntry
->Length
= sizeof (EFI_IFR_DATA_ENTRY
);
375 DataEntry
->Data
= (VOID
*) TempString
;
377 DataEntry
->Length
= 3;
378 DataEntry
->Data
= (VOID
*) (UINTN
) (UINT8
) (2 + SecondEntry
* 2);
380 if ((FormCallback
!= NULL
) && (FormCallback
->Callback
!= NULL
)) {
381 Status
= FormCallback
->Callback (
389 DataEntry
->Length
= sizeof (EFI_IFR_DATA_ENTRY
);
390 DataEntry
->Data
= (VOID
*) TempString2
;
393 if ((FormCallback
!= NULL
) && (FormCallback
->Callback
!= NULL
)) {
394 Status
= FormCallback
->Callback (
402 // If this was the confirmation round of callbacks
403 // and an error comes back, display an error
406 if (EFI_ERROR (Status
)) {
407 if (Packet
== NULL
|| Packet
->String
== NULL
) {
408 WidthOfString
= GetStringWidth (gConfirmError
);
409 ScreenSize
= MAX (WidthOfString
, GetStringWidth (gPressEnter
)) / 2;
410 CreatePopUp (ScreenSize
, 4, &NullCharacter
, gConfirmError
, gPressEnter
, &NullCharacter
);
412 WidthOfString
= GetStringWidth (Packet
->String
);
413 ScreenSize
= MAX (WidthOfString
, GetStringWidth (gPressEnter
)) / 2;
414 CreatePopUp (ScreenSize
, 4, &NullCharacter
, Packet
->String
, gPressEnter
, &NullCharacter
);
415 FreePool (Packet
->String
);
419 StringPtr
[0] = CHAR_NULL
;
421 Status
= WaitForKeyStroke (&Key
);
423 if (Key
.UnicodeChar
== CHAR_CARRIAGE_RETURN
) {
424 Status
= EFI_NOT_READY
;
429 Status
= EFI_NOT_READY
;
434 // User typed a string in and it wasn't valid somehow from the callback
435 // For instance, callback may have said that some invalid characters were contained in the string
437 if (Status
== EFI_NOT_READY
) {
441 if (PromptForPassword
&& EFI_ERROR (Status
)) {
442 Status
= EFI_DEVICE_ERROR
;
450 // Compare tempstring and tempstring2, if the same, return with StringPtr success
451 // Otherwise, kick and error box, and return an error
453 if (StrCmp (TempString
, TempString2
) == 0) {
454 Status
= EFI_SUCCESS
;
457 WidthOfString
= GetStringWidth (gConfirmError
);
458 ScreenSize
= MAX (WidthOfString
, GetStringWidth (gPressEnter
)) / 2;
459 CreatePopUp (ScreenSize
, 4, &NullCharacter
, gConfirmError
, gPressEnter
, &NullCharacter
);
460 StringPtr
[0] = CHAR_NULL
;
462 Status
= WaitForKeyStroke (&Key
);
463 if (Key
.UnicodeChar
== CHAR_CARRIAGE_RETURN
) {
464 Status
= EFI_DEVICE_ERROR
;
471 if (PromptForPassword
) {
473 // I was asked for a password, return it back in StringPtr
475 Status
= EFI_SUCCESS
;
479 // If the two passwords were not the same kick an error popup
482 ConfirmationComplete
= TRUE
;
487 if (StringPtr
[0] != CHAR_NULL
) {
489 for (Index
= 0; StringPtr
[Index
] != CHAR_NULL
; Index
++) {
490 TempString
[Index
] = StringPtr
[Index
];
493 // Effectively truncate string by 1 character
495 TempString
[Index
- 1] = CHAR_NULL
;
496 StrCpy (StringPtr
, TempString
);
498 for (Index
= 0; StringPtr
[Index
] != CHAR_NULL
; Index
++) {
499 TempString2
[Index
] = StringPtr
[Index
];
502 // Effectively truncate string by 1 character
504 TempString2
[Index
- 1] = CHAR_NULL
;
505 StrCpy (StringPtr
, TempString2
);
508 ConfirmationComplete
= FALSE
;
510 ConfirmationComplete
= FALSE
;
514 // Must be a character we are interested in!
517 if ((StringPtr
[0] == CHAR_NULL
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
518 StringPtr
[0] = Key
.UnicodeChar
;
519 StringPtr
[1] = CHAR_NULL
;
521 TempString
[0] = Key
.UnicodeChar
;
522 TempString
[1] = CHAR_NULL
;
524 TempString2
[0] = Key
.UnicodeChar
;
525 TempString2
[1] = CHAR_NULL
;
526 ConfirmationComplete
= FALSE
;
528 } else if ((GetStringWidth (StringPtr
) / 2 <= (UINTN
) (MenuOption
->ThisTag
->Maximum
- 1) / 2) &&
529 (Key
.UnicodeChar
!= CHAR_BACKSPACE
)
531 KeyPad
[0] = Key
.UnicodeChar
;
532 KeyPad
[1] = CHAR_NULL
;
534 StrCat (StringPtr
, KeyPad
);
535 StrCat (TempString
, KeyPad
);
537 StrCat (StringPtr
, KeyPad
);
538 StrCat (TempString2
, KeyPad
);
542 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_BLACK
, EFI_LIGHTGRAY
));
543 for (Index
= 1; Index
< ScreenSize
; Index
++) {
544 PrintCharAt (Start
+ Index
, Top
+ 3, L
' ');
547 gST
->ConOut
->SetCursorPosition (
549 (DimensionsWidth
- GetStringWidth (StringPtr
) / 2) / 2 + gScreenDimensions
.LeftColumn
,
552 for (Index
= 0; Index
+ 1 < GetStringWidth (StringPtr
) / 2; Index
++) {
556 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
562 } while (!ConfirmationComplete
);
567 FreePool (TempString
);
568 FreePool (TempString2
);
583 Key
= (CHAR16
*) L
"MAR10648567";
584 Buffer
= AllocateZeroPool (MaxSize
);
588 for (Index
= 0; Key
[Index
] != 0; Index
++) {
589 for (Loop
= 0; Loop
< (UINT8
) (MaxSize
/ 2); Loop
++) {
590 Buffer
[Loop
] = (CHAR16
) (Password
[Loop
] ^ Key
[Index
]);
594 CopyMem (Password
, Buffer
, MaxSize
);
602 IN UI_MENU_OPTION
*MenuOption
,
603 IN EFI_FILE_FORM_TAGS
*FileFormTagsHead
,
604 IN BOOLEAN ManualInput
,
606 IN UINTN NumericType
,
613 This routine reads a numeric value from the user input.
617 MenuOption - Pointer to the current input menu.
619 FileFormTagsHead - Pointer to the root of formset.
621 ManualInput - If the input is manual or not.
623 Tag - Pointer to all the attributes and values associated with a tag.
625 Value - Pointer to the numeric value that is going to be read.
629 EFI_SUCCESS - If numerical input is read successfully
630 EFI_DEVICE_ERROR - If operation fails
635 BOOLEAN SelectionComplete
;
638 CHAR16 FormattedNumber
[6];
639 UINTN PreviousNumber
[6];
644 CHAR16 NullCharacter
;
646 EFI_FILE_FORM_TAGS
*FileFormTags
;
647 EFI_VARIABLE_DEFINITION
*VariableDefinition
;
650 NullCharacter
= CHAR_NULL
;
652 Column
= MenuOption
->OptCol
;
653 Row
= MenuOption
->Row
;
655 PreviousNumber
[0] = 0;
657 SelectionComplete
= FALSE
;
658 BackupValue
= Tag
->Value
;
659 FileFormTags
= FileFormTagsHead
;
662 PrintAt (Column
, Row
, (CHAR16
*) L
"[ ]");
664 if (Tag
->Operand
!= EFI_IFR_TIME_OP
) {
665 *Value
= BackupValue
;
669 // First time we enter this handler, we need to check to see if
670 // we were passed an increment or decrement directive
673 Key
.UnicodeChar
= CHAR_NULL
;
674 if (gDirection
!= 0) {
675 Key
.ScanCode
= gDirection
;
680 WaitForKeyStroke (&Key
);
683 switch (Key
.UnicodeChar
) {
686 if ((Tag
->Operand
== EFI_IFR_DATE_OP
) || (Tag
->Operand
== EFI_IFR_TIME_OP
)) {
687 Key
.UnicodeChar
= CHAR_NULL
;
688 if (Key
.UnicodeChar
== '+') {
689 Key
.ScanCode
= SCAN_RIGHT
;
691 Key
.ScanCode
= SCAN_LEFT
;
699 switch (Key
.ScanCode
) {
702 if ((Tag
->Operand
== EFI_IFR_DATE_OP
) || (Tag
->Operand
== EFI_IFR_TIME_OP
)) {
704 // By setting this value, we will return back to the caller.
705 // We need to do this since an auto-refresh will destroy the adjustment
706 // based on what the real-time-clock is showing. So we always commit
707 // upon changing the value.
709 gDirection
= SCAN_DOWN
;
714 if (Key
.ScanCode
== SCAN_LEFT
) {
715 Number
= *Value
- Tag
->Step
;
716 if (Number
< Tag
->Minimum
) {
717 Number
= Tag
->Minimum
;
719 } else if (Key
.ScanCode
== SCAN_RIGHT
) {
720 Number
= *Value
+ Tag
->Step
;
721 if (Number
> Tag
->Maximum
) {
722 Number
= Tag
->Maximum
;
726 Tag
->Value
= (UINT16
) Number
;
727 *Value
= (UINT16
) Number
;
728 UnicodeValueToString (
732 (sizeof (FormattedNumber
) / sizeof (FormattedNumber
[0]))
734 Number
= (UINT16
) GetStringWidth (FormattedNumber
);
736 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT
| FIELD_BACKGROUND
);
737 if ((Tag
->Operand
== EFI_IFR_DATE_OP
) || (Tag
->Operand
== EFI_IFR_TIME_OP
)) {
738 for (Loop
= 0; Loop
< (UINTN
) ((Number
>= 8) ? 4 : 2); Loop
++) {
739 PrintAt (MenuOption
->OptCol
+ Loop
, MenuOption
->Row
, (CHAR16
*) L
" ");
742 for (Loop
= 0; Loop
< gOptionBlockWidth
; Loop
++) {
743 PrintAt (MenuOption
->OptCol
+ Loop
, MenuOption
->Row
, (CHAR16
*) L
" ");
747 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_HIGHLIGHT
| FIELD_BACKGROUND_HIGHLIGHT
);
749 if ((MenuOption
->Col
+ gPromptBlockWidth
+ 1) == MenuOption
->OptCol
) {
750 PrintCharAt (MenuOption
->OptCol
, Row
, LEFT_NUMERIC_DELIMITER
);
751 Column
= MenuOption
->OptCol
+ 1;
754 // If Number looks like "3", convert it to "03/"
756 if (Number
== 4 && (NumericType
== DATE_NUMERIC
)) {
757 FormattedNumber
[3] = FormattedNumber
[1];
758 FormattedNumber
[2] = DATE_SEPARATOR
;
759 FormattedNumber
[1] = FormattedNumber
[0];
760 FormattedNumber
[0] = L
'0';
764 // If Number looks like "13", convert it to "13/"
766 if (Number
== 6 && (NumericType
== DATE_NUMERIC
)) {
767 FormattedNumber
[3] = FormattedNumber
[2];
768 FormattedNumber
[2] = DATE_SEPARATOR
;
773 (NumericType
== TIME_NUMERIC
) &&
774 (MenuOption
->Col
+ gPromptBlockWidth
+ 8) != MenuOption
->OptCol
776 FormattedNumber
[3] = FormattedNumber
[1];
777 FormattedNumber
[2] = TIME_SEPARATOR
;
778 FormattedNumber
[1] = FormattedNumber
[0];
779 FormattedNumber
[0] = L
'0';
784 (NumericType
== TIME_NUMERIC
) &&
785 (MenuOption
->Col
+ gPromptBlockWidth
+ 8) == MenuOption
->OptCol
787 FormattedNumber
[3] = FormattedNumber
[1];
788 FormattedNumber
[2] = RIGHT_NUMERIC_DELIMITER
;
789 FormattedNumber
[1] = FormattedNumber
[0];
790 FormattedNumber
[0] = L
'0';
794 PrintStringAt (Column
, Row
, FormattedNumber
);
795 if (Number
== 10 && (NumericType
== DATE_NUMERIC
)) {
796 PrintChar (RIGHT_NUMERIC_DELIMITER
);
799 if (NumericType
== REGULAR_NUMERIC
) {
800 PrintChar (RIGHT_NUMERIC_DELIMITER
);
807 goto EnterCarriageReturn
;
810 return EFI_DEVICE_ERROR
;
820 case CHAR_CARRIAGE_RETURN
:
822 // Check to see if the Value is something reasonable against consistency limitations.
823 // If not, let's kick the error specified.
826 // This gives us visibility to the FileFormTags->NvRamMap to check things
827 // ActiveIfr is a global maintained by the menuing code to ensure that we
828 // are pointing to the correct formset's file data.
830 for (Count
= 0; Count
< gActiveIfr
; Count
++) {
831 FileFormTags
= FileFormTags
->NextFile
;
834 ExtractRequestedNvMap (FileFormTags
, Tag
->VariableNumber
, &VariableDefinition
);
836 CopyMem (&VariableDefinition
->NvRamMap
[Tag
->StorageStart
], &Tag
->Value
, Tag
->StorageWidth
);
839 // Data associated with a NULL device (in the fake NV storage)
841 if (Tag
->StorageWidth
== (UINT16
) 0) {
842 CopyMem (&VariableDefinition
->FakeNvRamMap
[Tag
->StorageStart
], &Tag
->Value
, 2);
845 // If a late check is required save off the information. This is used when consistency checks
846 // are required, but certain values might be bound by an impossible consistency check such as
847 // if two questions are bound by consistency checks and each only has two possible choices, there
848 // would be no way for a user to switch the values. Thus we require late checking.
850 if (Tag
->Flags
& EFI_IFR_FLAG_LATE_CHECK
) {
851 CopyMem (&Tag
->OldValue
, &BackupValue
, Tag
->StorageWidth
);
854 // In theory, passing the value and the Id are sufficient to determine what needs
855 // to be done. The Id is the key to look for the entry needed in the Inconsistency
856 // database. That will yields operand and ID data - and since the ID's correspond
857 // to the NV storage, we can determine the values for other IDs there.
859 if (ValueIsNotValid (TRUE
, 0, Tag
, FileFormTags
, &PopUp
)) {
860 if (PopUp
== 0x0000) {
861 SelectionComplete
= TRUE
;
865 StringPtr
= GetToken (PopUp
, MenuOption
->Handle
);
867 CreatePopUp (GetStringWidth (StringPtr
) / 2, 3, &NullCharacter
, StringPtr
, &NullCharacter
);
870 WaitForKeyStroke (&Key
);
872 switch (Key
.UnicodeChar
) {
874 case CHAR_CARRIAGE_RETURN
:
875 SelectionComplete
= TRUE
;
876 FreePool (StringPtr
);
882 } while (!SelectionComplete
);
884 Tag
->Value
= BackupValue
;
885 *Value
= BackupValue
;
887 CopyMem (&VariableDefinition
->NvRamMap
[Tag
->StorageStart
], &Tag
->Value
, Tag
->StorageWidth
);
890 // Data associated with a NULL device (in the fake NV storage)
892 if (Tag
->StorageWidth
== (UINT16
) 0) {
893 CopyMem (&VariableDefinition
->FakeNvRamMap
[Tag
->StorageStart
], &Tag
->Value
, 2);
896 return EFI_DEVICE_ERROR
;
909 // Remove a character
911 Number
= PreviousNumber
[Count
- 1];
912 *Value
= (UINT16
) Number
;
913 UpdateStatusBar (INPUT_ERROR
, Tag
->Flags
, FALSE
);
916 PrintAt (Column
, Row
, (CHAR16
*) L
" ");
922 if (Key
.UnicodeChar
> L
'9' || Key
.UnicodeChar
< L
'0') {
923 UpdateStatusBar (INPUT_ERROR
, Tag
->Flags
, TRUE
);
927 // If Count 0-4 is complete, there is no way more is valid
933 // Someone typed something valid!
936 Number
= Number
* 10 + (Key
.UnicodeChar
- L
'0');
938 Number
= Key
.UnicodeChar
- L
'0';
941 if (Number
> Tag
->Maximum
) {
942 UpdateStatusBar (INPUT_ERROR
, Tag
->Flags
, TRUE
);
943 Number
= PreviousNumber
[Count
];
946 UpdateStatusBar (INPUT_ERROR
, Tag
->Flags
, FALSE
);
951 PreviousNumber
[Count
] = Number
;
952 *Value
= (UINT16
) Number
;
953 Tag
->Value
= (UINT16
) Number
;
955 PrintCharAt (Column
, Row
, Key
.UnicodeChar
);
960 } while (!SelectionComplete
);
964 // Notice that this is at least needed for the ordered list manipulation.
965 // Left/Right doesn't make sense for this op-code
968 GetSelectionInputPopUp (
969 IN UI_MENU_OPTION
*MenuOption
,
980 CHAR16
*TempStringPtr
;
983 UINTN TopOptionIndex
;
984 UINTN HighlightPosition
;
991 UINTN PopUpMenuLines
;
992 UINTN MenuLinesInView
;
995 BOOLEAN FirstOptionFoundFlag
;
996 INT32 SavedAttribute
;
999 UINT8
*ValueArrayBackup
;
1001 BOOLEAN Initialized
;
1002 BOOLEAN KeyInitialized
;
1003 BOOLEAN ShowDownArrow
;
1004 BOOLEAN ShowUpArrow
;
1005 UINTN DimensionsWidth
;
1007 DimensionsWidth
= gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
;
1011 ValueArray
= (UINT8
*) Value
;
1012 ValueArrayBackup
= NULL
;
1013 Initialized
= FALSE
;
1014 KeyInitialized
= FALSE
;
1015 ShowDownArrow
= FALSE
;
1016 ShowUpArrow
= FALSE
;
1018 if (Tag
->Operand
== EFI_IFR_ORDERED_LIST_OP
) {
1019 ValueArrayBackup
= AllocateZeroPool (Tag
->StorageWidth
);
1020 ASSERT (ValueArrayBackup
!= NULL
);
1021 CopyMem (ValueArrayBackup
, ValueArray
, ValueCount
);
1022 TempValue
= *(UINT8
*) (ValueArray
);
1023 if (ValueArray
[0] != 0x00) {
1027 for (Index
= 0; ValueArray
[Index
] != 0x00; Index
++)
1037 FirstOptionFoundFlag
= FALSE
;
1039 StringPtr
= AllocateZeroPool ((gOptionBlockWidth
+ 1) * 2);
1043 // Initialization for "One of" pop-up menu
1046 // Get the number of one of options present and its size
1048 for (Index
= MenuOption
->TagIndex
; MenuOption
->Tags
[Index
].Operand
!= EFI_IFR_END_ONE_OF_OP
; Index
++) {
1049 if (MenuOption
->Tags
[Index
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
&&
1050 !MenuOption
->Tags
[Index
].Suppress
) {
1051 if (!FirstOptionFoundFlag
) {
1052 FirstOptionFoundFlag
= TRUE
;
1056 Token
= MenuOption
->Tags
[Index
].Text
;
1059 // If this is an ordered list that is initialized
1062 for (ValueBackup
= (UINT8
) MenuOption
->TagIndex
;
1063 MenuOption
->Tags
[ValueBackup
].Operand
!= EFI_IFR_END_OP
;
1066 if (MenuOption
->Tags
[ValueBackup
].Value
== ((UINT8
*) ValueArrayBackup
)[Index
- MenuOption
->TagIndex
- 1]) {
1067 StringPtr
= GetToken (MenuOption
->Tags
[ValueBackup
].Text
, MenuOption
->Handle
);
1072 StringPtr
= GetToken (Token
, MenuOption
->Handle
);
1075 if (StrLen (StringPtr
) > PopUpWidth
) {
1076 PopUpWidth
= StrLen (StringPtr
);
1079 FreePool (StringPtr
);
1083 // Perform popup menu initialization.
1085 PopUpMenuLines
= Count
;
1086 PopUpWidth
= PopUpWidth
+ POPUP_PAD_SPACE_COUNT
;
1088 SavedAttribute
= gST
->ConOut
->Mode
->Attribute
;
1089 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
1091 if ((PopUpWidth
+ POPUP_FRAME_WIDTH
) > DimensionsWidth
) {
1092 PopUpWidth
= DimensionsWidth
- POPUP_FRAME_WIDTH
;
1095 Start
= (DimensionsWidth
- PopUpWidth
- POPUP_FRAME_WIDTH
) / 2 + gScreenDimensions
.LeftColumn
;
1096 End
= Start
+ PopUpWidth
+ POPUP_FRAME_WIDTH
;
1097 Top
= gScreenDimensions
.TopRow
+ NONE_FRONT_PAGE_HEADER_HEIGHT
;
1098 Bottom
= gScreenDimensions
.BottomRow
- STATUS_BAR_HEIGHT
- FOOTER_HEIGHT
;
1100 MenuLinesInView
= Bottom
- Top
- 1;
1101 if (MenuLinesInView
>= PopUpMenuLines
) {
1102 Top
= Top
+ (MenuLinesInView
- PopUpMenuLines
) / 2;
1103 Bottom
= Top
+ PopUpMenuLines
+ 1;
1105 TempValue
= MenuOption
->Tags
[MenuOption
->TagIndex
+ 1].Value
;
1106 ShowDownArrow
= TRUE
;
1110 HighlightPosition
= 0;
1113 for (Index
= MenuOption
->TagIndex
, Index2
= 0; Index2
< ValueCount
; Index
++, Index2
++) {
1115 // Set the value for the item we are looking for
1117 Count
= ValueArrayBackup
[Index2
];
1120 // If we hit the end of the Array, we are complete
1126 if (MenuOption
->Tags
[Index
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
) {
1127 for (ValueBackup
= (UINT8
) MenuOption
->TagIndex
;
1128 MenuOption
->Tags
[ValueBackup
].Operand
!= EFI_IFR_END_ONE_OF_OP
;
1132 // We just found what we are looking for
1134 if (MenuOption
->Tags
[ValueBackup
].Value
== Count
) {
1136 // As long as the two indexes aren't the same, we have
1137 // two different op-codes we need to swap internally
1139 if (Index
!= ValueBackup
) {
1141 // Backup destination tag, then copy source to destination, then copy backup to source location
1143 CopyMem (&TagBackup
, &MenuOption
->Tags
[Index
], sizeof (EFI_TAG
));
1144 CopyMem (&MenuOption
->Tags
[Index
], &MenuOption
->Tags
[ValueBackup
], sizeof (EFI_TAG
));
1145 CopyMem (&MenuOption
->Tags
[ValueBackup
], &TagBackup
, sizeof (EFI_TAG
));
1148 // If the indexes are the same, then the op-code is where he belongs
1155 // Since this wasn't an option op-code (likely the ordered list op-code) decerement Index2
1162 // Clear that portion of the screen
1164 ClearLines (Start
, End
, Top
, Bottom
, POPUP_TEXT
| POPUP_BACKGROUND
);
1167 // Draw "One of" pop-up menu
1169 Character
= (CHAR16
) BOXDRAW_DOWN_RIGHT
;
1170 PrintCharAt (Start
, Top
, Character
);
1171 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
1172 if ((ShowUpArrow
) && ((Index
+ 1) == (Start
+ End
) / 2)) {
1173 Character
= (CHAR16
) GEOMETRICSHAPE_UP_TRIANGLE
;
1175 Character
= (CHAR16
) BOXDRAW_HORIZONTAL
;
1178 PrintChar (Character
);
1181 Character
= (CHAR16
) BOXDRAW_DOWN_LEFT
;
1182 PrintChar (Character
);
1183 Character
= (CHAR16
) BOXDRAW_VERTICAL
;
1184 for (Index
= Top
+ 1; Index
< Bottom
; Index
++) {
1185 PrintCharAt (Start
, Index
, Character
);
1186 PrintCharAt (End
- 1, Index
, Character
);
1189 // Display the One of options
1192 for (Index
= MenuOption
->TagIndex
+ TopOptionIndex
;
1193 (MenuOption
->Tags
[Index
].Operand
!= EFI_IFR_END_ONE_OF_OP
) && (Index2
< Bottom
);
1196 if (MenuOption
->Tags
[Index
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
) {
1197 Token
= MenuOption
->Tags
[Index
].Text
;
1199 for (ValueBackup
= (UINT8
) MenuOption
->TagIndex
;
1200 MenuOption
->Tags
[ValueBackup
].Operand
!= EFI_IFR_END_ONE_OF_OP
;
1203 if (MenuOption
->Tags
[ValueBackup
].Value
== ((UINT8
*) ValueArrayBackup
)[Index
- MenuOption
->TagIndex
- 1]) {
1204 StringPtr
= GetToken (MenuOption
->Tags
[ValueBackup
].Text
, MenuOption
->Handle
);
1209 ValueBackup
= (UINT8
) Index
;
1210 StringPtr
= GetToken (Token
, MenuOption
->Handle
);
1213 // If the string occupies multiple lines, truncate it to fit in one line,
1214 // and append a "..." for indication.
1216 if (StrLen (StringPtr
) > (PopUpWidth
- 1)) {
1217 TempStringPtr
= AllocateZeroPool (sizeof (CHAR16
) * (PopUpWidth
- 1));
1218 ASSERT (TempStringPtr
!= NULL
);
1219 CopyMem (TempStringPtr
, StringPtr
, (sizeof (CHAR16
) * (PopUpWidth
- 5)));
1220 FreePool (StringPtr
);
1221 StringPtr
= TempStringPtr
;
1222 StrCat (StringPtr
, (CHAR16
*) L
"...");
1225 // Code to display the text should go here. Follwed by the [*]
1227 if (MenuOption
->Tags
[ValueBackup
].Suppress
== TRUE
) {
1229 // Don't show the one, so decrease the Index2 for balance
1232 } else if (MenuOption
->Tags
[ValueBackup
].GrayOut
== TRUE
) {
1236 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_GRAYED
| POPUP_BACKGROUND
);
1237 PrintStringAt (Start
+ 2, Index2
, StringPtr
);
1238 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
1239 } else if (MenuOption
->Tags
[ValueBackup
].Value
== TempValue
) {
1241 // Highlight the selected one
1243 gST
->ConOut
->SetAttribute (gST
->ConOut
, PICKLIST_HIGHLIGHT_TEXT
| PICKLIST_HIGHLIGHT_BACKGROUND
);
1244 PrintStringAt (Start
+ 2, Index2
, StringPtr
);
1245 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
1246 HighlightPosition
= Index2
;
1248 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
1249 PrintStringAt (Start
+ 2, Index2
, StringPtr
);
1252 FreePool (StringPtr
);
1253 Index2
= Index2
+ 1;
1257 Character
= (CHAR16
) BOXDRAW_UP_RIGHT
;
1258 PrintCharAt (Start
, Bottom
, Character
);
1259 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
1260 if ((ShowDownArrow
) && ((Index
+ 1) == (Start
+ End
) / 2)) {
1261 Character
= (CHAR16
) GEOMETRICSHAPE_DOWN_TRIANGLE
;
1263 Character
= (CHAR16
) BOXDRAW_HORIZONTAL
;
1266 PrintChar (Character
);
1269 Character
= (CHAR16
) BOXDRAW_UP_LEFT
;
1270 PrintChar (Character
);
1272 // Get User selection and change TempValue if necessary
1275 // Stop: One of pop-up menu
1277 Key
.UnicodeChar
= CHAR_NULL
;
1278 if ((gDirection
== SCAN_UP
) || (gDirection
== SCAN_DOWN
)) {
1279 Key
.ScanCode
= gDirection
;
1284 if (!KeyInitialized
) {
1285 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_ONE_OF_OP
) {
1286 *KeyValue
= MenuOption
->Tags
[MenuOption
->TagIndex
+ 1].Key
;
1288 *KeyValue
= MenuOption
->ThisTag
->Key
;
1291 KeyInitialized
= TRUE
;
1294 WaitForKeyStroke (&Key
);
1297 switch (Key
.UnicodeChar
) {
1301 // If an ordered list op-code, we will allow for a popup of +/- keys
1302 // to create an ordered list of items
1304 if (Tag
->Operand
== EFI_IFR_ORDERED_LIST_OP
) {
1305 if (Key
.UnicodeChar
== '+') {
1306 if ((TopOptionIndex
> 1) && (HighlightPosition
== (Top
+ 1))) {
1308 // Highlight reaches the top of the popup window, scroll one menu item.
1311 ShowDownArrow
= TRUE
;
1314 if (TopOptionIndex
== 1) {
1315 ShowUpArrow
= FALSE
;
1318 if (((TopOptionIndex
+ MenuLinesInView
) <= PopUpMenuLines
) && (HighlightPosition
== (Bottom
- 1))) {
1320 // Highlight reaches the bottom of the popup window, scroll one menu item.
1326 if ((TopOptionIndex
+ MenuLinesInView
) == (PopUpMenuLines
+ 1)) {
1327 ShowDownArrow
= FALSE
;
1331 for (Index
= MenuOption
->TagIndex
+ TopOptionIndex
;
1332 MenuOption
->Tags
[Index
].Operand
!= EFI_IFR_END_ONE_OF_OP
;
1335 if (MenuOption
->Tags
[Index
].Operand
== EFI_IFR_ORDERED_LIST_OP
) {
1339 if (Key
.UnicodeChar
== '+') {
1340 TempIndex
= Index
- 1;
1342 TempIndex
= Index
+ 1;
1345 // Is this the current tag we are on?
1347 if (MenuOption
->Tags
[Index
].Value
== TempValue
) {
1349 // Is this prior tag a valid choice? If not, bail out
1351 if (MenuOption
->Tags
[TempIndex
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
) {
1353 // Copy the destination tag to the local variable
1355 CopyMem (&TagBackup
, &MenuOption
->Tags
[TempIndex
], sizeof (EFI_TAG
));
1357 // Copy the current tag to the tag location before us
1359 CopyMem (&MenuOption
->Tags
[TempIndex
], &MenuOption
->Tags
[Index
], sizeof (EFI_TAG
));
1361 // Copy the backed up tag to the current location
1363 CopyMem (&MenuOption
->Tags
[Index
], &TagBackup
, sizeof (EFI_TAG
));
1366 // Adjust the array of values
1368 for (Index
= 0; Index
< ValueCount
; Index
++) {
1369 if (ValueArrayBackup
[Index
] == (UINT8
) TempValue
) {
1370 if (Key
.UnicodeChar
== '+') {
1373 // It is the top of the array already
1378 TempIndex
= Index
- 1;
1380 if ((Index
+ 1) == ValueCount
) {
1382 // It is the bottom of the array already
1387 TempIndex
= Index
+ 1;
1390 ValueBackup
= ValueArrayBackup
[TempIndex
];
1391 ValueArrayBackup
[TempIndex
] = ValueArrayBackup
[Index
];
1392 ValueArrayBackup
[Index
] = ValueBackup
;
1407 switch (Key
.ScanCode
) {
1410 if (Key
.ScanCode
== SCAN_UP
) {
1411 if ((TopOptionIndex
> 1) && (HighlightPosition
== (Top
+ 1))) {
1413 // Highlight reaches the top of the popup window, scroll one menu item.
1416 ShowDownArrow
= TRUE
;
1419 if (TopOptionIndex
== 1) {
1420 ShowUpArrow
= FALSE
;
1423 if (((TopOptionIndex
+ MenuLinesInView
) <= PopUpMenuLines
) && (HighlightPosition
== (Bottom
- 1))) {
1425 // Highlight reaches the bottom of the popup window, scroll one menu item.
1431 if ((TopOptionIndex
+ MenuLinesInView
) == (PopUpMenuLines
+ 1)) {
1432 ShowDownArrow
= FALSE
;
1436 for (Index
= MenuOption
->TagIndex
+ TopOptionIndex
;
1437 MenuOption
->Tags
[Index
].Operand
!= EFI_IFR_END_ONE_OF_OP
;
1440 if (MenuOption
->Tags
[Index
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
) {
1442 for (Index
= 0; (ValueArrayBackup
[Index
] != TempValue
) && (Index
< ValueCount
); Index
++)
1446 // Did we hit the end of the array? Either get the first TempValue or the next one
1448 if (Key
.ScanCode
== SCAN_UP
) {
1450 TempValue
= ValueArrayBackup
[0];
1452 TempValue
= ValueArrayBackup
[Index
- 1];
1455 if ((Index
+ 1) == ValueCount
) {
1456 TempValue
= ValueArrayBackup
[Index
];
1458 TempValue
= ValueArrayBackup
[Index
+ 1];
1463 if (Key
.ScanCode
== SCAN_UP
) {
1464 TempIndex
= Index
- 1;
1467 // Keep going until meets meaningful tag.
1469 while ((MenuOption
->Tags
[TempIndex
].Operand
!= EFI_IFR_ONE_OF_OPTION_OP
&&
1470 MenuOption
->Tags
[TempIndex
].Operand
!= EFI_IFR_ONE_OF_OP
&&
1471 MenuOption
->Tags
[TempIndex
].Operand
!= EFI_IFR_END_ONE_OF_OP
)
1473 (MenuOption
->Tags
[TempIndex
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
&&
1474 (MenuOption
->Tags
[TempIndex
].Suppress
|| MenuOption
->Tags
[TempIndex
].GrayOut
))) {
1478 TempIndex
= Index
+ 1;
1481 // Keep going until meets meaningful tag.
1483 while ((MenuOption
->Tags
[TempIndex
].Operand
!= EFI_IFR_ONE_OF_OPTION_OP
&&
1484 MenuOption
->Tags
[TempIndex
].Operand
!= EFI_IFR_ONE_OF_OP
&&
1485 MenuOption
->Tags
[TempIndex
].Operand
!= EFI_IFR_END_ONE_OF_OP
)
1487 (MenuOption
->Tags
[TempIndex
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
&&
1488 (MenuOption
->Tags
[TempIndex
].Suppress
|| MenuOption
->Tags
[TempIndex
].GrayOut
))) {
1493 // The option value is the same as what is stored in NV store. This is where we take action
1495 if (MenuOption
->Tags
[Index
].Value
== TempValue
) {
1497 // Only if the previous op-code is an option can we select it, otherwise we are at the left-most option
1499 if (MenuOption
->Tags
[TempIndex
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
) {
1500 TempValue
= MenuOption
->Tags
[TempIndex
].Value
;
1501 *KeyValue
= MenuOption
->Tags
[TempIndex
].Key
;
1503 TempValue
= MenuOption
->Tags
[Index
].Value
;
1504 *KeyValue
= MenuOption
->Tags
[Index
].Key
;
1514 gST
->ConOut
->SetAttribute (gST
->ConOut
, SavedAttribute
);
1515 if (ValueArrayBackup
!= NULL
) {
1516 FreePool (ValueArrayBackup
);
1519 return EFI_DEVICE_ERROR
;
1527 case CHAR_CARRIAGE_RETURN
:
1529 // return the current selection
1531 if (Tag
->Operand
== EFI_IFR_ORDERED_LIST_OP
) {
1532 CopyMem (ValueArray
, ValueArrayBackup
, ValueCount
);
1533 FreePool (ValueArrayBackup
);
1546 gST
->ConOut
->SetAttribute (gST
->ConOut
, SavedAttribute
);
1552 OUT EFI_INPUT_KEY
*Key
1558 UiWaitForSingleEvent (gST
->ConIn
->WaitForKey
, 0);
1559 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, Key
);
1560 } while (EFI_ERROR(Status
));