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
) {
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
);
304 Status
= WaitForKeyStroke (&Key
);
305 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
308 Status
= EFI_NOT_READY
;
315 // Display PopUp Screen
317 ScreenSize
= GetStringWidth (gPromptForNewPassword
) / 2;
318 if (GetStringWidth (gConfirmPassword
) / 2 > ScreenSize
) {
319 ScreenSize
= GetStringWidth (gConfirmPassword
) / 2;
322 Start
= (DimensionsWidth
- ScreenSize
- 4) / 2 + gScreenDimensions
.LeftColumn
+ 2;
323 Top
= ((DimensionsHeight
- 6) / 2) + gScreenDimensions
.TopRow
- 1;
326 if (PromptForPassword
) {
327 CreatePopUp (ScreenSize
, 4, &NullCharacter
, gPromptForPassword
, Space
, &NullCharacter
);
329 CreatePopUp (ScreenSize
, 4, &NullCharacter
, gPromptForNewPassword
, Space
, &NullCharacter
);
332 CreatePopUp (ScreenSize
, 4, &NullCharacter
, gConfirmPassword
, Space
, &NullCharacter
);
333 StringPtr
[0] = CHAR_NULL
;
337 Status
= WaitForKeyStroke (&Key
);
339 switch (Key
.UnicodeChar
) {
341 if (Key
.ScanCode
== SCAN_ESC
) {
342 return EFI_NOT_READY
;
345 ConfirmationComplete
= FALSE
;
348 case CHAR_CARRIAGE_RETURN
:
349 if (Tag
->Flags
& EFI_IFR_FLAG_INTERACTIVE
) {
351 // User just typed a string in
353 DataEntry
= (EFI_IFR_DATA_ENTRY
*) (PageData
+ 1);
354 DataEntry
->OpCode
= EFI_IFR_PASSWORD_OP
;
357 // If the user just typed in a password, Data = 1
358 // If the user just typed in a password to confirm the previous password, Data = 2
361 DataEntry
->Length
= 3;
362 DataEntry
->Data
= (VOID
*) (UINTN
) (UINT8
) (1 + SecondEntry
* 2);
364 if ((FormCallback
!= NULL
) && (FormCallback
->Callback
!= NULL
)) {
365 Status
= FormCallback
->Callback (
373 DataEntry
->Length
= sizeof (EFI_IFR_DATA_ENTRY
);
374 DataEntry
->Data
= (VOID
*) TempString
;
376 DataEntry
->Length
= 3;
377 DataEntry
->Data
= (VOID
*) (UINTN
) (UINT8
) (2 + SecondEntry
* 2);
379 if ((FormCallback
!= NULL
) && (FormCallback
->Callback
!= NULL
)) {
380 Status
= FormCallback
->Callback (
388 DataEntry
->Length
= sizeof (EFI_IFR_DATA_ENTRY
);
389 DataEntry
->Data
= (VOID
*) TempString2
;
392 if ((FormCallback
!= NULL
) && (FormCallback
->Callback
!= NULL
)) {
393 Status
= FormCallback
->Callback (
401 // If this was the confirmation round of callbacks
402 // and an error comes back, display an error
405 if (EFI_ERROR (Status
)) {
406 if (Packet
->String
== NULL
) {
407 WidthOfString
= GetStringWidth (gConfirmError
);
408 ScreenSize
= MAX (WidthOfString
, GetStringWidth (gPressEnter
)) / 2;
409 CreatePopUp (ScreenSize
, 4, &NullCharacter
, gConfirmError
, gPressEnter
, &NullCharacter
);
411 WidthOfString
= GetStringWidth (Packet
->String
);
412 ScreenSize
= MAX (WidthOfString
, GetStringWidth (gPressEnter
)) / 2;
413 CreatePopUp (ScreenSize
, 4, &NullCharacter
, Packet
->String
, gPressEnter
, &NullCharacter
);
417 StringPtr
[0] = CHAR_NULL
;
419 Status
= WaitForKeyStroke (&Key
);
421 if (Key
.UnicodeChar
== CHAR_CARRIAGE_RETURN
) {
422 Status
= EFI_NOT_READY
;
427 Status
= EFI_NOT_READY
;
432 // User typed a string in and it wasn't valid somehow from the callback
433 // For instance, callback may have said that some invalid characters were contained in the string
435 if (Status
== EFI_NOT_READY
) {
439 if (PromptForPassword
&& EFI_ERROR (Status
)) {
440 Status
= EFI_DEVICE_ERROR
;
448 // Compare tempstring and tempstring2, if the same, return with StringPtr success
449 // Otherwise, kick and error box, and return an error
451 if (StrCmp (TempString
, TempString2
) == 0) {
452 Status
= EFI_SUCCESS
;
455 WidthOfString
= GetStringWidth (gConfirmError
);
456 ScreenSize
= MAX (WidthOfString
, GetStringWidth (gPressEnter
)) / 2;
457 CreatePopUp (ScreenSize
, 4, &NullCharacter
, gConfirmError
, gPressEnter
, &NullCharacter
);
458 StringPtr
[0] = CHAR_NULL
;
460 Status
= WaitForKeyStroke (&Key
);
461 if (Key
.UnicodeChar
== CHAR_CARRIAGE_RETURN
) {
462 Status
= EFI_DEVICE_ERROR
;
469 if (PromptForPassword
) {
471 // I was asked for a password, return it back in StringPtr
473 Status
= EFI_SUCCESS
;
477 // If the two passwords were not the same kick an error popup
480 ConfirmationComplete
= TRUE
;
485 if (StringPtr
[0] != CHAR_NULL
) {
487 for (Index
= 0; StringPtr
[Index
] != CHAR_NULL
; Index
++) {
488 TempString
[Index
] = StringPtr
[Index
];
491 // Effectively truncate string by 1 character
493 TempString
[Index
- 1] = CHAR_NULL
;
494 StrCpy (StringPtr
, TempString
);
496 for (Index
= 0; StringPtr
[Index
] != CHAR_NULL
; Index
++) {
497 TempString2
[Index
] = StringPtr
[Index
];
500 // Effectively truncate string by 1 character
502 TempString2
[Index
- 1] = CHAR_NULL
;
503 StrCpy (StringPtr
, TempString2
);
506 ConfirmationComplete
= FALSE
;
508 ConfirmationComplete
= FALSE
;
512 // Must be a character we are interested in!
515 if ((StringPtr
[0] == CHAR_NULL
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
517 StrnCpy (StringPtr
, &Key
.UnicodeChar
, 1);
518 StrnCpy (TempString
, &Key
.UnicodeChar
, 1);
520 StrnCpy (StringPtr
, &Key
.UnicodeChar
, 1);
521 StrnCpy (TempString2
, &Key
.UnicodeChar
, 1);
522 ConfirmationComplete
= FALSE
;
524 } else if ((GetStringWidth (StringPtr
) / 2 <= (UINTN
) (MenuOption
->ThisTag
->Maximum
- 1) / 2) &&
525 (Key
.UnicodeChar
!= CHAR_BACKSPACE
)
527 KeyPad
[0] = Key
.UnicodeChar
;
528 KeyPad
[1] = CHAR_NULL
;
530 StrCat (StringPtr
, KeyPad
);
531 StrCat (TempString
, KeyPad
);
533 StrCat (StringPtr
, KeyPad
);
534 StrCat (TempString2
, KeyPad
);
538 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_BLACK
, EFI_LIGHTGRAY
));
539 for (Index
= 1; Index
< ScreenSize
; Index
++) {
540 PrintCharAt (Start
+ Index
, Top
+ 3, L
' ');
543 gST
->ConOut
->SetCursorPosition (
545 (DimensionsWidth
- GetStringWidth (StringPtr
) / 2) / 2 + gScreenDimensions
.LeftColumn
,
548 for (Index
= 0; Index
+ 1 < GetStringWidth (StringPtr
) / 2; Index
++) {
552 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
558 } while (!ConfirmationComplete
);
563 FreePool (TempString
);
564 FreePool (TempString2
);
579 Key
= (CHAR16
*) L
"MAR10648567";
580 Buffer
= AllocateZeroPool (MaxSize
);
584 for (Index
= 0; Key
[Index
] != 0; Index
++) {
585 for (Loop
= 0; Loop
< (UINT8
) (MaxSize
/ 2); Loop
++) {
586 Buffer
[Loop
] = (CHAR16
) (Password
[Loop
] ^ Key
[Index
]);
590 CopyMem (Password
, Buffer
, MaxSize
);
598 IN UI_MENU_OPTION
*MenuOption
,
599 IN EFI_FILE_FORM_TAGS
*FileFormTagsHead
,
600 IN BOOLEAN ManualInput
,
602 IN UINTN NumericType
,
609 This routine reads a numeric value from the user input.
613 MenuOption - Pointer to the current input menu.
615 FileFormTagsHead - Pointer to the root of formset.
617 ManualInput - If the input is manual or not.
619 Tag - Pointer to all the attributes and values associated with a tag.
621 Value - Pointer to the numeric value that is going to be read.
625 EFI_SUCCESS - If numerical input is read successfully
626 EFI_DEVICE_ERROR - If operation fails
631 BOOLEAN SelectionComplete
;
634 CHAR16 FormattedNumber
[6];
635 UINTN PreviousNumber
[6];
640 CHAR16 NullCharacter
;
642 EFI_FILE_FORM_TAGS
*FileFormTags
;
643 EFI_VARIABLE_DEFINITION
*VariableDefinition
;
646 NullCharacter
= CHAR_NULL
;
648 Column
= MenuOption
->OptCol
;
649 Row
= MenuOption
->Row
;
651 PreviousNumber
[0] = 0;
653 SelectionComplete
= FALSE
;
654 BackupValue
= Tag
->Value
;
655 FileFormTags
= FileFormTagsHead
;
658 PrintAt (Column
, Row
, (CHAR16
*) L
"[ ]");
660 if (Tag
->Operand
!= EFI_IFR_TIME_OP
) {
661 *Value
= BackupValue
;
665 // First time we enter this handler, we need to check to see if
666 // we were passed an increment or decrement directive
669 Key
.UnicodeChar
= CHAR_NULL
;
670 if (gDirection
!= 0) {
671 Key
.ScanCode
= gDirection
;
676 WaitForKeyStroke (&Key
);
679 switch (Key
.UnicodeChar
) {
682 if ((Tag
->Operand
== EFI_IFR_DATE_OP
) || (Tag
->Operand
== EFI_IFR_TIME_OP
)) {
683 Key
.UnicodeChar
= CHAR_NULL
;
684 if (Key
.UnicodeChar
== '+') {
685 Key
.ScanCode
= SCAN_RIGHT
;
687 Key
.ScanCode
= SCAN_LEFT
;
695 switch (Key
.ScanCode
) {
698 if ((Tag
->Operand
== EFI_IFR_DATE_OP
) || (Tag
->Operand
== EFI_IFR_TIME_OP
)) {
700 // By setting this value, we will return back to the caller.
701 // We need to do this since an auto-refresh will destroy the adjustment
702 // based on what the real-time-clock is showing. So we always commit
703 // upon changing the value.
705 gDirection
= SCAN_DOWN
;
710 if (Key
.ScanCode
== SCAN_LEFT
) {
711 Number
= *Value
- Tag
->Step
;
712 if (Number
< Tag
->Minimum
) {
713 Number
= Tag
->Minimum
;
715 } else if (Key
.ScanCode
== SCAN_RIGHT
) {
716 Number
= *Value
+ Tag
->Step
;
717 if (Number
> Tag
->Maximum
) {
718 Number
= Tag
->Maximum
;
722 Tag
->Value
= (UINT16
) Number
;
723 *Value
= (UINT16
) Number
;
724 UnicodeValueToString (
728 (sizeof (FormattedNumber
) / sizeof (FormattedNumber
[0]))
730 Number
= (UINT16
) GetStringWidth (FormattedNumber
);
732 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT
| FIELD_BACKGROUND
);
733 if ((Tag
->Operand
== EFI_IFR_DATE_OP
) || (Tag
->Operand
== EFI_IFR_TIME_OP
)) {
734 for (Loop
= 0; Loop
< (UINTN
) ((Number
>= 8) ? 4 : 2); Loop
++) {
735 PrintAt (MenuOption
->OptCol
+ Loop
, MenuOption
->Row
, (CHAR16
*) L
" ");
738 for (Loop
= 0; Loop
< gOptionBlockWidth
; Loop
++) {
739 PrintAt (MenuOption
->OptCol
+ Loop
, MenuOption
->Row
, (CHAR16
*) L
" ");
743 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_HIGHLIGHT
| FIELD_BACKGROUND_HIGHLIGHT
);
745 if ((MenuOption
->Col
+ gPromptBlockWidth
+ 1) == MenuOption
->OptCol
) {
746 PrintCharAt (MenuOption
->OptCol
, Row
, LEFT_NUMERIC_DELIMITER
);
747 Column
= MenuOption
->OptCol
+ 1;
750 // If Number looks like "3", convert it to "03/"
752 if (Number
== 4 && (NumericType
== DATE_NUMERIC
)) {
753 FormattedNumber
[3] = FormattedNumber
[1];
754 FormattedNumber
[2] = DATE_SEPARATOR
;
755 FormattedNumber
[1] = FormattedNumber
[0];
756 FormattedNumber
[0] = L
'0';
760 // If Number looks like "13", convert it to "13/"
762 if (Number
== 6 && (NumericType
== DATE_NUMERIC
)) {
763 FormattedNumber
[3] = FormattedNumber
[2];
764 FormattedNumber
[2] = DATE_SEPARATOR
;
769 (NumericType
== TIME_NUMERIC
) &&
770 (MenuOption
->Col
+ gPromptBlockWidth
+ 8) != MenuOption
->OptCol
772 FormattedNumber
[3] = FormattedNumber
[1];
773 FormattedNumber
[2] = TIME_SEPARATOR
;
774 FormattedNumber
[1] = FormattedNumber
[0];
775 FormattedNumber
[0] = L
'0';
780 (NumericType
== TIME_NUMERIC
) &&
781 (MenuOption
->Col
+ gPromptBlockWidth
+ 8) == MenuOption
->OptCol
783 FormattedNumber
[3] = FormattedNumber
[1];
784 FormattedNumber
[2] = RIGHT_NUMERIC_DELIMITER
;
785 FormattedNumber
[1] = FormattedNumber
[0];
786 FormattedNumber
[0] = L
'0';
790 PrintStringAt (Column
, Row
, FormattedNumber
);
791 if (Number
== 10 && (NumericType
== DATE_NUMERIC
)) {
792 PrintChar (RIGHT_NUMERIC_DELIMITER
);
795 if (NumericType
== REGULAR_NUMERIC
) {
796 PrintChar (RIGHT_NUMERIC_DELIMITER
);
803 goto EnterCarriageReturn
;
806 return EFI_DEVICE_ERROR
;
816 case CHAR_CARRIAGE_RETURN
:
818 // Check to see if the Value is something reasonable against consistency limitations.
819 // If not, let's kick the error specified.
822 // This gives us visibility to the FileFormTags->NvRamMap to check things
823 // ActiveIfr is a global maintained by the menuing code to ensure that we
824 // are pointing to the correct formset's file data.
826 for (Count
= 0; Count
< gActiveIfr
; Count
++) {
827 FileFormTags
= FileFormTags
->NextFile
;
830 ExtractRequestedNvMap (FileFormTags
, Tag
->VariableNumber
, &VariableDefinition
);
832 CopyMem (&VariableDefinition
->NvRamMap
[Tag
->StorageStart
], &Tag
->Value
, Tag
->StorageWidth
);
835 // Data associated with a NULL device (in the fake NV storage)
837 if (Tag
->StorageWidth
== (UINT16
) 0) {
838 CopyMem (&VariableDefinition
->FakeNvRamMap
[Tag
->StorageStart
], &Tag
->Value
, 2);
841 // If a late check is required save off the information. This is used when consistency checks
842 // are required, but certain values might be bound by an impossible consistency check such as
843 // if two questions are bound by consistency checks and each only has two possible choices, there
844 // would be no way for a user to switch the values. Thus we require late checking.
846 if (Tag
->Flags
& EFI_IFR_FLAG_LATE_CHECK
) {
847 CopyMem (&Tag
->OldValue
, &BackupValue
, Tag
->StorageWidth
);
850 // In theory, passing the value and the Id are sufficient to determine what needs
851 // to be done. The Id is the key to look for the entry needed in the Inconsistency
852 // database. That will yields operand and ID data - and since the ID's correspond
853 // to the NV storage, we can determine the values for other IDs there.
855 if (ValueIsNotValid (TRUE
, 0, Tag
, FileFormTags
, &PopUp
)) {
856 if (PopUp
== 0x0000) {
857 SelectionComplete
= TRUE
;
861 StringPtr
= GetToken (PopUp
, MenuOption
->Handle
);
863 CreatePopUp (GetStringWidth (StringPtr
) / 2, 3, &NullCharacter
, StringPtr
, &NullCharacter
);
866 WaitForKeyStroke (&Key
);
868 switch (Key
.UnicodeChar
) {
870 case CHAR_CARRIAGE_RETURN
:
871 SelectionComplete
= TRUE
;
872 FreePool (StringPtr
);
878 } while (!SelectionComplete
);
880 Tag
->Value
= BackupValue
;
881 *Value
= BackupValue
;
883 CopyMem (&VariableDefinition
->NvRamMap
[Tag
->StorageStart
], &Tag
->Value
, Tag
->StorageWidth
);
886 // Data associated with a NULL device (in the fake NV storage)
888 if (Tag
->StorageWidth
== (UINT16
) 0) {
889 CopyMem (&VariableDefinition
->FakeNvRamMap
[Tag
->StorageStart
], &Tag
->Value
, 2);
892 return EFI_DEVICE_ERROR
;
905 // Remove a character
907 Number
= PreviousNumber
[Count
- 1];
908 *Value
= (UINT16
) Number
;
909 UpdateStatusBar (INPUT_ERROR
, Tag
->Flags
, FALSE
);
912 PrintAt (Column
, Row
, (CHAR16
*) L
" ");
918 if (Key
.UnicodeChar
> L
'9' || Key
.UnicodeChar
< L
'0') {
919 UpdateStatusBar (INPUT_ERROR
, Tag
->Flags
, TRUE
);
923 // If Count 0-4 is complete, there is no way more is valid
929 // Someone typed something valid!
932 Number
= Number
* 10 + (Key
.UnicodeChar
- L
'0');
934 Number
= Key
.UnicodeChar
- L
'0';
937 if (Number
> Tag
->Maximum
) {
938 UpdateStatusBar (INPUT_ERROR
, Tag
->Flags
, TRUE
);
939 Number
= PreviousNumber
[Count
];
942 UpdateStatusBar (INPUT_ERROR
, Tag
->Flags
, FALSE
);
947 PreviousNumber
[Count
] = Number
;
948 *Value
= (UINT16
) Number
;
949 Tag
->Value
= (UINT16
) Number
;
951 PrintCharAt (Column
, Row
, Key
.UnicodeChar
);
956 } while (!SelectionComplete
);
960 // Notice that this is at least needed for the ordered list manipulation.
961 // Left/Right doesn't make sense for this op-code
964 GetSelectionInputPopUp (
965 IN UI_MENU_OPTION
*MenuOption
,
976 CHAR16
*TempStringPtr
;
979 UINTN TopOptionIndex
;
980 UINTN HighlightPosition
;
987 UINTN PopUpMenuLines
;
988 UINTN MenuLinesInView
;
991 BOOLEAN FirstOptionFoundFlag
;
992 INT32 SavedAttribute
;
995 UINT8
*ValueArrayBackup
;
998 BOOLEAN KeyInitialized
;
999 BOOLEAN ShowDownArrow
;
1000 BOOLEAN ShowUpArrow
;
1001 UINTN DimensionsWidth
;
1003 DimensionsWidth
= gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
;
1007 ValueArray
= (UINT8
*) Value
;
1008 ValueArrayBackup
= NULL
;
1009 Initialized
= FALSE
;
1010 KeyInitialized
= FALSE
;
1011 ShowDownArrow
= FALSE
;
1012 ShowUpArrow
= FALSE
;
1014 if (Tag
->Operand
== EFI_IFR_ORDERED_LIST_OP
) {
1015 ValueArrayBackup
= AllocateZeroPool (Tag
->StorageWidth
);
1016 ASSERT (ValueArrayBackup
!= NULL
);
1017 CopyMem (ValueArrayBackup
, ValueArray
, ValueCount
);
1018 TempValue
= *(UINT8
*) (ValueArray
);
1019 if (ValueArray
[0] != 0x00) {
1023 for (Index
= 0; ValueArray
[Index
] != 0x00; Index
++)
1033 FirstOptionFoundFlag
= FALSE
;
1035 StringPtr
= AllocateZeroPool ((gOptionBlockWidth
+ 1) * 2);
1039 // Initialization for "One of" pop-up menu
1042 // Get the number of one of options present and its size
1044 for (Index
= MenuOption
->TagIndex
; MenuOption
->Tags
[Index
].Operand
!= EFI_IFR_END_ONE_OF_OP
; Index
++) {
1045 if (MenuOption
->Tags
[Index
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
&&
1046 !MenuOption
->Tags
[Index
].Suppress
) {
1047 if (!FirstOptionFoundFlag
) {
1048 FirstOptionFoundFlag
= TRUE
;
1052 Token
= MenuOption
->Tags
[Index
].Text
;
1055 // If this is an ordered list that is initialized
1058 for (ValueBackup
= (UINT8
) MenuOption
->TagIndex
;
1059 MenuOption
->Tags
[ValueBackup
].Operand
!= EFI_IFR_END_OP
;
1062 if (MenuOption
->Tags
[ValueBackup
].Value
== ((UINT8
*) ValueArrayBackup
)[Index
- MenuOption
->TagIndex
- 1]) {
1063 StringPtr
= GetToken (MenuOption
->Tags
[ValueBackup
].Text
, MenuOption
->Handle
);
1068 StringPtr
= GetToken (Token
, MenuOption
->Handle
);
1071 if (StrLen (StringPtr
) > PopUpWidth
) {
1072 PopUpWidth
= StrLen (StringPtr
);
1075 FreePool (StringPtr
);
1079 // Perform popup menu initialization.
1081 PopUpMenuLines
= Count
;
1082 PopUpWidth
= PopUpWidth
+ POPUP_PAD_SPACE_COUNT
;
1084 SavedAttribute
= gST
->ConOut
->Mode
->Attribute
;
1085 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
1087 if ((PopUpWidth
+ POPUP_FRAME_WIDTH
) > DimensionsWidth
) {
1088 PopUpWidth
= DimensionsWidth
- POPUP_FRAME_WIDTH
;
1091 Start
= (DimensionsWidth
- PopUpWidth
- POPUP_FRAME_WIDTH
) / 2 + gScreenDimensions
.LeftColumn
;
1092 End
= Start
+ PopUpWidth
+ POPUP_FRAME_WIDTH
;
1093 Top
= gScreenDimensions
.TopRow
+ NONE_FRONT_PAGE_HEADER_HEIGHT
;
1094 Bottom
= gScreenDimensions
.BottomRow
- STATUS_BAR_HEIGHT
- FOOTER_HEIGHT
;
1096 MenuLinesInView
= Bottom
- Top
- 1;
1097 if (MenuLinesInView
>= PopUpMenuLines
) {
1098 Top
= Top
+ (MenuLinesInView
- PopUpMenuLines
) / 2;
1099 Bottom
= Top
+ PopUpMenuLines
+ 1;
1101 TempValue
= MenuOption
->Tags
[MenuOption
->TagIndex
+ 1].Value
;
1102 ShowDownArrow
= TRUE
;
1106 HighlightPosition
= 0;
1109 for (Index
= MenuOption
->TagIndex
, Index2
= 0; Index2
< ValueCount
; Index
++, Index2
++) {
1111 // Set the value for the item we are looking for
1113 Count
= ValueArrayBackup
[Index2
];
1116 // If we hit the end of the Array, we are complete
1122 if (MenuOption
->Tags
[Index
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
) {
1123 for (ValueBackup
= (UINT8
) MenuOption
->TagIndex
;
1124 MenuOption
->Tags
[ValueBackup
].Operand
!= EFI_IFR_END_ONE_OF_OP
;
1128 // We just found what we are looking for
1130 if (MenuOption
->Tags
[ValueBackup
].Value
== Count
) {
1132 // As long as the two indexes aren't the same, we have
1133 // two different op-codes we need to swap internally
1135 if (Index
!= ValueBackup
) {
1137 // Backup destination tag, then copy source to destination, then copy backup to source location
1139 CopyMem (&TagBackup
, &MenuOption
->Tags
[Index
], sizeof (EFI_TAG
));
1140 CopyMem (&MenuOption
->Tags
[Index
], &MenuOption
->Tags
[ValueBackup
], sizeof (EFI_TAG
));
1141 CopyMem (&MenuOption
->Tags
[ValueBackup
], &TagBackup
, sizeof (EFI_TAG
));
1144 // If the indexes are the same, then the op-code is where he belongs
1151 // Since this wasn't an option op-code (likely the ordered list op-code) decerement Index2
1158 // Clear that portion of the screen
1160 ClearLines (Start
, End
, Top
, Bottom
, POPUP_TEXT
| POPUP_BACKGROUND
);
1163 // Draw "One of" pop-up menu
1165 Character
= (CHAR16
) BOXDRAW_DOWN_RIGHT
;
1166 PrintCharAt (Start
, Top
, Character
);
1167 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
1168 if ((ShowUpArrow
) && ((Index
+ 1) == (Start
+ End
) / 2)) {
1169 Character
= (CHAR16
) GEOMETRICSHAPE_UP_TRIANGLE
;
1171 Character
= (CHAR16
) BOXDRAW_HORIZONTAL
;
1174 PrintChar (Character
);
1177 Character
= (CHAR16
) BOXDRAW_DOWN_LEFT
;
1178 PrintChar (Character
);
1179 Character
= (CHAR16
) BOXDRAW_VERTICAL
;
1180 for (Index
= Top
+ 1; Index
< Bottom
; Index
++) {
1181 PrintCharAt (Start
, Index
, Character
);
1182 PrintCharAt (End
- 1, Index
, Character
);
1185 // Display the One of options
1188 for (Index
= MenuOption
->TagIndex
+ TopOptionIndex
;
1189 (MenuOption
->Tags
[Index
].Operand
!= EFI_IFR_END_ONE_OF_OP
) && (Index2
< Bottom
);
1192 if (MenuOption
->Tags
[Index
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
) {
1193 Token
= MenuOption
->Tags
[Index
].Text
;
1195 for (ValueBackup
= (UINT8
) MenuOption
->TagIndex
;
1196 MenuOption
->Tags
[ValueBackup
].Operand
!= EFI_IFR_END_ONE_OF_OP
;
1199 if (MenuOption
->Tags
[ValueBackup
].Value
== ((UINT8
*) ValueArrayBackup
)[Index
- MenuOption
->TagIndex
- 1]) {
1200 StringPtr
= GetToken (MenuOption
->Tags
[ValueBackup
].Text
, MenuOption
->Handle
);
1205 ValueBackup
= (UINT8
) Index
;
1206 StringPtr
= GetToken (Token
, MenuOption
->Handle
);
1209 // If the string occupies multiple lines, truncate it to fit in one line,
1210 // and append a "..." for indication.
1212 if (StrLen (StringPtr
) > (PopUpWidth
- 1)) {
1213 TempStringPtr
= AllocateZeroPool (sizeof (CHAR16
) * (PopUpWidth
- 1));
1214 ASSERT (TempStringPtr
!= NULL
);
1215 CopyMem (TempStringPtr
, StringPtr
, (sizeof (CHAR16
) * (PopUpWidth
- 5)));
1216 FreePool (StringPtr
);
1217 StringPtr
= TempStringPtr
;
1218 StrCat (StringPtr
, (CHAR16
*) L
"...");
1221 // Code to display the text should go here. Follwed by the [*]
1223 if (MenuOption
->Tags
[ValueBackup
].Suppress
== TRUE
) {
1225 // Don't show the one, so decrease the Index2 for balance
1228 } else if (MenuOption
->Tags
[ValueBackup
].GrayOut
== TRUE
) {
1232 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_GRAYED
| POPUP_BACKGROUND
);
1233 PrintStringAt (Start
+ 2, Index2
, StringPtr
);
1234 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
1235 } else if (MenuOption
->Tags
[ValueBackup
].Value
== TempValue
) {
1237 // Highlight the selected one
1239 gST
->ConOut
->SetAttribute (gST
->ConOut
, PICKLIST_HIGHLIGHT_TEXT
| PICKLIST_HIGHLIGHT_BACKGROUND
);
1240 PrintStringAt (Start
+ 2, Index2
, StringPtr
);
1241 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
1242 HighlightPosition
= Index2
;
1244 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
1245 PrintStringAt (Start
+ 2, Index2
, StringPtr
);
1248 FreePool (StringPtr
);
1249 Index2
= Index2
+ 1;
1253 Character
= (CHAR16
) BOXDRAW_UP_RIGHT
;
1254 PrintCharAt (Start
, Bottom
, Character
);
1255 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
1256 if ((ShowDownArrow
) && ((Index
+ 1) == (Start
+ End
) / 2)) {
1257 Character
= (CHAR16
) GEOMETRICSHAPE_DOWN_TRIANGLE
;
1259 Character
= (CHAR16
) BOXDRAW_HORIZONTAL
;
1262 PrintChar (Character
);
1265 Character
= (CHAR16
) BOXDRAW_UP_LEFT
;
1266 PrintChar (Character
);
1268 // Get User selection and change TempValue if necessary
1271 // Stop: One of pop-up menu
1273 Key
.UnicodeChar
= CHAR_NULL
;
1274 if ((gDirection
== SCAN_UP
) || (gDirection
== SCAN_DOWN
)) {
1275 Key
.ScanCode
= gDirection
;
1280 if (!KeyInitialized
) {
1281 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_ONE_OF_OP
) {
1282 *KeyValue
= MenuOption
->Tags
[MenuOption
->TagIndex
+ 1].Key
;
1284 *KeyValue
= MenuOption
->ThisTag
->Key
;
1287 KeyInitialized
= TRUE
;
1290 WaitForKeyStroke (&Key
);
1293 switch (Key
.UnicodeChar
) {
1297 // If an ordered list op-code, we will allow for a popup of +/- keys
1298 // to create an ordered list of items
1300 if (Tag
->Operand
== EFI_IFR_ORDERED_LIST_OP
) {
1301 if (Key
.UnicodeChar
== '+') {
1302 if ((TopOptionIndex
> 1) && (HighlightPosition
== (Top
+ 1))) {
1304 // Highlight reaches the top of the popup window, scroll one menu item.
1307 ShowDownArrow
= TRUE
;
1310 if (TopOptionIndex
== 1) {
1311 ShowUpArrow
= FALSE
;
1314 if (((TopOptionIndex
+ MenuLinesInView
) <= PopUpMenuLines
) && (HighlightPosition
== (Bottom
- 1))) {
1316 // Highlight reaches the bottom of the popup window, scroll one menu item.
1322 if ((TopOptionIndex
+ MenuLinesInView
) == (PopUpMenuLines
+ 1)) {
1323 ShowDownArrow
= FALSE
;
1327 for (Index
= MenuOption
->TagIndex
+ TopOptionIndex
;
1328 MenuOption
->Tags
[Index
].Operand
!= EFI_IFR_END_ONE_OF_OP
;
1331 if (MenuOption
->Tags
[Index
].Operand
== EFI_IFR_ORDERED_LIST_OP
) {
1335 if (Key
.UnicodeChar
== '+') {
1336 TempIndex
= Index
- 1;
1338 TempIndex
= Index
+ 1;
1341 // Is this the current tag we are on?
1343 if (MenuOption
->Tags
[Index
].Value
== TempValue
) {
1345 // Is this prior tag a valid choice? If not, bail out
1347 if (MenuOption
->Tags
[TempIndex
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
) {
1349 // Copy the destination tag to the local variable
1351 CopyMem (&TagBackup
, &MenuOption
->Tags
[TempIndex
], sizeof (EFI_TAG
));
1353 // Copy the current tag to the tag location before us
1355 CopyMem (&MenuOption
->Tags
[TempIndex
], &MenuOption
->Tags
[Index
], sizeof (EFI_TAG
));
1357 // Copy the backed up tag to the current location
1359 CopyMem (&MenuOption
->Tags
[Index
], &TagBackup
, sizeof (EFI_TAG
));
1362 // Adjust the array of values
1364 for (Index
= 0; Index
< ValueCount
; Index
++) {
1365 if (ValueArrayBackup
[Index
] == (UINT8
) TempValue
) {
1366 if (Key
.UnicodeChar
== '+') {
1369 // It is the top of the array already
1374 TempIndex
= Index
- 1;
1376 if ((Index
+ 1) == ValueCount
) {
1378 // It is the bottom of the array already
1383 TempIndex
= Index
+ 1;
1386 ValueBackup
= ValueArrayBackup
[TempIndex
];
1387 ValueArrayBackup
[TempIndex
] = ValueArrayBackup
[Index
];
1388 ValueArrayBackup
[Index
] = ValueBackup
;
1403 switch (Key
.ScanCode
) {
1406 if (Key
.ScanCode
== SCAN_UP
) {
1407 if ((TopOptionIndex
> 1) && (HighlightPosition
== (Top
+ 1))) {
1409 // Highlight reaches the top of the popup window, scroll one menu item.
1412 ShowDownArrow
= TRUE
;
1415 if (TopOptionIndex
== 1) {
1416 ShowUpArrow
= FALSE
;
1419 if (((TopOptionIndex
+ MenuLinesInView
) <= PopUpMenuLines
) && (HighlightPosition
== (Bottom
- 1))) {
1421 // Highlight reaches the bottom of the popup window, scroll one menu item.
1427 if ((TopOptionIndex
+ MenuLinesInView
) == (PopUpMenuLines
+ 1)) {
1428 ShowDownArrow
= FALSE
;
1432 for (Index
= MenuOption
->TagIndex
+ TopOptionIndex
;
1433 MenuOption
->Tags
[Index
].Operand
!= EFI_IFR_END_ONE_OF_OP
;
1436 if (MenuOption
->Tags
[Index
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
) {
1438 for (Index
= 0; (ValueArrayBackup
[Index
] != TempValue
) && (Index
< ValueCount
); Index
++)
1442 // Did we hit the end of the array? Either get the first TempValue or the next one
1444 if (Key
.ScanCode
== SCAN_UP
) {
1446 TempValue
= ValueArrayBackup
[0];
1448 TempValue
= ValueArrayBackup
[Index
- 1];
1451 if ((Index
+ 1) == ValueCount
) {
1452 TempValue
= ValueArrayBackup
[Index
];
1454 TempValue
= ValueArrayBackup
[Index
+ 1];
1459 if (Key
.ScanCode
== SCAN_UP
) {
1460 TempIndex
= Index
- 1;
1463 // Keep going until meets meaningful tag.
1465 while ((MenuOption
->Tags
[TempIndex
].Operand
!= EFI_IFR_ONE_OF_OPTION_OP
&&
1466 MenuOption
->Tags
[TempIndex
].Operand
!= EFI_IFR_ONE_OF_OP
&&
1467 MenuOption
->Tags
[TempIndex
].Operand
!= EFI_IFR_END_ONE_OF_OP
)
1469 (MenuOption
->Tags
[TempIndex
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
&&
1470 (MenuOption
->Tags
[TempIndex
].Suppress
|| MenuOption
->Tags
[TempIndex
].GrayOut
))) {
1474 TempIndex
= Index
+ 1;
1477 // Keep going until meets meaningful tag.
1479 while ((MenuOption
->Tags
[TempIndex
].Operand
!= EFI_IFR_ONE_OF_OPTION_OP
&&
1480 MenuOption
->Tags
[TempIndex
].Operand
!= EFI_IFR_ONE_OF_OP
&&
1481 MenuOption
->Tags
[TempIndex
].Operand
!= EFI_IFR_END_ONE_OF_OP
)
1483 (MenuOption
->Tags
[TempIndex
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
&&
1484 (MenuOption
->Tags
[TempIndex
].Suppress
|| MenuOption
->Tags
[TempIndex
].GrayOut
))) {
1489 // The option value is the same as what is stored in NV store. This is where we take action
1491 if (MenuOption
->Tags
[Index
].Value
== TempValue
) {
1493 // Only if the previous op-code is an option can we select it, otherwise we are at the left-most option
1495 if (MenuOption
->Tags
[TempIndex
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
) {
1496 TempValue
= MenuOption
->Tags
[TempIndex
].Value
;
1497 *KeyValue
= MenuOption
->Tags
[TempIndex
].Key
;
1499 TempValue
= MenuOption
->Tags
[Index
].Value
;
1500 *KeyValue
= MenuOption
->Tags
[Index
].Key
;
1510 gST
->ConOut
->SetAttribute (gST
->ConOut
, SavedAttribute
);
1511 if (ValueArrayBackup
!= NULL
) {
1512 FreePool (ValueArrayBackup
);
1515 return EFI_DEVICE_ERROR
;
1523 case CHAR_CARRIAGE_RETURN
:
1525 // return the current selection
1527 if (Tag
->Operand
== EFI_IFR_ORDERED_LIST_OP
) {
1528 CopyMem (ValueArray
, ValueArrayBackup
, ValueCount
);
1529 FreePool (ValueArrayBackup
);
1542 gST
->ConOut
->SetAttribute (gST
->ConOut
, SavedAttribute
);
1548 OUT EFI_INPUT_KEY
*Key
1554 UiWaitForSingleEvent (gST
->ConIn
->WaitForKey
, 0);
1555 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, Key
);
1556 } while (EFI_ERROR(Status
));