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.
19 #define EFI_MAX(_a, _b) ((_a) > (_b) ? (_a) : (_b))
23 IN UI_MENU_OPTION
*MenuOption
,
34 BOOLEAN SelectionComplete
;
36 CHAR16
*BufferedString
;
41 CHAR16
*PromptForDataString
;
42 UINTN DimensionsWidth
;
43 UINTN DimensionsHeight
;
44 BOOLEAN CursorVisible
;
46 DimensionsWidth
= gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
;
47 DimensionsHeight
= gScreenDimensions
.BottomRow
- gScreenDimensions
.TopRow
;
49 PromptForDataString
= GetToken (STRING_TOKEN (PROMPT_FOR_DATA
), gHiiHandle
);
51 NullCharacter
= CHAR_NULL
;
52 ScreenSize
= GetStringWidth (PromptForDataString
) / 2;
53 Tag
= MenuOption
->ThisTag
;
56 SelectionComplete
= FALSE
;
58 TempString
= AllocateZeroPool (MenuOption
->ThisTag
->Maximum
* 2);
61 if (ScreenSize
< (Tag
->Maximum
/ (UINTN
) 2)) {
62 ScreenSize
= Tag
->Maximum
/ 2;
65 if ((ScreenSize
+ 2) > DimensionsWidth
) {
66 ScreenSize
= DimensionsWidth
- 2;
69 BufferedString
= AllocateZeroPool (ScreenSize
* 2);
70 ASSERT (BufferedString
);
72 Start
= (DimensionsWidth
- ScreenSize
- 2) / 2 + gScreenDimensions
.LeftColumn
+ 1;
73 Top
= ((DimensionsHeight
- 6) / 2) + gScreenDimensions
.TopRow
- 1;
76 // Display prompt for string
78 CreatePopUp (ScreenSize
, 4, &NullCharacter
, PromptForDataString
, Space
, &NullCharacter
);
80 FreePool (PromptForDataString
);
82 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_BLACK
, EFI_LIGHTGRAY
));
84 CursorVisible
= gST
->ConOut
->Mode
->CursorVisible
;
85 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
88 Status
= WaitForKeyStroke (&Key
);
90 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_BLACK
, EFI_LIGHTGRAY
));
91 switch (Key
.UnicodeChar
) {
93 switch (Key
.ScanCode
) {
101 FreePool (TempString
);
102 FreePool (BufferedString
);
103 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
104 gST
->ConOut
->EnableCursor (gST
->ConOut
, CursorVisible
);
105 return EFI_DEVICE_ERROR
;
113 case CHAR_CARRIAGE_RETURN
:
114 if (GetStringWidth (StringPtr
) >= MenuOption
->ThisTag
->Minimum
) {
115 SelectionComplete
= TRUE
;
116 FreePool (TempString
);
117 FreePool (BufferedString
);
118 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
119 gST
->ConOut
->EnableCursor (gST
->ConOut
, CursorVisible
);
122 ScreenSize
= GetStringWidth (gMiniString
) / 2;
123 CreatePopUp (ScreenSize
, 4, &NullCharacter
, gMiniString
, gPressEnter
, &NullCharacter
);
125 // Simply create a popup to tell the user that they had typed in too few characters.
126 // To save code space, we can then treat this as an error and return back to the menu.
129 Status
= WaitForKeyStroke (&Key
);
130 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
131 FreePool (TempString
);
132 FreePool (BufferedString
);
133 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
134 gST
->ConOut
->EnableCursor (gST
->ConOut
, CursorVisible
);
135 return EFI_DEVICE_ERROR
;
141 if (StringPtr
[0] != CHAR_NULL
) {
142 for (Index
= 0; StringPtr
[Index
] != CHAR_NULL
; Index
++) {
143 TempString
[Index
] = StringPtr
[Index
];
146 // Effectively truncate string by 1 character
148 TempString
[Index
- 1] = CHAR_NULL
;
149 StrCpy (StringPtr
, TempString
);
154 // If it is the beginning of the string, don't worry about checking maximum limits
156 if ((StringPtr
[0] == CHAR_NULL
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
157 StrnCpy (StringPtr
, &Key
.UnicodeChar
, 1);
158 StrnCpy (TempString
, &Key
.UnicodeChar
, 1);
159 } else if ((GetStringWidth (StringPtr
) < MenuOption
->ThisTag
->Maximum
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
160 KeyPad
[0] = Key
.UnicodeChar
;
161 KeyPad
[1] = CHAR_NULL
;
162 StrCat (StringPtr
, KeyPad
);
163 StrCat (TempString
, KeyPad
);
166 // If the width of the input string is now larger than the screen, we nee to
167 // adjust the index to start printing portions of the string
169 SetUnicodeMem (BufferedString
, ScreenSize
- 1, L
' ');
171 PrintStringAt (Start
+ 1, Top
+ 3, BufferedString
);
173 if ((GetStringWidth (StringPtr
) / 2) > (DimensionsWidth
- 2)) {
174 Index
= (GetStringWidth (StringPtr
) / 2) - DimensionsWidth
+ 2;
179 for (Count
= 0; Index
+ 1 < GetStringWidth (StringPtr
) / 2; Index
++, Count
++) {
180 BufferedString
[Count
] = StringPtr
[Index
];
183 PrintStringAt (Start
+ 1, Top
+ 3, BufferedString
);
187 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
188 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, Start
+ GetStringWidth (StringPtr
) / 2, Top
+ 3);
189 } while (!SelectionComplete
);
190 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
191 gST
->ConOut
->EnableCursor (gST
->ConOut
, CursorVisible
);
197 IN UI_MENU_OPTION
*MenuOption
,
198 IN BOOLEAN PromptForPassword
,
200 IN EFI_IFR_DATA_ARRAY
*PageData
,
201 IN BOOLEAN SecondEntry
,
202 IN EFI_FILE_FORM_TAGS
*FileFormTags
,
203 OUT CHAR16
*StringPtr
208 CHAR16 NullCharacter
;
217 BOOLEAN Confirmation
;
218 BOOLEAN ConfirmationComplete
;
219 EFI_HII_CALLBACK_PACKET
*Packet
;
220 EFI_FORM_CALLBACK_PROTOCOL
*FormCallback
;
221 EFI_VARIABLE_DEFINITION
*VariableDefinition
;
222 UINTN DimensionsWidth
;
223 UINTN DimensionsHeight
;
224 EFI_IFR_DATA_ENTRY
*DataEntry
;
227 DimensionsWidth
= gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
;
228 DimensionsHeight
= gScreenDimensions
.BottomRow
- gScreenDimensions
.TopRow
;
230 VariableDefinition
= NULL
;
231 NullCharacter
= CHAR_NULL
;
233 Space
[1] = CHAR_NULL
;
234 Confirmation
= FALSE
;
235 ConfirmationComplete
= FALSE
;
236 Status
= EFI_SUCCESS
;
241 // Remember that dynamic pages in an environment where all pages are not
242 // dynamic require us to call back to the user to give them an opportunity
243 // to register fresh information in the HII database so that we can extract it.
245 Status
= gBS
->HandleProtocol (
246 (VOID
*) (UINTN
) MenuOption
->Tags
[0].CallbackHandle
,
247 &gEfiFormCallbackProtocolGuid
,
248 (VOID
**) &FormCallback
251 TempString
= AllocateZeroPool (MenuOption
->ThisTag
->Maximum
* 2);
252 TempString2
= AllocateZeroPool (MenuOption
->ThisTag
->Maximum
* 2);
255 ASSERT (TempString2
);
257 if (Tag
->Flags
& EFI_IFR_FLAG_INTERACTIVE
) {
259 // Password requires a callback to determine if a password exists
261 DataEntry
= (EFI_IFR_DATA_ENTRY
*) (PageData
+ 1);
262 DataEntry
->OpCode
= EFI_IFR_PASSWORD_OP
;
263 DataEntry
->Length
= 3;
265 ExtractRequestedNvMap (FileFormTags
, Tag
->VariableNumber
, &VariableDefinition
);
268 // The user is about to be prompted with a password field, Data = 0 (Return Status determines the type of prompt)
270 DataEntry
->Data
= (VOID
*) (UINTN
) (UINT8
) (0 + SecondEntry
* 2);
271 PageData
->NvRamMap
= VariableDefinition
->NvRamMap
;
273 if ((FormCallback
!= NULL
) && (FormCallback
->Callback
!= NULL
)) {
274 Status
= FormCallback
->Callback (
282 // If error on return, continue with the reading of a typed in password to verify user knows password
283 // If no error, there is no password set, so prompt for new password
284 // if the previous callback was to verify the user knew password, and user typed it correctly - should return no error
286 if (!EFI_ERROR (Status
)) {
287 PromptForPassword
= FALSE
;
290 // Simulate this as the second entry into this routine for an interactive behavior
293 } else if (Status
== EFI_NOT_READY
) {
295 if (Packet
!= NULL
) {
297 // Upon error, we will likely receive a string to print out
298 // Display error popup
300 WidthOfString
= GetStringWidth (Packet
->String
);
301 ScreenSize
= EFI_MAX(WidthOfString
, GetStringWidth (gPressEnter
)) / 2;
302 CreatePopUp (ScreenSize
, 4, &NullCharacter
, Packet
->String
, gPressEnter
, &NullCharacter
);
306 Status
= WaitForKeyStroke (&Key
);
307 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
310 Status
= EFI_NOT_READY
;
317 // Display PopUp Screen
319 ScreenSize
= GetStringWidth (gPromptForNewPassword
) / 2;
320 if (GetStringWidth (gConfirmPassword
) / 2 > ScreenSize
) {
321 ScreenSize
= GetStringWidth (gConfirmPassword
) / 2;
324 Start
= (DimensionsWidth
- ScreenSize
- 4) / 2 + gScreenDimensions
.LeftColumn
+ 2;
325 Top
= ((DimensionsHeight
- 6) / 2) + gScreenDimensions
.TopRow
- 1;
328 if (PromptForPassword
) {
329 CreatePopUp (ScreenSize
, 4, &NullCharacter
, gPromptForPassword
, Space
, &NullCharacter
);
331 CreatePopUp (ScreenSize
, 4, &NullCharacter
, gPromptForNewPassword
, Space
, &NullCharacter
);
334 CreatePopUp (ScreenSize
, 4, &NullCharacter
, gConfirmPassword
, Space
, &NullCharacter
);
335 StringPtr
[0] = CHAR_NULL
;
339 Status
= WaitForKeyStroke (&Key
);
341 switch (Key
.UnicodeChar
) {
343 if (Key
.ScanCode
== SCAN_ESC
) {
344 return EFI_NOT_READY
;
347 ConfirmationComplete
= FALSE
;
350 case CHAR_CARRIAGE_RETURN
:
351 if (Tag
->Flags
& EFI_IFR_FLAG_INTERACTIVE
) {
353 // User just typed a string in
355 DataEntry
= (EFI_IFR_DATA_ENTRY
*) (PageData
+ 1);
356 DataEntry
->OpCode
= EFI_IFR_PASSWORD_OP
;
359 // If the user just typed in a password, Data = 1
360 // If the user just typed in a password to confirm the previous password, Data = 2
363 DataEntry
->Length
= 3;
364 DataEntry
->Data
= (VOID
*) (UINTN
) (UINT8
) (1 + SecondEntry
* 2);
366 if ((FormCallback
!= NULL
) && (FormCallback
->Callback
!= NULL
)) {
367 Status
= FormCallback
->Callback (
375 DataEntry
->Length
= sizeof (EFI_IFR_DATA_ENTRY
);
376 DataEntry
->Data
= (VOID
*) TempString
;
378 DataEntry
->Length
= 3;
379 DataEntry
->Data
= (VOID
*) (UINTN
) (UINT8
) (2 + SecondEntry
* 2);
381 if ((FormCallback
!= NULL
) && (FormCallback
->Callback
!= NULL
)) {
382 Status
= FormCallback
->Callback (
390 DataEntry
->Length
= sizeof (EFI_IFR_DATA_ENTRY
);
391 DataEntry
->Data
= (VOID
*) TempString2
;
394 if ((FormCallback
!= NULL
) && (FormCallback
->Callback
!= NULL
)) {
395 Status
= FormCallback
->Callback (
403 // If this was the confirmation round of callbacks
404 // and an error comes back, display an error
407 if (EFI_ERROR (Status
)) {
408 if (Packet
->String
== NULL
) {
409 WidthOfString
= GetStringWidth (gConfirmError
);
410 ScreenSize
= EFI_MAX (WidthOfString
, GetStringWidth (gPressEnter
)) / 2;
411 CreatePopUp (ScreenSize
, 4, &NullCharacter
, gConfirmError
, gPressEnter
, &NullCharacter
);
413 WidthOfString
= GetStringWidth (Packet
->String
);
414 ScreenSize
= EFI_MAX (WidthOfString
, GetStringWidth (gPressEnter
)) / 2;
415 CreatePopUp (ScreenSize
, 4, &NullCharacter
, Packet
->String
, gPressEnter
, &NullCharacter
);
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
= EFI_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
)) {
519 StrnCpy (StringPtr
, &Key
.UnicodeChar
, 1);
520 StrnCpy (TempString
, &Key
.UnicodeChar
, 1);
522 StrnCpy (StringPtr
, &Key
.UnicodeChar
, 1);
523 StrnCpy (TempString2
, &Key
.UnicodeChar
, 1);
524 ConfirmationComplete
= FALSE
;
526 } else if ((GetStringWidth (StringPtr
) / 2 <= (UINTN
) (MenuOption
->ThisTag
->Maximum
- 1) / 2) &&
527 (Key
.UnicodeChar
!= CHAR_BACKSPACE
)
529 KeyPad
[0] = Key
.UnicodeChar
;
530 KeyPad
[1] = CHAR_NULL
;
532 StrCat (StringPtr
, KeyPad
);
533 StrCat (TempString
, KeyPad
);
535 StrCat (StringPtr
, KeyPad
);
536 StrCat (TempString2
, KeyPad
);
540 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_BLACK
, EFI_LIGHTGRAY
));
541 for (Index
= 1; Index
< ScreenSize
; Index
++) {
542 PrintCharAt (Start
+ Index
, Top
+ 3, L
' ');
545 gST
->ConOut
->SetCursorPosition (
547 (DimensionsWidth
- GetStringWidth (StringPtr
) / 2) / 2 + gScreenDimensions
.LeftColumn
,
550 for (Index
= 0; Index
+ 1 < GetStringWidth (StringPtr
) / 2; Index
++) {
554 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
560 } while (!ConfirmationComplete
);
565 FreePool (TempString
);
566 FreePool (TempString2
);
581 Key
= (CHAR16
*) L
"MAR10648567";
582 Buffer
= AllocateZeroPool (MaxSize
);
586 for (Index
= 0; Key
[Index
] != 0; Index
++) {
587 for (Loop
= 0; Loop
< (UINT8
) (MaxSize
/ 2); Loop
++) {
588 Buffer
[Loop
] = (CHAR16
) (Password
[Loop
] ^ Key
[Index
]);
592 CopyMem (Password
, Buffer
, MaxSize
);
600 IN UI_MENU_OPTION
*MenuOption
,
601 IN EFI_FILE_FORM_TAGS
*FileFormTagsHead
,
602 IN BOOLEAN ManualInput
,
604 IN UINTN NumericType
,
611 This routine reads a numeric value from the user input.
615 MenuOption - Pointer to the current input menu.
617 FileFormTagsHead - Pointer to the root of formset.
619 ManualInput - If the input is manual or not.
621 Tag - Pointer to all the attributes and values associated with a tag.
623 Value - Pointer to the numeric value that is going to be read.
627 EFI_SUCCESS - If numerical input is read successfully
628 EFI_DEVICE_ERROR - If operation fails
633 BOOLEAN SelectionComplete
;
636 CHAR16 FormattedNumber
[6];
637 UINTN PreviousNumber
[6];
642 CHAR16 NullCharacter
;
644 EFI_FILE_FORM_TAGS
*FileFormTags
;
645 EFI_VARIABLE_DEFINITION
*VariableDefinition
;
648 NullCharacter
= CHAR_NULL
;
650 Column
= MenuOption
->OptCol
;
651 Row
= MenuOption
->Row
;
653 PreviousNumber
[0] = 0;
655 SelectionComplete
= FALSE
;
656 BackupValue
= Tag
->Value
;
657 FileFormTags
= FileFormTagsHead
;
660 PrintAt (Column
, Row
, (CHAR16
*) L
"[ ]");
662 if (Tag
->Operand
!= EFI_IFR_TIME_OP
) {
663 *Value
= BackupValue
;
667 // First time we enter this handler, we need to check to see if
668 // we were passed an increment or decrement directive
671 Key
.UnicodeChar
= CHAR_NULL
;
672 if (gDirection
!= 0) {
673 Key
.ScanCode
= gDirection
;
678 WaitForKeyStroke (&Key
);
681 switch (Key
.UnicodeChar
) {
684 if ((Tag
->Operand
== EFI_IFR_DATE_OP
) || (Tag
->Operand
== EFI_IFR_TIME_OP
)) {
685 Key
.UnicodeChar
= CHAR_NULL
;
686 if (Key
.UnicodeChar
== '+') {
687 Key
.ScanCode
= SCAN_RIGHT
;
689 Key
.ScanCode
= SCAN_LEFT
;
697 switch (Key
.ScanCode
) {
700 if ((Tag
->Operand
== EFI_IFR_DATE_OP
) || (Tag
->Operand
== EFI_IFR_TIME_OP
)) {
702 // By setting this value, we will return back to the caller.
703 // We need to do this since an auto-refresh will destroy the adjustment
704 // based on what the real-time-clock is showing. So we always commit
705 // upon changing the value.
707 gDirection
= SCAN_DOWN
;
712 if (Key
.ScanCode
== SCAN_LEFT
) {
713 Number
= *Value
- Tag
->Step
;
714 if (Number
< Tag
->Minimum
) {
715 Number
= Tag
->Minimum
;
717 } else if (Key
.ScanCode
== SCAN_RIGHT
) {
718 Number
= *Value
+ Tag
->Step
;
719 if (Number
> Tag
->Maximum
) {
720 Number
= Tag
->Maximum
;
724 Tag
->Value
= (UINT16
) Number
;
725 *Value
= (UINT16
) Number
;
726 UnicodeValueToString (
730 (sizeof (FormattedNumber
) / sizeof (FormattedNumber
[0]))
732 Number
= (UINT16
) GetStringWidth (FormattedNumber
);
734 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT
| FIELD_BACKGROUND
);
735 if ((Tag
->Operand
== EFI_IFR_DATE_OP
) || (Tag
->Operand
== EFI_IFR_TIME_OP
)) {
736 for (Loop
= 0; Loop
< (UINTN
) ((Number
>= 8) ? 4 : 2); Loop
++) {
737 PrintAt (MenuOption
->OptCol
+ Loop
, MenuOption
->Row
, (CHAR16
*) L
" ");
740 for (Loop
= 0; Loop
< gOptionBlockWidth
; Loop
++) {
741 PrintAt (MenuOption
->OptCol
+ Loop
, MenuOption
->Row
, (CHAR16
*) L
" ");
745 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_HIGHLIGHT
| FIELD_BACKGROUND_HIGHLIGHT
);
747 if ((MenuOption
->Col
+ gPromptBlockWidth
+ 1) == MenuOption
->OptCol
) {
748 PrintCharAt (MenuOption
->OptCol
, Row
, LEFT_NUMERIC_DELIMITER
);
749 Column
= MenuOption
->OptCol
+ 1;
752 // If Number looks like "3", convert it to "03/"
754 if (Number
== 4 && (NumericType
== DATE_NUMERIC
)) {
755 FormattedNumber
[3] = FormattedNumber
[1];
756 FormattedNumber
[2] = DATE_SEPARATOR
;
757 FormattedNumber
[1] = FormattedNumber
[0];
758 FormattedNumber
[0] = L
'0';
762 // If Number looks like "13", convert it to "13/"
764 if (Number
== 6 && (NumericType
== DATE_NUMERIC
)) {
765 FormattedNumber
[3] = FormattedNumber
[2];
766 FormattedNumber
[2] = DATE_SEPARATOR
;
771 (NumericType
== TIME_NUMERIC
) &&
772 (MenuOption
->Col
+ gPromptBlockWidth
+ 8) != MenuOption
->OptCol
774 FormattedNumber
[3] = FormattedNumber
[1];
775 FormattedNumber
[2] = TIME_SEPARATOR
;
776 FormattedNumber
[1] = FormattedNumber
[0];
777 FormattedNumber
[0] = L
'0';
782 (NumericType
== TIME_NUMERIC
) &&
783 (MenuOption
->Col
+ gPromptBlockWidth
+ 8) == MenuOption
->OptCol
785 FormattedNumber
[3] = FormattedNumber
[1];
786 FormattedNumber
[2] = RIGHT_NUMERIC_DELIMITER
;
787 FormattedNumber
[1] = FormattedNumber
[0];
788 FormattedNumber
[0] = L
'0';
792 PrintStringAt (Column
, Row
, FormattedNumber
);
793 if (Number
== 10 && (NumericType
== DATE_NUMERIC
)) {
794 PrintChar (RIGHT_NUMERIC_DELIMITER
);
797 if (NumericType
== REGULAR_NUMERIC
) {
798 PrintChar (RIGHT_NUMERIC_DELIMITER
);
805 goto EnterCarriageReturn
;
808 return EFI_DEVICE_ERROR
;
818 case CHAR_CARRIAGE_RETURN
:
820 // Check to see if the Value is something reasonable against consistency limitations.
821 // If not, let's kick the error specified.
824 // This gives us visibility to the FileFormTags->NvRamMap to check things
825 // ActiveIfr is a global maintained by the menuing code to ensure that we
826 // are pointing to the correct formset's file data.
828 for (Count
= 0; Count
< gActiveIfr
; Count
++) {
829 FileFormTags
= FileFormTags
->NextFile
;
832 ExtractRequestedNvMap (FileFormTags
, Tag
->VariableNumber
, &VariableDefinition
);
834 CopyMem (&VariableDefinition
->NvRamMap
[Tag
->StorageStart
], &Tag
->Value
, Tag
->StorageWidth
);
837 // Data associated with a NULL device (in the fake NV storage)
839 if (Tag
->StorageWidth
== (UINT16
) 0) {
840 CopyMem (&VariableDefinition
->FakeNvRamMap
[Tag
->StorageStart
], &Tag
->Value
, 2);
843 // If a late check is required save off the information. This is used when consistency checks
844 // are required, but certain values might be bound by an impossible consistency check such as
845 // if two questions are bound by consistency checks and each only has two possible choices, there
846 // would be no way for a user to switch the values. Thus we require late checking.
848 if (Tag
->Flags
& EFI_IFR_FLAG_LATE_CHECK
) {
849 CopyMem (&Tag
->OldValue
, &BackupValue
, Tag
->StorageWidth
);
852 // In theory, passing the value and the Id are sufficient to determine what needs
853 // to be done. The Id is the key to look for the entry needed in the Inconsistency
854 // database. That will yields operand and ID data - and since the ID's correspond
855 // to the NV storage, we can determine the values for other IDs there.
857 if (ValueIsNotValid (TRUE
, 0, Tag
, FileFormTags
, &PopUp
)) {
858 if (PopUp
== 0x0000) {
859 SelectionComplete
= TRUE
;
863 StringPtr
= GetToken (PopUp
, MenuOption
->Handle
);
865 CreatePopUp (GetStringWidth (StringPtr
) / 2, 3, &NullCharacter
, StringPtr
, &NullCharacter
);
868 WaitForKeyStroke (&Key
);
870 switch (Key
.UnicodeChar
) {
872 case CHAR_CARRIAGE_RETURN
:
873 SelectionComplete
= TRUE
;
874 FreePool (StringPtr
);
880 } while (!SelectionComplete
);
882 Tag
->Value
= BackupValue
;
883 *Value
= BackupValue
;
885 CopyMem (&VariableDefinition
->NvRamMap
[Tag
->StorageStart
], &Tag
->Value
, Tag
->StorageWidth
);
888 // Data associated with a NULL device (in the fake NV storage)
890 if (Tag
->StorageWidth
== (UINT16
) 0) {
891 CopyMem (&VariableDefinition
->FakeNvRamMap
[Tag
->StorageStart
], &Tag
->Value
, 2);
894 return EFI_DEVICE_ERROR
;
907 // Remove a character
909 Number
= PreviousNumber
[Count
- 1];
910 *Value
= (UINT16
) Number
;
911 UpdateStatusBar (INPUT_ERROR
, Tag
->Flags
, FALSE
);
914 PrintAt (Column
, Row
, (CHAR16
*) L
" ");
920 if (Key
.UnicodeChar
> L
'9' || Key
.UnicodeChar
< L
'0') {
921 UpdateStatusBar (INPUT_ERROR
, Tag
->Flags
, TRUE
);
925 // If Count 0-4 is complete, there is no way more is valid
931 // Someone typed something valid!
934 Number
= Number
* 10 + (Key
.UnicodeChar
- L
'0');
936 Number
= Key
.UnicodeChar
- L
'0';
939 if (Number
> Tag
->Maximum
) {
940 UpdateStatusBar (INPUT_ERROR
, Tag
->Flags
, TRUE
);
941 Number
= PreviousNumber
[Count
];
944 UpdateStatusBar (INPUT_ERROR
, Tag
->Flags
, FALSE
);
949 PreviousNumber
[Count
] = Number
;
950 *Value
= (UINT16
) Number
;
951 Tag
->Value
= (UINT16
) Number
;
953 PrintCharAt (Column
, Row
, Key
.UnicodeChar
);
958 } while (!SelectionComplete
);
962 // Notice that this is at least needed for the ordered list manipulation.
963 // Left/Right doesn't make sense for this op-code
966 GetSelectionInputPopUp (
967 IN UI_MENU_OPTION
*MenuOption
,
978 CHAR16
*TempStringPtr
;
981 UINTN TopOptionIndex
;
982 UINTN HighlightPosition
;
989 UINTN PopUpMenuLines
;
990 UINTN MenuLinesInView
;
993 BOOLEAN FirstOptionFoundFlag
;
994 INT32 SavedAttribute
;
997 UINT8
*ValueArrayBackup
;
1000 BOOLEAN KeyInitialized
;
1001 BOOLEAN ShowDownArrow
;
1002 BOOLEAN ShowUpArrow
;
1003 UINTN DimensionsWidth
;
1005 DimensionsWidth
= gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
;
1009 ValueArray
= (UINT8
*) Value
;
1010 ValueArrayBackup
= NULL
;
1011 Initialized
= FALSE
;
1012 KeyInitialized
= FALSE
;
1013 ShowDownArrow
= FALSE
;
1014 ShowUpArrow
= FALSE
;
1016 if (Tag
->Operand
== EFI_IFR_ORDERED_LIST_OP
) {
1017 ValueArrayBackup
= AllocateZeroPool (Tag
->StorageWidth
);
1018 ASSERT (ValueArrayBackup
!= NULL
);
1019 CopyMem (ValueArrayBackup
, ValueArray
, ValueCount
);
1020 TempValue
= *(UINT8
*) (ValueArray
);
1021 if (ValueArray
[0] != 0x00) {
1025 for (Index
= 0; ValueArray
[Index
] != 0x00; Index
++)
1035 FirstOptionFoundFlag
= FALSE
;
1037 StringPtr
= AllocateZeroPool ((gOptionBlockWidth
+ 1) * 2);
1041 // Initialization for "One of" pop-up menu
1044 // Get the number of one of options present and its size
1046 for (Index
= MenuOption
->TagIndex
; MenuOption
->Tags
[Index
].Operand
!= EFI_IFR_END_ONE_OF_OP
; Index
++) {
1047 if (MenuOption
->Tags
[Index
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
&&
1048 !MenuOption
->Tags
[Index
].Suppress
) {
1049 if (!FirstOptionFoundFlag
) {
1050 FirstOptionFoundFlag
= TRUE
;
1054 Token
= MenuOption
->Tags
[Index
].Text
;
1057 // If this is an ordered list that is initialized
1060 for (ValueBackup
= (UINT8
) MenuOption
->TagIndex
;
1061 MenuOption
->Tags
[ValueBackup
].Operand
!= EFI_IFR_END_OP
;
1064 if (MenuOption
->Tags
[ValueBackup
].Value
== ((UINT8
*) ValueArrayBackup
)[Index
- MenuOption
->TagIndex
- 1]) {
1065 StringPtr
= GetToken (MenuOption
->Tags
[ValueBackup
].Text
, MenuOption
->Handle
);
1070 StringPtr
= GetToken (Token
, MenuOption
->Handle
);
1073 if (StrLen (StringPtr
) > PopUpWidth
) {
1074 PopUpWidth
= StrLen (StringPtr
);
1077 FreePool (StringPtr
);
1081 // Perform popup menu initialization.
1083 PopUpMenuLines
= Count
;
1084 PopUpWidth
= PopUpWidth
+ POPUP_PAD_SPACE_COUNT
;
1086 SavedAttribute
= gST
->ConOut
->Mode
->Attribute
;
1087 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
1089 if ((PopUpWidth
+ POPUP_FRAME_WIDTH
) > DimensionsWidth
) {
1090 PopUpWidth
= DimensionsWidth
- POPUP_FRAME_WIDTH
;
1093 Start
= (DimensionsWidth
- PopUpWidth
- POPUP_FRAME_WIDTH
) / 2 + gScreenDimensions
.LeftColumn
;
1094 End
= Start
+ PopUpWidth
+ POPUP_FRAME_WIDTH
;
1095 Top
= gScreenDimensions
.TopRow
+ NONE_FRONT_PAGE_HEADER_HEIGHT
;
1096 Bottom
= gScreenDimensions
.BottomRow
- STATUS_BAR_HEIGHT
- FOOTER_HEIGHT
;
1098 MenuLinesInView
= Bottom
- Top
- 1;
1099 if (MenuLinesInView
>= PopUpMenuLines
) {
1100 Top
= Top
+ (MenuLinesInView
- PopUpMenuLines
) / 2;
1101 Bottom
= Top
+ PopUpMenuLines
+ 1;
1103 TempValue
= MenuOption
->Tags
[MenuOption
->TagIndex
+ 1].Value
;
1104 ShowDownArrow
= TRUE
;
1108 HighlightPosition
= 0;
1111 for (Index
= MenuOption
->TagIndex
, Index2
= 0; Index2
< ValueCount
; Index
++, Index2
++) {
1113 // Set the value for the item we are looking for
1115 Count
= ValueArrayBackup
[Index2
];
1118 // If we hit the end of the Array, we are complete
1124 if (MenuOption
->Tags
[Index
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
) {
1125 for (ValueBackup
= (UINT8
) MenuOption
->TagIndex
;
1126 MenuOption
->Tags
[ValueBackup
].Operand
!= EFI_IFR_END_ONE_OF_OP
;
1130 // We just found what we are looking for
1132 if (MenuOption
->Tags
[ValueBackup
].Value
== Count
) {
1134 // As long as the two indexes aren't the same, we have
1135 // two different op-codes we need to swap internally
1137 if (Index
!= ValueBackup
) {
1139 // Backup destination tag, then copy source to destination, then copy backup to source location
1141 CopyMem (&TagBackup
, &MenuOption
->Tags
[Index
], sizeof (EFI_TAG
));
1142 CopyMem (&MenuOption
->Tags
[Index
], &MenuOption
->Tags
[ValueBackup
], sizeof (EFI_TAG
));
1143 CopyMem (&MenuOption
->Tags
[ValueBackup
], &TagBackup
, sizeof (EFI_TAG
));
1146 // If the indexes are the same, then the op-code is where he belongs
1153 // Since this wasn't an option op-code (likely the ordered list op-code) decerement Index2
1160 // Clear that portion of the screen
1162 ClearLines (Start
, End
, Top
, Bottom
, POPUP_TEXT
| POPUP_BACKGROUND
);
1165 // Draw "One of" pop-up menu
1167 Character
= (CHAR16
) BOXDRAW_DOWN_RIGHT
;
1168 PrintCharAt (Start
, Top
, Character
);
1169 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
1170 if ((ShowUpArrow
) && ((Index
+ 1) == (Start
+ End
) / 2)) {
1171 Character
= (CHAR16
) GEOMETRICSHAPE_UP_TRIANGLE
;
1173 Character
= (CHAR16
) BOXDRAW_HORIZONTAL
;
1176 PrintChar (Character
);
1179 Character
= (CHAR16
) BOXDRAW_DOWN_LEFT
;
1180 PrintChar (Character
);
1181 Character
= (CHAR16
) BOXDRAW_VERTICAL
;
1182 for (Index
= Top
+ 1; Index
< Bottom
; Index
++) {
1183 PrintCharAt (Start
, Index
, Character
);
1184 PrintCharAt (End
- 1, Index
, Character
);
1187 // Display the One of options
1190 for (Index
= MenuOption
->TagIndex
+ TopOptionIndex
;
1191 (MenuOption
->Tags
[Index
].Operand
!= EFI_IFR_END_ONE_OF_OP
) && (Index2
< Bottom
);
1194 if (MenuOption
->Tags
[Index
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
) {
1195 Token
= MenuOption
->Tags
[Index
].Text
;
1197 for (ValueBackup
= (UINT8
) MenuOption
->TagIndex
;
1198 MenuOption
->Tags
[ValueBackup
].Operand
!= EFI_IFR_END_ONE_OF_OP
;
1201 if (MenuOption
->Tags
[ValueBackup
].Value
== ((UINT8
*) ValueArrayBackup
)[Index
- MenuOption
->TagIndex
- 1]) {
1202 StringPtr
= GetToken (MenuOption
->Tags
[ValueBackup
].Text
, MenuOption
->Handle
);
1207 ValueBackup
= (UINT8
) Index
;
1208 StringPtr
= GetToken (Token
, MenuOption
->Handle
);
1211 // If the string occupies multiple lines, truncate it to fit in one line,
1212 // and append a "..." for indication.
1214 if (StrLen (StringPtr
) > (PopUpWidth
- 1)) {
1215 TempStringPtr
= AllocateZeroPool (sizeof (CHAR16
) * (PopUpWidth
- 1));
1216 ASSERT (TempStringPtr
!= NULL
);
1217 CopyMem (TempStringPtr
, StringPtr
, (sizeof (CHAR16
) * (PopUpWidth
- 5)));
1218 FreePool (StringPtr
);
1219 StringPtr
= TempStringPtr
;
1220 StrCat (StringPtr
, (CHAR16
*) L
"...");
1223 // Code to display the text should go here. Follwed by the [*]
1225 if (MenuOption
->Tags
[ValueBackup
].Suppress
== TRUE
) {
1227 // Don't show the one, so decrease the Index2 for balance
1230 } else if (MenuOption
->Tags
[ValueBackup
].GrayOut
== TRUE
) {
1234 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_GRAYED
| POPUP_BACKGROUND
);
1235 PrintStringAt (Start
+ 2, Index2
, StringPtr
);
1236 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
1237 } else if (MenuOption
->Tags
[ValueBackup
].Value
== TempValue
) {
1239 // Highlight the selected one
1241 gST
->ConOut
->SetAttribute (gST
->ConOut
, PICKLIST_HIGHLIGHT_TEXT
| PICKLIST_HIGHLIGHT_BACKGROUND
);
1242 PrintStringAt (Start
+ 2, Index2
, StringPtr
);
1243 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
1244 HighlightPosition
= Index2
;
1246 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
1247 PrintStringAt (Start
+ 2, Index2
, StringPtr
);
1250 FreePool (StringPtr
);
1251 Index2
= Index2
+ 1;
1255 Character
= (CHAR16
) BOXDRAW_UP_RIGHT
;
1256 PrintCharAt (Start
, Bottom
, Character
);
1257 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
1258 if ((ShowDownArrow
) && ((Index
+ 1) == (Start
+ End
) / 2)) {
1259 Character
= (CHAR16
) GEOMETRICSHAPE_DOWN_TRIANGLE
;
1261 Character
= (CHAR16
) BOXDRAW_HORIZONTAL
;
1264 PrintChar (Character
);
1267 Character
= (CHAR16
) BOXDRAW_UP_LEFT
;
1268 PrintChar (Character
);
1270 // Get User selection and change TempValue if necessary
1273 // Stop: One of pop-up menu
1275 Key
.UnicodeChar
= CHAR_NULL
;
1276 if ((gDirection
== SCAN_UP
) || (gDirection
== SCAN_DOWN
)) {
1277 Key
.ScanCode
= gDirection
;
1282 if (!KeyInitialized
) {
1283 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_ONE_OF_OP
) {
1284 *KeyValue
= MenuOption
->Tags
[MenuOption
->TagIndex
+ 1].Key
;
1286 *KeyValue
= MenuOption
->ThisTag
->Key
;
1289 KeyInitialized
= TRUE
;
1292 WaitForKeyStroke (&Key
);
1295 switch (Key
.UnicodeChar
) {
1299 // If an ordered list op-code, we will allow for a popup of +/- keys
1300 // to create an ordered list of items
1302 if (Tag
->Operand
== EFI_IFR_ORDERED_LIST_OP
) {
1303 if (Key
.UnicodeChar
== '+') {
1304 if ((TopOptionIndex
> 1) && (HighlightPosition
== (Top
+ 1))) {
1306 // Highlight reaches the top of the popup window, scroll one menu item.
1309 ShowDownArrow
= TRUE
;
1312 if (TopOptionIndex
== 1) {
1313 ShowUpArrow
= FALSE
;
1316 if (((TopOptionIndex
+ MenuLinesInView
) <= PopUpMenuLines
) && (HighlightPosition
== (Bottom
- 1))) {
1318 // Highlight reaches the bottom of the popup window, scroll one menu item.
1324 if ((TopOptionIndex
+ MenuLinesInView
) == (PopUpMenuLines
+ 1)) {
1325 ShowDownArrow
= FALSE
;
1329 for (Index
= MenuOption
->TagIndex
+ TopOptionIndex
;
1330 MenuOption
->Tags
[Index
].Operand
!= EFI_IFR_END_ONE_OF_OP
;
1333 if (MenuOption
->Tags
[Index
].Operand
== EFI_IFR_ORDERED_LIST_OP
) {
1337 if (Key
.UnicodeChar
== '+') {
1338 TempIndex
= Index
- 1;
1340 TempIndex
= Index
+ 1;
1343 // Is this the current tag we are on?
1345 if (MenuOption
->Tags
[Index
].Value
== TempValue
) {
1347 // Is this prior tag a valid choice? If not, bail out
1349 if (MenuOption
->Tags
[TempIndex
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
) {
1351 // Copy the destination tag to the local variable
1353 CopyMem (&TagBackup
, &MenuOption
->Tags
[TempIndex
], sizeof (EFI_TAG
));
1355 // Copy the current tag to the tag location before us
1357 CopyMem (&MenuOption
->Tags
[TempIndex
], &MenuOption
->Tags
[Index
], sizeof (EFI_TAG
));
1359 // Copy the backed up tag to the current location
1361 CopyMem (&MenuOption
->Tags
[Index
], &TagBackup
, sizeof (EFI_TAG
));
1364 // Adjust the array of values
1366 for (Index
= 0; Index
< ValueCount
; Index
++) {
1367 if (ValueArrayBackup
[Index
] == (UINT8
) TempValue
) {
1368 if (Key
.UnicodeChar
== '+') {
1371 // It is the top of the array already
1376 TempIndex
= Index
- 1;
1378 if ((Index
+ 1) == ValueCount
) {
1380 // It is the bottom of the array already
1385 TempIndex
= Index
+ 1;
1388 ValueBackup
= ValueArrayBackup
[TempIndex
];
1389 ValueArrayBackup
[TempIndex
] = ValueArrayBackup
[Index
];
1390 ValueArrayBackup
[Index
] = ValueBackup
;
1405 switch (Key
.ScanCode
) {
1408 if (Key
.ScanCode
== SCAN_UP
) {
1409 if ((TopOptionIndex
> 1) && (HighlightPosition
== (Top
+ 1))) {
1411 // Highlight reaches the top of the popup window, scroll one menu item.
1414 ShowDownArrow
= TRUE
;
1417 if (TopOptionIndex
== 1) {
1418 ShowUpArrow
= FALSE
;
1421 if (((TopOptionIndex
+ MenuLinesInView
) <= PopUpMenuLines
) && (HighlightPosition
== (Bottom
- 1))) {
1423 // Highlight reaches the bottom of the popup window, scroll one menu item.
1429 if ((TopOptionIndex
+ MenuLinesInView
) == (PopUpMenuLines
+ 1)) {
1430 ShowDownArrow
= FALSE
;
1434 for (Index
= MenuOption
->TagIndex
+ TopOptionIndex
;
1435 MenuOption
->Tags
[Index
].Operand
!= EFI_IFR_END_ONE_OF_OP
;
1438 if (MenuOption
->Tags
[Index
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
) {
1440 for (Index
= 0; (ValueArrayBackup
[Index
] != TempValue
) && (Index
< ValueCount
); Index
++)
1444 // Did we hit the end of the array? Either get the first TempValue or the next one
1446 if (Key
.ScanCode
== SCAN_UP
) {
1448 TempValue
= ValueArrayBackup
[0];
1450 TempValue
= ValueArrayBackup
[Index
- 1];
1453 if ((Index
+ 1) == ValueCount
) {
1454 TempValue
= ValueArrayBackup
[Index
];
1456 TempValue
= ValueArrayBackup
[Index
+ 1];
1461 if (Key
.ScanCode
== SCAN_UP
) {
1462 TempIndex
= Index
- 1;
1465 // Keep going until meets meaningful tag.
1467 while ((MenuOption
->Tags
[TempIndex
].Operand
!= EFI_IFR_ONE_OF_OPTION_OP
&&
1468 MenuOption
->Tags
[TempIndex
].Operand
!= EFI_IFR_ONE_OF_OP
&&
1469 MenuOption
->Tags
[TempIndex
].Operand
!= EFI_IFR_END_ONE_OF_OP
)
1471 (MenuOption
->Tags
[TempIndex
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
&&
1472 (MenuOption
->Tags
[TempIndex
].Suppress
|| MenuOption
->Tags
[TempIndex
].GrayOut
))) {
1476 TempIndex
= Index
+ 1;
1479 // Keep going until meets meaningful tag.
1481 while ((MenuOption
->Tags
[TempIndex
].Operand
!= EFI_IFR_ONE_OF_OPTION_OP
&&
1482 MenuOption
->Tags
[TempIndex
].Operand
!= EFI_IFR_ONE_OF_OP
&&
1483 MenuOption
->Tags
[TempIndex
].Operand
!= EFI_IFR_END_ONE_OF_OP
)
1485 (MenuOption
->Tags
[TempIndex
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
&&
1486 (MenuOption
->Tags
[TempIndex
].Suppress
|| MenuOption
->Tags
[TempIndex
].GrayOut
))) {
1491 // The option value is the same as what is stored in NV store. This is where we take action
1493 if (MenuOption
->Tags
[Index
].Value
== TempValue
) {
1495 // Only if the previous op-code is an option can we select it, otherwise we are at the left-most option
1497 if (MenuOption
->Tags
[TempIndex
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
) {
1498 TempValue
= MenuOption
->Tags
[TempIndex
].Value
;
1499 *KeyValue
= MenuOption
->Tags
[TempIndex
].Key
;
1501 TempValue
= MenuOption
->Tags
[Index
].Value
;
1502 *KeyValue
= MenuOption
->Tags
[Index
].Key
;
1512 gST
->ConOut
->SetAttribute (gST
->ConOut
, SavedAttribute
);
1513 if (ValueArrayBackup
!= NULL
) {
1514 FreePool (ValueArrayBackup
);
1517 return EFI_DEVICE_ERROR
;
1525 case CHAR_CARRIAGE_RETURN
:
1527 // return the current selection
1529 if (Tag
->Operand
== EFI_IFR_ORDERED_LIST_OP
) {
1530 CopyMem (ValueArray
, ValueArrayBackup
, ValueCount
);
1531 FreePool (ValueArrayBackup
);
1544 gST
->ConOut
->SetAttribute (gST
->ConOut
, SavedAttribute
);
1550 OUT EFI_INPUT_KEY
*Key
1556 UiWaitForSingleEvent (gST
->ConIn
->WaitForKey
, 0);
1557 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, Key
);
1558 } while (EFI_ERROR(Status
));