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
);
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
== NULL
|| 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
)) {
516 StringPtr
[0] = Key
.UnicodeChar
;
517 StringPtr
[1] = CHAR_NULL
;
519 TempString
[0] = Key
.UnicodeChar
;
520 TempString
[1] = CHAR_NULL
;
522 TempString2
[0] = Key
.UnicodeChar
;
523 TempString2
[1] = CHAR_NULL
;
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
));