2 Entry and initialization module for the browser.
4 Copyright (c) 2007 - 2013, 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.
15 #include "FormDisplay.h"
18 // Search table for UiDisplayMenu()
20 SCAN_CODE_TO_SCREEN_OPERATION gScanCodeToOperation
[] = {
51 UINTN mScanCodeNumber
= sizeof (gScanCodeToOperation
) / sizeof (gScanCodeToOperation
[0]);
53 SCREEN_OPERATION_T0_CONTROL_FLAG gScreenOperationToControlFlag
[] = {
96 EFI_GUID gDisplayEngineGuid
= {
97 0xE38C1029, 0xE38F, 0x45b9, {0x8F, 0x0D, 0xE2, 0xE6, 0x0B, 0xC9, 0xB2, 0x62}
100 FORM_ENTRY_INFO gFormEntryInfo
;
102 EFI_SCREEN_DESCRIPTOR gStatementDimensions
;
103 BOOLEAN mStatementLayoutIsChanged
= TRUE
;
104 USER_INPUT
*gUserInput
;
105 FORM_DISPLAY_ENGINE_FORM
*gFormData
;
106 EFI_HII_HANDLE gHiiHandle
;
108 LIST_ENTRY gMenuOption
;
109 DISPLAY_HIGHLIGHT_MENU_INFO gHighligthMenuInfo
= {0};
110 BOOLEAN mIsFirstForm
= TRUE
;
111 FORM_ENTRY_INFO gOldFormEntry
= {0};
114 // Browser Global Strings
116 CHAR16
*gFormNotFound
;
118 CHAR16
*gBrwoserError
;
120 CHAR16
*gPromptForData
;
121 CHAR16
*gPromptForPassword
;
122 CHAR16
*gPromptForNewPassword
;
123 CHAR16
*gConfirmPassword
;
124 CHAR16
*gConfirmError
;
125 CHAR16
*gPassowordInvalid
;
127 CHAR16
*gEmptyString
;
129 CHAR16
*gOptionMismatch
;
130 CHAR16
*gFormSuppress
;
131 CHAR16
*gProtocolNotFound
;
133 CHAR16 gModalSkipColumn
;
134 CHAR16 gPromptBlockWidth
;
135 CHAR16 gOptionBlockWidth
;
136 CHAR16 gHelpBlockWidth
;
137 CHAR16
*mUnknownString
;
139 FORM_DISPLAY_DRIVER_PRIVATE_DATA mPrivateData
= {
140 FORM_DISPLAY_DRIVER_SIGNATURE
,
144 DriverClearDisplayPage
,
151 Get the string based on the StringId and HII Package List Handle.
153 @param Token The String's ID.
154 @param HiiHandle The package list in the HII database to search for
155 the specified string.
157 @return The output string.
162 IN EFI_STRING_ID Token
,
163 IN EFI_HII_HANDLE HiiHandle
168 String
= HiiGetString (HiiHandle
, Token
, NULL
);
169 if (String
== NULL
) {
170 String
= AllocateCopyPool (StrSize (mUnknownString
), mUnknownString
);
171 ASSERT (String
!= NULL
);
174 return (CHAR16
*) String
;
179 Initialize the HII String Token to the correct values.
183 InitializeDisplayStrings (
187 mUnknownString
= GetToken (STRING_TOKEN (UNKNOWN_STRING
), gHiiHandle
);
188 gSaveFailed
= GetToken (STRING_TOKEN (SAVE_FAILED
), gHiiHandle
);
189 gPromptForData
= GetToken (STRING_TOKEN (PROMPT_FOR_DATA
), gHiiHandle
);
190 gPromptForPassword
= GetToken (STRING_TOKEN (PROMPT_FOR_PASSWORD
), gHiiHandle
);
191 gPromptForNewPassword
= GetToken (STRING_TOKEN (PROMPT_FOR_NEW_PASSWORD
), gHiiHandle
);
192 gConfirmPassword
= GetToken (STRING_TOKEN (CONFIRM_PASSWORD
), gHiiHandle
);
193 gConfirmError
= GetToken (STRING_TOKEN (CONFIRM_ERROR
), gHiiHandle
);
194 gPassowordInvalid
= GetToken (STRING_TOKEN (PASSWORD_INVALID
), gHiiHandle
);
195 gPressEnter
= GetToken (STRING_TOKEN (PRESS_ENTER
), gHiiHandle
);
196 gEmptyString
= GetToken (STRING_TOKEN (EMPTY_STRING
), gHiiHandle
);
197 gMiniString
= GetToken (STRING_TOKEN (MINI_STRING
), gHiiHandle
);
198 gOptionMismatch
= GetToken (STRING_TOKEN (OPTION_MISMATCH
), gHiiHandle
);
199 gFormSuppress
= GetToken (STRING_TOKEN (FORM_SUPPRESSED
), gHiiHandle
);
200 gProtocolNotFound
= GetToken (STRING_TOKEN (PROTOCOL_NOT_FOUND
), gHiiHandle
);
201 gFormNotFound
= GetToken (STRING_TOKEN (STATUS_BROWSER_FORM_NOT_FOUND
), gHiiHandle
);
202 gNoSubmitIf
= GetToken (STRING_TOKEN (STATUS_BROWSER_NO_SUBMIT_IF
), gHiiHandle
);
203 gBrwoserError
= GetToken (STRING_TOKEN (STATUS_BROWSER_ERROR
), gHiiHandle
);
207 Free up the resource allocated for all strings required
216 FreePool (mUnknownString
);
217 FreePool (gEmptyString
);
218 FreePool (gSaveFailed
);
219 FreePool (gPromptForData
);
220 FreePool (gPromptForPassword
);
221 FreePool (gPromptForNewPassword
);
222 FreePool (gConfirmPassword
);
223 FreePool (gConfirmError
);
224 FreePool (gPassowordInvalid
);
225 FreePool (gPressEnter
);
226 FreePool (gMiniString
);
227 FreePool (gOptionMismatch
);
228 FreePool (gFormSuppress
);
229 FreePool (gProtocolNotFound
);
230 FreePool (gBrwoserError
);
231 FreePool (gNoSubmitIf
);
232 FreePool (gFormNotFound
);
236 Get prompt string id from the opcode data buffer.
238 @param OpCode The input opcode buffer.
240 @return The prompt string id.
245 IN EFI_IFR_OP_HEADER
*OpCode
248 EFI_IFR_STATEMENT_HEADER
*Header
;
250 if (OpCode
->Length
<= sizeof (EFI_IFR_OP_HEADER
)) {
254 Header
= (EFI_IFR_STATEMENT_HEADER
*) (OpCode
+ 1);
256 return Header
->Prompt
;
260 Get the supported width for a particular op-code
262 @param Statement The curent statement.
263 @param AdjustWidth The width which is saved for the space.
265 @return Returns the number of CHAR16 characters that is support.
270 IN FORM_DISPLAY_ENGINE_STATEMENT
*Statement
,
271 OUT UINT16
*AdjustWidth
276 EFI_IFR_TEXT
*TestOp
;
279 // For modal form, clean the entire row.
281 if ((gFormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
282 return (UINT16
)(gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
- gModalSkipColumn
- SCROLL_ARROW_HEIGHT
);
288 // See if the second text parameter is really NULL
290 if (Statement
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) {
291 TestOp
= (EFI_IFR_TEXT
*) Statement
->OpCode
;
292 if (TestOp
->TextTwo
!= 0) {
293 String
= GetToken (TestOp
->TextTwo
, gFormData
->HiiHandle
);
294 Size
= StrLen (String
);
299 if ((Statement
->OpCode
->OpCode
== EFI_IFR_SUBTITLE_OP
) ||
300 (Statement
->OpCode
->OpCode
== EFI_IFR_REF_OP
) ||
301 (Statement
->OpCode
->OpCode
== EFI_IFR_PASSWORD_OP
) ||
302 (Statement
->OpCode
->OpCode
== EFI_IFR_ACTION_OP
) ||
303 (Statement
->OpCode
->OpCode
== EFI_IFR_RESET_BUTTON_OP
) ||
305 // Allow a wide display if text op-code and no secondary text op-code
307 ((Statement
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) && (Size
== 0))
311 // Return the space width.
313 if (AdjustWidth
!= NULL
) {
317 // Keep consistent with current behavior.
319 return (UINT16
) (gPromptBlockWidth
+ gOptionBlockWidth
- 2);
322 if (AdjustWidth
!= NULL
) {
325 return (UINT16
) (gPromptBlockWidth
- 1);
329 Will copy LineWidth amount of a string in the OutputString buffer and return the
330 number of CHAR16 characters that were copied into the OutputString buffer.
331 The output string format is:
332 Glyph Info + String info + '\0'.
334 In the code, it deals \r,\n,\r\n same as \n\r, also it not process the \r or \g.
336 @param InputString String description for this option.
337 @param LineWidth Width of the desired string to extract in CHAR16
339 @param GlyphWidth The glyph width of the begin of the char in the string.
340 @param Index Where in InputString to start the copy process
341 @param OutputString Buffer to copy the string into
343 @return Returns the number of CHAR16 characters that were copied into the OutputString
344 buffer, include extra glyph info and '\0' info.
349 IN CHAR16
*InputString
,
351 IN OUT UINT16
*GlyphWidth
,
353 OUT CHAR16
**OutputString
358 UINT16 OriginalGlyphWidth
;
360 UINT16 LastSpaceOffset
;
361 UINT16 LastGlyphWidth
;
363 if (InputString
== NULL
|| Index
== NULL
|| OutputString
== NULL
) {
367 if (LineWidth
== 0 || *GlyphWidth
== 0) {
372 // Save original glyph width.
374 OriginalGlyphWidth
= *GlyphWidth
;
375 LastGlyphWidth
= OriginalGlyphWidth
;
380 // 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.
381 // To avoid displaying this empty line in screen, just skip the two CHARs here.
383 if ((InputString
[*Index
] == NARROW_CHAR
) && (InputString
[*Index
+ 1] == CHAR_CARRIAGE_RETURN
)) {
388 // Fast-forward the string and see if there is a carriage-return in the string
390 for (StrOffset
= 0, GlyphOffset
= 0; GlyphOffset
<= LineWidth
; StrOffset
++) {
391 switch (InputString
[*Index
+ StrOffset
]) {
400 case CHAR_CARRIAGE_RETURN
:
407 GlyphOffset
= GlyphOffset
+ *GlyphWidth
;
410 // Record the last space info in this line. Will be used in rewind.
412 if ((InputString
[*Index
+ StrOffset
] == CHAR_SPACE
) && (GlyphOffset
<= LineWidth
)) {
413 LastSpaceOffset
= StrOffset
;
414 LastGlyphWidth
= *GlyphWidth
;
425 // Rewind the string from the maximum size until we see a space to break the line
427 if (GlyphOffset
> LineWidth
) {
429 // Rewind the string to last space char in this line.
431 if (LastSpaceOffset
!= 0) {
432 StrOffset
= LastSpaceOffset
;
433 *GlyphWidth
= LastGlyphWidth
;
436 // Roll back to last char in the line width.
443 // The CHAR_NULL has process last time, this time just return 0 to stand for the end.
445 if (StrOffset
== 0 && (InputString
[*Index
+ StrOffset
] == CHAR_NULL
)) {
450 // Need extra glyph info and '\0' info, so +2.
452 *OutputString
= AllocateZeroPool (((UINTN
) (StrOffset
+ 2) * sizeof(CHAR16
)));
453 if (*OutputString
== NULL
) {
458 // Save the glyph info at the begin of the string, will used by Print function.
460 if (OriginalGlyphWidth
== 1) {
461 *(*OutputString
) = NARROW_CHAR
;
463 *(*OutputString
) = WIDE_CHAR
;
466 CopyMem ((*OutputString
) + 1, &InputString
[*Index
], StrOffset
* sizeof(CHAR16
));
468 if (InputString
[*Index
+ StrOffset
] == CHAR_SPACE
) {
470 // Skip the space info at the begin of next line.
472 *Index
= (UINT16
) (*Index
+ StrOffset
+ 1);
473 } else if (InputString
[*Index
+ StrOffset
] == CHAR_LINEFEED
) {
475 // Skip the /n or /n/r info.
477 if (InputString
[*Index
+ StrOffset
+ 1] == CHAR_CARRIAGE_RETURN
) {
478 *Index
= (UINT16
) (*Index
+ StrOffset
+ 2);
480 *Index
= (UINT16
) (*Index
+ StrOffset
+ 1);
482 } else if (InputString
[*Index
+ StrOffset
] == CHAR_CARRIAGE_RETURN
) {
484 // Skip the /r or /r/n info.
486 if (InputString
[*Index
+ StrOffset
+ 1] == CHAR_LINEFEED
) {
487 *Index
= (UINT16
) (*Index
+ StrOffset
+ 2);
489 *Index
= (UINT16
) (*Index
+ StrOffset
+ 1);
492 *Index
= (UINT16
) (*Index
+ StrOffset
);
496 // Include extra glyph info and '\0' info, so +2.
498 return StrOffset
+ 2;
502 Add one menu option by specified description and context.
504 @param Statement Statement of this Menu Option.
505 @param MenuItemCount The index for this Option in the Menu.
506 @param NestIn Whether this statement is nest in another statement.
511 IN FORM_DISPLAY_ENGINE_STATEMENT
*Statement
,
512 IN UINT16
*MenuItemCount
,
516 UI_MENU_OPTION
*MenuOption
;
520 UINT16 NumberOfLines
;
524 CHAR16
*OutputString
;
525 EFI_STRING_ID PromptId
;
533 PromptId
= GetPrompt (Statement
->OpCode
);
534 ASSERT (PromptId
!= 0);
536 String
= GetToken (PromptId
, gFormData
->HiiHandle
);
537 ASSERT (String
!= NULL
);
539 Width
= GetWidth (Statement
, NULL
);
540 for (; GetLineByWidth (String
, Width
, &GlyphWidth
,&ArrayEntry
, &OutputString
) != 0x0000;) {
542 // If there is more string to process print on the next row and increment the Skip value
544 if (StrLen (&String
[ArrayEntry
]) != 0) {
547 FreePool (OutputString
);
550 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
|| Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
552 // Add three MenuOptions for Date/Time
553 // Data format : [01/02/2004] [11:22:33]
554 // Line number : 0 0 1 0 0 1
560 for (Index
= 0; Index
< Count
; Index
++) {
561 MenuOption
= AllocateZeroPool (sizeof (UI_MENU_OPTION
));
564 MenuOption
->Signature
= UI_MENU_OPTION_SIGNATURE
;
565 MenuOption
->Description
= String
;
566 MenuOption
->Handle
= gFormData
->HiiHandle
;
567 MenuOption
->ThisTag
= Statement
;
568 MenuOption
->NestInStatement
= NestIn
;
569 MenuOption
->EntryNumber
= *MenuItemCount
;
573 // Override LineNumber for the MenuOption in Date/Time sequence
575 MenuOption
->Skip
= 1;
577 MenuOption
->Skip
= NumberOfLines
;
579 MenuOption
->Sequence
= Index
;
581 if ((Statement
->Attribute
& HII_DISPLAY_GRAYOUT
) != 0) {
582 MenuOption
->GrayOut
= TRUE
;
584 MenuOption
->GrayOut
= FALSE
;
587 if ((Statement
->Attribute
& HII_DISPLAY_LOCK
) != 0 || (gFormData
->Attribute
& HII_DISPLAY_LOCK
) != 0) {
588 MenuOption
->GrayOut
= TRUE
;
592 // If the form or the question has the lock attribute, deal same as grayout.
594 if ((gFormData
->Attribute
& HII_DISPLAY_LOCK
) != 0 || (Statement
->Attribute
& HII_DISPLAY_LOCK
) != 0) {
595 MenuOption
->GrayOut
= TRUE
;
598 switch (Statement
->OpCode
->OpCode
) {
599 case EFI_IFR_ORDERED_LIST_OP
:
600 case EFI_IFR_ONE_OF_OP
:
601 case EFI_IFR_NUMERIC_OP
:
602 case EFI_IFR_TIME_OP
:
603 case EFI_IFR_DATE_OP
:
604 case EFI_IFR_CHECKBOX_OP
:
605 case EFI_IFR_PASSWORD_OP
:
606 case EFI_IFR_STRING_OP
:
608 // User could change the value of these items
610 MenuOption
->IsQuestion
= TRUE
;
612 case EFI_IFR_TEXT_OP
:
613 if (FeaturePcdGet (PcdBrowserGrayOutTextStatement
)) {
615 // Initializing GrayOut option as TRUE for Text setup options
616 // so that those options will be Gray in colour and un selectable.
618 MenuOption
->GrayOut
= TRUE
;
622 MenuOption
->IsQuestion
= FALSE
;
626 if ((Statement
->Attribute
& HII_DISPLAY_READONLY
) != 0) {
627 MenuOption
->ReadOnly
= TRUE
;
628 if (FeaturePcdGet (PcdBrowerGrayOutReadOnlyMenu
)) {
629 MenuOption
->GrayOut
= TRUE
;
633 InsertTailList (&gMenuOption
, &MenuOption
->Link
);
640 Create the menu list base on the form data info.
644 ConvertStatementToMenu (
648 UINT16 MenuItemCount
;
650 LIST_ENTRY
*NestLink
;
651 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
652 FORM_DISPLAY_ENGINE_STATEMENT
*NestStatement
;
655 InitializeListHead (&gMenuOption
);
657 Link
= GetFirstNode (&gFormData
->StatementListHead
);
658 while (!IsNull (&gFormData
->StatementListHead
, Link
)) {
659 Statement
= FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link
);
660 Link
= GetNextNode (&gFormData
->StatementListHead
, Link
);
663 // Skip the opcode not recognized by Display core.
665 if (Statement
->OpCode
->OpCode
== EFI_IFR_GUID_OP
) {
669 UiAddMenuOption (Statement
, &MenuItemCount
, FALSE
);
672 // Check the statement nest in this host statement.
674 NestLink
= GetFirstNode (&Statement
->NestStatementList
);
675 while (!IsNull (&Statement
->NestStatementList
, NestLink
)) {
676 NestStatement
= FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (NestLink
);
677 NestLink
= GetNextNode (&Statement
->NestStatementList
, NestLink
);
679 UiAddMenuOption (NestStatement
, &MenuItemCount
, TRUE
);
685 Count the storage space of a Unicode string.
687 This function handles the Unicode string with NARROW_CHAR
688 and WIDE_CHAR control characters. NARROW_HCAR and WIDE_CHAR
689 does not count in the resultant output. If a WIDE_CHAR is
690 hit, then 2 Unicode character will consume an output storage
691 space with size of CHAR16 till a NARROW_CHAR is hit.
693 If String is NULL, then ASSERT ().
695 @param String The input string to be counted.
697 @return Storage space for the input string.
707 UINTN IncrementValue
;
709 ASSERT (String
!= NULL
);
710 if (String
== NULL
) {
720 // Advance to the null-terminator or to the first width directive
723 (String
[Index
] != NARROW_CHAR
) && (String
[Index
] != WIDE_CHAR
) && (String
[Index
] != 0);
724 Index
++, Count
= Count
+ IncrementValue
729 // We hit the null-terminator, we now have a count
731 if (String
[Index
] == 0) {
735 // We encountered a narrow directive - strip it from the size calculation since it doesn't get printed
736 // and also set the flag that determines what we increment by.(if narrow, increment by 1, if wide increment by 2)
738 if (String
[Index
] == NARROW_CHAR
) {
740 // Skip to the next character
746 // Skip to the next character
751 } while (String
[Index
] != 0);
754 // Increment by one to include the null-terminator in the size
758 return Count
* sizeof (CHAR16
);
762 Base on the input option string to update the skip value for a menu option.
764 @param MenuOption The MenuOption to be checked.
765 @param OptionString The input option string.
769 UpdateSkipInfoForMenu (
770 IN UI_MENU_OPTION
*MenuOption
,
771 IN CHAR16
*OptionString
777 CHAR16
*OutputString
;
780 Width
= (UINT16
) gOptionBlockWidth
;
784 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
785 if (StrLen (&OptionString
[Index
]) != 0) {
789 FreePool (OutputString
);
792 if ((Row
> MenuOption
->Skip
) &&
793 (MenuOption
->ThisTag
->OpCode
->OpCode
!= EFI_IFR_DATE_OP
) &&
794 (MenuOption
->ThisTag
->OpCode
->OpCode
!= EFI_IFR_TIME_OP
)) {
795 MenuOption
->Skip
= Row
;
800 Update display lines for a Menu Option.
802 @param MenuOption The MenuOption to be checked.
806 UpdateOptionSkipLines (
807 IN UI_MENU_OPTION
*MenuOption
810 CHAR16
*OptionString
;
814 ProcessOptions (MenuOption
, FALSE
, &OptionString
, TRUE
);
815 if (OptionString
!= NULL
) {
816 UpdateSkipInfoForMenu (MenuOption
, OptionString
);
818 FreePool (OptionString
);
821 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) && (((EFI_IFR_TEXT
*)MenuOption
->ThisTag
->OpCode
)->TextTwo
!= 0)) {
822 OptionString
= GetToken (((EFI_IFR_TEXT
*)MenuOption
->ThisTag
->OpCode
)->TextTwo
, gFormData
->HiiHandle
);
824 if (OptionString
!= NULL
) {
825 UpdateSkipInfoForMenu (MenuOption
, OptionString
);
827 FreePool (OptionString
);
833 Check whether this Menu Option could be highlighted.
835 This is an internal function.
837 @param MenuOption The MenuOption to be checked.
839 @retval TRUE This Menu Option is selectable.
840 @retval FALSE This Menu Option could not be selected.
845 UI_MENU_OPTION
*MenuOption
848 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_SUBTITLE_OP
) ||
849 MenuOption
->GrayOut
|| MenuOption
->ReadOnly
) {
857 Move to next selectable statement.
859 This is an internal function.
861 @param GoUp The navigation direction. TRUE: up, FALSE: down.
862 @param CurrentPosition Current position.
863 @param GapToTop Gap position to top or bottom.
865 @return The row distance from current MenuOption to next selectable MenuOption.
867 @retval -1 Reach the begin of the menu, still can't find the selectable menu.
868 @retval Value Find the selectable menu, maybe the truly selectable, maybe the l
869 last menu showing at current form.
873 MoveToNextStatement (
875 IN OUT LIST_ENTRY
**CurrentPosition
,
881 UI_MENU_OPTION
*NextMenuOption
;
882 UI_MENU_OPTION
*PreMenuOption
;
885 Pos
= *CurrentPosition
;
886 PreMenuOption
= MENU_OPTION_FROM_LINK (Pos
);
889 NextMenuOption
= MENU_OPTION_FROM_LINK (Pos
);
891 // NextMenuOption->Row == 0 means this menu has not calculate
892 // the NextMenuOption->Skip value yet, just calculate here.
894 if (NextMenuOption
->Row
== 0) {
895 UpdateOptionSkipLines (NextMenuOption
);
898 if (GoUp
&& (PreMenuOption
!= NextMenuOption
)) {
900 // In this case, still can't find the selectable menu,
901 // return the last one in the showing form.
903 if ((UINTN
) Distance
+ NextMenuOption
->Skip
> GapToTop
) {
904 NextMenuOption
= PreMenuOption
;
909 // Current Position doesn't need to be caculated when go up.
910 // Caculate distanct at first when go up
912 Distance
+= NextMenuOption
->Skip
;
915 if (IsSelectable (NextMenuOption
)) {
920 // Arrive at begin of the menu list.
922 if ((GoUp
? Pos
->BackLink
: Pos
->ForwardLink
) == &gMenuOption
) {
929 // In this case, still can't find the selectable menu,
930 // return the last one in the showing form.
932 if ((UINTN
) Distance
+ NextMenuOption
->Skip
> GapToTop
) {
933 NextMenuOption
= PreMenuOption
;
937 Distance
+= NextMenuOption
->Skip
;
940 PreMenuOption
= NextMenuOption
;
941 Pos
= (GoUp
? Pos
->BackLink
: Pos
->ForwardLink
);
944 *CurrentPosition
= &NextMenuOption
->Link
;
950 Process option string for date/time opcode.
952 @param MenuOption Menu option point to date/time.
953 @param OptionString Option string input for process.
954 @param AddOptCol Whether need to update MenuOption->OptCol.
958 ProcessStringForDateTime (
959 UI_MENU_OPTION
*MenuOption
,
960 CHAR16
*OptionString
,
966 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
970 ASSERT (MenuOption
!= NULL
&& OptionString
!= NULL
);
972 Statement
= MenuOption
->ThisTag
;
975 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) {
976 Date
= (EFI_IFR_DATE
*) Statement
->OpCode
;
977 } else if (Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
978 Time
= (EFI_IFR_TIME
*) Statement
->OpCode
;
982 // If leading spaces on OptionString - remove the spaces
984 for (Index
= 0; OptionString
[Index
] == L
' '; Index
++) {
986 // Base on the blockspace to get the option column info.
989 MenuOption
->OptCol
++;
993 for (Count
= 0; OptionString
[Index
] != CHAR_NULL
; Index
++) {
994 OptionString
[Count
] = OptionString
[Index
];
997 OptionString
[Count
] = CHAR_NULL
;
1000 // Enable to suppress field in the opcode base on the flag.
1002 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) {
1004 // OptionString format is: <**: **: ****>
1008 if ((Date
->Flags
& EFI_QF_DATE_MONTH_SUPPRESS
) && (MenuOption
->Sequence
== 0)) {
1010 // At this point, only "<**:" in the optionstring.
1011 // Clean the day's ** field, after clean, the format is "< :"
1013 SetUnicodeMem (&OptionString
[1], 2, L
' ');
1014 } else if ((Date
->Flags
& EFI_QF_DATE_DAY_SUPPRESS
) && (MenuOption
->Sequence
== 1)) {
1016 // At this point, only "**:" in the optionstring.
1017 // Clean the month's "**" field, after clean, the format is " :"
1019 SetUnicodeMem (&OptionString
[0], 2, L
' ');
1020 } else if ((Date
->Flags
& EFI_QF_DATE_YEAR_SUPPRESS
) && (MenuOption
->Sequence
== 2)) {
1022 // At this point, only "****>" in the optionstring.
1023 // Clean the year's "****" field, after clean, the format is " >"
1025 SetUnicodeMem (&OptionString
[0], 4, L
' ');
1027 } else if (Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
1029 // OptionString format is: <**: **: **>
1030 // |hour|minute|second|
1033 if ((Time
->Flags
& QF_TIME_HOUR_SUPPRESS
) && (MenuOption
->Sequence
== 0)) {
1035 // At this point, only "<**:" in the optionstring.
1036 // Clean the hour's ** field, after clean, the format is "< :"
1038 SetUnicodeMem (&OptionString
[1], 2, L
' ');
1039 } else if ((Time
->Flags
& QF_TIME_MINUTE_SUPPRESS
) && (MenuOption
->Sequence
== 1)) {
1041 // At this point, only "**:" in the optionstring.
1042 // Clean the minute's "**" field, after clean, the format is " :"
1044 SetUnicodeMem (&OptionString
[0], 2, L
' ');
1045 } else if ((Time
->Flags
& QF_TIME_SECOND_SUPPRESS
) && (MenuOption
->Sequence
== 2)) {
1047 // At this point, only "**>" in the optionstring.
1048 // Clean the second's "**" field, after clean, the format is " >"
1050 SetUnicodeMem (&OptionString
[0], 2, L
' ');
1057 Adjust Data and Time position accordingly.
1058 Data format : [01/02/2004] [11:22:33]
1059 Line number : 0 0 1 0 0 1
1061 This is an internal function.
1063 @param DirectionUp the up or down direction. False is down. True is
1065 @param CurrentPosition Current position. On return: Point to the last
1066 Option (Year or Second) if up; Point to the first
1067 Option (Month or Hour) if down.
1069 @return Return line number to pad. It is possible that we stand on a zero-advance
1070 @return data or time opcode, so pad one line when we judge if we are going to scroll outside.
1074 AdjustDateAndTimePosition (
1075 IN BOOLEAN DirectionUp
,
1076 IN OUT LIST_ENTRY
**CurrentPosition
1080 LIST_ENTRY
*NewPosition
;
1081 UI_MENU_OPTION
*MenuOption
;
1082 UINTN PadLineNumber
;
1085 NewPosition
= *CurrentPosition
;
1086 MenuOption
= MENU_OPTION_FROM_LINK (NewPosition
);
1088 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) ||
1089 (MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TIME_OP
)) {
1091 // Calculate the distance from current position to the last Date/Time MenuOption
1094 while (MenuOption
->Skip
== 0) {
1096 NewPosition
= NewPosition
->ForwardLink
;
1097 MenuOption
= MENU_OPTION_FROM_LINK (NewPosition
);
1101 NewPosition
= *CurrentPosition
;
1104 // Since the behavior of hitting the up arrow on a Date/Time MenuOption is intended
1105 // to be one that back to the previous set of MenuOptions, we need to advance to the first
1106 // Date/Time MenuOption and leave the remaining logic in CfUiUp intact so the appropriate
1107 // checking can be done.
1109 while (Count
++ < 2) {
1110 NewPosition
= NewPosition
->BackLink
;
1114 // Since the behavior of hitting the down arrow on a Date/Time MenuOption is intended
1115 // to be one that progresses to the next set of MenuOptions, we need to advance to the last
1116 // Date/Time MenuOption and leave the remaining logic in CfUiDown intact so the appropriate
1117 // checking can be done.
1119 while (Count
-- > 0) {
1120 NewPosition
= NewPosition
->ForwardLink
;
1124 *CurrentPosition
= NewPosition
;
1127 return PadLineNumber
;
1131 Get step info from numeric opcode.
1133 @param[in] OpCode The input numeric op code.
1135 @return step info for this opcode.
1139 IN EFI_IFR_OP_HEADER
*OpCode
1142 EFI_IFR_NUMERIC
*NumericOp
;
1145 NumericOp
= (EFI_IFR_NUMERIC
*) OpCode
;
1147 switch (NumericOp
->Flags
& EFI_IFR_NUMERIC_SIZE
) {
1148 case EFI_IFR_NUMERIC_SIZE_1
:
1149 Step
= NumericOp
->data
.u8
.Step
;
1152 case EFI_IFR_NUMERIC_SIZE_2
:
1153 Step
= NumericOp
->data
.u16
.Step
;
1156 case EFI_IFR_NUMERIC_SIZE_4
:
1157 Step
= NumericOp
->data
.u32
.Step
;
1160 case EFI_IFR_NUMERIC_SIZE_8
:
1161 Step
= NumericOp
->data
.u64
.Step
;
1173 Find the registered HotKey based on KeyData.
1175 @param[in] KeyData A pointer to a buffer that describes the keystroke
1176 information for the hot key.
1178 @return The registered HotKey context. If no found, NULL will return.
1181 GetHotKeyFromRegisterList (
1182 IN EFI_INPUT_KEY
*KeyData
1186 BROWSER_HOT_KEY
*HotKey
;
1188 Link
= GetFirstNode (&gFormData
->HotKeyListHead
);
1189 while (!IsNull (&gFormData
->HotKeyListHead
, Link
)) {
1190 HotKey
= BROWSER_HOT_KEY_FROM_LINK (Link
);
1192 if (HotKey
->KeyData
->ScanCode
== KeyData
->ScanCode
) {
1196 Link
= GetNextNode (&gFormData
->HotKeyListHead
, Link
);
1204 Determine if the menu is the last menu that can be selected.
1206 This is an internal function.
1208 @param Direction The scroll direction. False is down. True is up.
1209 @param CurrentPos The current focus.
1211 @return FALSE -- the menu isn't the last menu that can be selected.
1212 @return TRUE -- the menu is the last menu that can be selected.
1217 IN BOOLEAN Direction
,
1218 IN LIST_ENTRY
*CurrentPos
1223 Temp
= Direction
? CurrentPos
->BackLink
: CurrentPos
->ForwardLink
;
1225 if (Temp
== &gMenuOption
) {
1233 Wait for a given event to fire, or for an optional timeout to expire.
1235 @param Event The event to wait for
1237 @retval UI_EVENT_TYPE The type of the event which is trigged.
1249 EFI_EVENT TimerEvent
;
1250 EFI_EVENT WaitList
[3];
1251 UI_EVENT_TYPE EventType
;
1254 Timeout
= FormExitTimeout(gFormData
);
1257 Status
= gBS
->CreateEvent (EVT_TIMER
, 0, NULL
, NULL
, &TimerEvent
);
1260 // Set the timer event
1269 WaitList
[0] = Event
;
1271 if (gFormData
->FormRefreshEvent
!= NULL
) {
1272 WaitList
[EventNum
] = gFormData
->FormRefreshEvent
;
1277 WaitList
[EventNum
] = TimerEvent
;
1281 Status
= gBS
->WaitForEvent (EventNum
, WaitList
, &Index
);
1282 ASSERT_EFI_ERROR (Status
);
1286 EventType
= UIEventKey
;
1290 if (gFormData
->FormRefreshEvent
!= NULL
) {
1291 EventType
= UIEventDriver
;
1293 ASSERT (Timeout
!= 0 && EventNum
== 2);
1294 EventType
= UIEventTimeOut
;
1299 ASSERT (Index
== 2 && EventNum
== 3);
1300 EventType
= UIEventTimeOut
;
1305 gBS
->CloseEvent (TimerEvent
);
1312 Get question id info from the input opcode header.
1314 @param OpCode The input opcode header pointer.
1316 @retval The question id for this opcode.
1321 IN EFI_IFR_OP_HEADER
*OpCode
1324 EFI_IFR_QUESTION_HEADER
*QuestionHeader
;
1326 if (OpCode
->Length
< sizeof (EFI_IFR_OP_HEADER
) + sizeof (EFI_IFR_QUESTION_HEADER
)) {
1330 QuestionHeader
= (EFI_IFR_QUESTION_HEADER
*)((UINT8
*) OpCode
+ sizeof(EFI_IFR_OP_HEADER
));
1332 return QuestionHeader
->QuestionId
;
1336 Find the first menu which will be show at the top.
1338 @param FormData The data info for this form.
1339 @param TopOfScreen The link_entry pointer to top menu.
1340 @param HighlightMenu The menu which will be highlight.
1341 @param SkipValue The skip value for the top menu.
1346 IN FORM_DISPLAY_ENGINE_FORM
*FormData
,
1347 OUT LIST_ENTRY
**TopOfScreen
,
1348 OUT LIST_ENTRY
**HighlightMenu
,
1357 UI_MENU_OPTION
*SavedMenuOption
;
1360 TopRow
= gStatementDimensions
.TopRow
+ SCROLL_ARROW_HEIGHT
;
1361 BottomRow
= gStatementDimensions
.BottomRow
- SCROLL_ARROW_HEIGHT
;
1364 // If not has input highlight statement, just return the first one in this form.
1366 if (FormData
->HighLightedStatement
== NULL
) {
1367 *TopOfScreen
= gMenuOption
.ForwardLink
;
1368 *HighlightMenu
= gMenuOption
.ForwardLink
;
1369 if (!IsListEmpty (&gMenuOption
)) {
1370 MoveToNextStatement (FALSE
, HighlightMenu
, BottomRow
- TopRow
);
1377 // Now base on the input highlight menu to find the top menu in this page.
1378 // Will base on the highlight menu show at the bottom to find the top menu.
1380 NewPos
= gMenuOption
.ForwardLink
;
1381 SavedMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
1383 while ((SavedMenuOption
->ThisTag
!= FormData
->HighLightedStatement
) ||
1384 (SavedMenuOption
->Sequence
!= gSequence
)) {
1385 NewPos
= NewPos
->ForwardLink
;
1386 if (NewPos
== &gMenuOption
) {
1388 // Not Found it, break
1392 SavedMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
1394 ASSERT (SavedMenuOption
->ThisTag
== FormData
->HighLightedStatement
);
1396 *HighlightMenu
= NewPos
;
1398 AdjustDateAndTimePosition(FALSE
, &NewPos
);
1399 SavedMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
1400 UpdateOptionSkipLines (SavedMenuOption
);
1403 // If highlight opcode is date/time, keep the highlight row info not change.
1405 if ((SavedMenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_DATE_OP
|| SavedMenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) &&
1406 (gHighligthMenuInfo
.QuestionId
!= 0) &&
1407 (gHighligthMenuInfo
.QuestionId
== GetQuestionIdInfo(SavedMenuOption
->ThisTag
->OpCode
))) {
1409 // Still show the highlight menu before exit from display engine.
1411 EndRow
= gHighligthMenuInfo
.DisplayRow
+ SavedMenuOption
->Skip
;
1417 // Base on the selected menu will show at the bottome of next page,
1418 // select the menu show at the top of the next page.
1421 for (Index
= TopRow
+ SavedMenuOption
->Skip
; Index
<= EndRow
; ) {
1422 Link
= Link
->BackLink
;
1424 // Already find the first menu in this form, means highlight menu
1425 // will show in first page of this form.
1427 if (Link
== &gMenuOption
) {
1428 *TopOfScreen
= gMenuOption
.ForwardLink
;
1432 SavedMenuOption
= MENU_OPTION_FROM_LINK (Link
);
1433 UpdateOptionSkipLines (SavedMenuOption
);
1434 Index
+= SavedMenuOption
->Skip
;
1438 // Found the menu which will show at the top of the page.
1440 if (Link
== NewPos
) {
1442 // The menu can show more than one pages, just show the menu at the top of the page.
1445 *TopOfScreen
= Link
;
1448 // Check whether need to skip some line for menu shows at the top of the page.
1450 *SkipValue
= Index
- EndRow
;
1451 if (*SkipValue
> 0 && *SkipValue
< (INTN
) SavedMenuOption
->Skip
) {
1452 *TopOfScreen
= Link
;
1455 *TopOfScreen
= Link
->ForwardLink
;
1461 Update highlight menu info.
1463 @param MenuOption The menu opton which is highlight.
1467 UpdateHighlightMenuInfo (
1468 IN UI_MENU_OPTION
*MenuOption
1471 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
1474 // This is the current selected statement
1476 Statement
= MenuOption
->ThisTag
;
1479 // Get the highlight statement.
1481 gUserInput
->SelectedStatement
= Statement
;
1482 gSequence
= (UINT16
) MenuOption
->Sequence
;
1485 // Record highlight row info for date/time opcode.
1487 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
|| Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
1488 gHighligthMenuInfo
.QuestionId
= GetQuestionIdInfo(Statement
->OpCode
);
1489 gHighligthMenuInfo
.DisplayRow
= (UINT16
) MenuOption
->Row
;
1491 gHighligthMenuInfo
.QuestionId
= 0;
1492 gHighligthMenuInfo
.DisplayRow
= 0;
1495 RefreshKeyHelp(gFormData
, Statement
, FALSE
);
1499 Update attribut for this menu.
1501 @param MenuOption The menu opton which this attribut used to.
1502 @param Highlight Whether this menu will be highlight.
1506 SetDisplayAttribute (
1507 IN UI_MENU_OPTION
*MenuOption
,
1508 IN BOOLEAN Highlight
1511 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
1513 Statement
= MenuOption
->ThisTag
;
1516 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetHighlightTextColor ());
1520 if (MenuOption
->GrayOut
) {
1521 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetGrayedTextColor ());
1523 if (Statement
->OpCode
->OpCode
== EFI_IFR_SUBTITLE_OP
) {
1524 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetSubTitleTextColor ());
1526 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
1532 Print string for this menu option.
1534 @param MenuOption The menu opton which this attribut used to.
1535 @param Col The column that this string will be print at.
1536 @param Row The row that this string will be print at.
1537 @param String The string which need to print.
1538 @param Width The width need to print, if string is less than the
1539 width, the block space will be used.
1540 @param Highlight Whether this menu will be highlight.
1545 IN UI_MENU_OPTION
*MenuOption
,
1550 IN BOOLEAN Highlight
1556 // Print string with normal color.
1559 PrintStringAtWithWidth (Col
, Row
, String
, Width
);
1564 // Print the highlight menu string.
1565 // First print the highlight string.
1567 SetDisplayAttribute(MenuOption
, TRUE
);
1568 Length
= PrintStringAt (Col
, Row
, String
);
1571 // Second, clean the empty after the string.
1573 SetDisplayAttribute(MenuOption
, FALSE
);
1574 PrintStringAtWithWidth (Col
+ Length
, Row
, L
"", Width
- Length
);
1578 Print string for this menu option.
1580 @param MenuOption The menu opton which this attribut used to.
1581 @param SkipWidth The skip width between the left to the start of the prompt.
1582 @param BeginCol The begin column for one menu.
1583 @param SkipLine The skip line for this menu.
1584 @param BottomRow The bottom row for this form.
1585 @param Highlight Whether this menu will be highlight.
1587 @retval EFI_SUCESSS Process the user selection success.
1592 IN UI_MENU_OPTION
*MenuOption
,
1597 IN BOOLEAN Highlight
1600 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
1605 CHAR16
*OptionString
;
1606 CHAR16
*OutputString
;
1615 UINTN PromptLineNum
;
1618 Statement
= MenuOption
->ThisTag
;
1619 Col
= MenuOption
->Col
;
1620 Row
= MenuOption
->Row
;
1627 // Set default color.
1629 SetDisplayAttribute (MenuOption
, FALSE
);
1632 // 1. Paint the option string.
1634 Status
= ProcessOptions (MenuOption
, FALSE
, &OptionString
, FALSE
);
1635 if (EFI_ERROR (Status
)) {
1639 if (OptionString
!= NULL
) {
1640 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
|| Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
1642 // Adjust option string for date/time opcode.
1644 ProcessStringForDateTime(MenuOption
, OptionString
, TRUE
);
1647 Width
= (UINT16
) gOptionBlockWidth
- 1;
1651 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
1652 if (((Temp2
== 0)) && (Row
<= BottomRow
)) {
1653 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
|| Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
1655 // For date/time question, it has three menu options for this qustion.
1656 // The first/second menu options with the skip value is 0. the last one
1657 // with skip value is 1.
1659 if (MenuOption
->Skip
!= 0) {
1661 // For date/ time, print the last past (year for date and second for time)
1662 // - 7 means skip [##/##/ for date and [##:##: for time.
1664 DisplayMenuString (MenuOption
,MenuOption
->OptCol
, Row
, OutputString
, Width
+ 1 - 7, Highlight
);
1667 // For date/ time, print the first and second past (year for date and second for time)
1669 DisplayMenuString (MenuOption
, MenuOption
->OptCol
, Row
, OutputString
, StrLen (OutputString
), Highlight
);
1672 DisplayMenuString (MenuOption
, MenuOption
->OptCol
, Row
, OutputString
, Width
+ 1, Highlight
);
1677 // If there is more string to process print on the next row and increment the Skip value
1679 if (StrLen (&OptionString
[Index
]) != 0) {
1683 // Since the Number of lines for this menu entry may or may not be reflected accurately
1684 // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
1685 // some testing to ensure we are keeping this in-sync.
1687 // If the difference in rows is greater than or equal to the skip value, increase the skip value
1689 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
1695 FreePool (OutputString
);
1704 FreePool (OptionString
);
1710 // 2. Pre calculate the skip value.
1712 if ((Statement
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) && (((EFI_IFR_TEXT
*)Statement
->OpCode
)->TextTwo
!= 0)) {
1713 StringPtr
= GetToken (((EFI_IFR_TEXT
*)Statement
->OpCode
)->TextTwo
, gFormData
->HiiHandle
);
1715 Width
= (UINT16
) gOptionBlockWidth
- 1;
1718 for (Index
= 0; GetLineByWidth (StringPtr
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
1719 if (StrLen (&StringPtr
[Index
]) != 0) {
1721 if ((Row
- OriginalRow
) >= MenuOption
->Skip
) {
1725 FreePool (OutputString
);
1729 FreePool (StringPtr
);
1734 // 3. Paint the description.
1736 PromptWidth
= GetWidth (Statement
, &AdjustValue
);
1741 if (MenuOption
->Description
== NULL
|| MenuOption
->Description
[0] == '\0') {
1742 while (Temp
++ < MenuOption
->Skip
) {
1743 PrintStringAtWithWidth (BeginCol
, Row
++, L
"", PromptWidth
+ AdjustValue
+ SkipWidth
);
1746 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, PromptWidth
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
1747 if ((Temp
== 0) && (Row
<= BottomRow
)) {
1749 // 1.Clean the start LEFT_SKIPPED_COLUMNS
1751 PrintStringAtWithWidth (BeginCol
, Row
, L
"", SkipWidth
);
1753 if (Statement
->OpCode
->OpCode
== EFI_IFR_REF_OP
&& MenuOption
->Col
>= 2) {
1755 // Print Arrow for Goto button.
1758 MenuOption
->Col
- 2,
1760 GEOMETRICSHAPE_RIGHT_TRIANGLE
1763 DisplayMenuString (MenuOption
, MenuOption
->Col
, Row
, OutputString
, PromptWidth
+ AdjustValue
, Highlight
);
1767 // If there is more string to process print on the next row and increment the Skip value
1769 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
1775 FreePool (OutputString
);
1784 // Clean the empty prompt line.
1785 // These line is used by option string but not prompt, so clean them here.
1787 Row
= OriginalRow
+ PromptLineNum
;
1788 while (PromptLineNum
+ SkipLine
< MenuOption
->Skip
&& Row
<= BottomRow
) {
1789 PrintStringAtWithWidth (BeginCol
, Row
, L
"", PromptWidth
+ AdjustValue
+ SkipWidth
);
1798 // 4. If this is a text op with secondary text information
1800 if ((Statement
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) && (((EFI_IFR_TEXT
*)Statement
->OpCode
)->TextTwo
!= 0)) {
1801 StringPtr
= GetToken (((EFI_IFR_TEXT
*)Statement
->OpCode
)->TextTwo
, gFormData
->HiiHandle
);
1803 Width
= (UINT16
) gOptionBlockWidth
- 1;
1807 for (Index
= 0; GetLineByWidth (StringPtr
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
1808 if ((Temp3
== 0) && (Row
<= BottomRow
)) {
1809 DisplayMenuString (MenuOption
, MenuOption
->OptCol
, Row
, OutputString
, Width
+ 1, Highlight
);
1812 // If there is more string to process print on the next row and increment the Skip value
1814 if (StrLen (&StringPtr
[Index
]) != 0) {
1820 FreePool (OutputString
);
1827 FreePool (StringPtr
);
1834 Display menu and wait for user to select one menu option, then return it.
1835 If AutoBoot is enabled, then if user doesn't select any option,
1836 after period of time, it will automatically return the first menu option.
1838 @param FormData The current form data info.
1840 @retval EFI_SUCESSS Process the user selection success.
1841 @retval EFI_NOT_FOUND Process option string for orderedlist/Oneof fail.
1846 IN FORM_DISPLAY_ENGINE_FORM
*FormData
1851 UINTN DistanceValue
;
1862 CHAR16
*OptionString
;
1863 CHAR16
*OutputString
;
1865 CHAR16
*HelpHeaderString
;
1866 CHAR16
*HelpBottomString
;
1875 LIST_ENTRY
*TopOfScreen
;
1876 LIST_ENTRY
*SavedListEntry
;
1877 UI_MENU_OPTION
*MenuOption
;
1878 UI_MENU_OPTION
*NextMenuOption
;
1879 UI_MENU_OPTION
*SavedMenuOption
;
1880 UI_MENU_OPTION
*PreviousMenuOption
;
1881 UI_CONTROL_FLAG ControlFlag
;
1882 UI_SCREEN_OPERATION ScreenOperation
;
1884 FORM_DISPLAY_ENGINE_STATEMENT
*Statement
;
1885 BROWSER_HOT_KEY
*HotKey
;
1886 UINTN HelpPageIndex
;
1887 UINTN HelpPageCount
;
1890 UINTN HelpHeaderLine
;
1891 UINTN HelpBottomLine
;
1892 BOOLEAN MultiHelpPage
;
1894 UINT16 EachLineWidth
;
1895 UINT16 HeaderLineWidth
;
1896 UINT16 BottomLineWidth
;
1897 EFI_STRING_ID HelpInfo
;
1898 UI_EVENT_TYPE EventType
;
1899 FORM_DISPLAY_ENGINE_STATEMENT
*InitialHighlight
;
1900 BOOLEAN SkipHighLight
;
1902 EventType
= UIEventNone
;
1903 Status
= EFI_SUCCESS
;
1905 HelpHeaderString
= NULL
;
1906 HelpBottomString
= NULL
;
1907 OptionString
= NULL
;
1908 ScreenOperation
= UiNoOperation
;
1917 MultiHelpPage
= FALSE
;
1919 HeaderLineWidth
= 0;
1920 BottomLineWidth
= 0;
1921 OutputString
= NULL
;
1925 SkipHighLight
= FALSE
;
1927 NextMenuOption
= NULL
;
1928 PreviousMenuOption
= NULL
;
1929 SavedMenuOption
= NULL
;
1933 gModalSkipColumn
= (CHAR16
) (gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
) / 6;
1934 InitialHighlight
= gFormData
->HighLightedStatement
;
1936 ZeroMem (&Key
, sizeof (EFI_INPUT_KEY
));
1940 // |<-.->|<-.........->|<- .........->|<-...........->|
1941 // Skip Prompt Option Help
1943 Width
= (CHAR16
) ((gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
) / 3);
1944 gOptionBlockWidth
= Width
+ 1;
1945 gHelpBlockWidth
= (CHAR16
) (Width
- LEFT_SKIPPED_COLUMNS
);
1946 gPromptBlockWidth
= (CHAR16
) (gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
- 2 * Width
- 1);
1948 TopRow
= gStatementDimensions
.TopRow
+ SCROLL_ARROW_HEIGHT
;
1949 BottomRow
= gStatementDimensions
.BottomRow
- SCROLL_ARROW_HEIGHT
- 1;
1952 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
1953 Col
= gStatementDimensions
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
+ gModalSkipColumn
;
1955 Col
= gStatementDimensions
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
;
1958 FindTopMenu(FormData
, &TopOfScreen
, &NewPos
, &SkipValue
);
1960 gST
->ConOut
->EnableCursor (gST
->ConOut
, FALSE
);
1962 ControlFlag
= CfInitialization
;
1964 switch (ControlFlag
) {
1965 case CfInitialization
:
1966 if ((gOldFormEntry
.HiiHandle
!= FormData
->HiiHandle
) ||
1967 (!CompareGuid (&gOldFormEntry
.FormSetGuid
, &FormData
->FormSetGuid
))) {
1969 // Clear Statement range if different formset is painted.
1972 gStatementDimensions
.LeftColumn
,
1973 gStatementDimensions
.RightColumn
,
1974 TopRow
- SCROLL_ARROW_HEIGHT
,
1975 BottomRow
+ SCROLL_ARROW_HEIGHT
,
1976 GetFieldTextColor ()
1980 ControlFlag
= CfRepaint
;
1984 ControlFlag
= CfRefreshHighLight
;
1994 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
1997 // 1. Check whether need to print the arrow up.
1999 if (!ValueIsScroll (TRUE
, TopOfScreen
)) {
2003 PrintStringAtWithWidth(gStatementDimensions
.LeftColumn
, TopRow
- 1, L
"", gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
);
2006 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetArrowColor ());
2008 gStatementDimensions
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
2009 TopRow
- SCROLL_ARROW_HEIGHT
,
2012 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
2016 // 2.Paint the menu.
2018 for (Link
= TopOfScreen
; Link
!= &gMenuOption
; Link
= Link
->ForwardLink
) {
2019 MenuOption
= MENU_OPTION_FROM_LINK (Link
);
2020 MenuOption
->Row
= Row
;
2021 MenuOption
->Col
= Col
;
2022 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
2023 MenuOption
->OptCol
= gStatementDimensions
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
+ gPromptBlockWidth
+ gModalSkipColumn
;
2025 MenuOption
->OptCol
= gStatementDimensions
.LeftColumn
+ LEFT_SKIPPED_COLUMNS
+ gPromptBlockWidth
;
2028 if (MenuOption
->NestInStatement
) {
2029 MenuOption
->Col
+= SUBTITLE_INDENT
;
2033 // Save the highlight menu, will be used in CfRefreshHighLight case.
2035 if (Link
== NewPos
) {
2036 SavedMenuOption
= MenuOption
;
2037 SkipHighLight
= TRUE
;
2040 DisplayOneMenu (MenuOption
,
2041 ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) ? LEFT_SKIPPED_COLUMNS
+ gModalSkipColumn
: LEFT_SKIPPED_COLUMNS
,
2042 gStatementDimensions
.LeftColumn
,
2043 Link
== TopOfScreen
? SkipValue
: 0,
2045 Link
== NewPos
&& IsSelectable(MenuOption
)
2049 // 3. Update the row info which will be used by next menu.
2051 if (Link
== TopOfScreen
) {
2052 Row
+= MenuOption
->Skip
- SkipValue
;
2054 Row
+= MenuOption
->Skip
;
2057 if (Row
> BottomRow
) {
2058 if (!ValueIsScroll (FALSE
, Link
)) {
2062 Row
= BottomRow
+ 1;
2068 // 3. Menus in this form may not cover all form, clean the remain field.
2070 while (Row
<= BottomRow
) {
2071 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
2072 PrintStringAtWithWidth(gStatementDimensions
.LeftColumn
, Row
++, L
"", gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
);
2074 PrintStringAtWithWidth(gStatementDimensions
.LeftColumn
, Row
++, L
"", gStatementDimensions
.RightColumn
- gHelpBlockWidth
- gStatementDimensions
.LeftColumn
);
2079 // 4. Print the down arrow row.
2081 PrintStringAtWithWidth(gStatementDimensions
.LeftColumn
, BottomRow
+ 1, L
"", gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
);
2084 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetArrowColor ());
2086 gStatementDimensions
.LeftColumn
+ gPromptBlockWidth
+ gOptionBlockWidth
+ 1,
2087 BottomRow
+ SCROLL_ARROW_HEIGHT
,
2090 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
2095 if (IsListEmpty (&gMenuOption
)) {
2096 ControlFlag
= CfReadKey
;
2101 case CfRefreshHighLight
:
2104 // MenuOption: Last menu option that need to remove hilight
2105 // MenuOption is set to NULL in Repaint
2106 // NewPos: Current menu option that need to hilight
2108 ControlFlag
= CfUpdateHelpString
;
2110 if (SkipHighLight
) {
2111 MenuOption
= SavedMenuOption
;
2112 SkipHighLight
= FALSE
;
2113 UpdateHighlightMenuInfo (MenuOption
);
2117 if (MenuOption
!= NULL
&& TopOfScreen
== &MenuOption
->Link
) {
2122 if (NewPos
== TopOfScreen
) {
2128 if (NewPos
!= NULL
&& (MenuOption
== NULL
|| NewPos
!= &MenuOption
->Link
)) {
2129 if (MenuOption
!= NULL
) {
2131 // Remove highlight on last Menu Option
2133 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, MenuOption
->Col
, MenuOption
->Row
);
2134 ProcessOptions (MenuOption
, FALSE
, &OptionString
, TRUE
);
2135 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
2136 if (OptionString
!= NULL
) {
2137 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) ||
2138 (MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TIME_OP
)
2140 ProcessStringForDateTime(MenuOption
, OptionString
, FALSE
);
2143 Width
= (UINT16
) gOptionBlockWidth
;
2144 OriginalRow
= MenuOption
->Row
;
2147 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
2148 if ((Temp
== 0) && (MenuOption
->Row
>= TopRow
) && (MenuOption
->Row
<= BottomRow
)) {
2149 PrintStringAt (MenuOption
->OptCol
, MenuOption
->Row
, OutputString
);
2152 // If there is more string to process print on the next row and increment the Skip value
2154 if (StrLen (&OptionString
[Index
]) != 0) {
2160 FreePool (OutputString
);
2166 MenuOption
->Row
= OriginalRow
;
2168 FreePool (OptionString
);
2171 if (MenuOption
->GrayOut
) {
2172 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetGrayedTextColor ());
2173 } else if (MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_SUBTITLE_OP
) {
2174 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetSubTitleTextColor ());
2177 OriginalRow
= MenuOption
->Row
;
2178 Width
= GetWidth (MenuOption
->ThisTag
, NULL
);
2181 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
2182 if ((Temp
== 0) && (MenuOption
->Row
>= TopRow
) && (MenuOption
->Row
<= BottomRow
)) {
2183 PrintStringAt (MenuOption
->Col
, MenuOption
->Row
, OutputString
);
2186 // If there is more string to process print on the next row and increment the Skip value
2188 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
2194 FreePool (OutputString
);
2200 MenuOption
->Row
= OriginalRow
;
2201 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
2207 // This is the current selected statement
2209 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2210 Statement
= MenuOption
->ThisTag
;
2212 UpdateHighlightMenuInfo (MenuOption
);
2214 if (!IsSelectable (MenuOption
)) {
2219 // Set reverse attribute
2221 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetHighlightTextColor ());
2222 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, MenuOption
->Col
, MenuOption
->Row
);
2224 ProcessOptions (MenuOption
, FALSE
, &OptionString
, TRUE
);
2225 if (OptionString
!= NULL
) {
2226 if (Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
|| Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
2227 ProcessStringForDateTime(MenuOption
, OptionString
, FALSE
);
2229 Width
= (UINT16
) gOptionBlockWidth
;
2231 OriginalRow
= MenuOption
->Row
;
2234 for (Index
= 0; GetLineByWidth (OptionString
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
2235 if ((Temp2
== 0) && (MenuOption
->Row
>= TopRow
) && (MenuOption
->Row
<= BottomRow
) ) {
2236 PrintStringAt (MenuOption
->OptCol
, MenuOption
->Row
, OutputString
);
2239 // If there is more string to process print on the next row and increment the Skip value
2241 if (StrLen (&OptionString
[Index
]) != 0) {
2247 FreePool (OutputString
);
2253 MenuOption
->Row
= OriginalRow
;
2255 FreePool (OptionString
);
2258 OriginalRow
= MenuOption
->Row
;
2260 Width
= GetWidth (Statement
, NULL
);
2263 for (Index
= 0; GetLineByWidth (MenuOption
->Description
, Width
, &GlyphWidth
, &Index
, &OutputString
) != 0x0000;) {
2264 if ((Temp2
== 0) && (MenuOption
->Row
>= TopRow
) && (MenuOption
->Row
<= BottomRow
) ) {
2265 PrintStringAt (MenuOption
->Col
, MenuOption
->Row
, OutputString
);
2268 // If there is more string to process print on the next row and increment the Skip value
2270 if (StrLen (&MenuOption
->Description
[Index
]) != 0) {
2276 FreePool (OutputString
);
2282 MenuOption
->Row
= OriginalRow
;
2288 // Clear reverse attribute
2290 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
2294 case CfUpdateHelpString
:
2295 ControlFlag
= CfPrepareToReadKey
;
2296 if ((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) {
2300 if (Repaint
|| NewLine
) {
2302 // Don't print anything if it is a NULL help token
2304 ASSERT(MenuOption
!= NULL
);
2305 HelpInfo
= ((EFI_IFR_STATEMENT_HEADER
*) ((CHAR8
*)MenuOption
->ThisTag
->OpCode
+ sizeof (EFI_IFR_OP_HEADER
)))->Help
;
2306 if (HelpInfo
== 0 || !IsSelectable (MenuOption
)) {
2307 StringPtr
= GetToken (STRING_TOKEN (EMPTY_STRING
), gHiiHandle
);
2309 StringPtr
= GetToken (HelpInfo
, gFormData
->HiiHandle
);
2312 RowCount
= BottomRow
- TopRow
+ 1;
2315 // 1.Calculate how many line the help string need to print.
2317 if (HelpString
!= NULL
) {
2318 FreePool (HelpString
);
2321 HelpLine
= ProcessHelpString (StringPtr
, &HelpString
, &EachLineWidth
, RowCount
);
2322 FreePool (StringPtr
);
2324 if (HelpLine
> RowCount
) {
2325 MultiHelpPage
= TRUE
;
2326 StringPtr
= GetToken (STRING_TOKEN(ADJUST_HELP_PAGE_UP
), gHiiHandle
);
2327 if (HelpHeaderString
!= NULL
) {
2328 FreePool (HelpHeaderString
);
2329 HelpHeaderString
= NULL
;
2331 HelpHeaderLine
= ProcessHelpString (StringPtr
, &HelpHeaderString
, &HeaderLineWidth
, 0);
2332 FreePool (StringPtr
);
2333 StringPtr
= GetToken (STRING_TOKEN(ADJUST_HELP_PAGE_DOWN
), gHiiHandle
);
2334 if (HelpBottomString
!= NULL
) {
2335 FreePool (HelpBottomString
);
2336 HelpBottomString
= NULL
;
2338 HelpBottomLine
= ProcessHelpString (StringPtr
, &HelpBottomString
, &BottomLineWidth
, 0);
2339 FreePool (StringPtr
);
2341 // Calculate the help page count.
2343 if (HelpLine
> 2 * RowCount
- 2) {
2344 HelpPageCount
= (HelpLine
- RowCount
+ 1) / (RowCount
- 2) + 1;
2345 if ((HelpLine
- RowCount
+ 1) % (RowCount
- 2) > 1) {
2352 MultiHelpPage
= FALSE
;
2357 // Check whether need to show the 'More(U/u)' at the begin.
2358 // Base on current direct info, here shows aligned to the right side of the column.
2359 // If the direction is multi line and aligned to right side may have problem, so
2360 // add ASSERT code here.
2362 if (HelpPageIndex
> 0) {
2363 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetInfoTextColor ());
2364 for (Index
= 0; Index
< HelpHeaderLine
; Index
++) {
2365 ASSERT (HelpHeaderLine
== 1);
2366 ASSERT (GetStringWidth (HelpHeaderString
) / 2 < (UINTN
) (gHelpBlockWidth
- 1));
2367 PrintStringAtWithWidth (
2368 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
2374 gStatementDimensions
.RightColumn
- GetStringWidth (HelpHeaderString
) / 2 - 1,
2376 &HelpHeaderString
[Index
* HeaderLineWidth
]
2381 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetHelpTextColor ());
2383 // Print the help string info.
2385 if (!MultiHelpPage
) {
2386 for (Index
= 0; Index
< HelpLine
; Index
++) {
2387 PrintStringAtWithWidth (
2388 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
2390 &HelpString
[Index
* EachLineWidth
],
2394 for (; Index
< RowCount
; Index
++) {
2395 PrintStringAtWithWidth (
2396 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
2402 gST
->ConOut
->SetCursorPosition(gST
->ConOut
, gStatementDimensions
.RightColumn
-1, BottomRow
);
2404 if (HelpPageIndex
== 0) {
2405 for (Index
= 0; Index
< RowCount
- HelpBottomLine
; Index
++) {
2406 PrintStringAtWithWidth (
2407 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
2409 &HelpString
[Index
* EachLineWidth
],
2414 for (Index
= 0; (Index
< RowCount
- HelpBottomLine
- HelpHeaderLine
) &&
2415 (Index
+ HelpPageIndex
* (RowCount
- 2) + 1 < HelpLine
); Index
++) {
2416 PrintStringAtWithWidth (
2417 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
2418 Index
+ TopRow
+ HelpHeaderLine
,
2419 &HelpString
[(Index
+ HelpPageIndex
* (RowCount
- 2) + 1)* EachLineWidth
],
2423 if (HelpPageIndex
== HelpPageCount
- 1) {
2424 for (; Index
< RowCount
- HelpHeaderLine
; Index
++) {
2425 PrintStringAtWithWidth (
2426 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
2427 Index
+ TopRow
+ HelpHeaderLine
,
2432 gST
->ConOut
->SetCursorPosition(gST
->ConOut
, gStatementDimensions
.RightColumn
-1, BottomRow
);
2438 // Check whether need to print the 'More(D/d)' at the bottom.
2439 // Base on current direct info, here shows aligned to the right side of the column.
2440 // If the direction is multi line and aligned to right side may have problem, so
2441 // add ASSERT code here.
2443 if (HelpPageIndex
< HelpPageCount
- 1 && MultiHelpPage
) {
2444 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetInfoTextColor ());
2445 for (Index
= 0; Index
< HelpBottomLine
; Index
++) {
2446 ASSERT (HelpBottomLine
== 1);
2447 ASSERT (GetStringWidth (HelpBottomString
) / 2 < (UINTN
) (gHelpBlockWidth
- 1));
2448 PrintStringAtWithWidth (
2449 gStatementDimensions
.RightColumn
- gHelpBlockWidth
,
2450 BottomRow
+ Index
- HelpBottomLine
+ 1,
2455 gStatementDimensions
.RightColumn
- GetStringWidth (HelpBottomString
) / 2 - 1,
2456 BottomRow
+ Index
- HelpBottomLine
+ 1,
2457 &HelpBottomString
[Index
* BottomLineWidth
]
2462 // Reset this flag every time we finish using it.
2468 case CfPrepareToReadKey
:
2469 ControlFlag
= CfReadKey
;
2470 ScreenOperation
= UiNoOperation
;
2474 ControlFlag
= CfScreenOperation
;
2477 // Wait for user's selection
2480 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
2481 if (!EFI_ERROR (Status
)) {
2482 EventType
= UIEventKey
;
2487 // If we encounter error, continue to read another key in.
2489 if (Status
!= EFI_NOT_READY
) {
2493 EventType
= UiWaitForEvent(gST
->ConIn
->WaitForKey
);
2494 if (EventType
== UIEventKey
) {
2495 gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
2500 if (EventType
== UIEventDriver
) {
2501 gUserInput
->Action
= BROWSER_ACTION_NONE
;
2502 ControlFlag
= CfExit
;
2506 if (EventType
== UIEventTimeOut
) {
2507 gUserInput
->Action
= BROWSER_ACTION_FORM_EXIT
;
2508 ControlFlag
= CfExit
;
2512 switch (Key
.UnicodeChar
) {
2513 case CHAR_CARRIAGE_RETURN
:
2514 if(MenuOption
== NULL
|| MenuOption
->GrayOut
|| MenuOption
->ReadOnly
) {
2515 ControlFlag
= CfReadKey
;
2519 ScreenOperation
= UiSelect
;
2524 // We will push the adjustment of these numeric values directly to the input handler
2525 // NOTE: we won't handle manual input numeric
2530 // If the screen has no menu items, and the user didn't select UiReset
2531 // ignore the selection and go back to reading keys.
2533 if(IsListEmpty (&gMenuOption
) || MenuOption
->GrayOut
|| MenuOption
->ReadOnly
) {
2534 ControlFlag
= CfReadKey
;
2538 ASSERT(MenuOption
!= NULL
);
2539 Statement
= MenuOption
->ThisTag
;
2540 if ((Statement
->OpCode
->OpCode
== EFI_IFR_DATE_OP
)
2541 || (Statement
->OpCode
->OpCode
== EFI_IFR_TIME_OP
)
2542 || ((Statement
->OpCode
->OpCode
== EFI_IFR_NUMERIC_OP
) && (GetFieldFromNum(Statement
->OpCode
) != 0))
2544 if (Key
.UnicodeChar
== '+') {
2545 gDirection
= SCAN_RIGHT
;
2547 gDirection
= SCAN_LEFT
;
2550 Status
= ProcessOptions (MenuOption
, TRUE
, &OptionString
, TRUE
);
2551 if (OptionString
!= NULL
) {
2552 FreePool (OptionString
);
2554 if (EFI_ERROR (Status
)) {
2556 // Repaint to clear possible error prompt pop-up
2561 ControlFlag
= CfExit
;
2567 ScreenOperation
= UiUp
;
2572 ScreenOperation
= UiDown
;
2576 if(IsListEmpty (&gMenuOption
)) {
2577 ControlFlag
= CfReadKey
;
2581 ASSERT(MenuOption
!= NULL
);
2582 if (MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_CHECKBOX_OP
&& !MenuOption
->GrayOut
&& !MenuOption
->ReadOnly
) {
2583 ScreenOperation
= UiSelect
;
2589 if (!MultiHelpPage
) {
2590 ControlFlag
= CfReadKey
;
2593 ControlFlag
= CfUpdateHelpString
;
2594 HelpPageIndex
= HelpPageIndex
< HelpPageCount
- 1 ? HelpPageIndex
+ 1 : HelpPageCount
- 1;
2599 if (!MultiHelpPage
) {
2600 ControlFlag
= CfReadKey
;
2603 ControlFlag
= CfUpdateHelpString
;
2604 HelpPageIndex
= HelpPageIndex
> 0 ? HelpPageIndex
- 1 : 0;
2608 for (Index
= 0; Index
< mScanCodeNumber
; Index
++) {
2609 if (Key
.ScanCode
== gScanCodeToOperation
[Index
].ScanCode
) {
2610 ScreenOperation
= gScanCodeToOperation
[Index
].ScreenOperation
;
2615 if (((FormData
->Attribute
& HII_DISPLAY_MODAL
) != 0) && (Key
.ScanCode
== SCAN_ESC
|| Index
== mScanCodeNumber
)) {
2617 // ModalForm has no ESC key and Hot Key.
2619 ControlFlag
= CfReadKey
;
2620 } else if (Index
== mScanCodeNumber
) {
2622 // Check whether Key matches the registered hot key.
2625 HotKey
= GetHotKeyFromRegisterList (&Key
);
2626 if (HotKey
!= NULL
) {
2627 ScreenOperation
= UiHotKey
;
2634 case CfScreenOperation
:
2635 if (ScreenOperation
!= UiReset
) {
2637 // If the screen has no menu items, and the user didn't select UiReset
2638 // ignore the selection and go back to reading keys.
2640 if (IsListEmpty (&gMenuOption
)) {
2641 ControlFlag
= CfReadKey
;
2647 Index
< sizeof (gScreenOperationToControlFlag
) / sizeof (gScreenOperationToControlFlag
[0]);
2650 if (ScreenOperation
== gScreenOperationToControlFlag
[Index
].ScreenOperation
) {
2651 ControlFlag
= gScreenOperationToControlFlag
[Index
].ControlFlag
;
2658 ControlFlag
= CfRepaint
;
2660 ASSERT(MenuOption
!= NULL
);
2661 Statement
= MenuOption
->ThisTag
;
2662 if (Statement
->OpCode
->OpCode
== EFI_IFR_TEXT_OP
) {
2666 switch (Statement
->OpCode
->OpCode
) {
2667 case EFI_IFR_REF_OP
:
2668 case EFI_IFR_ACTION_OP
:
2669 case EFI_IFR_RESET_BUTTON_OP
:
2670 ControlFlag
= CfExit
;
2675 // Editable Questions: oneof, ordered list, checkbox, numeric, string, password
2677 RefreshKeyHelp (gFormData
, Statement
, TRUE
);
2678 Status
= ProcessOptions (MenuOption
, TRUE
, &OptionString
, TRUE
);
2680 if (OptionString
!= NULL
) {
2681 FreePool (OptionString
);
2684 if (EFI_ERROR (Status
)) {
2687 RefreshKeyHelp (gFormData
, Statement
, FALSE
);
2690 ControlFlag
= CfExit
;
2698 // We come here when someone press ESC
2699 // If the policy is not exit front page when user press ESC, process here.
2701 if (!FormExitPolicy()) {
2704 ControlFlag
= CfRepaint
;
2709 // When user press ESC, it will try to show another menu, should clean the gSequence info.
2711 if (gSequence
!= 0) {
2715 gUserInput
->Action
= BROWSER_ACTION_FORM_EXIT
;
2716 ControlFlag
= CfExit
;
2720 ControlFlag
= CfRepaint
;
2722 gUserInput
->Action
= HotKey
->Action
;
2723 ControlFlag
= CfExit
;
2727 ControlFlag
= CfRepaint
;
2728 ASSERT(MenuOption
!= NULL
);
2729 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TIME_OP
)) {
2730 if (MenuOption
->Sequence
!= 0) {
2732 // In the middle or tail of the Date/Time op-code set, go left.
2734 ASSERT(NewPos
!= NULL
);
2735 NewPos
= NewPos
->BackLink
;
2741 ControlFlag
= CfRepaint
;
2742 ASSERT(MenuOption
!= NULL
);
2743 if ((MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) || (MenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TIME_OP
)) {
2744 if (MenuOption
->Sequence
!= 2) {
2746 // In the middle or tail of the Date/Time op-code set, go left.
2748 ASSERT(NewPos
!= NULL
);
2749 NewPos
= NewPos
->ForwardLink
;
2755 ControlFlag
= CfRepaint
;
2757 SavedListEntry
= NewPos
;
2759 ASSERT(NewPos
!= NULL
);
2761 // Adjust Date/Time position before we advance forward.
2763 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2764 if (NewPos
->BackLink
!= &gMenuOption
) {
2765 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2766 ASSERT (MenuOption
!= NULL
);
2768 NewPos
= NewPos
->BackLink
;
2770 PreviousMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2771 if (PreviousMenuOption
->Row
== 0) {
2772 UpdateOptionSkipLines (PreviousMenuOption
);
2774 DistanceValue
= PreviousMenuOption
->Skip
;
2776 if (MenuOption
->Row
>= DistanceValue
+ TopRow
) {
2777 Difference
= MoveToNextStatement (TRUE
, &NewPos
, MenuOption
->Row
- TopRow
- DistanceValue
);
2779 NextMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
2781 if (Difference
< 0) {
2783 // We hit the begining MenuOption that can be focused
2784 // so we simply scroll to the top.
2786 if (TopOfScreen
!= gMenuOption
.ForwardLink
) {
2787 TopOfScreen
= gMenuOption
.ForwardLink
;
2791 // Scroll up to the last page when we have arrived at top page.
2793 NewPos
= &gMenuOption
;
2794 TopOfScreen
= &gMenuOption
;
2795 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
2796 ScreenOperation
= UiPageUp
;
2797 ControlFlag
= CfScreenOperation
;
2800 } else if (MenuOption
->Row
< TopRow
+ DistanceValue
+ Difference
) {
2802 // Previous focus MenuOption is above the TopOfScreen, so we need to scroll
2804 TopOfScreen
= NewPos
;
2807 } else if (!IsSelectable (NextMenuOption
)) {
2809 // Continue to go up until scroll to next page or the selectable option is found.
2811 ScreenOperation
= UiUp
;
2812 ControlFlag
= CfScreenOperation
;
2816 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
2818 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2819 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2820 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
2821 UpdateStatusBar (INPUT_ERROR
, FALSE
);
2824 // Scroll up to the last page.
2826 NewPos
= &gMenuOption
;
2827 TopOfScreen
= &gMenuOption
;
2828 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
2829 ScreenOperation
= UiPageUp
;
2830 ControlFlag
= CfScreenOperation
;
2836 // SkipValue means lines is skipped when show the top menu option.
2838 ControlFlag
= CfRepaint
;
2840 ASSERT(NewPos
!= NULL
);
2842 // Already at the first menu option, Check the skip value.
2844 if (NewPos
->BackLink
== &gMenuOption
) {
2845 if (SkipValue
== 0) {
2860 // SkipValue > (BottomRow - TopRow + 1) means current menu has more than one
2861 // form of options to be show, so just update the SkipValue to show the next
2862 // parts of options.
2864 if (SkipValue
> (INTN
) (BottomRow
- TopRow
+ 1)) {
2865 SkipValue
-= BottomRow
- TopRow
+ 1;
2871 // First minus the menu of the top screen, it's value is SkipValue.
2873 Index
= (BottomRow
+ 1) - SkipValue
;
2874 while ((Index
> TopRow
) && (Link
->BackLink
!= &gMenuOption
)) {
2875 Link
= Link
->BackLink
;
2876 PreviousMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2877 if (PreviousMenuOption
->Row
== 0) {
2878 UpdateOptionSkipLines (PreviousMenuOption
);
2880 if (Index
< PreviousMenuOption
->Skip
) {
2883 Index
= Index
- PreviousMenuOption
->Skip
;
2886 if ((Link
->BackLink
== &gMenuOption
) && (Index
>= TopRow
)) {
2888 if (TopOfScreen
== &gMenuOption
) {
2889 TopOfScreen
= gMenuOption
.ForwardLink
;
2890 NewPos
= gMenuOption
.BackLink
;
2891 MoveToNextStatement (TRUE
, &NewPos
, BottomRow
- TopRow
);
2893 } else if (TopOfScreen
!= Link
) {
2896 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
2899 // Finally we know that NewPos is the last MenuOption can be focused.
2903 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
2906 if (Index
> TopRow
) {
2908 // At here, only case "Index < PreviousMenuOption->Skip" can reach here.
2910 SkipValue
= PreviousMenuOption
->Skip
- (Index
- TopRow
);
2911 } else if (Index
== TopRow
) {
2914 SkipValue
= TopRow
- Index
;
2918 // Move to the option in Next page.
2920 if (TopOfScreen
== &gMenuOption
) {
2921 NewPos
= gMenuOption
.BackLink
;
2922 MoveToNextStatement (TRUE
, &NewPos
, BottomRow
- TopRow
);
2925 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
2929 // There are more MenuOption needing scrolling up.
2936 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
2937 // Don't do this when we are already in the first page.
2939 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
2940 AdjustDateAndTimePosition (TRUE
, &NewPos
);
2945 // SkipValue means lines is skipped when show the top menu option.
2947 ControlFlag
= CfRepaint
;
2949 ASSERT (NewPos
!= NULL
);
2950 if (NewPos
->ForwardLink
== &gMenuOption
) {
2959 NextMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2960 Index
= TopRow
+ NextMenuOption
->Skip
- SkipValue
;
2962 // Count to the menu option which will show at the top of the next form.
2964 while ((Index
<= BottomRow
+ 1) && (Link
->ForwardLink
!= &gMenuOption
)) {
2965 Link
= Link
->ForwardLink
;
2966 NextMenuOption
= MENU_OPTION_FROM_LINK (Link
);
2967 Index
= Index
+ NextMenuOption
->Skip
;
2970 if ((Link
->ForwardLink
== &gMenuOption
) && (Index
<= BottomRow
+ 1)) {
2972 // Finally we know that NewPos is the last MenuOption can be focused.
2975 MoveToNextStatement (TRUE
, &Link
, Index
- TopRow
);
2978 // Calculate the skip line for top of screen menu.
2980 if (Link
== TopOfScreen
) {
2982 // The top of screen menu option occupies the entire form.
2984 SkipValue
+= BottomRow
- TopRow
+ 1;
2986 SkipValue
= NextMenuOption
->Skip
- (Index
- (BottomRow
+ 1));
2992 // Move to the Next selectable menu.
2994 MoveToNextStatement (FALSE
, &Link
, BottomRow
- TopRow
);
2998 // Save the menu as the next highlight menu.
3003 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
3004 // Don't do this when we are already in the last page.
3006 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3007 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3012 // SkipValue means lines is skipped when show the top menu option.
3013 // NewPos points to the menu which is highlighted now.
3015 ControlFlag
= CfRepaint
;
3018 // Since the behavior of hitting the down arrow on a Date/Time op-code is intended
3019 // to be one that progresses to the next set of op-codes, we need to advance to the last
3020 // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate
3021 // checking can be done. The only other logic we need to introduce is that if a Date/Time
3022 // op-code is the last entry in the menu, we need to rewind back to the first op-code of
3023 // the Date/Time op-code.
3025 SavedListEntry
= NewPos
;
3026 AdjustDateAndTimePosition (FALSE
, &NewPos
);
3028 if (NewPos
->ForwardLink
!= &gMenuOption
) {
3029 MenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3031 NewPos
= NewPos
->ForwardLink
;
3035 // Current menu not at the bottom of the form.
3037 if (BottomRow
>= MenuOption
->Row
+ MenuOption
->Skip
) {
3039 // Find the next selectable menu.
3041 Difference
= MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- MenuOption
->Row
- MenuOption
->Skip
);
3043 // We hit the end of MenuOption that can be focused
3044 // so we simply scroll to the first page.
3046 if (Difference
< 0) {
3048 // Scroll to the first page.
3050 if (TopOfScreen
!= gMenuOption
.ForwardLink
) {
3051 TopOfScreen
= gMenuOption
.ForwardLink
;
3055 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3057 NewPos
= gMenuOption
.ForwardLink
;
3058 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
3062 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
3064 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3065 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3069 NextMenuOption
= MENU_OPTION_FROM_LINK (NewPos
);
3070 if (NextMenuOption
->Row
== 0) {
3071 UpdateOptionSkipLines (NextMenuOption
);
3073 DistanceValue
= Difference
+ NextMenuOption
->Skip
;
3075 Temp
= MenuOption
->Row
+ MenuOption
->Skip
+ DistanceValue
- 1;
3076 if ((MenuOption
->Row
+ MenuOption
->Skip
== BottomRow
+ 1) &&
3077 (NextMenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_DATE_OP
||
3078 NextMenuOption
->ThisTag
->OpCode
->OpCode
== EFI_IFR_TIME_OP
)
3084 // If we are going to scroll, update TopOfScreen
3086 if (Temp
> BottomRow
) {
3089 // Is the current top of screen a zero-advance op-code?
3090 // If so, keep moving forward till we hit a >0 advance op-code
3092 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3095 // If bottom op-code is more than one line or top op-code is more than one line
3097 if ((DistanceValue
> 1) || (SavedMenuOption
->Skip
> 1)) {
3099 // Is the bottom op-code greater than or equal in size to the top op-code?
3101 if ((Temp
- BottomRow
) >= (SavedMenuOption
->Skip
- SkipValue
)) {
3103 // Skip the top op-code
3105 TopOfScreen
= TopOfScreen
->ForwardLink
;
3106 Difference
= (Temp
- BottomRow
) - (SavedMenuOption
->Skip
- SkipValue
);
3108 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3111 // If we have a remainder, skip that many more op-codes until we drain the remainder
3113 while (Difference
>= (INTN
) SavedMenuOption
->Skip
) {
3115 // Since the Difference is greater than or equal to this op-code's skip value, skip it
3117 Difference
= Difference
- (INTN
) SavedMenuOption
->Skip
;
3118 TopOfScreen
= TopOfScreen
->ForwardLink
;
3119 SavedMenuOption
= MENU_OPTION_FROM_LINK (TopOfScreen
);
3122 // Since we will act on this op-code in the next routine, and increment the
3123 // SkipValue, set the skips to one less than what is required.
3125 SkipValue
= Difference
- 1;
3128 // Since we will act on this op-code in the next routine, and increment the
3129 // SkipValue, set the skips to one less than what is required.
3131 SkipValue
+= (Temp
- BottomRow
) - 1;
3134 if ((SkipValue
+ 1) == (INTN
) SavedMenuOption
->Skip
) {
3135 TopOfScreen
= TopOfScreen
->ForwardLink
;
3140 // If the op-code at the top of the screen is more than one line, let's not skip it yet
3141 // Let's set a skip flag to smoothly scroll the top of the screen.
3143 if (SavedMenuOption
->Skip
> 1) {
3144 if (SavedMenuOption
== NextMenuOption
) {
3149 } else if (SavedMenuOption
->Skip
== 1) {
3153 TopOfScreen
= TopOfScreen
->ForwardLink
;
3155 } while (SavedMenuOption
->Skip
== 0);
3158 } else if (!IsSelectable (NextMenuOption
)) {
3160 // Continue to go down until scroll to next page or the selectable option is found.
3162 ScreenOperation
= UiDown
;
3163 ControlFlag
= CfScreenOperation
;
3166 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3168 UpdateStatusBar (INPUT_ERROR
, FALSE
);
3172 // Scroll to the first page.
3174 if (TopOfScreen
!= gMenuOption
.ForwardLink
) {
3175 TopOfScreen
= gMenuOption
.ForwardLink
;
3180 // Need to remove the current highlight menu.
3181 // MenuOption saved the last highlight menu info.
3183 MenuOption
= MENU_OPTION_FROM_LINK (SavedListEntry
);
3189 // Get the next highlight menu.
3191 NewPos
= gMenuOption
.ForwardLink
;
3192 MoveToNextStatement (FALSE
, &NewPos
, BottomRow
- TopRow
);
3196 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
3198 AdjustDateAndTimePosition (TRUE
, &TopOfScreen
);
3199 AdjustDateAndTimePosition (TRUE
, &NewPos
);
3202 case CfUiNoOperation
:
3203 ControlFlag
= CfRepaint
;
3207 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
3208 if (HelpString
!= NULL
) {
3209 FreePool (HelpString
);
3211 if (HelpHeaderString
!= NULL
) {
3212 FreePool (HelpHeaderString
);
3214 if (HelpBottomString
!= NULL
) {
3215 FreePool (HelpBottomString
);
3227 Base on the browser status info to show an pop up message.
3231 BrowserStatusProcess (
3238 if (gFormData
->BrowserStatus
== BROWSER_SUCCESS
) {
3242 if (gFormData
->ErrorString
!= NULL
) {
3243 ErrorInfo
= gFormData
->ErrorString
;
3245 switch (gFormData
->BrowserStatus
) {
3246 case BROWSER_SUBMIT_FAIL
:
3247 ErrorInfo
= gSaveFailed
;
3250 case BROWSER_NO_SUBMIT_IF
:
3251 ErrorInfo
= gNoSubmitIf
;
3254 case BROWSER_FORM_NOT_FOUND
:
3255 ErrorInfo
= gFormNotFound
;
3258 case BROWSER_FORM_SUPPRESS
:
3259 ErrorInfo
= gFormSuppress
;
3262 case BROWSER_PROTOCOL_NOT_FOUND
:
3263 ErrorInfo
= gProtocolNotFound
;
3267 ErrorInfo
= gBrwoserError
;
3273 // Error occur, prompt error message.
3276 CreateDialog (&Key
, gEmptyString
, ErrorInfo
, gPressEnter
, gEmptyString
, NULL
);
3277 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
3281 Display one form, and return user input.
3283 @param FormData Form Data to be shown.
3284 @param UserInputData User input data.
3286 @retval EFI_SUCCESS 1.Form Data is shown, and user input is got.
3287 2.Error info has show and return.
3288 @retval EFI_INVALID_PARAMETER The input screen dimension is not valid
3289 @retval EFI_NOT_FOUND New form data has some error.
3294 IN FORM_DISPLAY_ENGINE_FORM
*FormData
,
3295 OUT USER_INPUT
*UserInputData
3300 ASSERT (FormData
!= NULL
);
3301 if (FormData
== NULL
) {
3302 return EFI_INVALID_PARAMETER
;
3305 gUserInput
= UserInputData
;
3306 gFormData
= FormData
;
3309 // Process the status info first.
3311 BrowserStatusProcess();
3312 if (UserInputData
== NULL
) {
3314 // UserInputData == NULL, means only need to print the error info, return here.
3319 ConvertStatementToMenu();
3321 Status
= DisplayPageFrame (FormData
, &gStatementDimensions
);
3322 if (EFI_ERROR (Status
)) {
3327 // Check whether layout is changed.
3330 || (gOldFormEntry
.HiiHandle
!= FormData
->HiiHandle
)
3331 || (!CompareGuid (&gOldFormEntry
.FormSetGuid
, &FormData
->FormSetGuid
))
3332 || (gOldFormEntry
.FormId
!= FormData
->FormId
)) {
3333 mStatementLayoutIsChanged
= TRUE
;
3335 mStatementLayoutIsChanged
= FALSE
;
3338 Status
= UiDisplayMenu(FormData
);
3341 // Backup last form info.
3343 mIsFirstForm
= FALSE
;
3344 gOldFormEntry
.HiiHandle
= FormData
->HiiHandle
;
3345 CopyGuid (&gOldFormEntry
.FormSetGuid
, &FormData
->FormSetGuid
);
3346 gOldFormEntry
.FormId
= FormData
->FormId
;
3352 Clear Screen to the initial state.
3356 DriverClearDisplayPage (
3360 ClearDisplayPage ();
3361 mIsFirstForm
= TRUE
;
3365 Set Buffer to Value for Size bytes.
3367 @param Buffer Memory to set.
3368 @param Size Number of bytes to set
3369 @param Value Value of the set operation.
3382 while ((Size
--) != 0) {
3388 Initialize Setup Browser driver.
3390 @param ImageHandle The image handle.
3391 @param SystemTable The system table.
3393 @retval EFI_SUCCESS The Setup Browser module is initialized correctly..
3394 @return Other value if failed to initialize the Setup Browser module.
3399 InitializeDisplayEngine (
3400 IN EFI_HANDLE ImageHandle
,
3401 IN EFI_SYSTEM_TABLE
*SystemTable
3405 EFI_INPUT_KEY HotKey
;
3406 EFI_STRING NewString
;
3407 EDKII_FORM_BROWSER_EXTENSION2_PROTOCOL
*FormBrowserEx2
;
3410 // Publish our HII data
3412 gHiiHandle
= HiiAddPackages (
3413 &gDisplayEngineGuid
,
3415 DisplayEngineStrings
,
3418 ASSERT (gHiiHandle
!= NULL
);
3421 // Install Form Display protocol
3423 Status
= gBS
->InstallProtocolInterface (
3424 &mPrivateData
.Handle
,
3425 &gEdkiiFormDisplayEngineProtocolGuid
,
3426 EFI_NATIVE_INTERFACE
,
3427 &mPrivateData
.FromDisplayProt
3429 ASSERT_EFI_ERROR (Status
);
3431 InitializeDisplayStrings();
3433 ZeroMem (&gHighligthMenuInfo
, sizeof (gHighligthMenuInfo
));
3434 ZeroMem (&gOldFormEntry
, sizeof (gOldFormEntry
));
3437 // Use BrowserEx2 protocol to register HotKey.
3439 Status
= gBS
->LocateProtocol (&gEdkiiFormBrowserEx2ProtocolGuid
, NULL
, (VOID
**) &FormBrowserEx2
);
3440 if (!EFI_ERROR (Status
)) {
3442 // Register the default HotKey F9 and F10 again.
3444 HotKey
.UnicodeChar
= CHAR_NULL
;
3445 HotKey
.ScanCode
= SCAN_F10
;
3446 NewString
= HiiGetString (gHiiHandle
, STRING_TOKEN (FUNCTION_TEN_STRING
), NULL
);
3447 ASSERT (NewString
!= NULL
);
3448 FormBrowserEx2
->RegisterHotKey (&HotKey
, BROWSER_ACTION_SUBMIT
, 0, NewString
);
3450 HotKey
.ScanCode
= SCAN_F9
;
3451 NewString
= HiiGetString (gHiiHandle
, STRING_TOKEN (FUNCTION_NINE_STRING
), NULL
);
3452 ASSERT (NewString
!= NULL
);
3453 FormBrowserEx2
->RegisterHotKey (&HotKey
, BROWSER_ACTION_DEFAULT
, EFI_HII_DEFAULT_CLASS_STANDARD
, NewString
);
3460 This is the default unload handle for display core drivers.
3462 @param[in] ImageHandle The drivers' driver image.
3464 @retval EFI_SUCCESS The image is unloaded.
3465 @retval Others Failed to unload the image.
3470 UnloadDisplayEngine (
3471 IN EFI_HANDLE ImageHandle
3474 HiiRemovePackages(gHiiHandle
);
3476 FreeDisplayStrings ();