2 Utility functions for User Interface functions.
4 Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>
5 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.
17 LIST_ENTRY gMenuOption
;
18 LIST_ENTRY gMenuList
= INITIALIZE_LIST_HEAD_VARIABLE (gMenuList
);
19 MENU_REFRESH_ENTRY
*gMenuRefreshHead
; // Menu list used for refresh timer opcode.
20 MENU_REFRESH_ENTRY
*gMenuEventGuidRefreshHead
; // Menu list used for refresh event guid opcode.
23 // Search table for UiDisplayMenu()
25 SCAN_CODE_TO_SCREEN_OPERATION gScanCodeToOperation
[] = {
64 SCREEN_OPERATION_T0_CONTROL_FLAG gScreenOperationToControlFlag
[] = {
112 BOOLEAN GetLineByWidthFinished
= FALSE
;
116 Set Buffer to Value for Size bytes.
118 @param Buffer Memory to set.
119 @param Size Number of bytes to set
120 @param Value Value of the set operation.
133 while ((Size
--) != 0) {
140 Initialize Menu option list.
148 InitializeListHead (&gMenuOption
);
153 Free Menu option linked list.
161 UI_MENU_OPTION
*MenuOption
;
163 while (!IsListEmpty (&gMenuOption
)) {
164 MenuOption
= MENU_OPTION_FROM_LINK (gMenuOption
.ForwardLink
);
165 RemoveEntryList (&MenuOption
->Link
);
168 // We allocated space for this description when we did a GetToken, free it here
170 if (MenuOption
->Skip
!= 0) {
172 // For date/time, MenuOption->Description is shared by three Menu Options
173 // Data format : [01/02/2004] [11:22:33]
174 // Line number : 0 0 1 0 0 1
176 FreePool (MenuOption
->Description
);
178 FreePool (MenuOption
);
184 Create a menu with specified formset GUID and form ID, and add it as a child
185 of the given parent menu.
187 @param Parent The parent of menu to be added.
188 @param FormSetGuid The Formset Guid of menu to be added.
189 @param FormId The Form ID of menu to be added.
191 @return A pointer to the newly added menu or NULL if memory is insufficient.
196 IN OUT UI_MENU_LIST
*Parent
,
197 IN EFI_GUID
*FormSetGuid
,
201 UI_MENU_LIST
*MenuList
;
203 MenuList
= AllocateZeroPool (sizeof (UI_MENU_LIST
));
204 if (MenuList
== NULL
) {
208 MenuList
->Signature
= UI_MENU_LIST_SIGNATURE
;
209 InitializeListHead (&MenuList
->ChildListHead
);
211 CopyMem (&MenuList
->FormSetGuid
, FormSetGuid
, sizeof (EFI_GUID
));
212 MenuList
->FormId
= FormId
;
213 MenuList
->Parent
= Parent
;
215 if (Parent
== NULL
) {
217 // If parent is not specified, it is the root Form of a Formset
219 InsertTailList (&gMenuList
, &MenuList
->Link
);
221 InsertTailList (&Parent
->ChildListHead
, &MenuList
->Link
);
229 Search Menu with given FormId in the parent menu and all its child menus.
231 @param Parent The parent of menu to search.
232 @param FormId The Form ID of menu to search.
234 @return A pointer to menu found or NULL if not found.
238 UiFindChildMenuList (
239 IN UI_MENU_LIST
*Parent
,
245 UI_MENU_LIST
*MenuList
;
247 if (Parent
->FormId
== FormId
) {
251 Link
= GetFirstNode (&Parent
->ChildListHead
);
252 while (!IsNull (&Parent
->ChildListHead
, Link
)) {
253 Child
= UI_MENU_LIST_FROM_LINK (Link
);
255 MenuList
= UiFindChildMenuList (Child
, FormId
);
256 if (MenuList
!= NULL
) {
260 Link
= GetNextNode (&Parent
->ChildListHead
, Link
);
268 Search Menu with given FormSetGuid and FormId in all cached menu list.
270 @param FormSetGuid The Formset GUID of the menu to search.
271 @param FormId The Form ID of menu to search.
273 @return A pointer to menu found or NULL if not found.
278 IN EFI_GUID
*FormSetGuid
,
283 UI_MENU_LIST
*MenuList
;
286 Link
= GetFirstNode (&gMenuList
);
287 while (!IsNull (&gMenuList
, Link
)) {
288 MenuList
= UI_MENU_LIST_FROM_LINK (Link
);
290 if (CompareGuid (FormSetGuid
, &MenuList
->FormSetGuid
)) {
292 // This is the formset we are looking for, find the form in this formset
294 Child
= UiFindChildMenuList (MenuList
, FormId
);
300 Link
= GetNextNode (&gMenuList
, Link
);
308 Free Menu option linked list.
316 MENU_REFRESH_ENTRY
*OldMenuRefreshEntry
;
318 while (gMenuRefreshHead
!= NULL
) {
319 OldMenuRefreshEntry
= gMenuRefreshHead
->Next
;
320 FreePool (gMenuRefreshHead
);
321 gMenuRefreshHead
= OldMenuRefreshEntry
;
324 while (gMenuEventGuidRefreshHead
!= NULL
) {
325 OldMenuRefreshEntry
= gMenuEventGuidRefreshHead
->Next
;
326 if (gMenuEventGuidRefreshHead
!= NULL
) {
327 gBS
->CloseEvent(gMenuEventGuidRefreshHead
->Event
);
329 FreePool (gMenuEventGuidRefreshHead
);
330 gMenuEventGuidRefreshHead
= OldMenuRefreshEntry
;
339 @param MenuRefreshEntry Menu refresh structure which has info about the refresh question.
343 IN MENU_REFRESH_ENTRY
*MenuRefreshEntry
346 CHAR16
*OptionString
;
349 UI_MENU_SELECTION
*Selection
;
350 FORM_BROWSER_STATEMENT
*Question
;
352 Selection
= MenuRefreshEntry
->Selection
;
353 Question
= MenuRefreshEntry
->MenuOption
->ThisTag
;
355 Status
= GetQuestionValue (Selection
->FormSet
, Selection
->Form
, Question
, FALSE
);
356 if (EFI_ERROR (Status
)) {
361 ProcessOptions (Selection
, MenuRefreshEntry
->MenuOption
, FALSE
, &OptionString
);
363 if (OptionString
!= NULL
) {
365 // If leading spaces on OptionString - remove the spaces
367 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++)
371 // If old Text is longer than new string, need to clean the old string before paint the newer.
372 // This option is no need for time/date opcode, because time/data opcode has fixed string length.
374 if ((MenuRefreshEntry
->MenuOption
->ThisTag
->Operand
!= EFI_IFR_DATE_OP
) &&
375 (MenuRefreshEntry
->MenuOption
->ThisTag
->Operand
!= EFI_IFR_TIME_OP
)) {
377 MenuRefreshEntry
->CurrentColumn
,
378 MenuRefreshEntry
->CurrentColumn
+ gOptionBlockWidth
- 1,
379 MenuRefreshEntry
->CurrentRow
,
380 MenuRefreshEntry
->CurrentRow
,
381 PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
385 gST
->ConOut
->SetAttribute (gST
->ConOut
, MenuRefreshEntry
->CurrentAttribute
);
386 PrintStringAt (MenuRefreshEntry
->CurrentColumn
, MenuRefreshEntry
->CurrentRow
, &OptionString
[Index
]);
387 FreePool (OptionString
);
391 // Question value may be changed, need invoke its Callback()
393 Status
= ProcessCallBackFunction (Selection
, Question
, EFI_BROWSER_ACTION_CHANGING
, FALSE
);
399 Refresh the question which has refresh guid event attribute.
401 @param Event The event which has this function related.
402 @param Context The input context info related to this event or the status code return to the caller.
406 RefreshQuestionNotify(
411 MENU_REFRESH_ENTRY
*MenuRefreshEntry
;
412 UI_MENU_SELECTION
*Selection
;
415 // Reset FormPackage update flag
417 mHiiPackageListUpdated
= FALSE
;
419 MenuRefreshEntry
= (MENU_REFRESH_ENTRY
*)Context
;
420 ASSERT (MenuRefreshEntry
!= NULL
);
421 Selection
= MenuRefreshEntry
->Selection
;
423 RefreshQuestion (MenuRefreshEntry
);
425 if (mHiiPackageListUpdated
) {
427 // Package list is updated, force to reparse IFR binary of target Formset
429 mHiiPackageListUpdated
= FALSE
;
430 Selection
->Action
= UI_ACTION_REFRESH_FORMSET
;
444 MENU_REFRESH_ENTRY
*MenuRefreshEntry
;
446 UI_MENU_SELECTION
*Selection
;
448 if (gMenuRefreshHead
!= NULL
) {
450 // call from refresh interval process.
452 MenuRefreshEntry
= gMenuRefreshHead
;
453 Selection
= MenuRefreshEntry
->Selection
;
455 // Reset FormPackage update flag
457 mHiiPackageListUpdated
= FALSE
;
460 Status
= RefreshQuestion (MenuRefreshEntry
);
461 if (EFI_ERROR (Status
)) {
465 MenuRefreshEntry
= MenuRefreshEntry
->Next
;
467 } while (MenuRefreshEntry
!= NULL
);
469 if (mHiiPackageListUpdated
) {
471 // Package list is updated, force to reparse IFR binary of target Formset
473 mHiiPackageListUpdated
= FALSE
;
474 Selection
->Action
= UI_ACTION_REFRESH_FORMSET
;
484 Wait for a given event to fire, or for an optional timeout to expire.
486 @param Event The event to wait for
487 @param Timeout An optional timeout value in 100 ns units.
488 @param RefreshInterval Menu refresh interval (in seconds).
490 @retval EFI_SUCCESS Event fired before Timeout expired.
491 @retval EFI_TIME_OUT Timout expired before Event fired.
495 UiWaitForSingleEvent (
497 IN UINT64 Timeout
, OPTIONAL
498 IN UINT8 RefreshInterval OPTIONAL
503 EFI_EVENT TimerEvent
;
504 EFI_EVENT WaitList
[2];
508 // Create a timer event
510 Status
= gBS
->CreateEvent (EVT_TIMER
, 0, NULL
, NULL
, &TimerEvent
);
511 if (!EFI_ERROR (Status
)) {
513 // Set the timer event
522 // Wait for the original event or the timer
525 WaitList
[1] = TimerEvent
;
526 Status
= gBS
->WaitForEvent (2, WaitList
, &Index
);
527 gBS
->CloseEvent (TimerEvent
);
530 // If the timer expired, change the return to timed out
532 if (!EFI_ERROR (Status
) && Index
== 1) {
533 Status
= EFI_TIMEOUT
;
538 // Update screen every second
540 if (RefreshInterval
== 0) {
541 Timeout
= ONE_SECOND
;
543 Timeout
= RefreshInterval
* ONE_SECOND
;
547 Status
= gBS
->CreateEvent (EVT_TIMER
, 0, NULL
, NULL
, &TimerEvent
);
550 // Set the timer event
559 // Wait for the original event or the timer
562 WaitList
[1] = TimerEvent
;
563 Status
= gBS
->WaitForEvent (2, WaitList
, &Index
);
566 // If the timer expired, update anything that needs a refresh and keep waiting
568 if (!EFI_ERROR (Status
) && Index
== 1) {
569 Status
= EFI_TIMEOUT
;
570 if (RefreshInterval
!= 0) {
571 Status
= RefreshForm ();
575 gBS
->CloseEvent (TimerEvent
);
576 } while (Status
== EFI_TIMEOUT
);
584 Add one menu option by specified description and context.
586 @param String String description for this option.
587 @param Handle Hii handle for the package list.
588 @param Statement Statement of this Menu Option.
589 @param NumberOfLines Display lines for this Menu Option.
590 @param MenuItemCount The index for this Option in the Menu.
592 @retval Pointer Pointer to the added Menu Option.
598 IN EFI_HII_HANDLE Handle
,
599 IN FORM_BROWSER_STATEMENT
*Statement
,
600 IN UINT16 NumberOfLines
,
601 IN UINT16 MenuItemCount
604 UI_MENU_OPTION
*MenuOption
;
611 if (Statement
->Operand
== EFI_IFR_DATE_OP
|| Statement
->Operand
== EFI_IFR_TIME_OP
) {
613 // Add three MenuOptions for Date/Time
614 // Data format : [01/02/2004] [11:22:33]
615 // Line number : 0 0 1 0 0 1
620 if (Statement
->Storage
== NULL
) {
622 // For RTC type of date/time, set default refresh interval to be 1 second
624 if (Statement
->RefreshInterval
== 0) {
625 Statement
->RefreshInterval
= 1;
630 for (Index
= 0; Index
< Count
; Index
++) {
631 MenuOption
= AllocateZeroPool (sizeof (UI_MENU_OPTION
));
634 MenuOption
->Signature
= UI_MENU_OPTION_SIGNATURE
;
635 MenuOption
->Description
= String
;
636 MenuOption
->Handle
= Handle
;
637 MenuOption
->ThisTag
= Statement
;
638 MenuOption
->EntryNumber
= MenuItemCount
;
642 // Override LineNumber for the MenuOption in Date/Time sequence
644 MenuOption
->Skip
= 1;
646 MenuOption
->Skip
= NumberOfLines
;
648 MenuOption
->Sequence
= Index
;
650 if (Statement
->GrayOutExpression
!= NULL
) {
651 MenuOption
->GrayOut
= Statement
->GrayOutExpression
->Result
.Value
.b
;
654 switch (Statement
->Operand
) {
655 case EFI_IFR_ORDERED_LIST_OP
:
656 case EFI_IFR_ONE_OF_OP
:
657 case EFI_IFR_NUMERIC_OP
:
658 case EFI_IFR_TIME_OP
:
659 case EFI_IFR_DATE_OP
:
660 case EFI_IFR_CHECKBOX_OP
:
661 case EFI_IFR_PASSWORD_OP
:
662 case EFI_IFR_STRING_OP
:
664 // User could change the value of these items
666 MenuOption
->IsQuestion
= TRUE
;
669 case EFI_IFR_TEXT_OP
:
670 if (FeaturePcdGet (PcdBrowserGrayOutTextStatement
)) {
672 // Initializing GrayOut option as TRUE for Text setup options
673 // so that those options will be Gray in colour and un selectable.
675 MenuOption
->GrayOut
= TRUE
;
679 MenuOption
->IsQuestion
= FALSE
;
683 if ((Statement
->ValueExpression
!= NULL
) ||
684 ((Statement
->QuestionFlags
& EFI_IFR_FLAG_READ_ONLY
) != 0)) {
685 MenuOption
->ReadOnly
= TRUE
;
688 InsertTailList (&gMenuOption
, &MenuOption
->Link
);
696 Routine used to abstract a generic dialog interface and return the selected key or string
698 @param NumberOfLines The number of lines for the dialog box
699 @param HotKey Defines whether a single character is parsed
700 (TRUE) and returned in KeyValue or a string is
701 returned in StringBuffer. Two special characters
702 are considered when entering a string, a SCAN_ESC
703 and an CHAR_CARRIAGE_RETURN. SCAN_ESC terminates
704 string input and returns
705 @param MaximumStringSize The maximum size in bytes of a typed in string
706 (each character is a CHAR16) and the minimum
707 string returned is two bytes
708 @param StringBuffer The passed in pointer to the buffer which will
709 hold the typed in string if HotKey is FALSE
710 @param KeyValue The EFI_KEY value returned if HotKey is TRUE..
711 @param ... A series of (quantity == NumberOfLines) text
712 strings which will be used to construct the dialog
715 @retval EFI_SUCCESS Displayed dialog and received user interaction
716 @retval EFI_INVALID_PARAMETER One of the parameters was invalid (e.g.
717 (StringBuffer == NULL) && (HotKey == FALSE))
718 @retval EFI_DEVICE_ERROR User typed in an ESC character to exit the routine
724 IN UINTN NumberOfLines
,
726 IN UINTN MaximumStringSize
,
727 OUT CHAR16
*StringBuffer
,
728 OUT EFI_INPUT_KEY
*KeyValue
,
737 CHAR16
*BufferedString
;
744 BOOLEAN SelectionComplete
;
746 UINTN CurrentAttribute
;
747 UINTN DimensionsWidth
;
748 UINTN DimensionsHeight
;
750 DimensionsWidth
= gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
;
751 DimensionsHeight
= gScreenDimensions
.BottomRow
- gScreenDimensions
.TopRow
;
753 SelectionComplete
= FALSE
;
755 TempString
= AllocateZeroPool (MaximumStringSize
* 2);
756 BufferedString
= AllocateZeroPool (MaximumStringSize
* 2);
757 CurrentAttribute
= gST
->ConOut
->Mode
->Attribute
;
760 ASSERT (BufferedString
);
762 VA_START (Marker
, KeyValue
);
765 // Zero the outgoing buffer
767 ZeroMem (StringBuffer
, MaximumStringSize
);
770 if (KeyValue
== NULL
) {
771 return EFI_INVALID_PARAMETER
;
774 if (StringBuffer
== NULL
) {
775 return EFI_INVALID_PARAMETER
;
781 gST
->ConOut
->EnableCursor (gST
->ConOut
, FALSE
);
786 // Determine the largest string in the dialog box
787 // Notice we are starting with 1 since String is the first string
789 for (Count
= 0; Count
< NumberOfLines
; Count
++) {
790 StackString
= VA_ARG (Marker
, CHAR16
*);
792 if (StackString
[0] == L
' ') {
793 InputOffset
= Count
+ 1;
796 if ((GetStringWidth (StackString
) / 2) > LargestString
) {
798 // Size of the string visually and subtract the width by one for the null-terminator
800 LargestString
= (GetStringWidth (StackString
) / 2);
805 Start
= (DimensionsWidth
- LargestString
- 2) / 2 + gScreenDimensions
.LeftColumn
+ 1;
806 Top
= ((DimensionsHeight
- NumberOfLines
- 2) / 2) + gScreenDimensions
.TopRow
- 1;
813 VA_START (Marker
, KeyValue
);
814 CreateSharedPopUp (LargestString
, NumberOfLines
, Marker
);
818 // Take the first key typed and report it back?
821 Status
= WaitForKeyStroke (&Key
);
822 ASSERT_EFI_ERROR (Status
);
823 CopyMem (KeyValue
, &Key
, sizeof (EFI_INPUT_KEY
));
827 Status
= WaitForKeyStroke (&Key
);
829 switch (Key
.UnicodeChar
) {
831 switch (Key
.ScanCode
) {
833 FreePool (TempString
);
834 FreePool (BufferedString
);
835 gST
->ConOut
->SetAttribute (gST
->ConOut
, CurrentAttribute
);
836 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
837 return EFI_DEVICE_ERROR
;
845 case CHAR_CARRIAGE_RETURN
:
846 SelectionComplete
= TRUE
;
847 FreePool (TempString
);
848 FreePool (BufferedString
);
849 gST
->ConOut
->SetAttribute (gST
->ConOut
, CurrentAttribute
);
850 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
855 if (StringBuffer
[0] != CHAR_NULL
) {
856 for (Index
= 0; StringBuffer
[Index
] != CHAR_NULL
; Index
++) {
857 TempString
[Index
] = StringBuffer
[Index
];
860 // Effectively truncate string by 1 character
862 TempString
[Index
- 1] = CHAR_NULL
;
863 StrCpy (StringBuffer
, TempString
);
868 // If it is the beginning of the string, don't worry about checking maximum limits
870 if ((StringBuffer
[0] == CHAR_NULL
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
871 StrnCpy (StringBuffer
, &Key
.UnicodeChar
, 1);
872 StrnCpy (TempString
, &Key
.UnicodeChar
, 1);
873 } else if ((GetStringWidth (StringBuffer
) < MaximumStringSize
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
874 KeyPad
[0] = Key
.UnicodeChar
;
875 KeyPad
[1] = CHAR_NULL
;
876 StrCat (StringBuffer
, KeyPad
);
877 StrCat (TempString
, KeyPad
);
880 // If the width of the input string is now larger than the screen, we nee to
881 // adjust the index to start printing portions of the string
883 SetUnicodeMem (BufferedString
, LargestString
, L
' ');
885 PrintStringAt (Start
+ 1, Top
+ InputOffset
, BufferedString
);
887 if ((GetStringWidth (StringBuffer
) / 2) > (DimensionsWidth
- 2)) {
888 Index
= (GetStringWidth (StringBuffer
) / 2) - DimensionsWidth
+ 2;
893 for (Count
= 0; Index
+ 1 < GetStringWidth (StringBuffer
) / 2; Index
++, Count
++) {
894 BufferedString
[Count
] = StringBuffer
[Index
];
897 PrintStringAt (Start
+ 1, Top
+ InputOffset
, BufferedString
);
900 } while (!SelectionComplete
);
903 gST
->ConOut
->SetAttribute (gST
->ConOut
, CurrentAttribute
);
904 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
909 Draw a pop up windows based on the dimension, number of lines and
912 @param RequestedWidth The width of the pop-up.
913 @param NumberOfLines The number of lines.
914 @param Marker The variable argument list for the list of string to be printed.
919 IN UINTN RequestedWidth
,
920 IN UINTN NumberOfLines
,
932 UINTN DimensionsWidth
;
933 UINTN DimensionsHeight
;
935 DimensionsWidth
= gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
;
936 DimensionsHeight
= gScreenDimensions
.BottomRow
- gScreenDimensions
.TopRow
;
938 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
940 if ((RequestedWidth
+ 2) > DimensionsWidth
) {
941 RequestedWidth
= DimensionsWidth
- 2;
945 // Subtract the PopUp width from total Columns, allow for one space extra on
946 // each end plus a border.
948 Start
= (DimensionsWidth
- RequestedWidth
- 2) / 2 + gScreenDimensions
.LeftColumn
+ 1;
949 End
= Start
+ RequestedWidth
+ 1;
951 Top
= ((DimensionsHeight
- NumberOfLines
- 2) / 2) + gScreenDimensions
.TopRow
- 1;
952 Bottom
= Top
+ NumberOfLines
+ 2;
954 Character
= BOXDRAW_DOWN_RIGHT
;
955 PrintCharAt (Start
, Top
, Character
);
956 Character
= BOXDRAW_HORIZONTAL
;
957 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
958 PrintChar (Character
);
961 Character
= BOXDRAW_DOWN_LEFT
;
962 PrintChar (Character
);
963 Character
= BOXDRAW_VERTICAL
;
966 for (Index
= Top
; Index
+ 2 < Bottom
; Index
++, Count
++) {
967 String
= VA_ARG (Marker
, CHAR16
*);
970 // This will clear the background of the line - we never know who might have been
971 // here before us. This differs from the next clear in that it used the non-reverse
972 // video for normal printing.
974 if (GetStringWidth (String
) / 2 > 1) {
975 ClearLines (Start
, End
, Index
+ 1, Index
+ 1, POPUP_TEXT
| POPUP_BACKGROUND
);
979 // Passing in a space results in the assumption that this is where typing will occur
981 if (String
[0] == L
' ') {
982 ClearLines (Start
+ 1, End
- 1, Index
+ 1, Index
+ 1, POPUP_INVERSE_TEXT
| POPUP_INVERSE_BACKGROUND
);
986 // Passing in a NULL results in a blank space
988 if (String
[0] == CHAR_NULL
) {
989 ClearLines (Start
, End
, Index
+ 1, Index
+ 1, POPUP_TEXT
| POPUP_BACKGROUND
);
993 ((DimensionsWidth
- GetStringWidth (String
) / 2) / 2) + gScreenDimensions
.LeftColumn
+ 1,
997 gST
->ConOut
->SetAttribute (gST
->ConOut
, POPUP_TEXT
| POPUP_BACKGROUND
);
998 PrintCharAt (Start
, Index
+ 1, Character
);
999 PrintCharAt (End
- 1, Index
+ 1, Character
);
1002 Character
= BOXDRAW_UP_RIGHT
;
1003 PrintCharAt (Start
, Bottom
- 1, Character
);
1004 Character
= BOXDRAW_HORIZONTAL
;
1005 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
1006 PrintChar (Character
);
1009 Character
= BOXDRAW_UP_LEFT
;
1010 PrintChar (Character
);
1014 Draw a pop up windows based on the dimension, number of lines and
1017 @param RequestedWidth The width of the pop-up.
1018 @param NumberOfLines The number of lines.
1019 @param ... A series of text strings that displayed in the pop-up.
1024 CreateMultiStringPopUp (
1025 IN UINTN RequestedWidth
,
1026 IN UINTN NumberOfLines
,
1032 VA_START (Marker
, NumberOfLines
);
1034 CreateSharedPopUp (RequestedWidth
, NumberOfLines
, Marker
);
1041 Update status bar on the bottom of menu.
1043 @param Selection Current Selction info.
1044 @param MessageType The type of message to be shown.
1045 @param Flags The flags in Question header.
1046 @param State Set or clear.
1051 IN UI_MENU_SELECTION
*Selection
,
1052 IN UINTN MessageType
,
1058 CHAR16
*NvUpdateMessage
;
1059 CHAR16
*InputErrorMessage
;
1061 NvUpdateMessage
= GetToken (STRING_TOKEN (NV_UPDATE_MESSAGE
), gHiiHandle
);
1062 InputErrorMessage
= GetToken (STRING_TOKEN (INPUT_ERROR_MESSAGE
), gHiiHandle
);
1064 switch (MessageType
) {
1067 gST
->ConOut
->SetAttribute (gST
->ConOut
, ERROR_TEXT
);
1069 gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
,
1070 gScreenDimensions
.BottomRow
- 1,
1075 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextHighlightColor
));
1076 for (Index
= 0; Index
< (GetStringWidth (InputErrorMessage
) - 2) / 2; Index
++) {
1077 PrintAt (gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
+ Index
, gScreenDimensions
.BottomRow
- 1, L
" ");
1080 mInputError
= FALSE
;
1084 case NV_UPDATE_REQUIRED
:
1085 if ((gClassOfVfr
& FORMSET_CLASS_FRONT_PAGE
) != FORMSET_CLASS_FRONT_PAGE
) {
1087 gST
->ConOut
->SetAttribute (gST
->ConOut
, INFO_TEXT
);
1089 gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
,
1090 gScreenDimensions
.BottomRow
- 1,
1093 gResetRequired
= (BOOLEAN
) (gResetRequired
| ((Flags
& EFI_IFR_FLAG_RESET_REQUIRED
) == EFI_IFR_FLAG_RESET_REQUIRED
));
1095 if (Selection
!= NULL
) {
1096 Selection
->Form
->NvUpdateRequired
= TRUE
;
1099 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextHighlightColor
));
1100 for (Index
= 0; Index
< (GetStringWidth (NvUpdateMessage
) - 2) / 2; Index
++) {
1102 (gScreenDimensions
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ Index
),
1103 gScreenDimensions
.BottomRow
- 1,
1108 if (Selection
!= NULL
) {
1109 Selection
->Form
->NvUpdateRequired
= FALSE
;
1115 case REFRESH_STATUS_BAR
:
1117 UpdateStatusBar (Selection
, INPUT_ERROR
, Flags
, TRUE
);
1120 if (IsNvUpdateRequired(Selection
->FormSet
)) {
1121 UpdateStatusBar (NULL
, NV_UPDATE_REQUIRED
, Flags
, TRUE
);
1129 FreePool (InputErrorMessage
);
1130 FreePool (NvUpdateMessage
);
1136 Get the supported width for a particular op-code
1138 @param Statement The FORM_BROWSER_STATEMENT structure passed in.
1139 @param Handle The handle in the HII database being used
1141 @return Returns the number of CHAR16 characters that is support.
1146 IN FORM_BROWSER_STATEMENT
*Statement
,
1147 IN EFI_HII_HANDLE Handle
1157 // See if the second text parameter is really NULL
1159 if ((Statement
->Operand
== EFI_IFR_TEXT_OP
) && (Statement
->TextTwo
!= 0)) {
1160 String
= GetToken (Statement
->TextTwo
, Handle
);
1161 Size
= StrLen (String
);
1165 if ((Statement
->Operand
== EFI_IFR_SUBTITLE_OP
) ||
1166 (Statement
->Operand
== EFI_IFR_REF_OP
) ||
1167 (Statement
->Operand
== EFI_IFR_PASSWORD_OP
) ||
1168 (Statement
->Operand
== EFI_IFR_ACTION_OP
) ||
1169 (Statement
->Operand
== EFI_IFR_RESET_BUTTON_OP
) ||
1171 // Allow a wide display if text op-code and no secondary text op-code
1173 ((Statement
->Operand
== EFI_IFR_TEXT_OP
) && (Size
== 0))
1175 Width
= (UINT16
) (gPromptBlockWidth
+ gOptionBlockWidth
);
1177 Width
= (UINT16
) gPromptBlockWidth
;
1180 if (Statement
->InSubtitle
) {
1181 Width
-= SUBTITLE_INDENT
;
1184 return (UINT16
) (Width
- LEFT_SKIPPED_COLUMNS
);
1188 Will copy LineWidth amount of a string in the OutputString buffer and return the
1189 number of CHAR16 characters that were copied into the OutputString buffer.
1191 @param InputString String description for this option.
1192 @param LineWidth Width of the desired string to extract in CHAR16
1194 @param Index Where in InputString to start the copy process
1195 @param OutputString Buffer to copy the string into
1197 @return Returns the number of CHAR16 characters that were copied into the OutputString buffer.
1202 IN CHAR16
*InputString
,
1203 IN UINT16 LineWidth
,
1204 IN OUT UINTN
*Index
,
1205 OUT CHAR16
**OutputString
1211 if (GetLineByWidthFinished
) {
1212 GetLineByWidthFinished
= FALSE
;
1219 *OutputString
= AllocateZeroPool (((UINTN
) (LineWidth
+ 1) * 2));
1222 // Ensure we have got a valid buffer
1224 if (*OutputString
!= NULL
) {
1227 //NARROW_CHAR can not be printed in screen, so if a line only contain the two CHARs: 'NARROW_CHAR + CHAR_CARRIAGE_RETURN' , it is a empty line in Screen.
1228 //To avoid displaying this empty line in screen, just skip the two CHARs here.
1230 if ((InputString
[*Index
] == NARROW_CHAR
) && (InputString
[*Index
+ 1] == CHAR_CARRIAGE_RETURN
)) {
1231 *Index
= *Index
+ 2;
1235 // Fast-forward the string and see if there is a carriage-return in the string
1237 for (; (InputString
[*Index
+ Count2
] != CHAR_CARRIAGE_RETURN
) && (Count2
!= LineWidth
); Count2
++)
1241 // Copy the desired LineWidth of data to the output buffer.
1242 // Also make sure that we don't copy more than the string.
1243 // Also make sure that if there are linefeeds, we account for them.
1245 if ((StrSize (&InputString
[*Index
]) <= ((UINTN
) (LineWidth
+ 1) * 2)) &&
1246 (StrSize (&InputString
[*Index
]) <= ((UINTN
) (Count2
+ 1) * 2))
1249 // Convert to CHAR16 value and show that we are done with this operation
1251 LineWidth
= (UINT16
) ((StrSize (&InputString
[*Index
]) - 2) / 2);
1252 if (LineWidth
!= 0) {
1253 GetLineByWidthFinished
= TRUE
;
1256 if (Count2
== LineWidth
) {
1258 // Rewind the string from the maximum size until we see a space to break the line
1260 for (; (InputString
[*Index
+ LineWidth
] != CHAR_SPACE
) && (LineWidth
!= 0); LineWidth
--)
1262 if (LineWidth
== 0) {
1270 CopyMem (*OutputString
, &InputString
[*Index
], LineWidth
* 2);
1273 // If currently pointing to a space, increment the index to the first non-space character
1276 (InputString
[*Index
+ LineWidth
] == CHAR_SPACE
) || (InputString
[*Index
+ LineWidth
] == CHAR_CARRIAGE_RETURN
);
1280 *Index
= (UINT16
) (*Index
+ LineWidth
);
1289 Update display lines for a Menu Option.
1291 @param Selection The user's selection.
1292 @param MenuOption The MenuOption to be checked.
1293 @param OptionalString The option string.
1294 @param SkipValue The number of lins to skip.
1298 UpdateOptionSkipLines (
1299 IN UI_MENU_SELECTION
*Selection
,
1300 IN UI_MENU_OPTION
*MenuOption
,
1301 OUT CHAR16
**OptionalString
,
1309 CHAR16
*OutputString
;
1310 CHAR16
*OptionString
;
1313 OptionString
= *OptionalString
;
1314 OutputString
= NULL
;
1316 ProcessOptions (Selection
, MenuOption
, FALSE
, &OptionString
);
1318 if (OptionString
!= NULL
) {
1319 Width
= (UINT16
) gOptionBlockWidth
;
1323 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
1325 // If there is more string to process print on the next row and increment the Skip value
1327 if (StrLen (&OptionString
[Index
]) != 0) {
1328 if (SkipValue
== 0) {
1331 // Since the Number of lines for this menu entry may or may not be reflected accurately
1332 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
1333 // some testing to ensure we are keeping this in-sync.
1335 // If the difference in rows is greater than or equal to the skip value, increase the skip value
1337 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
1343 FreePool (OutputString
);
1344 if (SkipValue
!= 0) {
1352 *OptionalString
= OptionString
;
1357 Check whether this Menu Option could be highlighted.
1359 This is an internal function.
1361 @param MenuOption The MenuOption to be checked.
1363 @retval TRUE This Menu Option is selectable.
1364 @retval FALSE This Menu Option could not be selected.
1369 UI_MENU_OPTION
*MenuOption
1372 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
) ||
1373 MenuOption
->GrayOut
|| MenuOption
->ReadOnly
) {
1382 Determine if the menu is the last menu that can be selected.
1384 This is an internal function.
1386 @param Direction The scroll direction. False is down. True is up.
1387 @param CurrentPos The current focus.
1389 @return FALSE -- the menu isn't the last menu that can be selected.
1390 @return TRUE -- the menu is the last menu that can be selected.
1395 IN BOOLEAN Direction
,
1396 IN LIST_ENTRY
*CurrentPos
1401 Temp
= Direction
? CurrentPos
->BackLink
: CurrentPos
->ForwardLink
;
1403 if (Temp
== &gMenuOption
) {
1412 Move to next selectable statement.
1414 This is an internal function.
1416 @param GoUp The navigation direction. TRUE: up, FALSE: down.
1417 @param CurrentPosition Current position.
1418 @param GapToTop Gap position to top or bottom.
1420 @return The row distance from current MenuOption to next selectable MenuOption.
1424 MoveToNextStatement (
1426 IN OUT LIST_ENTRY
**CurrentPosition
,
1432 UI_MENU_OPTION
*NextMenuOption
;
1433 UI_MENU_OPTION
*PreMenuOption
;
1436 Pos
= *CurrentPosition
;
1437 PreMenuOption
= MENU_OPTION_FROM_LINK (Pos
);
1440 NextMenuOption
= MENU_OPTION_FROM_LINK (Pos
);
1441 if (GoUp
&& (PreMenuOption
!= NextMenuOption
)) {
1443 // Current Position doesn't need to be caculated when go up.
1444 // Caculate distanct at first when go up
1446 if ((UINTN
) Distance
+ NextMenuOption
->Skip
> GapToTop
) {
1447 NextMenuOption
= PreMenuOption
;
1450 Distance
+= NextMenuOption
->Skip
;
1452 if (IsSelectable (NextMenuOption
)) {
1455 if ((GoUp
? Pos
->BackLink
: Pos
->ForwardLink
) == &gMenuOption
) {
1464 // Caculate distanct at later when go down
1466 if ((UINTN
) Distance
+ NextMenuOption
->Skip
> GapToTop
) {
1467 NextMenuOption
= PreMenuOption
;
1470 Distance
+= NextMenuOption
->Skip
;
1472 PreMenuOption
= NextMenuOption
;
1473 Pos
= (GoUp
? Pos
->BackLink
: Pos
->ForwardLink
);
1476 *CurrentPosition
= &NextMenuOption
->Link
;
1482 Adjust Data and Time position accordingly.
1483 Data format : [01/02/2004] [11:22:33]
1484 Line number : 0 0 1 0 0 1
1486 This is an internal function.
1488 @param DirectionUp the up or down direction. False is down. True is
1490 @param CurrentPosition Current position. On return: Point to the last
1491 Option (Year or Second) if up; Point to the first
1492 Option (Month or Hour) if down.
1494 @return Return line number to pad. It is possible that we stand on a zero-advance
1495 @return data or time opcode, so pad one line when we judge if we are going to scroll outside.
1499 AdjustDateAndTimePosition (
1500 IN BOOLEAN DirectionUp
,
1501 IN OUT LIST_ENTRY
**CurrentPosition
1505 LIST_ENTRY
*NewPosition
;
1506 UI_MENU_OPTION
*MenuOption
;
1507 UINTN PadLineNumber
;
1510 NewPosition
= *CurrentPosition
;
1511 MenuOption
= MENU_OPTION_FROM_LINK (NewPosition
);
1513 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) ||
1514 (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
1516 // Calculate the distance from current position to the last Date/Time MenuOption
1519 while (MenuOption
->Skip
== 0) {
1521 NewPosition
= NewPosition
->ForwardLink
;
1522 MenuOption
= MENU_OPTION_FROM_LINK (NewPosition
);
1526 NewPosition
= *CurrentPosition
;
1529 // Since the behavior of hitting the up arrow on a Date/Time MenuOption is intended
1530 // to be one that back to the previous set of MenuOptions, we need to advance to the first
1531 // Date/Time MenuOption and leave the remaining logic in CfUiUp intact so the appropriate
1532 // checking can be done.
1534 while (Count
++ < 2) {
1535 NewPosition
= NewPosition
->BackLink
;
1539 // Since the behavior of hitting the down arrow on a Date/Time MenuOption is intended
1540 // to be one that progresses to the next set of MenuOptions, we need to advance to the last
1541 // Date/Time MenuOption and leave the remaining logic in CfUiDown intact so the appropriate
1542 // checking can be done.
1544 while (Count
-- > 0) {
1545 NewPosition
= NewPosition
->ForwardLink
;
1549 *CurrentPosition
= NewPosition
;
1552 return PadLineNumber
;
1556 Find HII Handle in the HII database associated with given Device Path.
1558 If DevicePath is NULL, then ASSERT.
1560 @param DevicePath Device Path associated with the HII package list
1563 @retval Handle HII package list Handle associated with the Device
1565 @retval NULL Hii Package list handle is not found.
1570 DevicePathToHiiHandle (
1571 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
1575 EFI_DEVICE_PATH_PROTOCOL
*TmpDevicePath
;
1580 EFI_HANDLE DriverHandle
;
1581 EFI_HII_HANDLE
*HiiHandles
;
1582 EFI_HII_HANDLE HiiHandle
;
1584 ASSERT (DevicePath
!= NULL
);
1586 TmpDevicePath
= DevicePath
;
1588 // Locate Device Path Protocol handle buffer
1590 Status
= gBS
->LocateDevicePath (
1591 &gEfiDevicePathProtocolGuid
,
1595 if (EFI_ERROR (Status
) || !IsDevicePathEnd (TmpDevicePath
)) {
1600 // Retrieve all HII Handles from HII database
1602 BufferSize
= 0x1000;
1603 HiiHandles
= AllocatePool (BufferSize
);
1604 ASSERT (HiiHandles
!= NULL
);
1605 Status
= mHiiDatabase
->ListPackageLists (
1607 EFI_HII_PACKAGE_TYPE_ALL
,
1612 if (Status
== EFI_BUFFER_TOO_SMALL
) {
1613 FreePool (HiiHandles
);
1614 HiiHandles
= AllocatePool (BufferSize
);
1615 ASSERT (HiiHandles
!= NULL
);
1617 Status
= mHiiDatabase
->ListPackageLists (
1619 EFI_HII_PACKAGE_TYPE_ALL
,
1626 if (EFI_ERROR (Status
)) {
1627 FreePool (HiiHandles
);
1632 // Search Hii Handle by Driver Handle
1635 HandleCount
= BufferSize
/ sizeof (EFI_HII_HANDLE
);
1636 for (Index
= 0; Index
< HandleCount
; Index
++) {
1637 Status
= mHiiDatabase
->GetPackageListHandle (
1642 if (!EFI_ERROR (Status
) && (Handle
== DriverHandle
)) {
1643 HiiHandle
= HiiHandles
[Index
];
1648 FreePool (HiiHandles
);
1653 Display menu and wait for user to select one menu option, then return it.
1654 If AutoBoot is enabled, then if user doesn't select any option,
1655 after period of time, it will automatically return the first menu option.
1657 @param Selection Menu selection.
1659 @retval EFI_SUCESSS This function always return successfully for now.
1664 IN OUT UI_MENU_SELECTION
*Selection
1670 UINTN DistanceValue
;
1682 CHAR16
*OptionString
;
1683 CHAR16
*OutputString
;
1684 CHAR16
*FormattedString
;
1690 BOOLEAN InitializedFlag
;
1695 LIST_ENTRY
*TopOfScreen
;
1696 LIST_ENTRY
*SavedListEntry
;
1697 UI_MENU_OPTION
*MenuOption
;
1698 UI_MENU_OPTION
*NextMenuOption
;
1699 UI_MENU_OPTION
*SavedMenuOption
;
1700 UI_MENU_OPTION
*PreviousMenuOption
;
1701 UI_CONTROL_FLAG ControlFlag
;
1702 EFI_SCREEN_DESCRIPTOR LocalScreen
;
1703 MENU_REFRESH_ENTRY
*MenuRefreshEntry
;
1704 MENU_REFRESH_ENTRY
*MenuUpdateEntry
;
1705 UI_SCREEN_OPERATION ScreenOperation
;
1706 UINT8 MinRefreshInterval
;
1709 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1710 FORM_BROWSER_STATEMENT
*Statement
;
1712 UINT8
*DevicePathBuffer
;
1714 UI_MENU_LIST
*CurrentMenu
;
1715 UI_MENU_LIST
*MenuList
;
1716 FORM_BROWSER_FORM
*RefForm
;
1717 UINTN ModalSkipColumn
;
1719 CopyMem (&LocalScreen
, &gScreenDimensions
, sizeof (EFI_SCREEN_DESCRIPTOR
));
1721 Status
= EFI_SUCCESS
;
1722 FormattedString
= NULL
;
1723 OptionString
= NULL
;
1724 ScreenOperation
= UiNoOperation
;
1726 MinRefreshInterval
= 0;
1729 OutputString
= NULL
;
1734 MenuRefreshEntry
= gMenuRefreshHead
;
1736 NextMenuOption
= NULL
;
1737 PreviousMenuOption
= NULL
;
1738 SavedMenuOption
= NULL
;
1740 ModalSkipColumn
= (LocalScreen
.RightColumn
- LocalScreen
.LeftColumn
) / 6;
1742 ZeroMem (&Key
, sizeof (EFI_INPUT_KEY
));
1744 if ((gClassOfVfr
& FORMSET_CLASS_FRONT_PAGE
) == FORMSET_CLASS_FRONT_PAGE
){
1745 TopRow
= LocalScreen
.TopRow
+ FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1746 Row
= LocalScreen
.TopRow
+ FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1748 TopRow
= LocalScreen
.TopRow
+ NONE_FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1749 Row
= LocalScreen
.TopRow
+ NONE_FRONT_PAGE_HEADER_HEIGHT
+ SCROLL_ARROW_HEIGHT
;
1752 if (Selection
->Form
->ModalForm
) {
1753 Col
= LocalScreen
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
+ ModalSkipColumn
;
1755 Col
= LocalScreen
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
;
1758 BottomRow
= LocalScreen
.BottomRow
- STATUS_BAR_HEIGHT
- FOOTER_HEIGHT
- SCROLL_ARROW_HEIGHT
- 1;
1760 Selection
->TopRow
= TopRow
;
1761 Selection
->BottomRow
= BottomRow
;
1762 Selection
->PromptCol
= Col
;
1763 Selection
->OptionCol
= gPromptBlockWidth
+ 1 + LocalScreen
.LeftColumn
;
1764 Selection
->Statement
= NULL
;
1766 TopOfScreen
= gMenuOption
.ForwardLink
;
1771 // Find current Menu
1773 CurrentMenu
= UiFindMenuList (&Selection
->FormSetGuid
, Selection
->FormId
);
1774 if (CurrentMenu
== NULL
) {
1776 // Current menu not found, add it to the menu tree
1778 CurrentMenu
= UiAddMenuList (NULL
, &Selection
->FormSetGuid
, Selection
->FormId
);
1780 ASSERT (CurrentMenu
!= NULL
);
1781 Selection
->CurrentMenu
= CurrentMenu
;
1783 if (Selection
->QuestionId
== 0) {
1785 // Highlight not specified, fetch it from cached menu
1787 Selection
->QuestionId
= CurrentMenu
->QuestionId
;
1791 // Init option as the current user's selection
1793 InitializedFlag
= TRUE
;
1794 NewPos
= gMenuOption
.ForwardLink
;
1796 gST
->ConOut
->EnableCursor (gST
->ConOut
, FALSE
);
1797 UpdateStatusBar (Selection
, REFRESH_STATUS_BAR
, (UINT8
) 0, TRUE
);
1799 ControlFlag
= CfInitialization
;
1800 Selection
->Action
= UI_ACTION_NONE
;
1802 switch (ControlFlag
) {
1803 case CfInitialization
:
1804 if (IsListEmpty (&gMenuOption
)) {
1805 ControlFlag
= CfReadKey
;
1807 ControlFlag
= CfCheckSelection
;
1811 case CfCheckSelection
:
1812 if (Selection
->Action
!= UI_ACTION_NONE
) {
1813 ControlFlag
= CfExit
;
1815 ControlFlag
= CfRepaint
;
1820 ControlFlag
= CfRefreshHighLight
;
1830 Temp
= (UINTN
) SkipValue
;
1831 Temp2
= (UINTN
) SkipValue
;
1833 if (Selection
->Form
->ModalForm
) {
1835 LocalScreen
.LeftColumn
+ ModalSkipColumn
,
1836 LocalScreen
.LeftColumn
+ ModalSkipColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
,
1837 TopRow
- SCROLL_ARROW_HEIGHT
,
1838 BottomRow
+ SCROLL_ARROW_HEIGHT
,
1839 PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
1843 LocalScreen
.LeftColumn
,
1844 LocalScreen
.RightColumn
,
1845 TopRow
- SCROLL_ARROW_HEIGHT
,
1846 BottomRow
+ SCROLL_ARROW_HEIGHT
,
1847 PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
1850 UiFreeRefreshList ();
1851 MinRefreshInterval
= 0;
1853 for (Link
= TopOfScreen
; Link
!= &gMenuOption
; Link
= Link
->ForwardLink
) {
1854 MenuOption
= MENU_OPTION_FROM_LINK (Link
);
1855 MenuOption
->Row
= Row
;
1856 MenuOption
->Col
= Col
;
1857 if (Selection
->Form
->ModalForm
) {
1858 MenuOption
->OptCol
= gPromptBlockWidth
+ 1 + LocalScreen
.LeftColumn
+ ModalSkipColumn
;
1860 MenuOption
->OptCol
= gPromptBlockWidth
+ 1 + LocalScreen
.LeftColumn
;
1863 Statement
= MenuOption
->ThisTag
;
1864 if (Statement
->InSubtitle
) {
1865 MenuOption
->Col
+= SUBTITLE_INDENT
;
1868 if (MenuOption
->GrayOut
) {
1869 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
);
1871 if (Statement
->Operand
== EFI_IFR_SUBTITLE_OP
) {
1872 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserSubtitleTextColor
) | FIELD_BACKGROUND
);
1876 Width
= GetWidth (Statement
, MenuOption
->Handle
);
1879 if (Statement
->Operand
== EFI_IFR_REF_OP
&& MenuOption
->Col
>= 2) {
1881 // Print Arrow for Goto button.
1884 MenuOption
->Col
- 2,
1887 GEOMETRICSHAPE_RIGHT_TRIANGLE
1891 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &Index
, &OutputString
) != 0x0000;) {
1892 if ((Temp
== 0) && (Row
<= BottomRow
)) {
1893 PrintStringAt (MenuOption
->Col
, Row
, OutputString
);
1896 // If there is more string to process print on the next row and increment the Skip value
1898 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
1904 FreePool (OutputString
);
1913 Status
= ProcessOptions (Selection
, MenuOption
, FALSE
, &OptionString
);
1914 if (EFI_ERROR (Status
)) {
1916 // Repaint to clear possible error prompt pop-up
1920 ControlFlag
= CfRepaint
;
1924 if (OptionString
!= NULL
) {
1925 if (Statement
->Operand
== EFI_IFR_DATE_OP
|| Statement
->Operand
== EFI_IFR_TIME_OP
) {
1927 // If leading spaces on OptionString - remove the spaces
1929 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++) {
1930 MenuOption
->OptCol
++;
1933 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
1934 OptionString
[Count
] = OptionString
[Index
];
1938 OptionString
[Count
] = CHAR_NULL
;
1942 // If Question has refresh guid, register the op-code.
1944 if (!CompareGuid (&Statement
->RefreshGuid
, &gZeroGuid
)) {
1945 if (gMenuEventGuidRefreshHead
== NULL
) {
1946 MenuUpdateEntry
= AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY
));
1947 gMenuEventGuidRefreshHead
= MenuUpdateEntry
;
1949 MenuUpdateEntry
= gMenuEventGuidRefreshHead
;
1950 while (MenuUpdateEntry
->Next
!= NULL
) {
1951 MenuUpdateEntry
= MenuUpdateEntry
->Next
;
1953 MenuUpdateEntry
->Next
= AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY
));
1955 ASSERT (MenuUpdateEntry
!= NULL
);
1956 Status
= gBS
->CreateEventEx (EVT_NOTIFY_SIGNAL
, TPL_NOTIFY
, RefreshQuestionNotify
, MenuUpdateEntry
, &Statement
->RefreshGuid
, &MenuUpdateEntry
->Event
);
1957 ASSERT (!EFI_ERROR (Status
));
1958 MenuUpdateEntry
->MenuOption
= MenuOption
;
1959 MenuUpdateEntry
->Selection
= Selection
;
1960 MenuUpdateEntry
->CurrentColumn
= MenuOption
->OptCol
;
1961 MenuUpdateEntry
->CurrentRow
= MenuOption
->Row
;
1962 if (MenuOption
->GrayOut
) {
1963 MenuUpdateEntry
->CurrentAttribute
= FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
;
1965 MenuUpdateEntry
->CurrentAttribute
= PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
;
1970 // If Question request refresh, register the op-code
1972 if (Statement
->RefreshInterval
!= 0) {
1974 // Menu will be refreshed at minimal interval of all Questions
1975 // which have refresh request
1977 if (MinRefreshInterval
== 0 || Statement
->RefreshInterval
< MinRefreshInterval
) {
1978 MinRefreshInterval
= Statement
->RefreshInterval
;
1981 if (gMenuRefreshHead
== NULL
) {
1982 MenuRefreshEntry
= AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY
));
1983 ASSERT (MenuRefreshEntry
!= NULL
);
1984 MenuRefreshEntry
->MenuOption
= MenuOption
;
1985 MenuRefreshEntry
->Selection
= Selection
;
1986 MenuRefreshEntry
->CurrentColumn
= MenuOption
->OptCol
;
1987 MenuRefreshEntry
->CurrentRow
= MenuOption
->Row
;
1988 if (MenuOption
->GrayOut
) {
1989 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
;
1991 MenuRefreshEntry
->CurrentAttribute
= PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
;
1993 gMenuRefreshHead
= MenuRefreshEntry
;
1996 // Advance to the last entry
1998 for (MenuRefreshEntry
= gMenuRefreshHead
;
1999 MenuRefreshEntry
->Next
!= NULL
;
2000 MenuRefreshEntry
= MenuRefreshEntry
->Next
2003 MenuRefreshEntry
->Next
= AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY
));
2004 ASSERT (MenuRefreshEntry
->Next
!= NULL
);
2005 MenuRefreshEntry
= MenuRefreshEntry
->Next
;
2006 MenuRefreshEntry
->MenuOption
= MenuOption
;
2007 MenuRefreshEntry
->Selection
= Selection
;
2008 MenuRefreshEntry
->CurrentColumn
= MenuOption
->OptCol
;
2009 MenuRefreshEntry
->CurrentRow
= MenuOption
->Row
;
2010 if (MenuOption
->GrayOut
) {
2011 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
;
2013 MenuRefreshEntry
->CurrentAttribute
= PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
;
2018 Width
= (UINT16
) gOptionBlockWidth
;
2021 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
2022 if ((Temp2
== 0) && (Row
<= BottomRow
)) {
2023 PrintStringAt (MenuOption
->OptCol
, Row
, OutputString
);
2026 // If there is more string to process print on the next row and increment the Skip value
2028 if (StrLen (&OptionString
[Index
]) != 0) {
2032 // Since the Number of lines for this menu entry may or may not be reflected accurately
2033 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
2034 // some testing to ensure we are keeping this in-sync.
2036 // If the difference in rows is greater than or equal to the skip value, increase the skip value
2038 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
2044 FreePool (OutputString
);
2053 FreePool (OptionString
);
2056 // If this is a text op with secondary text information
2058 if ((Statement
->Operand
== EFI_IFR_TEXT_OP
) && (Statement
->TextTwo
!= 0)) {
2059 StringPtr
= GetToken (Statement
->TextTwo
, MenuOption
->Handle
);
2061 Width
= (UINT16
) gOptionBlockWidth
;
2064 for (Index
= 0; GetLineByWidth (StringPtr
, Width
, &Index
, &OutputString
) != 0x0000;) {
2065 if ((Temp
== 0) && (Row
<= BottomRow
)) {
2066 PrintStringAt (MenuOption
->OptCol
, Row
, OutputString
);
2069 // If there is more string to process print on the next row and increment the Skip value
2071 if (StrLen (&StringPtr
[Index
]) != 0) {
2075 // Since the Number of lines for this menu entry may or may not be reflected accurately
2076 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
2077 // some testing to ensure we are keeping this in-sync.
2079 // If the difference in rows is greater than or equal to the skip value, increase the skip value
2081 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
2087 FreePool (OutputString
);
2094 FreePool (StringPtr
);
2096 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2099 // Need to handle the bottom of the display
2101 if (MenuOption
->Skip
> 1) {
2102 Row
+= MenuOption
->Skip
- SkipValue
;
2105 Row
+= MenuOption
->Skip
;
2108 if (Row
> BottomRow
) {
2109 if (!ValueIsScroll (FALSE
, Link
)) {
2113 Row
= BottomRow
+ 1;
2118 if (!ValueIsScroll (TRUE
, TopOfScreen
)) {
2123 gST
->ConOut
->SetAttribute (gST
->ConOut
, ARROW_TEXT
| ARROW_BACKGROUND
);
2125 LocalScreen
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
2126 TopRow
- SCROLL_ARROW_HEIGHT
,
2130 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2134 gST
->ConOut
->SetAttribute (gST
->ConOut
, ARROW_TEXT
| ARROW_BACKGROUND
);
2136 LocalScreen
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
2137 BottomRow
+ SCROLL_ARROW_HEIGHT
,
2141 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2148 case CfRefreshHighLight
:
2150 // MenuOption: Last menu option that need to remove hilight
2151 // MenuOption is set to NULL in Repaint
2152 // NewPos: Current menu option that need to hilight
2154 ControlFlag
= CfUpdateHelpString
;
2155 if (InitializedFlag
) {
2156 InitializedFlag
= FALSE
;
2157 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
2161 // Repaint flag is normally reset when finish processing CfUpdateHelpString. Temporarily
2162 // reset Repaint flag because we may break halfway and skip CfUpdateHelpString processing.
2164 SavedValue
= Repaint
;
2167 if (Selection
->QuestionId
!= 0) {
2168 NewPos
= gMenuOption
.ForwardLink
;
2169 SavedMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2171 while (SavedMenuOption
->ThisTag
->QuestionId
!= Selection
->QuestionId
&& NewPos
->ForwardLink
!= &gMenuOption
) {
2172 NewPos
= NewPos
->ForwardLink
;
2173 SavedMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2175 if (SavedMenuOption
->ThisTag
->QuestionId
== Selection
->QuestionId
) {
2177 // Target Question found, find its MenuOption
2181 for (Index
= TopRow
; Index
<= BottomRow
&& Link
!= NewPos
;) {
2182 SavedMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2183 Index
+= SavedMenuOption
->Skip
;
2184 Link
= Link
->ForwardLink
;
2187 if (Link
!= NewPos
|| Index
> BottomRow
) {
2189 // NewPos is not in the current page, simply scroll page so that NewPos is in the end of the page
2192 for (Index
= TopRow
; Index
<= BottomRow
; ) {
2193 Link
= Link
->BackLink
;
2194 SavedMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2195 Index
+= SavedMenuOption
->Skip
;
2197 TopOfScreen
= Link
->ForwardLink
;
2201 ControlFlag
= CfRepaint
;
2206 // Target Question not found, highlight the default menu option
2208 NewPos
= TopOfScreen
;
2211 Selection
->QuestionId
= 0;
2214 if (NewPos
!= NULL
&& (MenuOption
== NULL
|| NewPos
!= &MenuOption
->Link
)) {
2215 if (MenuOption
!= NULL
) {
2217 // Remove highlight on last Menu Option
2219 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, MenuOption
->Col
, MenuOption
->Row
);
2220 ProcessOptions (Selection
, MenuOption
, FALSE
, &OptionString
);
2221 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2222 if (OptionString
!= NULL
) {
2223 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) ||
2224 (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)
2227 // If leading spaces on OptionString - remove the spaces
2229 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++)
2232 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
2233 OptionString
[Count
] = OptionString
[Index
];
2237 OptionString
[Count
] = CHAR_NULL
;
2240 Width
= (UINT16
) gOptionBlockWidth
;
2241 OriginalRow
= MenuOption
->Row
;
2243 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
2244 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
2245 PrintStringAt (MenuOption
->OptCol
, MenuOption
->Row
, OutputString
);
2248 // If there is more string to process print on the next row and increment the Skip value
2250 if (StrLen (&OptionString
[Index
]) != 0) {
2254 FreePool (OutputString
);
2257 MenuOption
->Row
= OriginalRow
;
2259 FreePool (OptionString
);
2262 if (MenuOption
->GrayOut
) {
2263 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
);
2264 } else if (MenuOption
->ThisTag
->Operand
== EFI_IFR_SUBTITLE_OP
) {
2265 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserSubtitleTextColor
) | FIELD_BACKGROUND
);
2268 OriginalRow
= MenuOption
->Row
;
2269 Width
= GetWidth (MenuOption
->ThisTag
, MenuOption
->Handle
);
2271 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &Index
, &OutputString
) != 0x0000;) {
2272 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
2273 PrintStringAt (MenuOption
->Col
, MenuOption
->Row
, OutputString
);
2276 // If there is more string to process print on the next row and increment the Skip value
2278 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
2282 FreePool (OutputString
);
2285 MenuOption
->Row
= OriginalRow
;
2286 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2292 // This is the current selected statement
2294 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2295 Statement
= MenuOption
->ThisTag
;
2296 Selection
->Statement
= Statement
;
2297 if (!IsSelectable (MenuOption
)) {
2298 Repaint
= SavedValue
;
2299 UpdateKeyHelp (Selection
, MenuOption
, FALSE
);
2304 // Record highlight for current menu
2306 CurrentMenu
->QuestionId
= Statement
->QuestionId
;
2309 // Set reverse attribute
2311 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextHighlightColor
) | PcdGet8 (PcdBrowserFieldBackgroundHighlightColor
));
2312 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, MenuOption
->Col
, MenuOption
->Row
);
2315 // Assuming that we have a refresh linked-list created, lets annotate the
2316 // appropriate entry that we are highlighting with its new attribute. Just prior to this
2317 // lets reset all of the entries' attribute so we do not get multiple highlights in he refresh
2319 if (gMenuRefreshHead
!= NULL
) {
2320 for (MenuRefreshEntry
= gMenuRefreshHead
; MenuRefreshEntry
!= NULL
; MenuRefreshEntry
= MenuRefreshEntry
->Next
) {
2321 if (MenuRefreshEntry
->MenuOption
->GrayOut
) {
2322 MenuRefreshEntry
->CurrentAttribute
= FIELD_TEXT_GRAYED
| FIELD_BACKGROUND
;
2324 MenuRefreshEntry
->CurrentAttribute
= PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
;
2326 if (MenuRefreshEntry
->MenuOption
== MenuOption
) {
2327 MenuRefreshEntry
->CurrentAttribute
= PcdGet8 (PcdBrowserFieldTextHighlightColor
) | PcdGet8 (PcdBrowserFieldBackgroundHighlightColor
);
2332 ProcessOptions (Selection
, MenuOption
, FALSE
, &OptionString
);
2333 if (OptionString
!= NULL
) {
2334 if (Statement
->Operand
== EFI_IFR_DATE_OP
|| Statement
->Operand
== EFI_IFR_TIME_OP
) {
2336 // If leading spaces on OptionString - remove the spaces
2338 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++)
2341 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
2342 OptionString
[Count
] = OptionString
[Index
];
2346 OptionString
[Count
] = CHAR_NULL
;
2348 Width
= (UINT16
) gOptionBlockWidth
;
2350 OriginalRow
= MenuOption
->Row
;
2352 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &Index
, &OutputString
) != 0x0000;) {
2353 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
2354 PrintStringAt (MenuOption
->OptCol
, MenuOption
->Row
, OutputString
);
2357 // If there is more string to process print on the next row and increment the Skip value
2359 if (StrLen (&OptionString
[Index
]) != 0) {
2363 FreePool (OutputString
);
2366 MenuOption
->Row
= OriginalRow
;
2368 FreePool (OptionString
);
2371 OriginalRow
= MenuOption
->Row
;
2373 Width
= GetWidth (Statement
, MenuOption
->Handle
);
2375 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &Index
, &OutputString
) != 0x0000;) {
2376 if (MenuOption
->Row
>= TopRow
&& MenuOption
->Row
<= BottomRow
) {
2377 PrintStringAt (MenuOption
->Col
, MenuOption
->Row
, OutputString
);
2380 // If there is more string to process print on the next row and increment the Skip value
2382 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
2386 FreePool (OutputString
);
2389 MenuOption
->Row
= OriginalRow
;
2394 UpdateKeyHelp (Selection
, MenuOption
, FALSE
);
2397 // Clear reverse attribute
2399 gST
->ConOut
->SetAttribute (gST
->ConOut
, PcdGet8 (PcdBrowserFieldTextColor
) | FIELD_BACKGROUND
);
2402 // Repaint flag will be used when process CfUpdateHelpString, so restore its value
2403 // if we didn't break halfway when process CfRefreshHighLight.
2405 Repaint
= SavedValue
;
2408 case CfUpdateHelpString
:
2409 ControlFlag
= CfPrepareToReadKey
;
2410 if (Selection
->Form
->ModalForm
) {
2414 if (Repaint
|| NewLine
) {
2416 // Don't print anything if it is a NULL help token
2418 ASSERT(MenuOption
!= NULL
);
2419 if (MenuOption
->ThisTag
->Help
== 0 || !IsSelectable (MenuOption
)) {
2422 StringPtr
= GetToken (MenuOption
->ThisTag
->Help
, MenuOption
->Handle
);
2425 ProcessHelpString (StringPtr
, &FormattedString
, BottomRow
- TopRow
);
2427 gST
->ConOut
->SetAttribute (gST
->ConOut
, HELP_TEXT
| FIELD_BACKGROUND
);
2429 for (Index
= 0; Index
< BottomRow
- TopRow
; Index
++) {
2431 // Pad String with spaces to simulate a clearing of the previous line
2433 for (; GetStringWidth (&FormattedString
[Index
* gHelpBlockWidth
* 2]) / 2 < gHelpBlockWidth
;) {
2434 StrCat (&FormattedString
[Index
* gHelpBlockWidth
* 2], L
" ");
2438 LocalScreen
.RightColumn
- gHelpBlockWidth
,
2440 &FormattedString
[Index
* gHelpBlockWidth
* 2]
2445 // Reset this flag every time we finish using it.
2451 case CfPrepareToReadKey
:
2452 ControlFlag
= CfReadKey
;
2453 ScreenOperation
= UiNoOperation
;
2457 ControlFlag
= CfScreenOperation
;
2460 // Wait for user's selection
2463 Status
= UiWaitForSingleEvent (gST
->ConIn
->WaitForKey
, 0, MinRefreshInterval
);
2464 } while (Status
== EFI_TIMEOUT
);
2466 if (Selection
->Action
== UI_ACTION_REFRESH_FORMSET
) {
2468 // IFR is updated in Callback of refresh opcode, re-parse it
2470 Selection
->Statement
= NULL
;
2474 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
2476 // If we encounter error, continue to read another key in.
2478 if (EFI_ERROR (Status
)) {
2479 ControlFlag
= CfReadKey
;
2483 switch (Key
.UnicodeChar
) {
2484 case CHAR_CARRIAGE_RETURN
:
2485 ScreenOperation
= UiSelect
;
2490 // We will push the adjustment of these numeric values directly to the input handler
2491 // NOTE: we won't handle manual input numeric
2496 // If the screen has no menu items, and the user didn't select UiReset
2497 // ignore the selection and go back to reading keys.
2499 if(IsListEmpty (&gMenuOption
)) {
2500 ControlFlag
= CfReadKey
;
2504 ASSERT(MenuOption
!= NULL
);
2505 Statement
= MenuOption
->ThisTag
;
2506 if ((Statement
->Operand
== EFI_IFR_DATE_OP
)
2507 || (Statement
->Operand
== EFI_IFR_TIME_OP
)
2508 || ((Statement
->Operand
== EFI_IFR_NUMERIC_OP
) && (Statement
->Step
!= 0))
2510 if (Key
.UnicodeChar
== '+') {
2511 gDirection
= SCAN_RIGHT
;
2513 gDirection
= SCAN_LEFT
;
2515 Status
= ProcessOptions (Selection
, MenuOption
, TRUE
, &OptionString
);
2516 if (EFI_ERROR (Status
)) {
2518 // Repaint to clear possible error prompt pop-up
2523 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2525 if (OptionString
!= NULL
) {
2526 FreePool (OptionString
);
2532 ScreenOperation
= UiUp
;
2537 ScreenOperation
= UiDown
;
2541 if ((gClassOfVfr
& FORMSET_CLASS_FRONT_PAGE
) != FORMSET_CLASS_FRONT_PAGE
) {
2543 // If the screen has no menu items, and the user didn't select UiReset
2544 // ignore the selection and go back to reading keys.
2546 if(IsListEmpty (&gMenuOption
)) {
2547 ControlFlag
= CfReadKey
;
2551 ASSERT(MenuOption
!= NULL
);
2552 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_CHECKBOX_OP
&& !MenuOption
->GrayOut
) {
2553 ScreenOperation
= UiSelect
;
2559 if (((Key
.ScanCode
== SCAN_F9
) && ((gFunctionKeySetting
& FUNCTION_NINE
) != FUNCTION_NINE
)) ||
2560 ((Key
.ScanCode
== SCAN_F10
) && ((gFunctionKeySetting
& FUNCTION_TEN
) != FUNCTION_TEN
))
2563 // If the function key has been disabled, just ignore the key.
2566 for (Index
= 0; Index
< sizeof (gScanCodeToOperation
) / sizeof (gScanCodeToOperation
[0]); Index
++) {
2567 if (Selection
->Form
->ModalForm
&&
2568 (Key
.ScanCode
== SCAN_F9
|| Key
.ScanCode
== SCAN_F10
|| Key
.ScanCode
== SCAN_ESC
)) {
2569 ControlFlag
= CfReadKey
;
2573 if (Key
.ScanCode
== gScanCodeToOperation
[Index
].ScanCode
) {
2574 if (Key
.ScanCode
== SCAN_F9
) {
2576 // Reset to standard default
2578 DefaultId
= EFI_HII_DEFAULT_CLASS_STANDARD
;
2580 ScreenOperation
= gScanCodeToOperation
[Index
].ScreenOperation
;
2589 case CfScreenOperation
:
2590 if (ScreenOperation
!= UiReset
) {
2592 // If the screen has no menu items, and the user didn't select UiReset
2593 // ignore the selection and go back to reading keys.
2595 if (IsListEmpty (&gMenuOption
)) {
2596 ControlFlag
= CfReadKey
;
2602 Index
< sizeof (gScreenOperationToControlFlag
) / sizeof (gScreenOperationToControlFlag
[0]);
2605 if (ScreenOperation
== gScreenOperationToControlFlag
[Index
].ScreenOperation
) {
2606 ControlFlag
= gScreenOperationToControlFlag
[Index
].ControlFlag
;
2613 ControlFlag
= CfCheckSelection
;
2615 ASSERT(MenuOption
!= NULL
);
2616 Statement
= MenuOption
->ThisTag
;
2617 if (Statement
->Operand
== EFI_IFR_TEXT_OP
) {
2622 // Keep highlight on current MenuOption
2624 Selection
->QuestionId
= Statement
->QuestionId
;
2626 switch (Statement
->Operand
) {
2627 case EFI_IFR_REF_OP
:
2628 if (Statement
->RefDevicePath
!= 0) {
2629 if (Selection
->Form
->ModalForm
) {
2633 // Goto another Hii Package list
2635 Selection
->Action
= UI_ACTION_REFRESH_FORMSET
;
2637 StringPtr
= GetToken (Statement
->RefDevicePath
, Selection
->FormSet
->HiiHandle
);
2638 if (StringPtr
== NULL
) {
2640 // No device path string not found, exit
2642 Selection
->Action
= UI_ACTION_EXIT
;
2643 Selection
->Statement
= NULL
;
2646 BufferSize
= StrLen (StringPtr
) / 2;
2647 DevicePath
= AllocatePool (BufferSize
);
2648 ASSERT (DevicePath
!= NULL
);
2651 // Convert from Device Path String to DevicePath Buffer in the reverse order.
2653 DevicePathBuffer
= (UINT8
*) DevicePath
;
2654 for (Index
= 0; StringPtr
[Index
] != L
'\0'; Index
++) {
2655 TemStr
[0] = StringPtr
[Index
];
2656 DigitUint8
= (UINT8
) StrHexToUint64 (TemStr
);
2657 if (DigitUint8
== 0 && TemStr
[0] != L
'0') {
2659 // Invalid Hex Char as the tail.
2663 if ((Index
& 1) == 0) {
2664 DevicePathBuffer
[Index
/2] = DigitUint8
;
2666 DevicePathBuffer
[Index
/2] = (UINT8
) ((DevicePathBuffer
[Index
/2] << 4) + DigitUint8
);
2670 Selection
->Handle
= DevicePathToHiiHandle (DevicePath
);
2671 if (Selection
->Handle
== NULL
) {
2673 // If target Hii Handle not found, exit
2675 Selection
->Action
= UI_ACTION_EXIT
;
2676 Selection
->Statement
= NULL
;
2680 FreePool (StringPtr
);
2681 FreePool (DevicePath
);
2683 CopyMem (&Selection
->FormSetGuid
, &Statement
->RefFormSetId
, sizeof (EFI_GUID
));
2684 Selection
->FormId
= Statement
->RefFormId
;
2685 Selection
->QuestionId
= Statement
->RefQuestionId
;
2686 } else if (!CompareGuid (&Statement
->RefFormSetId
, &gZeroGuid
)) {
2687 if (Selection
->Form
->ModalForm
) {
2691 // Goto another Formset, check for uncommitted data
2693 Selection
->Action
= UI_ACTION_REFRESH_FORMSET
;
2695 CopyMem (&Selection
->FormSetGuid
, &Statement
->RefFormSetId
, sizeof (EFI_GUID
));
2696 Selection
->FormId
= Statement
->RefFormId
;
2697 Selection
->QuestionId
= Statement
->RefQuestionId
;
2698 } else if (Statement
->RefFormId
!= 0) {
2700 // Check whether target From is suppressed.
2702 RefForm
= IdToForm (Selection
->FormSet
, Statement
->RefFormId
);
2704 if ((RefForm
!= NULL
) && (RefForm
->SuppressExpression
!= NULL
)) {
2705 Status
= EvaluateExpression (Selection
->FormSet
, RefForm
, RefForm
->SuppressExpression
);
2706 if (EFI_ERROR (Status
)) {
2710 if (RefForm
->SuppressExpression
->Result
.Value
.b
) {
2712 // Form is suppressed.
2715 CreateDialog (4, TRUE
, 0, NULL
, &Key
, gEmptyString
, gFormSuppress
, gPressEnter
, gEmptyString
);
2716 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
2724 // Goto another form inside this formset,
2726 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2729 // Link current form so that we can always go back when someone hits the ESC
2731 MenuList
= UiFindMenuList (&Selection
->FormSetGuid
, Statement
->RefFormId
);
2732 if (MenuList
== NULL
) {
2733 MenuList
= UiAddMenuList (CurrentMenu
, &Selection
->FormSetGuid
, Statement
->RefFormId
);
2736 Selection
->FormId
= Statement
->RefFormId
;
2737 Selection
->QuestionId
= Statement
->RefQuestionId
;
2738 } else if (Statement
->RefQuestionId
!= 0) {
2740 // Goto another Question
2742 Selection
->QuestionId
= Statement
->RefQuestionId
;
2744 if ((Statement
->QuestionFlags
& EFI_IFR_FLAG_CALLBACK
) != 0) {
2745 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2754 case EFI_IFR_ACTION_OP
:
2756 // Process the Config string <ConfigResp>
2758 Status
= ProcessQuestionConfig (Selection
, Statement
);
2760 if (EFI_ERROR (Status
)) {
2765 // The action button may change some Question value, so refresh the form
2767 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2770 case EFI_IFR_RESET_BUTTON_OP
:
2772 // Reset Question to default value specified by DefaultId
2774 ControlFlag
= CfUiDefault
;
2775 DefaultId
= Statement
->DefaultId
;
2780 // Editable Questions: oneof, ordered list, checkbox, numeric, string, password
2782 UpdateKeyHelp (Selection
, MenuOption
, TRUE
);
2783 Status
= ProcessOptions (Selection
, MenuOption
, TRUE
, &OptionString
);
2785 if (EFI_ERROR (Status
)) {
2788 UpdateKeyHelp (Selection
, MenuOption
, FALSE
);
2790 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
2793 if (OptionString
!= NULL
) {
2794 FreePool (OptionString
);
2802 // We come here when someone press ESC
2804 ControlFlag
= CfCheckSelection
;
2805 if (FindNextMenu (Selection
, &Repaint
, &NewLine
)) {
2811 ControlFlag
= CfCheckSelection
;
2812 ASSERT(MenuOption
!= NULL
);
2813 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
2814 if (MenuOption
->Sequence
!= 0) {
2816 // In the middle or tail of the Date/Time op-code set, go left.
2818 ASSERT(NewPos
!= NULL
);
2819 NewPos
= NewPos
->BackLink
;
2825 ControlFlag
= CfCheckSelection
;
2826 ASSERT(MenuOption
!= NULL
);
2827 if ((MenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)) {
2828 if (MenuOption
->Sequence
!= 2) {
2830 // In the middle or tail of the Date/Time op-code set, go left.
2832 ASSERT(NewPos
!= NULL
);
2833 NewPos
= NewPos
->ForwardLink
;
2839 ControlFlag
= CfCheckSelection
;
2841 SavedListEntry
= NewPos
;
2843 ASSERT(NewPos
!= NULL
);
2845 // Adjust Date/Time position before we advance forward.
2847 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2848 if (NewPos
->BackLink
!= &gMenuOption
) {
2849 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2851 NewPos
= NewPos
->BackLink
;
2853 PreviousMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2854 DistanceValue
= PreviousMenuOption
->Skip
;
2856 if (MenuOption
->Row
>= DistanceValue
+ TopRow
) {
2857 Difference
= MoveToNextStatement (TRUE
, &NewPos
, MenuOption
->Row
- TopRow
- DistanceValue
);
2859 NextMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2861 ASSERT (MenuOption
!= NULL
);
2862 if (Difference
< 0) {
2864 // We hit the begining MenuOption that can be focused
2865 // so we simply scroll to the top.
2867 if (TopOfScreen
!= gMenuOption
.ForwardLink
) {
2868 TopOfScreen
= gMenuOption
.ForwardLink
;
2872 // Scroll up to the last page when we have arrived at top page.
2874 NewPos
= &gMenuOption
;
2875 TopOfScreen
= &gMenuOption
;
2876 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
2877 ScreenOperation
= UiPageUp
;
2878 ControlFlag
= CfScreenOperation
;
2881 } else if (MenuOption
->Row
< TopRow
+ DistanceValue
+ Difference
) {
2883 // Previous focus MenuOption is above the TopOfScreen, so we need to scroll
2885 TopOfScreen
= NewPos
;
2889 } else if (!IsSelectable (NextMenuOption
)) {
2891 // Continue to go up until scroll to next page or the selectable option is found.
2893 ScreenOperation
= UiUp
;
2894 ControlFlag
= CfScreenOperation
;
2898 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
2900 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2901 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2902 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
2903 UpdateStatusBar (Selection
, INPUT_ERROR
, MenuOption
->ThisTag
->QuestionFlags
, FALSE
);
2906 // Scroll up to the last page.
2908 NewPos
= &gMenuOption
;
2909 TopOfScreen
= &gMenuOption
;
2910 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
2911 ScreenOperation
= UiPageUp
;
2912 ControlFlag
= CfScreenOperation
;
2917 ControlFlag
= CfCheckSelection
;
2919 ASSERT(NewPos
!= NULL
);
2920 if (NewPos
->BackLink
== &gMenuOption
) {
2930 while ((Index
>= TopRow
) && (Link
->BackLink
!= &gMenuOption
)) {
2931 Link
= Link
->BackLink
;
2932 PreviousMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2933 if (Index
< PreviousMenuOption
->Skip
) {
2937 Index
= Index
- PreviousMenuOption
->Skip
;
2940 if ((Link
->BackLink
== &gMenuOption
) && (Index
>= TopRow
)) {
2941 if (TopOfScreen
== &gMenuOption
) {
2942 TopOfScreen
= gMenuOption
.ForwardLink
;
2943 NewPos
= gMenuOption
.BackLink
;
2944 MoveToNextStatement (TRUE
, &NewPos
, BottomRow
- TopRow
);
2946 } else if (TopOfScreen
!= Link
) {
2949 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
2952 // Finally we know that NewPos is the last MenuOption can be focused.
2956 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
2959 if (Index
+ 1 < TopRow
) {
2961 // Back up the previous option.
2963 Link
= Link
->ForwardLink
;
2967 // Move to the option in Next page.
2969 if (TopOfScreen
== &gMenuOption
) {
2970 NewPos
= gMenuOption
.BackLink
;
2971 MoveToNextStatement (TRUE
, &NewPos
, BottomRow
- TopRow
);
2974 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
2978 // There are more MenuOption needing scrolling up.
2985 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
2986 // Don't do this when we are already in the first page.
2988 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2989 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2993 ControlFlag
= CfCheckSelection
;
2995 ASSERT (NewPos
!= NULL
);
2996 if (NewPos
->ForwardLink
== &gMenuOption
) {
3005 NextMenuOption
= MENU_OPTION_FROM_LINK (Link
);
3007 while ((Index
<= BottomRow
) && (Link
->ForwardLink
!= &gMenuOption
)) {
3008 Index
= Index
+ NextMenuOption
->Skip
;
3009 Link
= Link
->ForwardLink
;
3010 NextMenuOption
= MENU_OPTION_FROM_LINK (Link
);
3013 if ((Link
->ForwardLink
== &gMenuOption
) && (Index
<= BottomRow
)) {
3015 // Finally we know that NewPos is the last MenuOption can be focused.
3018 MoveToNextStatement (TRUE
, &Link
, Index
- TopRow
);
3020 if (Index
- 1 > BottomRow
) {
3022 // Back up the previous option.
3024 Link
= Link
->BackLink
;
3027 // There are more MenuOption needing scrolling down.
3032 // Move to the option in Next page.
3034 MoveToNextStatement (FALSE
, &Link
, BottomRow
- TopRow
);
3038 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
3039 // Don't do this when we are already in the last page.
3042 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3043 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3047 ControlFlag
= CfCheckSelection
;
3049 // Since the behavior of hitting the down arrow on a Date/Time op-code is intended
3050 // to be one that progresses to the next set of op-codes, we need to advance to the last
3051 // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate
3052 // checking can be done. The only other logic we need to introduce is that if a Date/Time
3053 // op-code is the last entry in the menu, we need to rewind back to the first op-code of
3054 // the Date/Time op-code.
3056 SavedListEntry
= NewPos
;
3057 AdjustDateAndTimePosition (FALSE
, &NewPos
);
3059 if (NewPos
->ForwardLink
!= &gMenuOption
) {
3060 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3062 NewPos
= NewPos
->ForwardLink
;
3065 if (BottomRow
>= MenuOption
->Row
+ MenuOption
->Skip
) {
3066 Difference
= MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- MenuOption
->Row
- MenuOption
->Skip
);
3068 // We hit the end of MenuOption that can be focused
3069 // so we simply scroll to the first page.
3071 if (Difference
< 0) {
3073 // Scroll to the first page.
3075 if (TopOfScreen
!= gMenuOption
.ForwardLink
) {
3076 TopOfScreen
= gMenuOption
.ForwardLink
;
3080 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3082 NewPos
= gMenuOption
.ForwardLink
;
3083 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
3086 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
3088 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3089 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3093 NextMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3096 // An option might be multi-line, so we need to reflect that data in the overall skip value
3098 UpdateOptionSkipLines (Selection
, NextMenuOption
, &OptionString
, (UINTN
) SkipValue
);
3099 DistanceValue
= Difference
+ NextMenuOption
->Skip
;
3101 Temp
= MenuOption
->Row
+ MenuOption
->Skip
+ DistanceValue
- 1;
3102 if ((MenuOption
->Row
+ MenuOption
->Skip
== BottomRow
+ 1) &&
3103 (NextMenuOption
->ThisTag
->Operand
== EFI_IFR_DATE_OP
||
3104 NextMenuOption
->ThisTag
->Operand
== EFI_IFR_TIME_OP
)
3110 // If we are going to scroll, update TopOfScreen
3112 if (Temp
> BottomRow
) {
3115 // Is the current top of screen a zero-advance op-code?
3116 // If so, keep moving forward till we hit a >0 advance op-code
3118 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3121 // If bottom op-code is more than one line or top op-code is more than one line
3123 if ((DistanceValue
> 1) || (MenuOption
->Skip
> 1)) {
3125 // Is the bottom op-code greater than or equal in size to the top op-code?
3127 if ((Temp
- BottomRow
) >= (SavedMenuOption
->Skip
- OldSkipValue
)) {
3129 // Skip the top op-code
3131 TopOfScreen
= TopOfScreen
->ForwardLink
;
3132 Difference
= (Temp
- BottomRow
) - (SavedMenuOption
->Skip
- OldSkipValue
);
3134 OldSkipValue
= Difference
;
3136 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3139 // If we have a remainder, skip that many more op-codes until we drain the remainder
3141 while (Difference
>= (INTN
) SavedMenuOption
->Skip
) {
3143 // Since the Difference is greater than or equal to this op-code's skip value, skip it
3145 Difference
= Difference
- (INTN
) SavedMenuOption
->Skip
;
3146 TopOfScreen
= TopOfScreen
->ForwardLink
;
3147 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3150 // Since we will act on this op-code in the next routine, and increment the
3151 // SkipValue, set the skips to one less than what is required.
3153 SkipValue
= Difference
- 1;
3157 // Since we will act on this op-code in the next routine, and increment the
3158 // SkipValue, set the skips to one less than what is required.
3160 SkipValue
= OldSkipValue
+ (Temp
- BottomRow
) - 1;
3163 if ((OldSkipValue
+ 1) == (INTN
) SavedMenuOption
->Skip
) {
3164 TopOfScreen
= TopOfScreen
->ForwardLink
;
3167 SkipValue
= OldSkipValue
;
3171 // If the op-code at the top of the screen is more than one line, let's not skip it yet
3172 // Let's set a skip flag to smoothly scroll the top of the screen.
3174 if (SavedMenuOption
->Skip
> 1) {
3175 if (SavedMenuOption
== NextMenuOption
) {
3180 } else if (SavedMenuOption
->Skip
== 1) {
3184 TopOfScreen
= TopOfScreen
->ForwardLink
;
3186 } while (SavedMenuOption
->Skip
== 0);
3189 OldSkipValue
= SkipValue
;
3190 } else if (!IsSelectable (NextMenuOption
)) {
3192 // Continue to go down until scroll to next page or the selectable option is found.
3194 ScreenOperation
= UiDown
;
3195 ControlFlag
= CfScreenOperation
;
3198 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3200 UpdateStatusBar (Selection
, INPUT_ERROR
, MenuOption
->ThisTag
->QuestionFlags
, FALSE
);
3204 // Scroll to the first page.
3206 if (TopOfScreen
!= gMenuOption
.ForwardLink
) {
3207 TopOfScreen
= gMenuOption
.ForwardLink
;
3211 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3214 NewPos
= gMenuOption
.ForwardLink
;
3215 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
3219 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
3221 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3222 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3226 ControlFlag
= CfCheckSelection
;
3231 Status
= SubmitForm (Selection
->FormSet
, Selection
->Form
, FALSE
);
3233 if (!EFI_ERROR (Status
)) {
3234 ASSERT(MenuOption
!= NULL
);
3235 UpdateStatusBar (Selection
, INPUT_ERROR
, MenuOption
->ThisTag
->QuestionFlags
, FALSE
);
3236 UpdateStatusBar (Selection
, NV_UPDATE_REQUIRED
, MenuOption
->ThisTag
->QuestionFlags
, FALSE
);
3239 CreateDialog (4, TRUE
, 0, NULL
, &Key
, gEmptyString
, gSaveFailed
, gPressEnter
, gEmptyString
);
3240 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
3248 ControlFlag
= CfCheckSelection
;
3249 if (!Selection
->FormEditable
) {
3251 // This Form is not editable, ignore the F9 (reset to default)
3256 Status
= ExtractFormDefault (Selection
->FormSet
, Selection
->Form
, DefaultId
);
3258 if (!EFI_ERROR (Status
)) {
3259 Selection
->Action
= UI_ACTION_REFRESH_FORM
;
3260 Selection
->Statement
= NULL
;
3263 // Show NV update flag on status bar
3265 UpdateNvInfoInForm(Selection
->FormSet
, TRUE
);
3266 gResetRequired
= TRUE
;
3270 case CfUiNoOperation
:
3271 ControlFlag
= CfCheckSelection
;
3275 UiFreeRefreshList ();
3277 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
3278 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, Row
+ 4);
3279 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
3280 gST
->ConOut
->OutputString (gST
->ConOut
, L
"\n");