]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.c
Fix form flash issue.
[mirror_edk2.git] / MdeModulePkg / Universal / DisplayEngineDxe / FormDisplay.c
1 /** @file
2 Entry and initialization module for the browser.
3
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
9
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.
12
13 **/
14
15 #include "FormDisplay.h"
16
17 //
18 // Search table for UiDisplayMenu()
19 //
20 SCAN_CODE_TO_SCREEN_OPERATION gScanCodeToOperation[] = {
21 {
22 SCAN_UP,
23 UiUp,
24 },
25 {
26 SCAN_DOWN,
27 UiDown,
28 },
29 {
30 SCAN_PAGE_UP,
31 UiPageUp,
32 },
33 {
34 SCAN_PAGE_DOWN,
35 UiPageDown,
36 },
37 {
38 SCAN_ESC,
39 UiReset,
40 },
41 {
42 SCAN_LEFT,
43 UiLeft,
44 },
45 {
46 SCAN_RIGHT,
47 UiRight,
48 }
49 };
50
51 UINTN mScanCodeNumber = sizeof (gScanCodeToOperation) / sizeof (gScanCodeToOperation[0]);
52
53 SCREEN_OPERATION_T0_CONTROL_FLAG gScreenOperationToControlFlag[] = {
54 {
55 UiNoOperation,
56 CfUiNoOperation,
57 },
58 {
59 UiSelect,
60 CfUiSelect,
61 },
62 {
63 UiUp,
64 CfUiUp,
65 },
66 {
67 UiDown,
68 CfUiDown,
69 },
70 {
71 UiLeft,
72 CfUiLeft,
73 },
74 {
75 UiRight,
76 CfUiRight,
77 },
78 {
79 UiReset,
80 CfUiReset,
81 },
82 {
83 UiPageUp,
84 CfUiPageUp,
85 },
86 {
87 UiPageDown,
88 CfUiPageDown
89 },
90 {
91 UiHotKey,
92 CfUiHotKey
93 }
94 };
95
96 EFI_GUID gDisplayEngineGuid = {
97 0xE38C1029, 0xE38F, 0x45b9, {0x8F, 0x0D, 0xE2, 0xE6, 0x0B, 0xC9, 0xB2, 0x62}
98 };
99
100 FORM_ENTRY_INFO gFormEntryInfo;
101 UINTN gSequence;
102 EFI_SCREEN_DESCRIPTOR gStatementDimensions;
103 BOOLEAN mStatementLayoutIsChanged = TRUE;
104 USER_INPUT *gUserInput;
105 FORM_DISPLAY_ENGINE_FORM *gFormData;
106 EFI_HII_HANDLE gHiiHandle;
107 UINT16 gDirection;
108 LIST_ENTRY gMenuOption;
109 DISPLAY_HIGHLIGHT_MENU_INFO gHighligthMenuInfo = {0};
110 BOOLEAN mIsFirstForm = TRUE;
111 FORM_ENTRY_INFO gOldFormEntry = {0};
112
113 //
114 // Browser Global Strings
115 //
116 CHAR16 *gFormNotFound;
117 CHAR16 *gNoSubmitIf;
118 CHAR16 *gBrwoserError;
119 CHAR16 *gSaveFailed;
120 CHAR16 *gPromptForData;
121 CHAR16 *gPromptForPassword;
122 CHAR16 *gPromptForNewPassword;
123 CHAR16 *gConfirmPassword;
124 CHAR16 *gConfirmError;
125 CHAR16 *gPassowordInvalid;
126 CHAR16 *gPressEnter;
127 CHAR16 *gEmptyString;
128 CHAR16 *gMiniString;
129 CHAR16 *gOptionMismatch;
130 CHAR16 *gFormSuppress;
131 CHAR16 *gProtocolNotFound;
132
133 CHAR16 gModalSkipColumn;
134 CHAR16 gPromptBlockWidth;
135 CHAR16 gOptionBlockWidth;
136 CHAR16 gHelpBlockWidth;
137 CHAR16 *mUnknownString;
138
139 FORM_DISPLAY_DRIVER_PRIVATE_DATA mPrivateData = {
140 FORM_DISPLAY_DRIVER_SIGNATURE,
141 NULL,
142 {
143 FormDisplay,
144 DriverClearDisplayPage,
145 ConfirmDataChange
146 }
147 };
148
149
150 /**
151 Get the string based on the StringId and HII Package List Handle.
152
153 @param Token The String's ID.
154 @param HiiHandle The package list in the HII database to search for
155 the specified string.
156
157 @return The output string.
158
159 **/
160 CHAR16 *
161 GetToken (
162 IN EFI_STRING_ID Token,
163 IN EFI_HII_HANDLE HiiHandle
164 )
165 {
166 EFI_STRING String;
167
168 String = HiiGetString (HiiHandle, Token, NULL);
169 if (String == NULL) {
170 String = AllocateCopyPool (StrSize (mUnknownString), mUnknownString);
171 ASSERT (String != NULL);
172 }
173
174 return (CHAR16 *) String;
175 }
176
177
178 /**
179 Initialize the HII String Token to the correct values.
180
181 **/
182 VOID
183 InitializeDisplayStrings (
184 VOID
185 )
186 {
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);
204 }
205
206 /**
207 Free up the resource allocated for all strings required
208 by Setup Browser.
209
210 **/
211 VOID
212 FreeDisplayStrings (
213 VOID
214 )
215 {
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);
233 }
234
235 /**
236 Get prompt string id from the opcode data buffer.
237
238 @param OpCode The input opcode buffer.
239
240 @return The prompt string id.
241
242 **/
243 EFI_STRING_ID
244 GetPrompt (
245 IN EFI_IFR_OP_HEADER *OpCode
246 )
247 {
248 EFI_IFR_STATEMENT_HEADER *Header;
249
250 if (OpCode->Length <= sizeof (EFI_IFR_OP_HEADER)) {
251 return 0;
252 }
253
254 Header = (EFI_IFR_STATEMENT_HEADER *) (OpCode + 1);
255
256 return Header->Prompt;
257 }
258
259 /**
260 Get the supported width for a particular op-code
261
262 @param Statement The curent statement.
263 @param AdjustWidth The width which is saved for the space.
264
265 @return Returns the number of CHAR16 characters that is support.
266
267 **/
268 UINT16
269 GetWidth (
270 IN FORM_DISPLAY_ENGINE_STATEMENT *Statement,
271 OUT UINT16 *AdjustWidth
272 )
273 {
274 CHAR16 *String;
275 UINTN Size;
276 EFI_IFR_TEXT *TestOp;
277
278 //
279 // For modal form, clean the entire row.
280 //
281 if ((gFormData->Attribute & HII_DISPLAY_MODAL) != 0) {
282 return (UINT16)(gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn - gModalSkipColumn - SCROLL_ARROW_HEIGHT);
283 }
284
285 Size = 0;
286
287 //
288 // See if the second text parameter is really NULL
289 //
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);
295 FreePool (String);
296 }
297 }
298
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) ||
304 //
305 // Allow a wide display if text op-code and no secondary text op-code
306 //
307 ((Statement->OpCode->OpCode == EFI_IFR_TEXT_OP) && (Size == 0))
308 ) {
309
310 //
311 // Return the space width.
312 //
313 if (AdjustWidth != NULL) {
314 *AdjustWidth = 2;
315 }
316 //
317 // Keep consistent with current behavior.
318 //
319 return (UINT16) (gPromptBlockWidth + gOptionBlockWidth - 2);
320 }
321
322 if (AdjustWidth != NULL) {
323 *AdjustWidth = 1;
324 }
325 return (UINT16) (gPromptBlockWidth - 1);
326 }
327
328 /**
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'.
333
334 In the code, it deals \r,\n,\r\n same as \n\r, also it not process the \r or \g.
335
336 @param InputString String description for this option.
337 @param LineWidth Width of the desired string to extract in CHAR16
338 characters
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
342
343 @return Returns the number of CHAR16 characters that were copied into the OutputString
344 buffer, include extra glyph info and '\0' info.
345
346 **/
347 UINT16
348 GetLineByWidth (
349 IN CHAR16 *InputString,
350 IN UINT16 LineWidth,
351 IN OUT UINT16 *GlyphWidth,
352 IN OUT UINTN *Index,
353 OUT CHAR16 **OutputString
354 )
355 {
356 UINT16 StrOffset;
357 UINT16 GlyphOffset;
358 UINT16 OriginalGlyphWidth;
359 BOOLEAN ReturnFlag;
360 UINT16 LastSpaceOffset;
361 UINT16 LastGlyphWidth;
362
363 if (InputString == NULL || Index == NULL || OutputString == NULL) {
364 return 0;
365 }
366
367 if (LineWidth == 0 || *GlyphWidth == 0) {
368 return 0;
369 }
370
371 //
372 // Save original glyph width.
373 //
374 OriginalGlyphWidth = *GlyphWidth;
375 LastGlyphWidth = OriginalGlyphWidth;
376 ReturnFlag = FALSE;
377 LastSpaceOffset = 0;
378
379 //
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.
382 //
383 if ((InputString[*Index] == NARROW_CHAR) && (InputString[*Index + 1] == CHAR_CARRIAGE_RETURN)) {
384 *Index = *Index + 2;
385 }
386
387 //
388 // Fast-forward the string and see if there is a carriage-return in the string
389 //
390 for (StrOffset = 0, GlyphOffset = 0; GlyphOffset <= LineWidth; StrOffset++) {
391 switch (InputString[*Index + StrOffset]) {
392 case NARROW_CHAR:
393 *GlyphWidth = 1;
394 break;
395
396 case WIDE_CHAR:
397 *GlyphWidth = 2;
398 break;
399
400 case CHAR_CARRIAGE_RETURN:
401 case CHAR_LINEFEED:
402 case CHAR_NULL:
403 ReturnFlag = TRUE;
404 break;
405
406 default:
407 GlyphOffset = GlyphOffset + *GlyphWidth;
408
409 //
410 // Record the last space info in this line. Will be used in rewind.
411 //
412 if ((InputString[*Index + StrOffset] == CHAR_SPACE) && (GlyphOffset <= LineWidth)) {
413 LastSpaceOffset = StrOffset;
414 LastGlyphWidth = *GlyphWidth;
415 }
416 break;
417 }
418
419 if (ReturnFlag) {
420 break;
421 }
422 }
423
424 //
425 // Rewind the string from the maximum size until we see a space to break the line
426 //
427 if (GlyphOffset > LineWidth) {
428 //
429 // Rewind the string to last space char in this line.
430 //
431 if (LastSpaceOffset != 0) {
432 StrOffset = LastSpaceOffset;
433 *GlyphWidth = LastGlyphWidth;
434 } else {
435 //
436 // Roll back to last char in the line width.
437 //
438 StrOffset--;
439 }
440 }
441
442 //
443 // The CHAR_NULL has process last time, this time just return 0 to stand for the end.
444 //
445 if (StrOffset == 0 && (InputString[*Index + StrOffset] == CHAR_NULL)) {
446 return 0;
447 }
448
449 //
450 // Need extra glyph info and '\0' info, so +2.
451 //
452 *OutputString = AllocateZeroPool (((UINTN) (StrOffset + 2) * sizeof(CHAR16)));
453 if (*OutputString == NULL) {
454 return 0;
455 }
456
457 //
458 // Save the glyph info at the begin of the string, will used by Print function.
459 //
460 if (OriginalGlyphWidth == 1) {
461 *(*OutputString) = NARROW_CHAR;
462 } else {
463 *(*OutputString) = WIDE_CHAR;
464 }
465
466 CopyMem ((*OutputString) + 1, &InputString[*Index], StrOffset * sizeof(CHAR16));
467
468 if (InputString[*Index + StrOffset] == CHAR_SPACE) {
469 //
470 // Skip the space info at the begin of next line.
471 //
472 *Index = (UINT16) (*Index + StrOffset + 1);
473 } else if (InputString[*Index + StrOffset] == CHAR_LINEFEED) {
474 //
475 // Skip the /n or /n/r info.
476 //
477 if (InputString[*Index + StrOffset + 1] == CHAR_CARRIAGE_RETURN) {
478 *Index = (UINT16) (*Index + StrOffset + 2);
479 } else {
480 *Index = (UINT16) (*Index + StrOffset + 1);
481 }
482 } else if (InputString[*Index + StrOffset] == CHAR_CARRIAGE_RETURN) {
483 //
484 // Skip the /r or /r/n info.
485 //
486 if (InputString[*Index + StrOffset + 1] == CHAR_LINEFEED) {
487 *Index = (UINT16) (*Index + StrOffset + 2);
488 } else {
489 *Index = (UINT16) (*Index + StrOffset + 1);
490 }
491 } else {
492 *Index = (UINT16) (*Index + StrOffset);
493 }
494
495 //
496 // Include extra glyph info and '\0' info, so +2.
497 //
498 return StrOffset + 2;
499 }
500
501 /**
502 Add one menu option by specified description and context.
503
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.
507
508 **/
509 VOID
510 UiAddMenuOption (
511 IN FORM_DISPLAY_ENGINE_STATEMENT *Statement,
512 IN UINT16 *MenuItemCount,
513 IN BOOLEAN NestIn
514 )
515 {
516 UI_MENU_OPTION *MenuOption;
517 UINTN Index;
518 UINTN Count;
519 CHAR16 *String;
520 UINT16 NumberOfLines;
521 UINT16 GlyphWidth;
522 UINT16 Width;
523 UINTN ArrayEntry;
524 CHAR16 *OutputString;
525 EFI_STRING_ID PromptId;
526
527 NumberOfLines = 1;
528 ArrayEntry = 0;
529 GlyphWidth = 1;
530 Count = 1;
531 MenuOption = NULL;
532
533 PromptId = GetPrompt (Statement->OpCode);
534 ASSERT (PromptId != 0);
535
536 String = GetToken (PromptId, gFormData->HiiHandle);
537 ASSERT (String != NULL);
538
539 Width = GetWidth (Statement, NULL);
540 for (; GetLineByWidth (String, Width, &GlyphWidth,&ArrayEntry, &OutputString) != 0x0000;) {
541 //
542 // If there is more string to process print on the next row and increment the Skip value
543 //
544 if (StrLen (&String[ArrayEntry]) != 0) {
545 NumberOfLines++;
546 }
547 FreePool (OutputString);
548 }
549
550 if (Statement->OpCode->OpCode == EFI_IFR_DATE_OP || Statement->OpCode->OpCode == EFI_IFR_TIME_OP) {
551 //
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
555 //
556 NumberOfLines = 0;
557 Count = 3;
558 }
559
560 for (Index = 0; Index < Count; Index++) {
561 MenuOption = AllocateZeroPool (sizeof (UI_MENU_OPTION));
562 ASSERT (MenuOption);
563
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;
570
571 if (Index == 2) {
572 //
573 // Override LineNumber for the MenuOption in Date/Time sequence
574 //
575 MenuOption->Skip = 1;
576 } else {
577 MenuOption->Skip = NumberOfLines;
578 }
579 MenuOption->Sequence = Index;
580
581 if ((Statement->Attribute & HII_DISPLAY_GRAYOUT) != 0) {
582 MenuOption->GrayOut = TRUE;
583 } else {
584 MenuOption->GrayOut = FALSE;
585 }
586
587 if ((Statement->Attribute & HII_DISPLAY_LOCK) != 0 || (gFormData->Attribute & HII_DISPLAY_LOCK) != 0) {
588 MenuOption->GrayOut = TRUE;
589 }
590
591 //
592 // If the form or the question has the lock attribute, deal same as grayout.
593 //
594 if ((gFormData->Attribute & HII_DISPLAY_LOCK) != 0 || (Statement->Attribute & HII_DISPLAY_LOCK) != 0) {
595 MenuOption->GrayOut = TRUE;
596 }
597
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:
607 //
608 // User could change the value of these items
609 //
610 MenuOption->IsQuestion = TRUE;
611 break;
612 case EFI_IFR_TEXT_OP:
613 if (FeaturePcdGet (PcdBrowserGrayOutTextStatement)) {
614 //
615 // Initializing GrayOut option as TRUE for Text setup options
616 // so that those options will be Gray in colour and un selectable.
617 //
618 MenuOption->GrayOut = TRUE;
619 }
620 break;
621 default:
622 MenuOption->IsQuestion = FALSE;
623 break;
624 }
625
626 if ((Statement->Attribute & HII_DISPLAY_READONLY) != 0) {
627 MenuOption->ReadOnly = TRUE;
628 if (FeaturePcdGet (PcdBrowerGrayOutReadOnlyMenu)) {
629 MenuOption->GrayOut = TRUE;
630 }
631 }
632
633 InsertTailList (&gMenuOption, &MenuOption->Link);
634 }
635
636 (*MenuItemCount)++;
637 }
638
639 /**
640 Create the menu list base on the form data info.
641
642 **/
643 VOID
644 ConvertStatementToMenu (
645 VOID
646 )
647 {
648 UINT16 MenuItemCount;
649 LIST_ENTRY *Link;
650 LIST_ENTRY *NestLink;
651 FORM_DISPLAY_ENGINE_STATEMENT *Statement;
652 FORM_DISPLAY_ENGINE_STATEMENT *NestStatement;
653
654 MenuItemCount = 0;
655 InitializeListHead (&gMenuOption);
656
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);
661
662 //
663 // Skip the opcode not recognized by Display core.
664 //
665 if (Statement->OpCode->OpCode == EFI_IFR_GUID_OP) {
666 continue;
667 }
668
669 UiAddMenuOption (Statement, &MenuItemCount, FALSE);
670
671 //
672 // Check the statement nest in this host statement.
673 //
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);
678
679 UiAddMenuOption (NestStatement, &MenuItemCount, TRUE);
680 }
681 }
682 }
683
684 /**
685 Count the storage space of a Unicode string.
686
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.
692
693 If String is NULL, then ASSERT ().
694
695 @param String The input string to be counted.
696
697 @return Storage space for the input string.
698
699 **/
700 UINTN
701 GetStringWidth (
702 IN CHAR16 *String
703 )
704 {
705 UINTN Index;
706 UINTN Count;
707 UINTN IncrementValue;
708
709 ASSERT (String != NULL);
710 if (String == NULL) {
711 return 0;
712 }
713
714 Index = 0;
715 Count = 0;
716 IncrementValue = 1;
717
718 do {
719 //
720 // Advance to the null-terminator or to the first width directive
721 //
722 for (;
723 (String[Index] != NARROW_CHAR) && (String[Index] != WIDE_CHAR) && (String[Index] != 0);
724 Index++, Count = Count + IncrementValue
725 )
726 ;
727
728 //
729 // We hit the null-terminator, we now have a count
730 //
731 if (String[Index] == 0) {
732 break;
733 }
734 //
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)
737 //
738 if (String[Index] == NARROW_CHAR) {
739 //
740 // Skip to the next character
741 //
742 Index++;
743 IncrementValue = 1;
744 } else {
745 //
746 // Skip to the next character
747 //
748 Index++;
749 IncrementValue = 2;
750 }
751 } while (String[Index] != 0);
752
753 //
754 // Increment by one to include the null-terminator in the size
755 //
756 Count++;
757
758 return Count * sizeof (CHAR16);
759 }
760
761 /**
762 Base on the input option string to update the skip value for a menu option.
763
764 @param MenuOption The MenuOption to be checked.
765 @param OptionString The input option string.
766
767 **/
768 VOID
769 UpdateSkipInfoForMenu (
770 IN UI_MENU_OPTION *MenuOption,
771 IN CHAR16 *OptionString
772 )
773 {
774 UINTN Index;
775 UINT16 Width;
776 UINTN Row;
777 CHAR16 *OutputString;
778 UINT16 GlyphWidth;
779
780 Width = (UINT16) gOptionBlockWidth;
781 GlyphWidth = 1;
782 Row = 1;
783
784 for (Index = 0; GetLineByWidth (OptionString, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {
785 if (StrLen (&OptionString[Index]) != 0) {
786 Row++;
787 }
788
789 FreePool (OutputString);
790 }
791
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;
796 }
797 }
798
799 /**
800 Update display lines for a Menu Option.
801
802 @param MenuOption The MenuOption to be checked.
803
804 **/
805 VOID
806 UpdateOptionSkipLines (
807 IN UI_MENU_OPTION *MenuOption
808 )
809 {
810 CHAR16 *OptionString;
811
812 OptionString = NULL;
813
814 ProcessOptions (MenuOption, FALSE, &OptionString, TRUE);
815 if (OptionString != NULL) {
816 UpdateSkipInfoForMenu (MenuOption, OptionString);
817
818 FreePool (OptionString);
819 }
820
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);
823
824 if (OptionString != NULL) {
825 UpdateSkipInfoForMenu (MenuOption, OptionString);
826
827 FreePool (OptionString);
828 }
829 }
830 }
831
832 /**
833 Check whether this Menu Option could be highlighted.
834
835 This is an internal function.
836
837 @param MenuOption The MenuOption to be checked.
838
839 @retval TRUE This Menu Option is selectable.
840 @retval FALSE This Menu Option could not be selected.
841
842 **/
843 BOOLEAN
844 IsSelectable (
845 UI_MENU_OPTION *MenuOption
846 )
847 {
848 if ((MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_SUBTITLE_OP) ||
849 MenuOption->GrayOut || MenuOption->ReadOnly) {
850 return FALSE;
851 } else {
852 return TRUE;
853 }
854 }
855
856 /**
857 Move to next selectable statement.
858
859 This is an internal function.
860
861 @param GoUp The navigation direction. TRUE: up, FALSE: down.
862 @param CurrentPosition Current position.
863 @param GapToTop Gap position to top or bottom.
864
865 @return The row distance from current MenuOption to next selectable MenuOption.
866
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.
870
871 **/
872 INTN
873 MoveToNextStatement (
874 IN BOOLEAN GoUp,
875 IN OUT LIST_ENTRY **CurrentPosition,
876 IN UINTN GapToTop
877 )
878 {
879 INTN Distance;
880 LIST_ENTRY *Pos;
881 UI_MENU_OPTION *NextMenuOption;
882 UI_MENU_OPTION *PreMenuOption;
883
884 Distance = 0;
885 Pos = *CurrentPosition;
886 PreMenuOption = MENU_OPTION_FROM_LINK (Pos);
887
888 while (TRUE) {
889 NextMenuOption = MENU_OPTION_FROM_LINK (Pos);
890 //
891 // NextMenuOption->Row == 0 means this menu has not calculate
892 // the NextMenuOption->Skip value yet, just calculate here.
893 //
894 if (NextMenuOption->Row == 0) {
895 UpdateOptionSkipLines (NextMenuOption);
896 }
897
898 if (GoUp && (PreMenuOption != NextMenuOption)) {
899 //
900 // In this case, still can't find the selectable menu,
901 // return the last one in the showing form.
902 //
903 if ((UINTN) Distance + NextMenuOption->Skip > GapToTop) {
904 NextMenuOption = PreMenuOption;
905 break;
906 }
907
908 //
909 // Current Position doesn't need to be caculated when go up.
910 // Caculate distanct at first when go up
911 //
912 Distance += NextMenuOption->Skip;
913 }
914
915 if (IsSelectable (NextMenuOption)) {
916 break;
917 }
918
919 //
920 // Arrive at begin of the menu list.
921 //
922 if ((GoUp ? Pos->BackLink : Pos->ForwardLink) == &gMenuOption) {
923 Distance = -1;
924 break;
925 }
926
927 if (!GoUp) {
928 //
929 // In this case, still can't find the selectable menu,
930 // return the last one in the showing form.
931 //
932 if ((UINTN) Distance + NextMenuOption->Skip > GapToTop) {
933 NextMenuOption = PreMenuOption;
934 break;
935 }
936
937 Distance += NextMenuOption->Skip;
938 }
939
940 PreMenuOption = NextMenuOption;
941 Pos = (GoUp ? Pos->BackLink : Pos->ForwardLink);
942 }
943
944 *CurrentPosition = &NextMenuOption->Link;
945 return Distance;
946 }
947
948
949 /**
950 Process option string for date/time opcode.
951
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.
955
956 **/
957 VOID
958 ProcessStringForDateTime (
959 UI_MENU_OPTION *MenuOption,
960 CHAR16 *OptionString,
961 BOOLEAN AddOptCol
962 )
963 {
964 UINTN Index;
965 UINTN Count;
966 FORM_DISPLAY_ENGINE_STATEMENT *Statement;
967 EFI_IFR_DATE *Date;
968 EFI_IFR_TIME *Time;
969
970 ASSERT (MenuOption != NULL && OptionString != NULL);
971
972 Statement = MenuOption->ThisTag;
973 Date = NULL;
974 Time = NULL;
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;
979 }
980
981 //
982 // If leading spaces on OptionString - remove the spaces
983 //
984 for (Index = 0; OptionString[Index] == L' '; Index++) {
985 //
986 // Base on the blockspace to get the option column info.
987 //
988 if (AddOptCol) {
989 MenuOption->OptCol++;
990 }
991 }
992
993 for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {
994 OptionString[Count] = OptionString[Index];
995 Count++;
996 }
997 OptionString[Count] = CHAR_NULL;
998
999 //
1000 // Enable to suppress field in the opcode base on the flag.
1001 //
1002 if (Statement->OpCode->OpCode == EFI_IFR_DATE_OP) {
1003 //
1004 // OptionString format is: <**: **: ****>
1005 // |month|day|year|
1006 // 4 3 5
1007 //
1008 if ((Date->Flags & EFI_QF_DATE_MONTH_SUPPRESS) && (MenuOption->Sequence == 0)) {
1009 //
1010 // At this point, only "<**:" in the optionstring.
1011 // Clean the day's ** field, after clean, the format is "< :"
1012 //
1013 SetUnicodeMem (&OptionString[1], 2, L' ');
1014 } else if ((Date->Flags & EFI_QF_DATE_DAY_SUPPRESS) && (MenuOption->Sequence == 1)) {
1015 //
1016 // At this point, only "**:" in the optionstring.
1017 // Clean the month's "**" field, after clean, the format is " :"
1018 //
1019 SetUnicodeMem (&OptionString[0], 2, L' ');
1020 } else if ((Date->Flags & EFI_QF_DATE_YEAR_SUPPRESS) && (MenuOption->Sequence == 2)) {
1021 //
1022 // At this point, only "****>" in the optionstring.
1023 // Clean the year's "****" field, after clean, the format is " >"
1024 //
1025 SetUnicodeMem (&OptionString[0], 4, L' ');
1026 }
1027 } else if (Statement->OpCode->OpCode == EFI_IFR_TIME_OP) {
1028 //
1029 // OptionString format is: <**: **: **>
1030 // |hour|minute|second|
1031 // 4 3 3
1032 //
1033 if ((Time->Flags & QF_TIME_HOUR_SUPPRESS) && (MenuOption->Sequence == 0)) {
1034 //
1035 // At this point, only "<**:" in the optionstring.
1036 // Clean the hour's ** field, after clean, the format is "< :"
1037 //
1038 SetUnicodeMem (&OptionString[1], 2, L' ');
1039 } else if ((Time->Flags & QF_TIME_MINUTE_SUPPRESS) && (MenuOption->Sequence == 1)) {
1040 //
1041 // At this point, only "**:" in the optionstring.
1042 // Clean the minute's "**" field, after clean, the format is " :"
1043 //
1044 SetUnicodeMem (&OptionString[0], 2, L' ');
1045 } else if ((Time->Flags & QF_TIME_SECOND_SUPPRESS) && (MenuOption->Sequence == 2)) {
1046 //
1047 // At this point, only "**>" in the optionstring.
1048 // Clean the second's "**" field, after clean, the format is " >"
1049 //
1050 SetUnicodeMem (&OptionString[0], 2, L' ');
1051 }
1052 }
1053 }
1054
1055
1056 /**
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
1060
1061 This is an internal function.
1062
1063 @param DirectionUp the up or down direction. False is down. True is
1064 up.
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.
1068
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.
1071
1072 **/
1073 UINTN
1074 AdjustDateAndTimePosition (
1075 IN BOOLEAN DirectionUp,
1076 IN OUT LIST_ENTRY **CurrentPosition
1077 )
1078 {
1079 UINTN Count;
1080 LIST_ENTRY *NewPosition;
1081 UI_MENU_OPTION *MenuOption;
1082 UINTN PadLineNumber;
1083
1084 PadLineNumber = 0;
1085 NewPosition = *CurrentPosition;
1086 MenuOption = MENU_OPTION_FROM_LINK (NewPosition);
1087
1088 if ((MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_DATE_OP) ||
1089 (MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_TIME_OP)) {
1090 //
1091 // Calculate the distance from current position to the last Date/Time MenuOption
1092 //
1093 Count = 0;
1094 while (MenuOption->Skip == 0) {
1095 Count++;
1096 NewPosition = NewPosition->ForwardLink;
1097 MenuOption = MENU_OPTION_FROM_LINK (NewPosition);
1098 PadLineNumber = 1;
1099 }
1100
1101 NewPosition = *CurrentPosition;
1102 if (DirectionUp) {
1103 //
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.
1108 //
1109 while (Count++ < 2) {
1110 NewPosition = NewPosition->BackLink;
1111 }
1112 } else {
1113 //
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.
1118 //
1119 while (Count-- > 0) {
1120 NewPosition = NewPosition->ForwardLink;
1121 }
1122 }
1123
1124 *CurrentPosition = NewPosition;
1125 }
1126
1127 return PadLineNumber;
1128 }
1129
1130 /**
1131 Get step info from numeric opcode.
1132
1133 @param[in] OpCode The input numeric op code.
1134
1135 @return step info for this opcode.
1136 **/
1137 UINT64
1138 GetFieldFromNum (
1139 IN EFI_IFR_OP_HEADER *OpCode
1140 )
1141 {
1142 EFI_IFR_NUMERIC *NumericOp;
1143 UINT64 Step;
1144
1145 NumericOp = (EFI_IFR_NUMERIC *) OpCode;
1146
1147 switch (NumericOp->Flags & EFI_IFR_NUMERIC_SIZE) {
1148 case EFI_IFR_NUMERIC_SIZE_1:
1149 Step = NumericOp->data.u8.Step;
1150 break;
1151
1152 case EFI_IFR_NUMERIC_SIZE_2:
1153 Step = NumericOp->data.u16.Step;
1154 break;
1155
1156 case EFI_IFR_NUMERIC_SIZE_4:
1157 Step = NumericOp->data.u32.Step;
1158 break;
1159
1160 case EFI_IFR_NUMERIC_SIZE_8:
1161 Step = NumericOp->data.u64.Step;
1162 break;
1163
1164 default:
1165 Step = 0;
1166 break;
1167 }
1168
1169 return Step;
1170 }
1171
1172 /**
1173 Find the registered HotKey based on KeyData.
1174
1175 @param[in] KeyData A pointer to a buffer that describes the keystroke
1176 information for the hot key.
1177
1178 @return The registered HotKey context. If no found, NULL will return.
1179 **/
1180 BROWSER_HOT_KEY *
1181 GetHotKeyFromRegisterList (
1182 IN EFI_INPUT_KEY *KeyData
1183 )
1184 {
1185 LIST_ENTRY *Link;
1186 BROWSER_HOT_KEY *HotKey;
1187
1188 Link = GetFirstNode (&gFormData->HotKeyListHead);
1189 while (!IsNull (&gFormData->HotKeyListHead, Link)) {
1190 HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);
1191
1192 if (HotKey->KeyData->ScanCode == KeyData->ScanCode) {
1193 return HotKey;
1194 }
1195
1196 Link = GetNextNode (&gFormData->HotKeyListHead, Link);
1197 }
1198
1199 return NULL;
1200 }
1201
1202
1203 /**
1204 Determine if the menu is the last menu that can be selected.
1205
1206 This is an internal function.
1207
1208 @param Direction The scroll direction. False is down. True is up.
1209 @param CurrentPos The current focus.
1210
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.
1213
1214 **/
1215 BOOLEAN
1216 ValueIsScroll (
1217 IN BOOLEAN Direction,
1218 IN LIST_ENTRY *CurrentPos
1219 )
1220 {
1221 LIST_ENTRY *Temp;
1222
1223 Temp = Direction ? CurrentPos->BackLink : CurrentPos->ForwardLink;
1224
1225 if (Temp == &gMenuOption) {
1226 return TRUE;
1227 }
1228
1229 return FALSE;
1230 }
1231
1232 /**
1233 Wait for a given event to fire, or for an optional timeout to expire.
1234
1235 @param Event The event to wait for
1236
1237 @retval UI_EVENT_TYPE The type of the event which is trigged.
1238
1239 **/
1240 UI_EVENT_TYPE
1241 UiWaitForEvent (
1242 IN EFI_EVENT Event
1243 )
1244 {
1245 EFI_STATUS Status;
1246 UINTN Index;
1247 UINTN EventNum;
1248 UINT64 Timeout;
1249 EFI_EVENT TimerEvent;
1250 EFI_EVENT WaitList[3];
1251 UI_EVENT_TYPE EventType;
1252
1253 TimerEvent = NULL;
1254 Timeout = FormExitTimeout(gFormData);
1255
1256 if (Timeout != 0) {
1257 Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);
1258
1259 //
1260 // Set the timer event
1261 //
1262 gBS->SetTimer (
1263 TimerEvent,
1264 TimerRelative,
1265 Timeout
1266 );
1267 }
1268
1269 WaitList[0] = Event;
1270 EventNum = 1;
1271 if (gFormData->FormRefreshEvent != NULL) {
1272 WaitList[EventNum] = gFormData->FormRefreshEvent;
1273 EventNum ++;
1274 }
1275
1276 if (Timeout != 0) {
1277 WaitList[EventNum] = TimerEvent;
1278 EventNum ++;
1279 }
1280
1281 Status = gBS->WaitForEvent (EventNum, WaitList, &Index);
1282 ASSERT_EFI_ERROR (Status);
1283
1284 switch (Index) {
1285 case 0:
1286 EventType = UIEventKey;
1287 break;
1288
1289 case 1:
1290 if (gFormData->FormRefreshEvent != NULL) {
1291 EventType = UIEventDriver;
1292 } else {
1293 ASSERT (Timeout != 0 && EventNum == 2);
1294 EventType = UIEventTimeOut;
1295 }
1296 break;
1297
1298 default:
1299 ASSERT (Index == 2 && EventNum == 3);
1300 EventType = UIEventTimeOut;
1301 break;
1302 }
1303
1304 if (Timeout != 0) {
1305 gBS->CloseEvent (TimerEvent);
1306 }
1307
1308 return EventType;
1309 }
1310
1311 /**
1312 Get question id info from the input opcode header.
1313
1314 @param OpCode The input opcode header pointer.
1315
1316 @retval The question id for this opcode.
1317
1318 **/
1319 EFI_QUESTION_ID
1320 GetQuestionIdInfo (
1321 IN EFI_IFR_OP_HEADER *OpCode
1322 )
1323 {
1324 EFI_IFR_QUESTION_HEADER *QuestionHeader;
1325
1326 if (OpCode->Length < sizeof (EFI_IFR_OP_HEADER) + sizeof (EFI_IFR_QUESTION_HEADER)) {
1327 return 0;
1328 }
1329
1330 QuestionHeader = (EFI_IFR_QUESTION_HEADER *)((UINT8 *) OpCode + sizeof(EFI_IFR_OP_HEADER));
1331
1332 return QuestionHeader->QuestionId;
1333 }
1334
1335 /**
1336 Find the first menu which will be show at the top.
1337
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.
1342
1343 **/
1344 VOID
1345 FindTopMenu (
1346 IN FORM_DISPLAY_ENGINE_FORM *FormData,
1347 OUT LIST_ENTRY **TopOfScreen,
1348 OUT LIST_ENTRY **HighlightMenu,
1349 OUT INTN *SkipValue
1350 )
1351 {
1352 LIST_ENTRY *Link;
1353 LIST_ENTRY *NewPos;
1354 UINTN TopRow;
1355 UINTN BottomRow;
1356 UINTN Index;
1357 UI_MENU_OPTION *SavedMenuOption;
1358 UINTN EndRow;
1359
1360 TopRow = gStatementDimensions.TopRow + SCROLL_ARROW_HEIGHT;
1361 BottomRow = gStatementDimensions.BottomRow - SCROLL_ARROW_HEIGHT;
1362
1363 //
1364 // If not has input highlight statement, just return the first one in this form.
1365 //
1366 if (FormData->HighLightedStatement == NULL) {
1367 *TopOfScreen = gMenuOption.ForwardLink;
1368 *HighlightMenu = gMenuOption.ForwardLink;
1369 if (!IsListEmpty (&gMenuOption)) {
1370 MoveToNextStatement (FALSE, HighlightMenu, BottomRow - TopRow);
1371 }
1372 *SkipValue = 0;
1373 return;
1374 }
1375
1376 //
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.
1379 //
1380 NewPos = gMenuOption.ForwardLink;
1381 SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos);
1382
1383 while ((SavedMenuOption->ThisTag != FormData->HighLightedStatement) ||
1384 (SavedMenuOption->Sequence != gSequence)) {
1385 NewPos = NewPos->ForwardLink;
1386 if (NewPos == &gMenuOption) {
1387 //
1388 // Not Found it, break
1389 //
1390 break;
1391 }
1392 SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos);
1393 }
1394 ASSERT (SavedMenuOption->ThisTag == FormData->HighLightedStatement);
1395
1396 *HighlightMenu = NewPos;
1397
1398 AdjustDateAndTimePosition(FALSE, &NewPos);
1399 SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos);
1400 UpdateOptionSkipLines (SavedMenuOption);
1401
1402 //
1403 // If highlight opcode is date/time, keep the highlight row info not change.
1404 //
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))) {
1408 //
1409 // Still show the highlight menu before exit from display engine.
1410 //
1411 EndRow = gHighligthMenuInfo.DisplayRow + SavedMenuOption->Skip;
1412 } else {
1413 EndRow = BottomRow;
1414 }
1415
1416 //
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.
1419 //
1420 Link = NewPos;
1421 for (Index = TopRow + SavedMenuOption->Skip; Index <= EndRow; ) {
1422 Link = Link->BackLink;
1423 //
1424 // Already find the first menu in this form, means highlight menu
1425 // will show in first page of this form.
1426 //
1427 if (Link == &gMenuOption) {
1428 *TopOfScreen = gMenuOption.ForwardLink;
1429 *SkipValue = 0;
1430 return;
1431 }
1432 SavedMenuOption = MENU_OPTION_FROM_LINK (Link);
1433 UpdateOptionSkipLines (SavedMenuOption);
1434 Index += SavedMenuOption->Skip;
1435 }
1436
1437 //
1438 // Found the menu which will show at the top of the page.
1439 //
1440 if (Link == NewPos) {
1441 //
1442 // The menu can show more than one pages, just show the menu at the top of the page.
1443 //
1444 *SkipValue = 0;
1445 *TopOfScreen = Link;
1446 } else {
1447 //
1448 // Check whether need to skip some line for menu shows at the top of the page.
1449 //
1450 *SkipValue = Index - EndRow;
1451 if (*SkipValue > 0 && *SkipValue < (INTN) SavedMenuOption->Skip) {
1452 *TopOfScreen = Link;
1453 } else {
1454 *SkipValue = 0;
1455 *TopOfScreen = Link->ForwardLink;
1456 }
1457 }
1458 }
1459
1460 /**
1461 Update highlight menu info.
1462
1463 @param MenuOption The menu opton which is highlight.
1464
1465 **/
1466 VOID
1467 UpdateHighlightMenuInfo (
1468 IN UI_MENU_OPTION *MenuOption
1469 )
1470 {
1471 FORM_DISPLAY_ENGINE_STATEMENT *Statement;
1472
1473 //
1474 // This is the current selected statement
1475 //
1476 Statement = MenuOption->ThisTag;
1477
1478 //
1479 // Get the highlight statement.
1480 //
1481 gUserInput->SelectedStatement = Statement;
1482 gSequence = (UINT16) MenuOption->Sequence;
1483
1484 //
1485 // Record highlight row info for date/time opcode.
1486 //
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;
1490 } else {
1491 gHighligthMenuInfo.QuestionId = 0;
1492 gHighligthMenuInfo.DisplayRow = 0;
1493 }
1494
1495 RefreshKeyHelp(gFormData, Statement, FALSE);
1496 }
1497
1498 /**
1499 Update attribut for this menu.
1500
1501 @param MenuOption The menu opton which this attribut used to.
1502 @param Highlight Whether this menu will be highlight.
1503
1504 **/
1505 VOID
1506 SetDisplayAttribute (
1507 IN UI_MENU_OPTION *MenuOption,
1508 IN BOOLEAN Highlight
1509 )
1510 {
1511 FORM_DISPLAY_ENGINE_STATEMENT *Statement;
1512
1513 Statement = MenuOption->ThisTag;
1514
1515 if (Highlight) {
1516 gST->ConOut->SetAttribute (gST->ConOut, GetHighlightTextColor ());
1517 return;
1518 }
1519
1520 if (MenuOption->GrayOut) {
1521 gST->ConOut->SetAttribute (gST->ConOut, GetGrayedTextColor ());
1522 } else {
1523 if (Statement->OpCode->OpCode == EFI_IFR_SUBTITLE_OP) {
1524 gST->ConOut->SetAttribute (gST->ConOut, GetSubTitleTextColor ());
1525 } else {
1526 gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());
1527 }
1528 }
1529 }
1530
1531 /**
1532 Print string for this menu option.
1533
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.
1541
1542 **/
1543 VOID
1544 DisplayMenuString (
1545 IN UI_MENU_OPTION *MenuOption,
1546 IN UINTN Col,
1547 IN UINTN Row,
1548 IN CHAR16 *String,
1549 IN UINTN Width,
1550 IN BOOLEAN Highlight
1551 )
1552 {
1553 UINTN Length;
1554
1555 //
1556 // Print string with normal color.
1557 //
1558 if (!Highlight) {
1559 PrintStringAtWithWidth (Col, Row, String, Width);
1560 return;
1561 }
1562
1563 //
1564 // Print the highlight menu string.
1565 // First print the highlight string.
1566 //
1567 SetDisplayAttribute(MenuOption, TRUE);
1568 Length = PrintStringAt (Col, Row, String);
1569
1570 //
1571 // Second, clean the empty after the string.
1572 //
1573 SetDisplayAttribute(MenuOption, FALSE);
1574 PrintStringAtWithWidth (Col + Length, Row, L"", Width - Length);
1575 }
1576
1577 /**
1578 Print string for this menu option.
1579
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.
1586
1587 @retval EFI_SUCESSS Process the user selection success.
1588
1589 **/
1590 EFI_STATUS
1591 DisplayOneMenu (
1592 IN UI_MENU_OPTION *MenuOption,
1593 IN UINTN SkipWidth,
1594 IN UINTN BeginCol,
1595 IN UINTN SkipLine,
1596 IN UINTN BottomRow,
1597 IN BOOLEAN Highlight
1598 )
1599 {
1600 FORM_DISPLAY_ENGINE_STATEMENT *Statement;
1601 UINTN Index;
1602 UINT16 Width;
1603 UINT16 PromptWidth;
1604 CHAR16 *StringPtr;
1605 CHAR16 *OptionString;
1606 CHAR16 *OutputString;
1607 UINTN OriginalRow;
1608 UINT16 GlyphWidth;
1609 UINTN Temp;
1610 UINTN Temp2;
1611 UINTN Temp3;
1612 EFI_STATUS Status;
1613 UINTN Row;
1614 UINTN Col;
1615 UINTN PromptLineNum;
1616 CHAR16 AdjustValue;
1617
1618 Statement = MenuOption->ThisTag;
1619 Col = MenuOption->Col;
1620 Row = MenuOption->Row;
1621 Temp = SkipLine;
1622 Temp2 = SkipLine;
1623 Temp3 = SkipLine;
1624 AdjustValue = 0;
1625
1626 //
1627 // Set default color.
1628 //
1629 SetDisplayAttribute (MenuOption, FALSE);
1630
1631 //
1632 // 1. Paint the option string.
1633 //
1634 Status = ProcessOptions (MenuOption, FALSE, &OptionString, FALSE);
1635 if (EFI_ERROR (Status)) {
1636 return Status;
1637 }
1638
1639 if (OptionString != NULL) {
1640 if (Statement->OpCode->OpCode == EFI_IFR_DATE_OP || Statement->OpCode->OpCode == EFI_IFR_TIME_OP) {
1641 //
1642 // Adjust option string for date/time opcode.
1643 //
1644 ProcessStringForDateTime(MenuOption, OptionString, TRUE);
1645 }
1646
1647 Width = (UINT16) gOptionBlockWidth - 1;
1648 OriginalRow = Row;
1649 GlyphWidth = 1;
1650
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) {
1654 //
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.
1658 //
1659 if (MenuOption->Skip != 0) {
1660 //
1661 // For date/ time, print the last past (year for date and second for time)
1662 // - 7 means skip [##/##/ for date and [##:##: for time.
1663 //
1664 DisplayMenuString (MenuOption,MenuOption->OptCol, Row, OutputString, Width + 1 - 7, Highlight);
1665 } else {
1666 //
1667 // For date/ time, print the first and second past (year for date and second for time)
1668 //
1669 DisplayMenuString (MenuOption, MenuOption->OptCol, Row, OutputString, StrLen (OutputString), Highlight);
1670 }
1671 } else {
1672 DisplayMenuString (MenuOption, MenuOption->OptCol, Row, OutputString, Width + 1, Highlight);
1673 }
1674 }
1675
1676 //
1677 // If there is more string to process print on the next row and increment the Skip value
1678 //
1679 if (StrLen (&OptionString[Index]) != 0) {
1680 if (Temp2 == 0) {
1681 Row++;
1682 //
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.
1686 //
1687 // If the difference in rows is greater than or equal to the skip value, increase the skip value
1688 //
1689 if ((Row - OriginalRow) >= MenuOption->Skip) {
1690 MenuOption->Skip++;
1691 }
1692 }
1693 }
1694
1695 FreePool (OutputString);
1696 if (Temp2 != 0) {
1697 Temp2--;
1698 }
1699 }
1700
1701 Row = OriginalRow;
1702 Highlight = FALSE;
1703
1704 FreePool (OptionString);
1705 }
1706 Temp2 = 0;
1707
1708
1709 //
1710 // 2. Pre calculate the skip value.
1711 //
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);
1714
1715 Width = (UINT16) gOptionBlockWidth - 1;
1716 OriginalRow = Row;
1717 GlyphWidth = 1;
1718 for (Index = 0; GetLineByWidth (StringPtr, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {
1719 if (StrLen (&StringPtr[Index]) != 0) {
1720 Row++;
1721 if ((Row - OriginalRow) >= MenuOption->Skip) {
1722 MenuOption->Skip++;
1723 }
1724 }
1725 FreePool (OutputString);
1726 }
1727
1728 Row = OriginalRow;
1729 FreePool (StringPtr);
1730 }
1731
1732
1733 //
1734 // 3. Paint the description.
1735 //
1736 PromptWidth = GetWidth (Statement, &AdjustValue);
1737 OriginalRow = Row;
1738 GlyphWidth = 1;
1739 PromptLineNum = 0;
1740
1741 if (MenuOption->Description == NULL || MenuOption->Description[0] == '\0') {
1742 while (Temp++ < MenuOption->Skip) {
1743 PrintStringAtWithWidth (BeginCol, Row++, L"", PromptWidth + AdjustValue + SkipWidth);
1744 }
1745 } else {
1746 for (Index = 0; GetLineByWidth (MenuOption->Description, PromptWidth, &GlyphWidth, &Index, &OutputString) != 0x0000;) {
1747 if ((Temp == 0) && (Row <= BottomRow)) {
1748 //
1749 // 1.Clean the start LEFT_SKIPPED_COLUMNS
1750 //
1751 PrintStringAtWithWidth (BeginCol, Row, L"", SkipWidth);
1752
1753 if (Statement->OpCode->OpCode == EFI_IFR_REF_OP && MenuOption->Col >= 2) {
1754 //
1755 // Print Arrow for Goto button.
1756 //
1757 PrintCharAt (
1758 MenuOption->Col - 2,
1759 Row,
1760 GEOMETRICSHAPE_RIGHT_TRIANGLE
1761 );
1762 }
1763 DisplayMenuString (MenuOption, MenuOption->Col, Row, OutputString, PromptWidth + AdjustValue, Highlight);
1764 PromptLineNum ++;
1765 }
1766 //
1767 // If there is more string to process print on the next row and increment the Skip value
1768 //
1769 if (StrLen (&MenuOption->Description[Index]) != 0) {
1770 if (Temp == 0) {
1771 Row++;
1772 }
1773 }
1774
1775 FreePool (OutputString);
1776 if (Temp != 0) {
1777 Temp--;
1778 }
1779 }
1780
1781 Highlight = FALSE;
1782
1783 //
1784 // Clean the empty prompt line.
1785 // These line is used by option string but not prompt, so clean them here.
1786 //
1787 Row = OriginalRow + PromptLineNum;
1788 while (PromptLineNum + SkipLine < MenuOption->Skip && Row <= BottomRow) {
1789 PrintStringAtWithWidth (BeginCol, Row, L"", PromptWidth + AdjustValue + SkipWidth);
1790 PromptLineNum ++;
1791 Row ++;
1792 }
1793 }
1794 Row = OriginalRow;
1795
1796
1797 //
1798 // 4. If this is a text op with secondary text information
1799 //
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);
1802
1803 Width = (UINT16) gOptionBlockWidth - 1;
1804 OriginalRow = Row;
1805 GlyphWidth = 1;
1806
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);
1810 }
1811 //
1812 // If there is more string to process print on the next row and increment the Skip value
1813 //
1814 if (StrLen (&StringPtr[Index]) != 0) {
1815 if (Temp3 == 0) {
1816 Row++;
1817 }
1818 }
1819
1820 FreePool (OutputString);
1821 if (Temp3 != 0) {
1822 Temp3--;
1823 }
1824 }
1825
1826 Row = OriginalRow;
1827 FreePool (StringPtr);
1828 }
1829
1830 return EFI_SUCCESS;
1831 }
1832
1833 /**
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.
1837
1838 @param FormData The current form data info.
1839
1840 @retval EFI_SUCESSS Process the user selection success.
1841 @retval EFI_NOT_FOUND Process option string for orderedlist/Oneof fail.
1842
1843 **/
1844 EFI_STATUS
1845 UiDisplayMenu (
1846 IN FORM_DISPLAY_ENGINE_FORM *FormData
1847 )
1848 {
1849 INTN SkipValue;
1850 INTN Difference;
1851 UINTN DistanceValue;
1852 UINTN Row;
1853 UINTN Col;
1854 UINTN Temp;
1855 UINTN Temp2;
1856 UINTN TopRow;
1857 UINTN BottomRow;
1858 UINTN OriginalRow;
1859 UINTN Index;
1860 UINT16 Width;
1861 CHAR16 *StringPtr;
1862 CHAR16 *OptionString;
1863 CHAR16 *OutputString;
1864 CHAR16 *HelpString;
1865 CHAR16 *HelpHeaderString;
1866 CHAR16 *HelpBottomString;
1867 BOOLEAN NewLine;
1868 BOOLEAN Repaint;
1869 BOOLEAN UpArrow;
1870 BOOLEAN DownArrow;
1871 EFI_STATUS Status;
1872 EFI_INPUT_KEY Key;
1873 LIST_ENTRY *Link;
1874 LIST_ENTRY *NewPos;
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;
1883 UINT16 DefaultId;
1884 FORM_DISPLAY_ENGINE_STATEMENT *Statement;
1885 BROWSER_HOT_KEY *HotKey;
1886 UINTN HelpPageIndex;
1887 UINTN HelpPageCount;
1888 UINTN RowCount;
1889 UINTN HelpLine;
1890 UINTN HelpHeaderLine;
1891 UINTN HelpBottomLine;
1892 BOOLEAN MultiHelpPage;
1893 UINT16 GlyphWidth;
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;
1901
1902 EventType = UIEventNone;
1903 Status = EFI_SUCCESS;
1904 HelpString = NULL;
1905 HelpHeaderString = NULL;
1906 HelpBottomString = NULL;
1907 OptionString = NULL;
1908 ScreenOperation = UiNoOperation;
1909 NewLine = TRUE;
1910 DefaultId = 0;
1911 HelpPageCount = 0;
1912 HelpLine = 0;
1913 RowCount = 0;
1914 HelpBottomLine = 0;
1915 HelpHeaderLine = 0;
1916 HelpPageIndex = 0;
1917 MultiHelpPage = FALSE;
1918 EachLineWidth = 0;
1919 HeaderLineWidth = 0;
1920 BottomLineWidth = 0;
1921 OutputString = NULL;
1922 UpArrow = FALSE;
1923 DownArrow = FALSE;
1924 SkipValue = 0;
1925 SkipHighLight = FALSE;
1926
1927 NextMenuOption = NULL;
1928 PreviousMenuOption = NULL;
1929 SavedMenuOption = NULL;
1930 HotKey = NULL;
1931 Repaint = TRUE;
1932 MenuOption = NULL;
1933 gModalSkipColumn = (CHAR16) (gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn) / 6;
1934 InitialHighlight = gFormData->HighLightedStatement;
1935
1936 ZeroMem (&Key, sizeof (EFI_INPUT_KEY));
1937
1938 //
1939 // Left right
1940 // |<-.->|<-.........->|<- .........->|<-...........->|
1941 // Skip Prompt Option Help
1942 //
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);
1947
1948 TopRow = gStatementDimensions.TopRow + SCROLL_ARROW_HEIGHT;
1949 BottomRow = gStatementDimensions.BottomRow - SCROLL_ARROW_HEIGHT - 1;
1950
1951 Row = TopRow;
1952 if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {
1953 Col = gStatementDimensions.LeftColumn + LEFT_SKIPPED_COLUMNS + gModalSkipColumn;
1954 } else {
1955 Col = gStatementDimensions.LeftColumn + LEFT_SKIPPED_COLUMNS;
1956 }
1957
1958 FindTopMenu(FormData, &TopOfScreen, &NewPos, &SkipValue);
1959
1960 gST->ConOut->EnableCursor (gST->ConOut, FALSE);
1961
1962 ControlFlag = CfInitialization;
1963 while (TRUE) {
1964 switch (ControlFlag) {
1965 case CfInitialization:
1966 if ((gOldFormEntry.HiiHandle != FormData->HiiHandle) ||
1967 (!CompareGuid (&gOldFormEntry.FormSetGuid, &FormData->FormSetGuid))) {
1968 //
1969 // Clear Statement range if different formset is painted.
1970 //
1971 ClearLines (
1972 gStatementDimensions.LeftColumn,
1973 gStatementDimensions.RightColumn,
1974 TopRow - SCROLL_ARROW_HEIGHT,
1975 BottomRow + SCROLL_ARROW_HEIGHT,
1976 GetFieldTextColor ()
1977 );
1978
1979 }
1980 ControlFlag = CfRepaint;
1981 break;
1982
1983 case CfRepaint:
1984 ControlFlag = CfRefreshHighLight;
1985
1986 if (Repaint) {
1987 //
1988 // Display menu
1989 //
1990 DownArrow = FALSE;
1991 UpArrow = FALSE;
1992 Row = TopRow;
1993
1994 gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());
1995
1996 //
1997 // 1. Check whether need to print the arrow up.
1998 //
1999 if (!ValueIsScroll (TRUE, TopOfScreen)) {
2000 UpArrow = TRUE;
2001 }
2002
2003 PrintStringAtWithWidth(gStatementDimensions.LeftColumn, TopRow - 1, L"", gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn);
2004
2005 if (UpArrow) {
2006 gST->ConOut->SetAttribute (gST->ConOut, GetArrowColor ());
2007 PrintCharAt (
2008 gStatementDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1,
2009 TopRow - SCROLL_ARROW_HEIGHT,
2010 ARROW_UP
2011 );
2012 gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());
2013 }
2014
2015 //
2016 // 2.Paint the menu.
2017 //
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;
2024 } else {
2025 MenuOption->OptCol = gStatementDimensions.LeftColumn + LEFT_SKIPPED_COLUMNS + gPromptBlockWidth;
2026 }
2027
2028 if (MenuOption->NestInStatement) {
2029 MenuOption->Col += SUBTITLE_INDENT;
2030 }
2031
2032 //
2033 // Save the highlight menu, will be used in CfRefreshHighLight case.
2034 //
2035 if (Link == NewPos) {
2036 SavedMenuOption = MenuOption;
2037 SkipHighLight = TRUE;
2038 }
2039
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,
2044 BottomRow,
2045 Link == NewPos && IsSelectable(MenuOption)
2046 );
2047
2048 //
2049 // 3. Update the row info which will be used by next menu.
2050 //
2051 if (Link == TopOfScreen) {
2052 Row += MenuOption->Skip - SkipValue;
2053 } else {
2054 Row += MenuOption->Skip;
2055 }
2056
2057 if (Row > BottomRow) {
2058 if (!ValueIsScroll (FALSE, Link)) {
2059 DownArrow = TRUE;
2060 }
2061
2062 Row = BottomRow + 1;
2063 break;
2064 }
2065 }
2066
2067 //
2068 // 3. Menus in this form may not cover all form, clean the remain field.
2069 //
2070 while (Row <= BottomRow) {
2071 if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {
2072 PrintStringAtWithWidth(gStatementDimensions.LeftColumn, Row++, L"", gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn);
2073 } else {
2074 PrintStringAtWithWidth(gStatementDimensions.LeftColumn, Row++, L"", gStatementDimensions.RightColumn - gHelpBlockWidth - gStatementDimensions.LeftColumn);
2075 }
2076 }
2077
2078 //
2079 // 4. Print the down arrow row.
2080 //
2081 PrintStringAtWithWidth(gStatementDimensions.LeftColumn, BottomRow + 1, L"", gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn);
2082
2083 if (DownArrow) {
2084 gST->ConOut->SetAttribute (gST->ConOut, GetArrowColor ());
2085 PrintCharAt (
2086 gStatementDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1,
2087 BottomRow + SCROLL_ARROW_HEIGHT,
2088 ARROW_DOWN
2089 );
2090 gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());
2091 }
2092
2093 MenuOption = NULL;
2094
2095 if (IsListEmpty (&gMenuOption)) {
2096 ControlFlag = CfReadKey;
2097 }
2098 }
2099 break;
2100
2101 case CfRefreshHighLight:
2102
2103 //
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
2107 //
2108 ControlFlag = CfUpdateHelpString;
2109
2110 if (SkipHighLight) {
2111 MenuOption = SavedMenuOption;
2112 SkipHighLight = FALSE;
2113 UpdateHighlightMenuInfo (MenuOption);
2114 break;
2115 }
2116
2117 if (MenuOption != NULL && TopOfScreen == &MenuOption->Link) {
2118 Temp = SkipValue;
2119 } else {
2120 Temp = 0;
2121 }
2122 if (NewPos == TopOfScreen) {
2123 Temp2 = SkipValue;
2124 } else {
2125 Temp2 = 0;
2126 }
2127
2128 if (NewPos != NULL && (MenuOption == NULL || NewPos != &MenuOption->Link)) {
2129 if (MenuOption != NULL) {
2130 //
2131 // Remove highlight on last Menu Option
2132 //
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)
2139 ) {
2140 ProcessStringForDateTime(MenuOption, OptionString, FALSE);
2141 }
2142
2143 Width = (UINT16) gOptionBlockWidth;
2144 OriginalRow = MenuOption->Row;
2145 GlyphWidth = 1;
2146
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);
2150 }
2151 //
2152 // If there is more string to process print on the next row and increment the Skip value
2153 //
2154 if (StrLen (&OptionString[Index]) != 0) {
2155 if (Temp == 0) {
2156 MenuOption->Row++;
2157 }
2158 }
2159
2160 FreePool (OutputString);
2161 if (Temp != 0) {
2162 Temp--;
2163 }
2164 }
2165
2166 MenuOption->Row = OriginalRow;
2167
2168 FreePool (OptionString);
2169 } else {
2170 if (NewLine) {
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 ());
2175 }
2176
2177 OriginalRow = MenuOption->Row;
2178 Width = GetWidth (MenuOption->ThisTag, NULL);
2179 GlyphWidth = 1;
2180
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);
2184 }
2185 //
2186 // If there is more string to process print on the next row and increment the Skip value
2187 //
2188 if (StrLen (&MenuOption->Description[Index]) != 0) {
2189 if (Temp == 0) {
2190 MenuOption->Row++;
2191 }
2192 }
2193
2194 FreePool (OutputString);
2195 if (Temp != 0) {
2196 Temp--;
2197 }
2198 }
2199
2200 MenuOption->Row = OriginalRow;
2201 gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());
2202 }
2203 }
2204 }
2205
2206 //
2207 // This is the current selected statement
2208 //
2209 MenuOption = MENU_OPTION_FROM_LINK (NewPos);
2210 Statement = MenuOption->ThisTag;
2211
2212 UpdateHighlightMenuInfo (MenuOption);
2213
2214 if (!IsSelectable (MenuOption)) {
2215 break;
2216 }
2217
2218 //
2219 // Set reverse attribute
2220 //
2221 gST->ConOut->SetAttribute (gST->ConOut, GetHighlightTextColor ());
2222 gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row);
2223
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);
2228 }
2229 Width = (UINT16) gOptionBlockWidth;
2230
2231 OriginalRow = MenuOption->Row;
2232 GlyphWidth = 1;
2233
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);
2237 }
2238 //
2239 // If there is more string to process print on the next row and increment the Skip value
2240 //
2241 if (StrLen (&OptionString[Index]) != 0) {
2242 if (Temp2 == 0) {
2243 MenuOption->Row++;
2244 }
2245 }
2246
2247 FreePool (OutputString);
2248 if (Temp2 != 0) {
2249 Temp2--;
2250 }
2251 }
2252
2253 MenuOption->Row = OriginalRow;
2254
2255 FreePool (OptionString);
2256 } else {
2257 if (NewLine) {
2258 OriginalRow = MenuOption->Row;
2259
2260 Width = GetWidth (Statement, NULL);
2261 GlyphWidth = 1;
2262
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);
2266 }
2267 //
2268 // If there is more string to process print on the next row and increment the Skip value
2269 //
2270 if (StrLen (&MenuOption->Description[Index]) != 0) {
2271 if (Temp2 == 0) {
2272 MenuOption->Row++;
2273 }
2274 }
2275
2276 FreePool (OutputString);
2277 if (Temp2 != 0) {
2278 Temp2--;
2279 }
2280 }
2281
2282 MenuOption->Row = OriginalRow;
2283
2284 }
2285 }
2286
2287 //
2288 // Clear reverse attribute
2289 //
2290 gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());
2291 }
2292 break;
2293
2294 case CfUpdateHelpString:
2295 ControlFlag = CfPrepareToReadKey;
2296 if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {
2297 break;
2298 }
2299
2300 if (Repaint || NewLine) {
2301 //
2302 // Don't print anything if it is a NULL help token
2303 //
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);
2308 } else {
2309 StringPtr = GetToken (HelpInfo, gFormData->HiiHandle);
2310 }
2311
2312 RowCount = BottomRow - TopRow + 1;
2313 HelpPageIndex = 0;
2314 //
2315 // 1.Calculate how many line the help string need to print.
2316 //
2317 if (HelpString != NULL) {
2318 FreePool (HelpString);
2319 HelpString = NULL;
2320 }
2321 HelpLine = ProcessHelpString (StringPtr, &HelpString, &EachLineWidth, RowCount);
2322 FreePool (StringPtr);
2323
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;
2330 }
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;
2337 }
2338 HelpBottomLine = ProcessHelpString (StringPtr, &HelpBottomString, &BottomLineWidth, 0);
2339 FreePool (StringPtr);
2340 //
2341 // Calculate the help page count.
2342 //
2343 if (HelpLine > 2 * RowCount - 2) {
2344 HelpPageCount = (HelpLine - RowCount + 1) / (RowCount - 2) + 1;
2345 if ((HelpLine - RowCount + 1) % (RowCount - 2) > 1) {
2346 HelpPageCount += 1;
2347 }
2348 } else {
2349 HelpPageCount = 2;
2350 }
2351 } else {
2352 MultiHelpPage = FALSE;
2353 }
2354 }
2355
2356 //
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.
2361 //
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,
2369 Index + TopRow,
2370 gEmptyString,
2371 gHelpBlockWidth
2372 );
2373 PrintStringAt (
2374 gStatementDimensions.RightColumn - GetStringWidth (HelpHeaderString) / 2 - 1,
2375 Index + TopRow,
2376 &HelpHeaderString[Index * HeaderLineWidth]
2377 );
2378 }
2379 }
2380
2381 gST->ConOut->SetAttribute (gST->ConOut, GetHelpTextColor ());
2382 //
2383 // Print the help string info.
2384 //
2385 if (!MultiHelpPage) {
2386 for (Index = 0; Index < HelpLine; Index++) {
2387 PrintStringAtWithWidth (
2388 gStatementDimensions.RightColumn - gHelpBlockWidth,
2389 Index + TopRow,
2390 &HelpString[Index * EachLineWidth],
2391 gHelpBlockWidth
2392 );
2393 }
2394 for (; Index < RowCount; Index ++) {
2395 PrintStringAtWithWidth (
2396 gStatementDimensions.RightColumn - gHelpBlockWidth,
2397 Index + TopRow,
2398 gEmptyString,
2399 gHelpBlockWidth
2400 );
2401 }
2402 gST->ConOut->SetCursorPosition(gST->ConOut, gStatementDimensions.RightColumn-1, BottomRow);
2403 } else {
2404 if (HelpPageIndex == 0) {
2405 for (Index = 0; Index < RowCount - HelpBottomLine; Index++) {
2406 PrintStringAtWithWidth (
2407 gStatementDimensions.RightColumn - gHelpBlockWidth,
2408 Index + TopRow,
2409 &HelpString[Index * EachLineWidth],
2410 gHelpBlockWidth
2411 );
2412 }
2413 } else {
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],
2420 gHelpBlockWidth
2421 );
2422 }
2423 if (HelpPageIndex == HelpPageCount - 1) {
2424 for (; Index < RowCount - HelpHeaderLine; Index ++) {
2425 PrintStringAtWithWidth (
2426 gStatementDimensions.RightColumn - gHelpBlockWidth,
2427 Index + TopRow + HelpHeaderLine,
2428 gEmptyString,
2429 gHelpBlockWidth
2430 );
2431 }
2432 gST->ConOut->SetCursorPosition(gST->ConOut, gStatementDimensions.RightColumn-1, BottomRow);
2433 }
2434 }
2435 }
2436
2437 //
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.
2442 //
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,
2451 gEmptyString,
2452 gHelpBlockWidth
2453 );
2454 PrintStringAt (
2455 gStatementDimensions.RightColumn - GetStringWidth (HelpBottomString) / 2 - 1,
2456 BottomRow + Index - HelpBottomLine + 1,
2457 &HelpBottomString[Index * BottomLineWidth]
2458 );
2459 }
2460 }
2461 //
2462 // Reset this flag every time we finish using it.
2463 //
2464 Repaint = FALSE;
2465 NewLine = FALSE;
2466 break;
2467
2468 case CfPrepareToReadKey:
2469 ControlFlag = CfReadKey;
2470 ScreenOperation = UiNoOperation;
2471 break;
2472
2473 case CfReadKey:
2474 ControlFlag = CfScreenOperation;
2475
2476 //
2477 // Wait for user's selection
2478 //
2479 while (TRUE) {
2480 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
2481 if (!EFI_ERROR (Status)) {
2482 EventType = UIEventKey;
2483 break;
2484 }
2485
2486 //
2487 // If we encounter error, continue to read another key in.
2488 //
2489 if (Status != EFI_NOT_READY) {
2490 continue;
2491 }
2492
2493 EventType = UiWaitForEvent(gST->ConIn->WaitForKey);
2494 if (EventType == UIEventKey) {
2495 gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
2496 }
2497 break;
2498 }
2499
2500 if (EventType == UIEventDriver) {
2501 gUserInput->Action = BROWSER_ACTION_NONE;
2502 ControlFlag = CfExit;
2503 break;
2504 }
2505
2506 if (EventType == UIEventTimeOut) {
2507 gUserInput->Action = BROWSER_ACTION_FORM_EXIT;
2508 ControlFlag = CfExit;
2509 break;
2510 }
2511
2512 switch (Key.UnicodeChar) {
2513 case CHAR_CARRIAGE_RETURN:
2514 if(MenuOption == NULL || MenuOption->GrayOut || MenuOption->ReadOnly) {
2515 ControlFlag = CfReadKey;
2516 break;
2517 }
2518
2519 ScreenOperation = UiSelect;
2520 gDirection = 0;
2521 break;
2522
2523 //
2524 // We will push the adjustment of these numeric values directly to the input handler
2525 // NOTE: we won't handle manual input numeric
2526 //
2527 case '+':
2528 case '-':
2529 //
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.
2532 //
2533 if(IsListEmpty (&gMenuOption) || MenuOption->GrayOut || MenuOption->ReadOnly) {
2534 ControlFlag = CfReadKey;
2535 break;
2536 }
2537
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))
2543 ){
2544 if (Key.UnicodeChar == '+') {
2545 gDirection = SCAN_RIGHT;
2546 } else {
2547 gDirection = SCAN_LEFT;
2548 }
2549
2550 Status = ProcessOptions (MenuOption, TRUE, &OptionString, TRUE);
2551 if (OptionString != NULL) {
2552 FreePool (OptionString);
2553 }
2554 if (EFI_ERROR (Status)) {
2555 //
2556 // Repaint to clear possible error prompt pop-up
2557 //
2558 Repaint = TRUE;
2559 NewLine = TRUE;
2560 } else {
2561 ControlFlag = CfExit;
2562 }
2563 }
2564 break;
2565
2566 case '^':
2567 ScreenOperation = UiUp;
2568 break;
2569
2570 case 'V':
2571 case 'v':
2572 ScreenOperation = UiDown;
2573 break;
2574
2575 case ' ':
2576 if(IsListEmpty (&gMenuOption)) {
2577 ControlFlag = CfReadKey;
2578 break;
2579 }
2580
2581 ASSERT(MenuOption != NULL);
2582 if (MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_CHECKBOX_OP && !MenuOption->GrayOut && !MenuOption->ReadOnly) {
2583 ScreenOperation = UiSelect;
2584 }
2585 break;
2586
2587 case 'D':
2588 case 'd':
2589 if (!MultiHelpPage) {
2590 ControlFlag = CfReadKey;
2591 break;
2592 }
2593 ControlFlag = CfUpdateHelpString;
2594 HelpPageIndex = HelpPageIndex < HelpPageCount - 1 ? HelpPageIndex + 1 : HelpPageCount - 1;
2595 break;
2596
2597 case 'U':
2598 case 'u':
2599 if (!MultiHelpPage) {
2600 ControlFlag = CfReadKey;
2601 break;
2602 }
2603 ControlFlag = CfUpdateHelpString;
2604 HelpPageIndex = HelpPageIndex > 0 ? HelpPageIndex - 1 : 0;
2605 break;
2606
2607 case CHAR_NULL:
2608 for (Index = 0; Index < mScanCodeNumber; Index++) {
2609 if (Key.ScanCode == gScanCodeToOperation[Index].ScanCode) {
2610 ScreenOperation = gScanCodeToOperation[Index].ScreenOperation;
2611 break;
2612 }
2613 }
2614
2615 if (((FormData->Attribute & HII_DISPLAY_MODAL) != 0) && (Key.ScanCode == SCAN_ESC || Index == mScanCodeNumber)) {
2616 //
2617 // ModalForm has no ESC key and Hot Key.
2618 //
2619 ControlFlag = CfReadKey;
2620 } else if (Index == mScanCodeNumber) {
2621 //
2622 // Check whether Key matches the registered hot key.
2623 //
2624 HotKey = NULL;
2625 HotKey = GetHotKeyFromRegisterList (&Key);
2626 if (HotKey != NULL) {
2627 ScreenOperation = UiHotKey;
2628 }
2629 }
2630 break;
2631 }
2632 break;
2633
2634 case CfScreenOperation:
2635 if (ScreenOperation != UiReset) {
2636 //
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.
2639 //
2640 if (IsListEmpty (&gMenuOption)) {
2641 ControlFlag = CfReadKey;
2642 break;
2643 }
2644 }
2645
2646 for (Index = 0;
2647 Index < sizeof (gScreenOperationToControlFlag) / sizeof (gScreenOperationToControlFlag[0]);
2648 Index++
2649 ) {
2650 if (ScreenOperation == gScreenOperationToControlFlag[Index].ScreenOperation) {
2651 ControlFlag = gScreenOperationToControlFlag[Index].ControlFlag;
2652 break;
2653 }
2654 }
2655 break;
2656
2657 case CfUiSelect:
2658 ControlFlag = CfRepaint;
2659
2660 ASSERT(MenuOption != NULL);
2661 Statement = MenuOption->ThisTag;
2662 if (Statement->OpCode->OpCode == EFI_IFR_TEXT_OP) {
2663 break;
2664 }
2665
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;
2671 break;
2672
2673 default:
2674 //
2675 // Editable Questions: oneof, ordered list, checkbox, numeric, string, password
2676 //
2677 RefreshKeyHelp (gFormData, Statement, TRUE);
2678 Status = ProcessOptions (MenuOption, TRUE, &OptionString, TRUE);
2679
2680 if (OptionString != NULL) {
2681 FreePool (OptionString);
2682 }
2683
2684 if (EFI_ERROR (Status)) {
2685 Repaint = TRUE;
2686 NewLine = TRUE;
2687 RefreshKeyHelp (gFormData, Statement, FALSE);
2688 break;
2689 } else {
2690 ControlFlag = CfExit;
2691 break;
2692 }
2693 }
2694 break;
2695
2696 case CfUiReset:
2697 //
2698 // We come here when someone press ESC
2699 // If the policy is not exit front page when user press ESC, process here.
2700 //
2701 if (!FormExitPolicy()) {
2702 Repaint = TRUE;
2703 NewLine = TRUE;
2704 ControlFlag = CfRepaint;
2705 break;
2706 }
2707
2708 //
2709 // When user press ESC, it will try to show another menu, should clean the gSequence info.
2710 //
2711 if (gSequence != 0) {
2712 gSequence = 0;
2713 }
2714
2715 gUserInput->Action = BROWSER_ACTION_FORM_EXIT;
2716 ControlFlag = CfExit;
2717 break;
2718
2719 case CfUiHotKey:
2720 ControlFlag = CfRepaint;
2721
2722 gUserInput->Action = HotKey->Action;
2723 ControlFlag = CfExit;
2724 break;
2725
2726 case CfUiLeft:
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) {
2731 //
2732 // In the middle or tail of the Date/Time op-code set, go left.
2733 //
2734 ASSERT(NewPos != NULL);
2735 NewPos = NewPos->BackLink;
2736 }
2737 }
2738 break;
2739
2740 case CfUiRight:
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) {
2745 //
2746 // In the middle or tail of the Date/Time op-code set, go left.
2747 //
2748 ASSERT(NewPos != NULL);
2749 NewPos = NewPos->ForwardLink;
2750 }
2751 }
2752 break;
2753
2754 case CfUiUp:
2755 ControlFlag = CfRepaint;
2756
2757 SavedListEntry = NewPos;
2758
2759 ASSERT(NewPos != NULL);
2760 //
2761 // Adjust Date/Time position before we advance forward.
2762 //
2763 AdjustDateAndTimePosition (TRUE, &NewPos);
2764 if (NewPos->BackLink != &gMenuOption) {
2765 MenuOption = MENU_OPTION_FROM_LINK (NewPos);
2766 ASSERT (MenuOption != NULL);
2767 NewLine = TRUE;
2768 NewPos = NewPos->BackLink;
2769
2770 PreviousMenuOption = MENU_OPTION_FROM_LINK (NewPos);
2771 if (PreviousMenuOption->Row == 0) {
2772 UpdateOptionSkipLines (PreviousMenuOption);
2773 }
2774 DistanceValue = PreviousMenuOption->Skip;
2775 Difference = 0;
2776 if (MenuOption->Row >= DistanceValue + TopRow) {
2777 Difference = MoveToNextStatement (TRUE, &NewPos, MenuOption->Row - TopRow - DistanceValue);
2778 }
2779 NextMenuOption = MENU_OPTION_FROM_LINK (NewPos);
2780
2781 if (Difference < 0) {
2782 //
2783 // We hit the begining MenuOption that can be focused
2784 // so we simply scroll to the top.
2785 //
2786 if (TopOfScreen != gMenuOption.ForwardLink) {
2787 TopOfScreen = gMenuOption.ForwardLink;
2788 Repaint = TRUE;
2789 } else {
2790 //
2791 // Scroll up to the last page when we have arrived at top page.
2792 //
2793 NewPos = &gMenuOption;
2794 TopOfScreen = &gMenuOption;
2795 MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);
2796 ScreenOperation = UiPageUp;
2797 ControlFlag = CfScreenOperation;
2798 break;
2799 }
2800 } else if (MenuOption->Row < TopRow + DistanceValue + Difference) {
2801 //
2802 // Previous focus MenuOption is above the TopOfScreen, so we need to scroll
2803 //
2804 TopOfScreen = NewPos;
2805 Repaint = TRUE;
2806 SkipValue = 0;
2807 } else if (!IsSelectable (NextMenuOption)) {
2808 //
2809 // Continue to go up until scroll to next page or the selectable option is found.
2810 //
2811 ScreenOperation = UiUp;
2812 ControlFlag = CfScreenOperation;
2813 }
2814
2815 //
2816 // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
2817 //
2818 AdjustDateAndTimePosition (TRUE, &TopOfScreen);
2819 AdjustDateAndTimePosition (TRUE, &NewPos);
2820 MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);
2821 UpdateStatusBar (INPUT_ERROR, FALSE);
2822 } else {
2823 //
2824 // Scroll up to the last page.
2825 //
2826 NewPos = &gMenuOption;
2827 TopOfScreen = &gMenuOption;
2828 MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);
2829 ScreenOperation = UiPageUp;
2830 ControlFlag = CfScreenOperation;
2831 }
2832 break;
2833
2834 case CfUiPageUp:
2835 //
2836 // SkipValue means lines is skipped when show the top menu option.
2837 //
2838 ControlFlag = CfRepaint;
2839
2840 ASSERT(NewPos != NULL);
2841 //
2842 // Already at the first menu option, Check the skip value.
2843 //
2844 if (NewPos->BackLink == &gMenuOption) {
2845 if (SkipValue == 0) {
2846 NewLine = FALSE;
2847 Repaint = FALSE;
2848 } else {
2849 NewLine = TRUE;
2850 Repaint = TRUE;
2851 SkipValue = 0;
2852 }
2853 break;
2854 }
2855
2856 NewLine = TRUE;
2857 Repaint = TRUE;
2858
2859 //
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.
2863 //
2864 if (SkipValue > (INTN) (BottomRow - TopRow + 1)) {
2865 SkipValue -= BottomRow - TopRow + 1;
2866 break;
2867 }
2868
2869 Link = TopOfScreen;
2870 //
2871 // First minus the menu of the top screen, it's value is SkipValue.
2872 //
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);
2879 }
2880 if (Index < PreviousMenuOption->Skip) {
2881 break;
2882 }
2883 Index = Index - PreviousMenuOption->Skip;
2884 }
2885
2886 if ((Link->BackLink == &gMenuOption) && (Index >= TopRow)) {
2887 SkipValue = 0;
2888 if (TopOfScreen == &gMenuOption) {
2889 TopOfScreen = gMenuOption.ForwardLink;
2890 NewPos = gMenuOption.BackLink;
2891 MoveToNextStatement (TRUE, &NewPos, BottomRow - TopRow);
2892 Repaint = FALSE;
2893 } else if (TopOfScreen != Link) {
2894 TopOfScreen = Link;
2895 NewPos = Link;
2896 MoveToNextStatement (FALSE, &NewPos, BottomRow - TopRow);
2897 } else {
2898 //
2899 // Finally we know that NewPos is the last MenuOption can be focused.
2900 //
2901 Repaint = FALSE;
2902 NewPos = Link;
2903 MoveToNextStatement (FALSE, &NewPos, BottomRow - TopRow);
2904 }
2905 } else {
2906 if (Index > TopRow) {
2907 //
2908 // At here, only case "Index < PreviousMenuOption->Skip" can reach here.
2909 //
2910 SkipValue = PreviousMenuOption->Skip - (Index - TopRow);
2911 } else if (Index == TopRow) {
2912 SkipValue = 0;
2913 } else {
2914 SkipValue = TopRow - Index;
2915 }
2916
2917 //
2918 // Move to the option in Next page.
2919 //
2920 if (TopOfScreen == &gMenuOption) {
2921 NewPos = gMenuOption.BackLink;
2922 MoveToNextStatement (TRUE, &NewPos, BottomRow - TopRow);
2923 } else {
2924 NewPos = Link;
2925 MoveToNextStatement (FALSE, &NewPos, BottomRow - TopRow);
2926 }
2927
2928 //
2929 // There are more MenuOption needing scrolling up.
2930 //
2931 TopOfScreen = Link;
2932 MenuOption = NULL;
2933 }
2934
2935 //
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.
2938 //
2939 AdjustDateAndTimePosition (TRUE, &TopOfScreen);
2940 AdjustDateAndTimePosition (TRUE, &NewPos);
2941 break;
2942
2943 case CfUiPageDown:
2944 //
2945 // SkipValue means lines is skipped when show the top menu option.
2946 //
2947 ControlFlag = CfRepaint;
2948
2949 ASSERT (NewPos != NULL);
2950 if (NewPos->ForwardLink == &gMenuOption) {
2951 NewLine = FALSE;
2952 Repaint = FALSE;
2953 break;
2954 }
2955
2956 NewLine = TRUE;
2957 Repaint = TRUE;
2958 Link = TopOfScreen;
2959 NextMenuOption = MENU_OPTION_FROM_LINK (Link);
2960 Index = TopRow + NextMenuOption->Skip - SkipValue;
2961 //
2962 // Count to the menu option which will show at the top of the next form.
2963 //
2964 while ((Index <= BottomRow + 1) && (Link->ForwardLink != &gMenuOption)) {
2965 Link = Link->ForwardLink;
2966 NextMenuOption = MENU_OPTION_FROM_LINK (Link);
2967 Index = Index + NextMenuOption->Skip;
2968 }
2969
2970 if ((Link->ForwardLink == &gMenuOption) && (Index <= BottomRow + 1)) {
2971 //
2972 // Finally we know that NewPos is the last MenuOption can be focused.
2973 //
2974 Repaint = FALSE;
2975 MoveToNextStatement (TRUE, &Link, Index - TopRow);
2976 } else {
2977 //
2978 // Calculate the skip line for top of screen menu.
2979 //
2980 if (Link == TopOfScreen) {
2981 //
2982 // The top of screen menu option occupies the entire form.
2983 //
2984 SkipValue += BottomRow - TopRow + 1;
2985 } else {
2986 SkipValue = NextMenuOption->Skip - (Index - (BottomRow + 1));
2987 }
2988
2989 TopOfScreen = Link;
2990 MenuOption = NULL;
2991 //
2992 // Move to the Next selectable menu.
2993 //
2994 MoveToNextStatement (FALSE, &Link, BottomRow - TopRow);
2995 }
2996
2997 //
2998 // Save the menu as the next highlight menu.
2999 //
3000 NewPos = Link;
3001
3002 //
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.
3005 //
3006 AdjustDateAndTimePosition (TRUE, &TopOfScreen);
3007 AdjustDateAndTimePosition (TRUE, &NewPos);
3008 break;
3009
3010 case CfUiDown:
3011 //
3012 // SkipValue means lines is skipped when show the top menu option.
3013 // NewPos points to the menu which is highlighted now.
3014 //
3015 ControlFlag = CfRepaint;
3016
3017 //
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.
3024 //
3025 SavedListEntry = NewPos;
3026 AdjustDateAndTimePosition (FALSE, &NewPos);
3027
3028 if (NewPos->ForwardLink != &gMenuOption) {
3029 MenuOption = MENU_OPTION_FROM_LINK (NewPos);
3030 NewLine = TRUE;
3031 NewPos = NewPos->ForwardLink;
3032
3033 Difference = 0;
3034 //
3035 // Current menu not at the bottom of the form.
3036 //
3037 if (BottomRow >= MenuOption->Row + MenuOption->Skip) {
3038 //
3039 // Find the next selectable menu.
3040 //
3041 Difference = MoveToNextStatement (FALSE, &NewPos, BottomRow - MenuOption->Row - MenuOption->Skip);
3042 //
3043 // We hit the end of MenuOption that can be focused
3044 // so we simply scroll to the first page.
3045 //
3046 if (Difference < 0) {
3047 //
3048 // Scroll to the first page.
3049 //
3050 if (TopOfScreen != gMenuOption.ForwardLink) {
3051 TopOfScreen = gMenuOption.ForwardLink;
3052 Repaint = TRUE;
3053 MenuOption = NULL;
3054 } else {
3055 MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);
3056 }
3057 NewPos = gMenuOption.ForwardLink;
3058 MoveToNextStatement (FALSE, &NewPos, BottomRow - TopRow);
3059
3060 SkipValue = 0;
3061 //
3062 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
3063 //
3064 AdjustDateAndTimePosition (TRUE, &TopOfScreen);
3065 AdjustDateAndTimePosition (TRUE, &NewPos);
3066 break;
3067 }
3068 }
3069 NextMenuOption = MENU_OPTION_FROM_LINK (NewPos);
3070 if (NextMenuOption->Row == 0) {
3071 UpdateOptionSkipLines (NextMenuOption);
3072 }
3073 DistanceValue = Difference + NextMenuOption->Skip;
3074
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)
3079 ) {
3080 Temp ++;
3081 }
3082
3083 //
3084 // If we are going to scroll, update TopOfScreen
3085 //
3086 if (Temp > BottomRow) {
3087 do {
3088 //
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
3091 //
3092 SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);
3093
3094 //
3095 // If bottom op-code is more than one line or top op-code is more than one line
3096 //
3097 if ((DistanceValue > 1) || (SavedMenuOption->Skip > 1)) {
3098 //
3099 // Is the bottom op-code greater than or equal in size to the top op-code?
3100 //
3101 if ((Temp - BottomRow) >= (SavedMenuOption->Skip - SkipValue)) {
3102 //
3103 // Skip the top op-code
3104 //
3105 TopOfScreen = TopOfScreen->ForwardLink;
3106 Difference = (Temp - BottomRow) - (SavedMenuOption->Skip - SkipValue);
3107
3108 SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);
3109
3110 //
3111 // If we have a remainder, skip that many more op-codes until we drain the remainder
3112 //
3113 while (Difference >= (INTN) SavedMenuOption->Skip) {
3114 //
3115 // Since the Difference is greater than or equal to this op-code's skip value, skip it
3116 //
3117 Difference = Difference - (INTN) SavedMenuOption->Skip;
3118 TopOfScreen = TopOfScreen->ForwardLink;
3119 SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);
3120 }
3121 //
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.
3124 //
3125 SkipValue = Difference - 1;
3126 } else {
3127 //
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.
3130 //
3131 SkipValue += (Temp - BottomRow) - 1;
3132 }
3133 } else {
3134 if ((SkipValue + 1) == (INTN) SavedMenuOption->Skip) {
3135 TopOfScreen = TopOfScreen->ForwardLink;
3136 break;
3137 }
3138 }
3139 //
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.
3142 //
3143 if (SavedMenuOption->Skip > 1) {
3144 if (SavedMenuOption == NextMenuOption) {
3145 SkipValue = 0;
3146 } else {
3147 SkipValue++;
3148 }
3149 } else if (SavedMenuOption->Skip == 1) {
3150 SkipValue = 0;
3151 } else {
3152 SkipValue = 0;
3153 TopOfScreen = TopOfScreen->ForwardLink;
3154 }
3155 } while (SavedMenuOption->Skip == 0);
3156
3157 Repaint = TRUE;
3158 } else if (!IsSelectable (NextMenuOption)) {
3159 //
3160 // Continue to go down until scroll to next page or the selectable option is found.
3161 //
3162 ScreenOperation = UiDown;
3163 ControlFlag = CfScreenOperation;
3164 }
3165
3166 MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);
3167
3168 UpdateStatusBar (INPUT_ERROR, FALSE);
3169
3170 } else {
3171 //
3172 // Scroll to the first page.
3173 //
3174 if (TopOfScreen != gMenuOption.ForwardLink) {
3175 TopOfScreen = gMenuOption.ForwardLink;
3176 Repaint = TRUE;
3177 MenuOption = NULL;
3178 } else {
3179 //
3180 // Need to remove the current highlight menu.
3181 // MenuOption saved the last highlight menu info.
3182 //
3183 MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);
3184 }
3185
3186 SkipValue = 0;
3187 NewLine = TRUE;
3188 //
3189 // Get the next highlight menu.
3190 //
3191 NewPos = gMenuOption.ForwardLink;
3192 MoveToNextStatement (FALSE, &NewPos, BottomRow - TopRow);
3193 }
3194
3195 //
3196 // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
3197 //
3198 AdjustDateAndTimePosition (TRUE, &TopOfScreen);
3199 AdjustDateAndTimePosition (TRUE, &NewPos);
3200 break;
3201
3202 case CfUiNoOperation:
3203 ControlFlag = CfRepaint;
3204 break;
3205
3206 case CfExit:
3207 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
3208 if (HelpString != NULL) {
3209 FreePool (HelpString);
3210 }
3211 if (HelpHeaderString != NULL) {
3212 FreePool (HelpHeaderString);
3213 }
3214 if (HelpBottomString != NULL) {
3215 FreePool (HelpBottomString);
3216 }
3217 return EFI_SUCCESS;
3218
3219 default:
3220 break;
3221 }
3222 }
3223 }
3224
3225 /**
3226
3227 Base on the browser status info to show an pop up message.
3228
3229 **/
3230 VOID
3231 BrowserStatusProcess (
3232 VOID
3233 )
3234 {
3235 CHAR16 *ErrorInfo;
3236 EFI_INPUT_KEY Key;
3237
3238 if (gFormData->BrowserStatus == BROWSER_SUCCESS) {
3239 return;
3240 }
3241
3242 if (gFormData->ErrorString != NULL) {
3243 ErrorInfo = gFormData->ErrorString;
3244 } else {
3245 switch (gFormData->BrowserStatus) {
3246 case BROWSER_SUBMIT_FAIL:
3247 ErrorInfo = gSaveFailed;
3248 break;
3249
3250 case BROWSER_NO_SUBMIT_IF:
3251 ErrorInfo = gNoSubmitIf;
3252 break;
3253
3254 case BROWSER_FORM_NOT_FOUND:
3255 ErrorInfo = gFormNotFound;
3256 break;
3257
3258 case BROWSER_FORM_SUPPRESS:
3259 ErrorInfo = gFormSuppress;
3260 break;
3261
3262 case BROWSER_PROTOCOL_NOT_FOUND:
3263 ErrorInfo = gProtocolNotFound;
3264 break;
3265
3266 default:
3267 ErrorInfo = gBrwoserError;
3268 break;
3269 }
3270 }
3271
3272 //
3273 // Error occur, prompt error message.
3274 //
3275 do {
3276 CreateDialog (&Key, gEmptyString, ErrorInfo, gPressEnter, gEmptyString, NULL);
3277 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
3278 }
3279
3280 /**
3281 Display one form, and return user input.
3282
3283 @param FormData Form Data to be shown.
3284 @param UserInputData User input data.
3285
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.
3290 **/
3291 EFI_STATUS
3292 EFIAPI
3293 FormDisplay (
3294 IN FORM_DISPLAY_ENGINE_FORM *FormData,
3295 OUT USER_INPUT *UserInputData
3296 )
3297 {
3298 EFI_STATUS Status;
3299
3300 ASSERT (FormData != NULL);
3301 if (FormData == NULL) {
3302 return EFI_INVALID_PARAMETER;
3303 }
3304
3305 gUserInput = UserInputData;
3306 gFormData = FormData;
3307
3308 //
3309 // Process the status info first.
3310 //
3311 BrowserStatusProcess();
3312 if (UserInputData == NULL) {
3313 //
3314 // UserInputData == NULL, means only need to print the error info, return here.
3315 //
3316 return EFI_SUCCESS;
3317 }
3318
3319 ConvertStatementToMenu();
3320
3321 Status = DisplayPageFrame (FormData, &gStatementDimensions);
3322 if (EFI_ERROR (Status)) {
3323 return Status;
3324 }
3325
3326 //
3327 // Check whether layout is changed.
3328 //
3329 if (mIsFirstForm
3330 || (gOldFormEntry.HiiHandle != FormData->HiiHandle)
3331 || (!CompareGuid (&gOldFormEntry.FormSetGuid, &FormData->FormSetGuid))
3332 || (gOldFormEntry.FormId != FormData->FormId)) {
3333 mStatementLayoutIsChanged = TRUE;
3334 } else {
3335 mStatementLayoutIsChanged = FALSE;
3336 }
3337
3338 Status = UiDisplayMenu(FormData);
3339
3340 //
3341 // Backup last form info.
3342 //
3343 mIsFirstForm = FALSE;
3344 gOldFormEntry.HiiHandle = FormData->HiiHandle;
3345 CopyGuid (&gOldFormEntry.FormSetGuid, &FormData->FormSetGuid);
3346 gOldFormEntry.FormId = FormData->FormId;
3347
3348 return Status;
3349 }
3350
3351 /**
3352 Clear Screen to the initial state.
3353 **/
3354 VOID
3355 EFIAPI
3356 DriverClearDisplayPage (
3357 VOID
3358 )
3359 {
3360 ClearDisplayPage ();
3361 mIsFirstForm = TRUE;
3362 }
3363
3364 /**
3365 Set Buffer to Value for Size bytes.
3366
3367 @param Buffer Memory to set.
3368 @param Size Number of bytes to set
3369 @param Value Value of the set operation.
3370
3371 **/
3372 VOID
3373 SetUnicodeMem (
3374 IN VOID *Buffer,
3375 IN UINTN Size,
3376 IN CHAR16 Value
3377 )
3378 {
3379 CHAR16 *Ptr;
3380
3381 Ptr = Buffer;
3382 while ((Size--) != 0) {
3383 *(Ptr++) = Value;
3384 }
3385 }
3386
3387 /**
3388 Initialize Setup Browser driver.
3389
3390 @param ImageHandle The image handle.
3391 @param SystemTable The system table.
3392
3393 @retval EFI_SUCCESS The Setup Browser module is initialized correctly..
3394 @return Other value if failed to initialize the Setup Browser module.
3395
3396 **/
3397 EFI_STATUS
3398 EFIAPI
3399 InitializeDisplayEngine (
3400 IN EFI_HANDLE ImageHandle,
3401 IN EFI_SYSTEM_TABLE *SystemTable
3402 )
3403 {
3404 EFI_STATUS Status;
3405 EFI_INPUT_KEY HotKey;
3406 EFI_STRING NewString;
3407 EDKII_FORM_BROWSER_EXTENSION2_PROTOCOL *FormBrowserEx2;
3408
3409 //
3410 // Publish our HII data
3411 //
3412 gHiiHandle = HiiAddPackages (
3413 &gDisplayEngineGuid,
3414 ImageHandle,
3415 DisplayEngineStrings,
3416 NULL
3417 );
3418 ASSERT (gHiiHandle != NULL);
3419
3420 //
3421 // Install Form Display protocol
3422 //
3423 Status = gBS->InstallProtocolInterface (
3424 &mPrivateData.Handle,
3425 &gEdkiiFormDisplayEngineProtocolGuid,
3426 EFI_NATIVE_INTERFACE,
3427 &mPrivateData.FromDisplayProt
3428 );
3429 ASSERT_EFI_ERROR (Status);
3430
3431 InitializeDisplayStrings();
3432
3433 ZeroMem (&gHighligthMenuInfo, sizeof (gHighligthMenuInfo));
3434 ZeroMem (&gOldFormEntry, sizeof (gOldFormEntry));
3435
3436 //
3437 // Use BrowserEx2 protocol to register HotKey.
3438 //
3439 Status = gBS->LocateProtocol (&gEdkiiFormBrowserEx2ProtocolGuid, NULL, (VOID **) &FormBrowserEx2);
3440 if (!EFI_ERROR (Status)) {
3441 //
3442 // Register the default HotKey F9 and F10 again.
3443 //
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);
3449
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);
3454 }
3455
3456 return EFI_SUCCESS;
3457 }
3458
3459 /**
3460 This is the default unload handle for display core drivers.
3461
3462 @param[in] ImageHandle The drivers' driver image.
3463
3464 @retval EFI_SUCCESS The image is unloaded.
3465 @retval Others Failed to unload the image.
3466
3467 **/
3468 EFI_STATUS
3469 EFIAPI
3470 UnloadDisplayEngine (
3471 IN EFI_HANDLE ImageHandle
3472 )
3473 {
3474 HiiRemovePackages(gHiiHandle);
3475
3476 FreeDisplayStrings ();
3477
3478 return EFI_SUCCESS;
3479 }