Home | History | Annotate | Download | only in CustomizedDisplayLib
      1 /** @file
      2 
      3   This library class defines a set of interfaces to customize Display module
      4 
      5 Copyright (c) 2013-2015, Intel Corporation. All rights reserved.<BR>
      6 This program and the accompanying materials are licensed and made available under
      7 the terms and conditions of the BSD License that accompanies this distribution.
      8 The full text of the license may be found at
      9 http://opensource.org/licenses/bsd-license.php.
     10 
     11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 #include "CustomizedDisplayLibInternal.h"
     16 
     17 EFI_SCREEN_DESCRIPTOR         gScreenDimensions;
     18 CHAR16                        *mLibUnknownString;
     19 extern EFI_HII_HANDLE         mCDLStringPackHandle;
     20 CHAR16                        *mSpaceBuffer;
     21 #define SPACE_BUFFER_SIZE      1000
     22 
     23 //
     24 // Browser Global Strings
     25 //
     26 CHAR16            *gEnterString;
     27 CHAR16            *gEnterCommitString;
     28 CHAR16            *gEnterEscapeString;
     29 CHAR16            *gEscapeString;
     30 CHAR16            *gMoveHighlight;
     31 CHAR16            *gDecNumericInput;
     32 CHAR16            *gHexNumericInput;
     33 CHAR16            *gToggleCheckBox;
     34 CHAR16            *gLibEmptyString;
     35 CHAR16            *gAreYouSure;
     36 CHAR16            *gYesResponse;
     37 CHAR16            *gNoResponse;
     38 CHAR16            *gPlusString;
     39 CHAR16            *gMinusString;
     40 CHAR16            *gAdjustNumber;
     41 CHAR16            *gSaveChanges;
     42 CHAR16            *gNvUpdateMessage;
     43 CHAR16            *gInputErrorMessage;
     44 
     45 /**
     46 
     47   Print banner info for front page.
     48 
     49   @param[in]  FormData             Form Data to be shown in Page
     50 
     51 **/
     52 VOID
     53 PrintBannerInfo (
     54   IN FORM_DISPLAY_ENGINE_FORM       *FormData
     55   )
     56 {
     57   UINT8                  Line;
     58   UINT8                  Alignment;
     59   CHAR16                 *StrFrontPageBanner;
     60   UINT8                  RowIdx;
     61   UINT8                  ColumnIdx;
     62 
     63   //
     64   //    ClearLines(0, LocalScreen.RightColumn, 0, BANNER_HEIGHT-1, BANNER_TEXT | BANNER_BACKGROUND);
     65   //
     66   ClearLines (
     67     gScreenDimensions.LeftColumn,
     68     gScreenDimensions.RightColumn,
     69     gScreenDimensions.TopRow,
     70     FRONT_PAGE_HEADER_HEIGHT - 1 + gScreenDimensions.TopRow,
     71     BANNER_TEXT | BANNER_BACKGROUND
     72     );
     73 
     74   //
     75   //    for (Line = 0; Line < BANNER_HEIGHT; Line++) {
     76   //
     77   for (Line = (UINT8) gScreenDimensions.TopRow; Line < BANNER_HEIGHT + (UINT8) gScreenDimensions.TopRow; Line++) {
     78     //
     79     //      for (Alignment = 0; Alignment < BANNER_COLUMNS; Alignment++) {
     80     //
     81     for (Alignment = (UINT8) gScreenDimensions.LeftColumn;
     82          Alignment < BANNER_COLUMNS + (UINT8) gScreenDimensions.LeftColumn;
     83          Alignment++
     84         ) {
     85       RowIdx    = (UINT8) (Line - (UINT8) gScreenDimensions.TopRow);
     86       ColumnIdx = (UINT8) (Alignment - (UINT8) gScreenDimensions.LeftColumn);
     87 
     88       ASSERT (RowIdx < BANNER_HEIGHT && ColumnIdx < BANNER_COLUMNS);
     89 
     90       if (gBannerData!= NULL && gBannerData->Banner[RowIdx][ColumnIdx] != 0x0000) {
     91         StrFrontPageBanner = LibGetToken (gBannerData->Banner[RowIdx][ColumnIdx], FormData->HiiHandle);
     92       } else {
     93         continue;
     94       }
     95 
     96       switch (Alignment - gScreenDimensions.LeftColumn) {
     97       case 0:
     98         //
     99         // Handle left column
    100         //
    101         PrintStringAt (gScreenDimensions.LeftColumn + BANNER_LEFT_COLUMN_INDENT, Line, StrFrontPageBanner);
    102         break;
    103 
    104       case 1:
    105         //
    106         // Handle center column
    107         //
    108         PrintStringAt (
    109           gScreenDimensions.LeftColumn + (gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn) / 3,
    110           Line,
    111           StrFrontPageBanner
    112           );
    113         break;
    114 
    115       case 2:
    116         //
    117         // Handle right column
    118         //
    119         PrintStringAt (
    120           gScreenDimensions.LeftColumn + (gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn) * 2 / 3,
    121           Line,
    122           StrFrontPageBanner
    123           );
    124         break;
    125       }
    126 
    127       FreePool (StrFrontPageBanner);
    128     }
    129   }
    130 }
    131 
    132 /**
    133   Print framework and form title for a page.
    134 
    135   @param[in]  FormData             Form Data to be shown in Page
    136 **/
    137 VOID
    138 PrintFramework (
    139   IN FORM_DISPLAY_ENGINE_FORM       *FormData
    140   )
    141 {
    142   UINTN                  Index;
    143   CHAR16                 Character;
    144   CHAR16                 *Buffer;
    145   UINTN                  Row;
    146   CHAR16                 *TitleStr;
    147   UINTN                  TitleColumn;
    148 
    149   if (gClassOfVfr != FORMSET_CLASS_PLATFORM_SETUP) {
    150     //
    151     // Only Setup page needs Framework
    152     //
    153     ClearLines (
    154       gScreenDimensions.LeftColumn,
    155       gScreenDimensions.RightColumn,
    156       gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight,
    157       gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - 1,
    158       KEYHELP_TEXT | KEYHELP_BACKGROUND
    159       );
    160     return;
    161   }
    162 
    163   Buffer = AllocateZeroPool (0x10000);
    164   ASSERT (Buffer != NULL);
    165   Character = BOXDRAW_HORIZONTAL;
    166   for (Index = 0; Index + 2 < (gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn); Index++) {
    167     Buffer[Index] = Character;
    168   }
    169 
    170   //
    171   // Print Top border line
    172   // +------------------------------------------------------------------------------+
    173   // ?                                                                             ?
    174   // +------------------------------------------------------------------------------+
    175   //
    176   gST->ConOut->SetAttribute (gST->ConOut, TITLE_TEXT | TITLE_BACKGROUND);
    177   Character = BOXDRAW_DOWN_RIGHT;
    178 
    179   PrintCharAt (gScreenDimensions.LeftColumn, gScreenDimensions.TopRow, Character);
    180   PrintStringAt ((UINTN) -1, (UINTN) -1, Buffer);
    181 
    182   Character = BOXDRAW_DOWN_LEFT;
    183   PrintCharAt ((UINTN) -1, (UINTN) -1, Character);
    184 
    185   Character = BOXDRAW_VERTICAL;
    186   for (Row = gScreenDimensions.TopRow + 1; Row <= gScreenDimensions.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 2; Row++) {
    187     PrintCharAt (gScreenDimensions.LeftColumn, Row, Character);
    188     PrintCharAt (gScreenDimensions.RightColumn - 1, Row, Character);
    189   }
    190 
    191   //
    192   // Print Form Title
    193   //
    194   TitleStr = LibGetToken (FormData->FormTitle, FormData->HiiHandle);
    195   ASSERT (TitleStr != NULL);
    196   TitleColumn = (gScreenDimensions.RightColumn + gScreenDimensions.LeftColumn - LibGetStringWidth (TitleStr) / 2) / 2;
    197   PrintStringAtWithWidth (gScreenDimensions.LeftColumn + 1, gScreenDimensions.TopRow + 1, gLibEmptyString, TitleColumn - gScreenDimensions.LeftColumn - 1);
    198   PrintStringAtWithWidth (
    199     TitleColumn,
    200     gScreenDimensions.TopRow + 1,
    201     TitleStr,
    202     gScreenDimensions.RightColumn - 1 - TitleColumn
    203     );
    204   FreePool (TitleStr);
    205 
    206   Character = BOXDRAW_UP_RIGHT;
    207   PrintCharAt (gScreenDimensions.LeftColumn, gScreenDimensions.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 1, Character);
    208   PrintStringAt ((UINTN) -1, (UINTN) -1, Buffer);
    209 
    210   Character = BOXDRAW_UP_LEFT;
    211   PrintCharAt ((UINTN) -1, (UINTN) -1, Character);
    212 
    213   //
    214   // Print Bottom border line
    215   // +------------------------------------------------------------------------------+
    216   // ?                                                                             ?
    217   // +------------------------------------------------------------------------------+
    218   //
    219   Character = BOXDRAW_DOWN_RIGHT;
    220   PrintCharAt (gScreenDimensions.LeftColumn, gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight, Character);
    221 
    222   PrintStringAt ((UINTN) -1, (UINTN) -1, Buffer);
    223 
    224   Character = BOXDRAW_DOWN_LEFT;
    225   PrintCharAt ((UINTN) -1, (UINTN) -1, Character);
    226   Character = BOXDRAW_VERTICAL;
    227   for (Row = gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight + 1;
    228        Row <= gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - 2;
    229        Row++
    230       ) {
    231     PrintCharAt (gScreenDimensions.LeftColumn, Row, Character);
    232     PrintCharAt (gScreenDimensions.RightColumn - 1, Row, Character);
    233   }
    234 
    235   Character = BOXDRAW_UP_RIGHT;
    236   PrintCharAt (gScreenDimensions.LeftColumn, gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - 1, Character);
    237 
    238   PrintStringAt ((UINTN) -1, (UINTN) -1, Buffer);
    239 
    240   Character = BOXDRAW_UP_LEFT;
    241   PrintCharAt ((UINTN) -1, (UINTN) -1, Character);
    242 
    243   FreePool (Buffer);
    244 }
    245 
    246 /**
    247   Process some op code which is not recognized by browser core.
    248 
    249   @param OpCodeData                  The pointer to the op code buffer.
    250 
    251   @return EFI_SUCCESS            Pass the statement success.
    252 
    253 **/
    254 VOID
    255 ProcessUserOpcode(
    256   IN  EFI_IFR_OP_HEADER         *OpCodeData
    257   )
    258 {
    259   EFI_GUID *   ClassGuid;
    260   UINT8        ClassGuidNum;
    261 
    262   ClassGuid    = NULL;
    263   ClassGuidNum = 0;
    264 
    265   switch (OpCodeData->OpCode) {
    266     case EFI_IFR_FORM_SET_OP:
    267       //
    268       // process the statement outside of form,if it is formset op, get its formsetguid or classguid and compared with gFrontPageFormSetGuid
    269       //
    270       if (CompareMem (PcdGetPtr (PcdFrontPageFormSetGuid), &((EFI_IFR_FORM_SET *) OpCodeData)->Guid, sizeof (EFI_GUID)) == 0){
    271         gClassOfVfr = FORMSET_CLASS_FRONT_PAGE;
    272       } else{
    273         ClassGuidNum = (UINT8)(((EFI_IFR_FORM_SET *)OpCodeData)->Flags & 0x3);
    274         ClassGuid    = (EFI_GUID *)(VOID *)((UINT8 *)OpCodeData + sizeof (EFI_IFR_FORM_SET));
    275         while (ClassGuidNum-- > 0){
    276           if (CompareGuid((EFI_GUID*)PcdGetPtr (PcdFrontPageFormSetGuid),ClassGuid)){
    277             gClassOfVfr = FORMSET_CLASS_FRONT_PAGE;
    278             break;
    279           }
    280           ClassGuid ++;
    281         }
    282       }
    283       break;
    284 
    285     case EFI_IFR_GUID_OP:
    286       if (CompareGuid (&gEfiIfrTianoGuid, (EFI_GUID *)((CHAR8*) OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) {
    287         //
    288         // Tiano specific GUIDed opcodes
    289         //
    290         switch (((EFI_IFR_GUID_LABEL *) OpCodeData)->ExtendOpCode) {
    291         case EFI_IFR_EXTEND_OP_LABEL:
    292           //
    293           // just ignore label
    294           //
    295           break;
    296 
    297         case EFI_IFR_EXTEND_OP_BANNER:
    298           //
    299           // Only in front page form set, we care about the banner data.
    300           //
    301           if (gClassOfVfr == FORMSET_CLASS_FRONT_PAGE) {
    302             //
    303             // Initialize Driver private data
    304             //
    305             if (gBannerData == NULL) {
    306               gBannerData = AllocateZeroPool (sizeof (BANNER_DATA));
    307               ASSERT (gBannerData != NULL);
    308             }
    309 
    310             CopyMem (
    311               &gBannerData->Banner[((EFI_IFR_GUID_BANNER *) OpCodeData)->LineNumber][
    312               ((EFI_IFR_GUID_BANNER *) OpCodeData)->Alignment],
    313               &((EFI_IFR_GUID_BANNER *) OpCodeData)->Title,
    314               sizeof (EFI_STRING_ID)
    315               );
    316           }
    317           break;
    318 
    319         case EFI_IFR_EXTEND_OP_SUBCLASS:
    320           if (((EFI_IFR_GUID_SUBCLASS *) OpCodeData)->SubClass == EFI_FRONT_PAGE_SUBCLASS) {
    321             gClassOfVfr = FORMSET_CLASS_FRONT_PAGE;
    322           }
    323           break;
    324 
    325         default:
    326           break;
    327         }
    328       }
    329       break;
    330 
    331     default:
    332       break;
    333   }
    334 }
    335 
    336 /**
    337   Process some op codes which is out side of current form.
    338 
    339   @param FormData                Pointer to the form data.
    340 
    341   @return EFI_SUCCESS            Pass the statement success.
    342 
    343 **/
    344 VOID
    345 ProcessExternedOpcode (
    346   IN FORM_DISPLAY_ENGINE_FORM       *FormData
    347   )
    348 {
    349   LIST_ENTRY                    *Link;
    350   LIST_ENTRY                    *NestLink;
    351   FORM_DISPLAY_ENGINE_STATEMENT *Statement;
    352   FORM_DISPLAY_ENGINE_STATEMENT *NestStatement;
    353 
    354   Link = GetFirstNode (&FormData->StatementListOSF);
    355   while (!IsNull (&FormData->StatementListOSF, Link)) {
    356     Statement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link);
    357     Link = GetNextNode (&FormData->StatementListOSF, Link);
    358 
    359     ProcessUserOpcode(Statement->OpCode);
    360   }
    361 
    362   Link = GetFirstNode (&FormData->StatementListHead);
    363   while (!IsNull (&FormData->StatementListHead, Link)) {
    364     Statement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link);
    365     Link = GetNextNode (&FormData->StatementListHead, Link);
    366 
    367     ProcessUserOpcode(Statement->OpCode);
    368 
    369     NestLink = GetFirstNode (&Statement->NestStatementList);
    370     while (!IsNull (&Statement->NestStatementList, NestLink)) {
    371       NestStatement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (NestLink);
    372       NestLink = GetNextNode (&Statement->NestStatementList, NestLink);
    373 
    374       ProcessUserOpcode(NestStatement->OpCode);
    375     }
    376 
    377   }
    378 }
    379 
    380 /**
    381   Validate the input screen diemenstion info.
    382 
    383   @param  FormData               The input form data info.
    384 
    385   @return EFI_SUCCESS            The input screen info is acceptable.
    386   @return EFI_INVALID_PARAMETER  The input screen info is not acceptable.
    387 
    388 **/
    389 EFI_STATUS
    390 ScreenDiemensionInfoValidate (
    391   IN FORM_DISPLAY_ENGINE_FORM       *FormData
    392   )
    393 {
    394   LIST_ENTRY           *Link;
    395   UINTN                Index;
    396 
    397   //
    398   // Calculate total number of Register HotKeys.
    399   //
    400   Index = 0;
    401   if (!IsListEmpty (&FormData->HotKeyListHead)){
    402     Link  = GetFirstNode (&FormData->HotKeyListHead);
    403     while (!IsNull (&FormData->HotKeyListHead, Link)) {
    404       Link = GetNextNode (&FormData->HotKeyListHead, Link);
    405       Index ++;
    406     }
    407   }
    408 
    409   //
    410   // Show three HotKeys help information on one row.
    411   //
    412   gFooterHeight = FOOTER_HEIGHT + (Index / 3);
    413 
    414 
    415   ZeroMem (&gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));
    416   gST->ConOut->QueryMode (
    417                  gST->ConOut,
    418                  gST->ConOut->Mode->Mode,
    419                  &gScreenDimensions.RightColumn,
    420                  &gScreenDimensions.BottomRow
    421                  );
    422 
    423   //
    424   // Check local dimension vs. global dimension.
    425   //
    426   if (FormData->ScreenDimensions != NULL) {
    427     if ((gScreenDimensions.RightColumn < FormData->ScreenDimensions->RightColumn) ||
    428         (gScreenDimensions.BottomRow < FormData->ScreenDimensions->BottomRow)
    429         ) {
    430       return EFI_INVALID_PARAMETER;
    431     } else {
    432       //
    433       // Local dimension validation.
    434       //
    435       if ((FormData->ScreenDimensions->RightColumn > FormData->ScreenDimensions->LeftColumn) &&
    436           (FormData->ScreenDimensions->BottomRow > FormData->ScreenDimensions->TopRow) &&
    437           ((FormData->ScreenDimensions->RightColumn - FormData->ScreenDimensions->LeftColumn) > 2) &&
    438           ((FormData->ScreenDimensions->BottomRow - FormData->ScreenDimensions->TopRow) > STATUS_BAR_HEIGHT +
    439             FRONT_PAGE_HEADER_HEIGHT + gFooterHeight + 3)) {
    440         CopyMem (&gScreenDimensions, (VOID *) FormData->ScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));
    441       } else {
    442         return EFI_INVALID_PARAMETER;
    443       }
    444     }
    445   }
    446 
    447   return EFI_SUCCESS;
    448 }
    449 
    450 /**
    451   Get the string based on the StringId and HII Package List Handle.
    452 
    453   @param  Token                  The String's ID.
    454   @param  HiiHandle              The package list in the HII database to search for
    455                                  the specified string.
    456 
    457   @return The output string.
    458 
    459 **/
    460 CHAR16 *
    461 LibGetToken (
    462   IN  EFI_STRING_ID                Token,
    463   IN  EFI_HII_HANDLE               HiiHandle
    464   )
    465 {
    466   EFI_STRING  String;
    467 
    468   String = HiiGetString (HiiHandle, Token, NULL);
    469   if (String == NULL) {
    470     String = AllocateCopyPool (StrSize (mLibUnknownString), mLibUnknownString);
    471     ASSERT (String != NULL);
    472   }
    473 
    474   return (CHAR16 *) String;
    475 }
    476 
    477 
    478 /**
    479   Count the storage space of a Unicode string.
    480 
    481   This function handles the Unicode string with NARROW_CHAR
    482   and WIDE_CHAR control characters. NARROW_HCAR and WIDE_CHAR
    483   does not count in the resultant output. If a WIDE_CHAR is
    484   hit, then 2 Unicode character will consume an output storage
    485   space with size of CHAR16 till a NARROW_CHAR is hit.
    486 
    487   If String is NULL, then ASSERT ().
    488 
    489   @param String          The input string to be counted.
    490 
    491   @return Storage space for the input string.
    492 
    493 **/
    494 UINTN
    495 LibGetStringWidth (
    496   IN CHAR16               *String
    497   )
    498 {
    499   UINTN Index;
    500   UINTN Count;
    501   UINTN IncrementValue;
    502 
    503   ASSERT (String != NULL);
    504   if (String == NULL) {
    505     return 0;
    506   }
    507 
    508   Index           = 0;
    509   Count           = 0;
    510   IncrementValue  = 1;
    511 
    512   do {
    513     //
    514     // Advance to the null-terminator or to the first width directive
    515     //
    516     for (;
    517          (String[Index] != NARROW_CHAR) && (String[Index] != WIDE_CHAR) && (String[Index] != 0);
    518          Index++, Count = Count + IncrementValue
    519         )
    520       ;
    521 
    522     //
    523     // We hit the null-terminator, we now have a count
    524     //
    525     if (String[Index] == 0) {
    526       break;
    527     }
    528     //
    529     // We encountered a narrow directive - strip it from the size calculation since it doesn't get printed
    530     // and also set the flag that determines what we increment by.(if narrow, increment by 1, if wide increment by 2)
    531     //
    532     if (String[Index] == NARROW_CHAR) {
    533       //
    534       // Skip to the next character
    535       //
    536       Index++;
    537       IncrementValue = 1;
    538     } else {
    539       //
    540       // Skip to the next character
    541       //
    542       Index++;
    543       IncrementValue = 2;
    544     }
    545   } while (String[Index] != 0);
    546 
    547   //
    548   // Increment by one to include the null-terminator in the size
    549   //
    550   Count++;
    551 
    552   return Count * sizeof (CHAR16);
    553 }
    554 
    555 /**
    556   Show all registered HotKey help strings on bottom Rows.
    557 
    558   @param FormData          The curent input form data info.
    559   @param SetState          Set HotKey or Clear HotKey
    560 
    561 **/
    562 VOID
    563 PrintHotKeyHelpString (
    564   IN FORM_DISPLAY_ENGINE_FORM      *FormData,
    565   IN BOOLEAN                       SetState
    566   )
    567 {
    568   UINTN                  CurrentCol;
    569   UINTN                  CurrentRow;
    570   UINTN                  BottomRowOfHotKeyHelp;
    571   UINTN                  ColumnIndexWidth;
    572   UINTN                  ColumnWidth;
    573   UINTN                  ColumnIndex;
    574   UINTN                  Index;
    575   EFI_SCREEN_DESCRIPTOR  LocalScreen;
    576   LIST_ENTRY             *Link;
    577   BROWSER_HOT_KEY        *HotKey;
    578   CHAR16                 BakChar;
    579   CHAR16                 *ColumnStr;
    580 
    581   CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));
    582   ColumnWidth            = (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3;
    583   BottomRowOfHotKeyHelp  = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 3;
    584   ColumnStr              = gLibEmptyString;
    585 
    586   //
    587   // Calculate total number of Register HotKeys.
    588   //
    589   Index = 0;
    590   Link  = GetFirstNode (&FormData->HotKeyListHead);
    591   while (!IsNull (&FormData->HotKeyListHead, Link)) {
    592     HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);
    593     //
    594     // Calculate help information Column and Row.
    595     //
    596     ColumnIndex = Index % 3;
    597     if (ColumnIndex == 0) {
    598       CurrentCol       = LocalScreen.LeftColumn + 2 * ColumnWidth;
    599       ColumnIndexWidth = ColumnWidth - 1;
    600     } else if (ColumnIndex == 1) {
    601       CurrentCol       = LocalScreen.LeftColumn + ColumnWidth;
    602       ColumnIndexWidth = ColumnWidth;
    603     } else {
    604       CurrentCol       = LocalScreen.LeftColumn + 2;
    605       ColumnIndexWidth = ColumnWidth - 2;
    606     }
    607     CurrentRow = BottomRowOfHotKeyHelp - Index / 3;
    608 
    609     //
    610     // Help string can't exceed ColumnWidth. One Row will show three Help information.
    611     //
    612     BakChar = L'\0';
    613     if (StrLen (HotKey->HelpString) > ColumnIndexWidth) {
    614       BakChar = HotKey->HelpString[ColumnIndexWidth];
    615       HotKey->HelpString[ColumnIndexWidth] = L'\0';
    616     }
    617 
    618     //
    619     // Print HotKey help string on bottom Row.
    620     //
    621     if (SetState) {
    622       ColumnStr = HotKey->HelpString;
    623     }
    624     PrintStringAtWithWidth (CurrentCol, CurrentRow, ColumnStr, ColumnIndexWidth);
    625 
    626     if (BakChar != L'\0') {
    627       HotKey->HelpString[ColumnIndexWidth] = BakChar;
    628     }
    629     //
    630     // Get Next Hot Key.
    631     //
    632     Link = GetNextNode (&FormData->HotKeyListHead, Link);
    633     Index ++;
    634   }
    635 
    636   if (SetState) {
    637     //
    638     // Clear KeyHelp
    639     //
    640     CurrentRow  = BottomRowOfHotKeyHelp - Index / 3;
    641     ColumnIndex = Index % 3;
    642     if (ColumnIndex == 0) {
    643       CurrentCol       = LocalScreen.LeftColumn + 2 * ColumnWidth;
    644       ColumnIndexWidth = ColumnWidth - 1;
    645       ColumnIndex ++;
    646       PrintStringAtWithWidth (CurrentCol, CurrentRow, gLibEmptyString, ColumnIndexWidth);
    647     }
    648     if (ColumnIndex == 1) {
    649       CurrentCol       = LocalScreen.LeftColumn + ColumnWidth;
    650       ColumnIndexWidth = ColumnWidth;
    651       PrintStringAtWithWidth (CurrentCol, CurrentRow, gLibEmptyString, ColumnIndexWidth);
    652     }
    653   }
    654 
    655   return;
    656 }
    657 
    658 /**
    659   Get step info from numeric opcode.
    660 
    661   @param[in] OpCode     The input numeric op code.
    662 
    663   @return step info for this opcode.
    664 **/
    665 UINT64
    666 LibGetFieldFromNum (
    667   IN  EFI_IFR_OP_HEADER     *OpCode
    668   )
    669 {
    670   EFI_IFR_NUMERIC       *NumericOp;
    671   UINT64                Step;
    672 
    673   NumericOp = (EFI_IFR_NUMERIC *) OpCode;
    674 
    675   switch (NumericOp->Flags & EFI_IFR_NUMERIC_SIZE) {
    676   case EFI_IFR_NUMERIC_SIZE_1:
    677     Step    = NumericOp->data.u8.Step;
    678     break;
    679 
    680   case EFI_IFR_NUMERIC_SIZE_2:
    681     Step    = NumericOp->data.u16.Step;
    682     break;
    683 
    684   case EFI_IFR_NUMERIC_SIZE_4:
    685     Step    = NumericOp->data.u32.Step;
    686     break;
    687 
    688   case EFI_IFR_NUMERIC_SIZE_8:
    689     Step    = NumericOp->data.u64.Step;
    690     break;
    691 
    692   default:
    693     Step = 0;
    694     break;
    695   }
    696 
    697   return Step;
    698 }
    699 
    700 /**
    701   Initialize the HII String Token to the correct values.
    702 
    703 **/
    704 VOID
    705 InitializeLibStrings (
    706   VOID
    707   )
    708 {
    709   mLibUnknownString        = L"!";
    710 
    711   gEnterString          = LibGetToken (STRING_TOKEN (ENTER_STRING), mCDLStringPackHandle);
    712   gEnterCommitString    = LibGetToken (STRING_TOKEN (ENTER_COMMIT_STRING), mCDLStringPackHandle);
    713   gEnterEscapeString    = LibGetToken (STRING_TOKEN (ENTER_ESCAPE_STRING), mCDLStringPackHandle);
    714   gEscapeString         = LibGetToken (STRING_TOKEN (ESCAPE_STRING), mCDLStringPackHandle);
    715   gMoveHighlight        = LibGetToken (STRING_TOKEN (MOVE_HIGHLIGHT), mCDLStringPackHandle);
    716   gDecNumericInput      = LibGetToken (STRING_TOKEN (DEC_NUMERIC_INPUT), mCDLStringPackHandle);
    717   gHexNumericInput      = LibGetToken (STRING_TOKEN (HEX_NUMERIC_INPUT), mCDLStringPackHandle);
    718   gToggleCheckBox       = LibGetToken (STRING_TOKEN (TOGGLE_CHECK_BOX), mCDLStringPackHandle);
    719 
    720   gAreYouSure           = LibGetToken (STRING_TOKEN (ARE_YOU_SURE), mCDLStringPackHandle);
    721   gYesResponse          = LibGetToken (STRING_TOKEN (ARE_YOU_SURE_YES), mCDLStringPackHandle);
    722   gNoResponse           = LibGetToken (STRING_TOKEN (ARE_YOU_SURE_NO), mCDLStringPackHandle);
    723   gPlusString           = LibGetToken (STRING_TOKEN (PLUS_STRING), mCDLStringPackHandle);
    724   gMinusString          = LibGetToken (STRING_TOKEN (MINUS_STRING), mCDLStringPackHandle);
    725   gAdjustNumber         = LibGetToken (STRING_TOKEN (ADJUST_NUMBER), mCDLStringPackHandle);
    726   gSaveChanges          = LibGetToken (STRING_TOKEN (SAVE_CHANGES), mCDLStringPackHandle);
    727 
    728   gLibEmptyString       = LibGetToken (STRING_TOKEN (EMPTY_STRING), mCDLStringPackHandle);
    729 
    730   gNvUpdateMessage      = LibGetToken (STRING_TOKEN (NV_UPDATE_MESSAGE), mCDLStringPackHandle);
    731   gInputErrorMessage    = LibGetToken (STRING_TOKEN (INPUT_ERROR_MESSAGE), mCDLStringPackHandle);
    732 
    733   //
    734   // SpaceBuffer;
    735   //
    736   mSpaceBuffer = AllocatePool ((SPACE_BUFFER_SIZE + 1) * sizeof (CHAR16));
    737   ASSERT (mSpaceBuffer != NULL);
    738   LibSetUnicodeMem (mSpaceBuffer, SPACE_BUFFER_SIZE, L' ');
    739   mSpaceBuffer[SPACE_BUFFER_SIZE] = L'\0';
    740 }
    741 
    742 
    743 /**
    744   Free the HII String.
    745 
    746 **/
    747 VOID
    748 FreeLibStrings (
    749   VOID
    750   )
    751 {
    752   FreePool (gEnterString);
    753   FreePool (gEnterCommitString);
    754   FreePool (gEnterEscapeString);
    755   FreePool (gEscapeString);
    756   FreePool (gMoveHighlight);
    757   FreePool (gDecNumericInput);
    758   FreePool (gHexNumericInput);
    759   FreePool (gToggleCheckBox);
    760 
    761   FreePool (gAreYouSure);
    762   FreePool (gYesResponse);
    763   FreePool (gNoResponse);
    764   FreePool (gPlusString);
    765   FreePool (gMinusString);
    766   FreePool (gAdjustNumber);
    767   FreePool (gSaveChanges);
    768 
    769   FreePool (gLibEmptyString);
    770 
    771   FreePool (gNvUpdateMessage);
    772   FreePool (gInputErrorMessage);
    773 
    774   FreePool (mSpaceBuffer);
    775 }
    776 
    777 /**
    778   Wait for a key to be pressed by user.
    779 
    780   @param Key         The key which is pressed by user.
    781 
    782   @retval EFI_SUCCESS The function always completed successfully.
    783 
    784 **/
    785 EFI_STATUS
    786 WaitForKeyStroke (
    787   OUT  EFI_INPUT_KEY           *Key
    788   )
    789 {
    790   EFI_STATUS  Status;
    791   UINTN       Index;
    792 
    793   while (TRUE) {
    794     Status = gST->ConIn->ReadKeyStroke (gST->ConIn, Key);
    795     if (!EFI_ERROR (Status)) {
    796       break;
    797     }
    798 
    799     if (Status != EFI_NOT_READY) {
    800       continue;
    801     }
    802 
    803     gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &Index);
    804   }
    805   return Status;
    806 }
    807 
    808 
    809 /**
    810   Set Buffer to Value for Size bytes.
    811 
    812   @param  Buffer                 Memory to set.
    813   @param  Size                   Number of bytes to set
    814   @param  Value                  Value of the set operation.
    815 
    816 **/
    817 VOID
    818 LibSetUnicodeMem (
    819   IN VOID   *Buffer,
    820   IN UINTN  Size,
    821   IN CHAR16 Value
    822   )
    823 {
    824   CHAR16  *Ptr;
    825 
    826   Ptr = Buffer;
    827   while ((Size--)  != 0) {
    828     *(Ptr++) = Value;
    829   }
    830 }
    831 
    832 /**
    833   The internal function prints to the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
    834   protocol instance.
    835 
    836   @param Width           Width of string to be print.
    837   @param Column          The position of the output string.
    838   @param Row             The position of the output string.
    839   @param Out             The EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL instance.
    840   @param Fmt             The format string.
    841   @param Args            The additional argument for the variables in the format string.
    842 
    843   @return Number of Unicode character printed.
    844 
    845 **/
    846 UINTN
    847 PrintInternal (
    848   IN UINTN                            Width,
    849   IN UINTN                            Column,
    850   IN UINTN                            Row,
    851   IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *Out,
    852   IN CHAR16                           *Fmt,
    853   IN VA_LIST                          Args
    854   )
    855 {
    856   CHAR16  *Buffer;
    857   CHAR16  *BackupBuffer;
    858   UINTN   Index;
    859   UINTN   PreviousIndex;
    860   UINTN   Count;
    861   UINTN   TotalCount;
    862   UINTN   PrintWidth;
    863   UINTN   CharWidth;
    864 
    865   //
    866   // For now, allocate an arbitrarily long buffer
    867   //
    868   Buffer        = AllocateZeroPool (0x10000);
    869   BackupBuffer  = AllocateZeroPool (0x10000);
    870   ASSERT (Buffer);
    871   ASSERT (BackupBuffer);
    872 
    873   if (Column != (UINTN) -1) {
    874     Out->SetCursorPosition (Out, Column, Row);
    875   }
    876 
    877   UnicodeVSPrint (Buffer, 0x10000, Fmt, Args);
    878 
    879   Out->Mode->Attribute = Out->Mode->Attribute & 0x7f;
    880 
    881   Out->SetAttribute (Out, Out->Mode->Attribute);
    882 
    883   Index         = 0;
    884   PreviousIndex = 0;
    885   Count         = 0;
    886   TotalCount    = 0;
    887   PrintWidth    = 0;
    888   CharWidth     = 1;
    889 
    890   do {
    891     for (; (Buffer[Index] != NARROW_CHAR) && (Buffer[Index] != WIDE_CHAR) && (Buffer[Index] != 0); Index++) {
    892       BackupBuffer[Index] = Buffer[Index];
    893     }
    894 
    895     if (Buffer[Index] == 0) {
    896       break;
    897     }
    898 
    899     //
    900     // Print this out, we are about to switch widths
    901     //
    902     Out->OutputString (Out, &BackupBuffer[PreviousIndex]);
    903     Count = StrLen (&BackupBuffer[PreviousIndex]);
    904     PrintWidth += Count * CharWidth;
    905     TotalCount += Count;
    906 
    907     //
    908     // Preserve the current index + 1, since this is where we will start printing from next
    909     //
    910     PreviousIndex = Index + 1;
    911 
    912     //
    913     // We are at a narrow or wide character directive.  Set attributes and strip it and print it
    914     //
    915     if (Buffer[Index] == NARROW_CHAR) {
    916       //
    917       // Preserve bits 0 - 6 and zero out the rest
    918       //
    919       Out->Mode->Attribute = Out->Mode->Attribute & 0x7f;
    920       Out->SetAttribute (Out, Out->Mode->Attribute);
    921       CharWidth = 1;
    922     } else {
    923       //
    924       // Must be wide, set bit 7 ON
    925       //
    926       Out->Mode->Attribute = Out->Mode->Attribute | EFI_WIDE_ATTRIBUTE;
    927       Out->SetAttribute (Out, Out->Mode->Attribute);
    928       CharWidth = 2;
    929     }
    930 
    931     Index++;
    932 
    933   } while (Buffer[Index] != 0);
    934 
    935   //
    936   // We hit the end of the string - print it
    937   //
    938   Out->OutputString (Out, &BackupBuffer[PreviousIndex]);
    939   Count = StrLen (&BackupBuffer[PreviousIndex]);
    940   PrintWidth += Count * CharWidth;
    941   TotalCount += Count;
    942   if (PrintWidth < Width) {
    943     Out->Mode->Attribute = Out->Mode->Attribute & 0x7f;
    944     Out->SetAttribute (Out, Out->Mode->Attribute);
    945     Out->OutputString (Out, &mSpaceBuffer[SPACE_BUFFER_SIZE - Width + PrintWidth]);
    946   }
    947 
    948   FreePool (Buffer);
    949   FreePool (BackupBuffer);
    950   return TotalCount;
    951 }
    952 
    953 /**
    954   Prints a formatted unicode string to the default console, at
    955   the supplied cursor position.
    956 
    957   @param  Width      Width of String to be printed.
    958   @param  Column     The cursor position to print the string at.
    959   @param  Row        The cursor position to print the string at.
    960   @param  Fmt        Format string.
    961   @param  ...        Variable argument list for format string.
    962 
    963   @return Length of string printed to the console
    964 
    965 **/
    966 UINTN
    967 EFIAPI
    968 PrintAt (
    969   IN UINTN     Width,
    970   IN UINTN     Column,
    971   IN UINTN     Row,
    972   IN CHAR16    *Fmt,
    973   ...
    974   )
    975 {
    976   VA_LIST Args;
    977   UINTN   LengthOfPrinted;
    978 
    979   VA_START (Args, Fmt);
    980   LengthOfPrinted = PrintInternal (Width, Column, Row, gST->ConOut, Fmt, Args);
    981   VA_END (Args);
    982   return LengthOfPrinted;
    983 }
    984 
    985