]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/SetupBrowserDxe/Ui.c
Disable change value for grayout or readonly menu.
[mirror_edk2.git] / MdeModulePkg / Universal / SetupBrowserDxe / Ui.c
index 553c2546b29a172a6d7d307eee95be094d1b8de4..ca2ec3b169f7ff97db9e6c9f31218bc9da49a27f 100644 (file)
@@ -16,7 +16,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 \r
 LIST_ENTRY          gMenuOption;\r
 LIST_ENTRY          gMenuList = INITIALIZE_LIST_HEAD_VARIABLE (gMenuList);\r
-MENU_REFRESH_ENTRY  *gMenuRefreshHead;\r
+MENU_REFRESH_ENTRY  *gMenuRefreshHead;                // Menu list used for refresh timer opcode.\r
+MENU_REFRESH_ENTRY  *gMenuEventGuidRefreshHead;       // Menu list used for refresh event guid opcode.\r
 \r
 //\r
 // Search table for UiDisplayMenu()\r
@@ -49,26 +50,16 @@ SCAN_CODE_TO_SCREEN_OPERATION     gScanCodeToOperation[] = {
   {\r
     SCAN_RIGHT,\r
     UiRight,\r
-  },\r
-  {\r
-    SCAN_F9,\r
-    UiDefault,\r
-  },\r
-  {\r
-    SCAN_F10,\r
-    UiSave\r
   }\r
 };\r
 \r
+UINTN mScanCodeNumber = sizeof (gScanCodeToOperation) / sizeof (gScanCodeToOperation[0]);\r
+\r
 SCREEN_OPERATION_T0_CONTROL_FLAG  gScreenOperationToControlFlag[] = {\r
   {\r
     UiNoOperation,\r
     CfUiNoOperation,\r
   },\r
-  {\r
-    UiDefault,\r
-    CfUiDefault,\r
-  },\r
   {\r
     UiSelect,\r
     CfUiSelect,\r
@@ -93,10 +84,6 @@ SCREEN_OPERATION_T0_CONTROL_FLAG  gScreenOperationToControlFlag[] = {
     UiReset,\r
     CfUiReset,\r
   },\r
-  {\r
-    UiSave,\r
-    CfUiSave,\r
-  },\r
   {\r
     UiPageUp,\r
     CfUiPageUp,\r
@@ -104,6 +91,10 @@ SCREEN_OPERATION_T0_CONTROL_FLAG  gScreenOperationToControlFlag[] = {
   {\r
     UiPageDown,\r
     CfUiPageDown\r
+  }, \r
+  {\r
+    UiHotKey,\r
+    CfUiHotKey\r
   }\r
 };\r
 \r
@@ -184,6 +175,7 @@ UiFreeMenu (
   of the given parent menu.\r
 \r
   @param  Parent                 The parent of menu to be added.\r
+  @param  HiiHandle              Hii handle related to this formset.\r
   @param  FormSetGuid            The Formset Guid of menu to be added.\r
   @param  FormId                 The Form ID of menu to be added.\r
 \r
@@ -193,6 +185,7 @@ UiFreeMenu (
 UI_MENU_LIST *\r
 UiAddMenuList (\r
   IN OUT UI_MENU_LIST     *Parent,\r
+  IN EFI_HII_HANDLE       HiiHandle,\r
   IN EFI_GUID             *FormSetGuid,\r
   IN UINT16               FormId\r
   )\r
@@ -207,6 +200,7 @@ UiAddMenuList (
   MenuList->Signature = UI_MENU_LIST_SIGNATURE;\r
   InitializeListHead (&MenuList->ChildListHead);\r
 \r
+  MenuList->HiiHandle = HiiHandle;\r
   CopyMem (&MenuList->FormSetGuid, FormSetGuid, sizeof (EFI_GUID));\r
   MenuList->FormId = FormId;\r
   MenuList->Parent = Parent;\r
@@ -225,9 +219,10 @@ UiAddMenuList (
 \r
 \r
 /**\r
-  Search Menu with given FormId in the parent menu and all its child menus.\r
+  Search Menu with given FormId and FormSetGuid in all cached menu list.\r
 \r
   @param  Parent                 The parent of menu to search.\r
+  @param  FormSetGuid            The Formset GUID of the menu to search.  \r
   @param  FormId                 The Form ID of menu to search.\r
 \r
   @return A pointer to menu found or NULL if not found.\r
@@ -236,6 +231,7 @@ UiAddMenuList (
 UI_MENU_LIST *\r
 UiFindChildMenuList (\r
   IN UI_MENU_LIST         *Parent,\r
+  IN EFI_GUID             *FormSetGuid, \r
   IN UINT16               FormId\r
   )\r
 {\r
@@ -243,7 +239,9 @@ UiFindChildMenuList (
   UI_MENU_LIST    *Child;\r
   UI_MENU_LIST    *MenuList;\r
 \r
-  if (Parent->FormId == FormId) {\r
+  ASSERT (Parent != NULL);\r
+\r
+  if (Parent->FormId == FormId && CompareGuid (FormSetGuid, &Parent->FormSetGuid)) {\r
     return Parent;\r
   }\r
 \r
@@ -251,7 +249,7 @@ UiFindChildMenuList (
   while (!IsNull (&Parent->ChildListHead, Link)) {\r
     Child = UI_MENU_LIST_FROM_LINK (Link);\r
 \r
-    MenuList = UiFindChildMenuList (Child, FormId);\r
+    MenuList = UiFindChildMenuList (Child, FormSetGuid, FormId);\r
     if (MenuList != NULL) {\r
       return MenuList;\r
     }\r
@@ -286,14 +284,9 @@ UiFindMenuList (
   while (!IsNull (&gMenuList, Link)) {\r
     MenuList = UI_MENU_LIST_FROM_LINK (Link);\r
 \r
-    if (CompareGuid (FormSetGuid, &MenuList->FormSetGuid)) {\r
-      //\r
-      // This is the formset we are looking for, find the form in this formset\r
-      //\r
-      Child = UiFindChildMenuList (MenuList, FormId);\r
-      if (Child != NULL) {\r
-        return Child;\r
-      }\r
+    Child = UiFindChildMenuList(MenuList, FormSetGuid, FormId);\r
+    if (Child != NULL) {\r
+      return Child;\r
     }\r
 \r
     Link = GetNextNode (&gMenuList, Link);\r
@@ -320,102 +313,235 @@ UiFreeRefreshList (
     gMenuRefreshHead = OldMenuRefreshEntry;\r
   }\r
 \r
-  gMenuRefreshHead = NULL;\r
+  while (gMenuEventGuidRefreshHead != NULL) {\r
+    OldMenuRefreshEntry = gMenuEventGuidRefreshHead->Next;\r
+    if (gMenuEventGuidRefreshHead != NULL) {\r
+      gBS->CloseEvent(gMenuEventGuidRefreshHead->Event);\r
+    }\r
+    FreePool (gMenuEventGuidRefreshHead);\r
+    gMenuEventGuidRefreshHead = OldMenuRefreshEntry;\r
+  }\r
 }\r
 \r
 \r
+/**\r
+  Process option string for date/time opcode.\r
+\r
+  @param  MenuOption              Menu option point to date/time.\r
+  @param  OptionString            Option string input for process.\r
+  @param  AddOptCol               Whether need to update MenuOption->OptCol. \r
+\r
+**/\r
+VOID \r
+ProcessStringForDateTime (\r
+  UI_MENU_OPTION                  *MenuOption,\r
+  CHAR16                          *OptionString,\r
+  BOOLEAN                         AddOptCol\r
+  )\r
+{\r
+  UINTN Index;\r
+  UINTN Count;\r
+  FORM_BROWSER_STATEMENT          *Statement;\r
+\r
+  ASSERT (MenuOption != NULL && OptionString != NULL);\r
+  \r
+  Statement = MenuOption->ThisTag;\r
+  \r
+  //\r
+  // If leading spaces on OptionString - remove the spaces\r
+  //\r
+  for (Index = 0; OptionString[Index] == L' '; Index++) {\r
+    //\r
+    // Base on the blockspace to get the option column info.\r
+    //\r
+    if (AddOptCol) {\r
+      MenuOption->OptCol++;\r
+    }\r
+  }\r
+  \r
+  for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {\r
+    OptionString[Count] = OptionString[Index];\r
+    Count++;\r
+  }\r
+  OptionString[Count] = CHAR_NULL;\r
+  \r
+  //\r
+  // Enable to suppress field in the opcode base on the flag.\r
+  //\r
+  if (Statement->Operand == EFI_IFR_DATE_OP) {\r
+    //\r
+    // OptionString format is: <**:  **: ****>\r
+    //                        |month|day|year|\r
+    //                          4     3    5\r
+    //\r
+    if ((Statement->Flags & EFI_QF_DATE_MONTH_SUPPRESS) && (MenuOption->Sequence == 0)) {\r
+      //\r
+      // At this point, only "<**:" in the optionstring. \r
+      // Clean the day's ** field, after clean, the format is "<  :"\r
+      //\r
+      SetUnicodeMem (&OptionString[1], 2, L' ');\r
+    } else if ((Statement->Flags & EFI_QF_DATE_DAY_SUPPRESS) && (MenuOption->Sequence == 1)) {\r
+      //\r
+      // At this point, only "**:" in the optionstring. \r
+      // Clean the month's "**" field, after clean, the format is "  :"\r
+      //                \r
+      SetUnicodeMem (&OptionString[0], 2, L' ');\r
+    } else if ((Statement->Flags & EFI_QF_DATE_YEAR_SUPPRESS) && (MenuOption->Sequence == 2)) {\r
+      //\r
+      // At this point, only "****>" in the optionstring. \r
+      // Clean the year's "****" field, after clean, the format is "  >"\r
+      //                \r
+      SetUnicodeMem (&OptionString[0], 4, L' ');\r
+    }\r
+  } else if (Statement->Operand == EFI_IFR_TIME_OP) {\r
+    //\r
+    // OptionString format is: <**:  **:    **>\r
+    //                        |hour|minute|second|\r
+    //                          4     3      3\r
+    //\r
+    if ((Statement->Flags & QF_TIME_HOUR_SUPPRESS) && (MenuOption->Sequence == 0)) {\r
+      //\r
+      // At this point, only "<**:" in the optionstring. \r
+      // Clean the hour's ** field, after clean, the format is "<  :"\r
+      //\r
+      SetUnicodeMem (&OptionString[1], 2, L' ');\r
+    } else if ((Statement->Flags & QF_TIME_MINUTE_SUPPRESS) && (MenuOption->Sequence == 1)) {\r
+      //\r
+      // At this point, only "**:" in the optionstring. \r
+      // Clean the minute's "**" field, after clean, the format is "  :"\r
+      //                \r
+      SetUnicodeMem (&OptionString[0], 2, L' ');\r
+    } else if ((Statement->Flags & QF_TIME_SECOND_SUPPRESS) && (MenuOption->Sequence == 2)) {\r
+      //\r
+      // At this point, only "**>" in the optionstring. \r
+      // Clean the second's "**" field, after clean, the format is "  >"\r
+      //                \r
+      SetUnicodeMem (&OptionString[0], 2, L' ');\r
+    }\r
+  }\r
+}\r
 \r
 /**\r
-  Refresh screen.\r
+  Refresh question.\r
 \r
+  @param     MenuRefreshEntry    Menu refresh structure which has info about the refresh question.\r
 **/\r
-EFI_STATUS\r
-RefreshForm (\r
-  VOID\r
+EFI_STATUS \r
+RefreshQuestion (\r
+  IN   MENU_REFRESH_ENTRY    *MenuRefreshEntry\r
   )\r
 {\r
   CHAR16                          *OptionString;\r
-  MENU_REFRESH_ENTRY              *MenuRefreshEntry;\r
-  UINTN                           Index;\r
   EFI_STATUS                      Status;\r
   UI_MENU_SELECTION               *Selection;\r
   FORM_BROWSER_STATEMENT          *Question;\r
-  EFI_HII_CONFIG_ACCESS_PROTOCOL  *ConfigAccess;\r
-  EFI_BROWSER_ACTION_REQUEST      ActionRequest;\r
-  CHAR16                          *PadString;\r
 \r
-  if (gMenuRefreshHead != NULL) {\r
+  Selection = MenuRefreshEntry->Selection;\r
+  Question = MenuRefreshEntry->MenuOption->ThisTag;\r
 \r
-    MenuRefreshEntry = gMenuRefreshHead;\r
+  Status = GetQuestionValue (Selection->FormSet, Selection->Form, Question, FALSE);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  OptionString = NULL;\r
+  ProcessOptions (Selection, MenuRefreshEntry->MenuOption, FALSE, &OptionString);\r
 \r
+  if (OptionString != NULL) {\r
     //\r
-    // Reset FormPackage update flag\r
+    // If old Text is longer than new string, need to clean the old string before paint the newer.\r
+    // This option is no need for time/date opcode, because time/data opcode has fixed string length.\r
     //\r
-    mHiiPackageListUpdated = FALSE;\r
+    if ((MenuRefreshEntry->MenuOption->ThisTag->Operand != EFI_IFR_DATE_OP) &&\r
+      (MenuRefreshEntry->MenuOption->ThisTag->Operand != EFI_IFR_TIME_OP)) {\r
+      ClearLines (\r
+        MenuRefreshEntry->CurrentColumn, \r
+        MenuRefreshEntry->CurrentColumn + gOptionBlockWidth - 1,\r
+        MenuRefreshEntry->CurrentRow,\r
+        MenuRefreshEntry->CurrentRow,\r
+        PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND\r
+        );\r
+    }\r
 \r
-    do {\r
-      gST->ConOut->SetAttribute (gST->ConOut, MenuRefreshEntry->CurrentAttribute);\r
+    gST->ConOut->SetAttribute (gST->ConOut, MenuRefreshEntry->CurrentAttribute);\r
+    ProcessStringForDateTime(MenuRefreshEntry->MenuOption, OptionString, FALSE);\r
+    PrintStringAt (MenuRefreshEntry->CurrentColumn, MenuRefreshEntry->CurrentRow, OptionString);\r
+    FreePool (OptionString);\r
+  }\r
 \r
-      Selection = MenuRefreshEntry->Selection;\r
-      Question = MenuRefreshEntry->MenuOption->ThisTag;\r
+  //\r
+  // Question value may be changed, need invoke its Callback()\r
+  //\r
+  Status = ProcessCallBackFunction (Selection, Question, EFI_BROWSER_ACTION_CHANGING, FALSE);\r
 \r
-      Status = GetQuestionValue (Selection->FormSet, Selection->Form, Question, FALSE);\r
-      if (EFI_ERROR (Status)) {\r
-        return Status;\r
-      }\r
+  return Status;\r
+}\r
 \r
-      OptionString = NULL;\r
-      ProcessOptions (Selection, MenuRefreshEntry->MenuOption, FALSE, &OptionString);\r
+/**\r
+  Refresh the question which has refresh guid event attribute.\r
+  \r
+  @param Event    The event which has this function related.     \r
+  @param Context  The input context info related to this event or the status code return to the caller.\r
+**/\r
+VOID\r
+EFIAPI\r
+RefreshQuestionNotify(\r
+  IN      EFI_EVENT Event,\r
+  IN      VOID      *Context\r
+  )\r
+{\r
+  MENU_REFRESH_ENTRY              *MenuRefreshEntry;\r
+  UI_MENU_SELECTION               *Selection;\r
 \r
-      if (OptionString != NULL) {\r
-        //\r
-        // If leading spaces on OptionString - remove the spaces\r
-        //\r
-        for (Index = 0; OptionString[Index] == L' '; Index++)\r
-          ;\r
+  //\r
+  // Reset FormPackage update flag\r
+  //\r
+  mHiiPackageListUpdated = FALSE;\r
 \r
-        PadString = AllocatePool (gOptionBlockWidth * sizeof (CHAR16));\r
-        SetMem16 (PadString, (gOptionBlockWidth - 1) * sizeof (CHAR16), CHAR_SPACE);\r
-        PadString[gOptionBlockWidth - 1] = 0;\r
-        PrintStringAt (MenuRefreshEntry->CurrentColumn, MenuRefreshEntry->CurrentRow, PadString);\r
-        FreePool (PadString);\r
-        PrintStringAt (MenuRefreshEntry->CurrentColumn, MenuRefreshEntry->CurrentRow, &OptionString[Index]);\r
-        FreePool (OptionString);\r
-      }\r
+  MenuRefreshEntry = (MENU_REFRESH_ENTRY *)Context;\r
+  ASSERT (MenuRefreshEntry != NULL);\r
+  Selection = MenuRefreshEntry->Selection;\r
 \r
-      //\r
-      // Question value may be changed, need invoke its Callback()\r
-      //\r
-      ConfigAccess = Selection->FormSet->ConfigAccess;\r
-      if (((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) && (ConfigAccess != NULL)) {\r
-        ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
-        Status = ConfigAccess->Callback (\r
-                                 ConfigAccess,\r
-                                 EFI_BROWSER_ACTION_CHANGING,\r
-                                 Question->QuestionId,\r
-                                 Question->HiiValue.Type,\r
-                                 &Question->HiiValue.Value,\r
-                                 &ActionRequest\r
-                                 );\r
-        if (!EFI_ERROR (Status)) {\r
-          switch (ActionRequest) {\r
-          case EFI_BROWSER_ACTION_REQUEST_RESET:\r
-            gResetRequired = TRUE;\r
-            break;\r
+  RefreshQuestion (MenuRefreshEntry);\r
+  \r
+  if (mHiiPackageListUpdated) {\r
+    //\r
+    // Package list is updated, force to reparse IFR binary of target Formset\r
+    //\r
+    mHiiPackageListUpdated = FALSE;\r
+    Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
+  } \r
+}\r
 \r
-          case EFI_BROWSER_ACTION_REQUEST_SUBMIT:\r
-            SubmitForm (Selection->FormSet, Selection->Form);\r
-            break;\r
 \r
-          case EFI_BROWSER_ACTION_REQUEST_EXIT:\r
-            Selection->Action = UI_ACTION_EXIT;\r
-            gNvUpdateRequired = FALSE;\r
-            break;\r
+/**\r
+  Refresh screen.\r
 \r
-          default:\r
-            break;\r
-          }\r
-        }\r
+**/\r
+EFI_STATUS\r
+RefreshForm (\r
+  VOID\r
+  )\r
+{\r
+  MENU_REFRESH_ENTRY              *MenuRefreshEntry;\r
+  EFI_STATUS                      Status;\r
+  UI_MENU_SELECTION               *Selection;\r
+\r
+  if (gMenuRefreshHead != NULL) {\r
+    //\r
+    // call from refresh interval process.\r
+    //\r
+    MenuRefreshEntry = gMenuRefreshHead;\r
+    Selection = MenuRefreshEntry->Selection;\r
+    //\r
+    // Reset FormPackage update flag\r
+    //\r
+    mHiiPackageListUpdated = FALSE;\r
+\r
+    do {\r
+      Status = RefreshQuestion (MenuRefreshEntry);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
       }\r
 \r
       MenuRefreshEntry = MenuRefreshEntry->Next;\r
@@ -541,6 +667,7 @@ UiWaitForSingleEvent (
 \r
   @param  String                 String description for this option.\r
   @param  Handle                 Hii handle for the package list.\r
+  @param  Form                   The form this statement belong to.\r
   @param  Statement              Statement of this Menu Option.\r
   @param  NumberOfLines          Display lines for this Menu Option.\r
   @param  MenuItemCount          The index for this Option in the Menu.\r
@@ -552,6 +679,7 @@ UI_MENU_OPTION *
 UiAddMenuOption (\r
   IN CHAR16                  *String,\r
   IN EFI_HII_HANDLE          Handle,\r
+  IN FORM_BROWSER_FORM       *Form,\r
   IN FORM_BROWSER_STATEMENT  *Statement,\r
   IN UINT16                  NumberOfLines,\r
   IN UINT16                  MenuItemCount\r
@@ -607,6 +735,13 @@ UiAddMenuOption (
       MenuOption->GrayOut = Statement->GrayOutExpression->Result.Value.b;\r
     }\r
 \r
+    //\r
+    // If the form or the question has the lock attribute, deal same as grayout.\r
+    //\r
+    if (Form->Locked || Statement->Locked) {\r
+      MenuOption->GrayOut = TRUE;\r
+    }\r
+    \r
     switch (Statement->Operand) {\r
     case EFI_IFR_ORDERED_LIST_OP:\r
     case EFI_IFR_ONE_OF_OP:\r
@@ -622,6 +757,15 @@ UiAddMenuOption (
       MenuOption->IsQuestion = TRUE;\r
       break;\r
 \r
+    case EFI_IFR_TEXT_OP:\r
+      if (FeaturePcdGet (PcdBrowserGrayOutTextStatement)) {\r
+        //\r
+        // Initializing GrayOut option as TRUE for Text setup options \r
+        // so that those options will be Gray in colour and un selectable.\r
+        //\r
+        MenuOption->GrayOut = TRUE;\r
+      }\r
+\r
     default:\r
       MenuOption->IsQuestion = FALSE;\r
       break;\r
@@ -987,6 +1131,7 @@ CreateMultiStringPopUp (
 /**\r
   Update status bar on the bottom of menu.\r
 \r
+  @param  Selection              Current Selction info.\r
   @param  MessageType            The type of message to be shown.\r
   @param  Flags                  The flags in Question header.\r
   @param  State                  Set or clear.\r
@@ -994,6 +1139,7 @@ CreateMultiStringPopUp (
 **/\r
 VOID\r
 UpdateStatusBar (\r
+  IN  UI_MENU_SELECTION           *Selection,\r
   IN  UINTN                       MessageType,\r
   IN  UINT8                       Flags,\r
   IN  BOOLEAN                     State\r
@@ -1002,7 +1148,10 @@ UpdateStatusBar (
   UINTN           Index;\r
   CHAR16          *NvUpdateMessage;\r
   CHAR16          *InputErrorMessage;\r
-\r
+  LIST_ENTRY              *Link;\r
+  FORM_BROWSER_FORMSET    *LocalFormSet;\r
+  FORM_BROWSER_STATEMENT  *Question;\r
+  \r
   NvUpdateMessage   = GetToken (STRING_TOKEN (NV_UPDATE_MESSAGE), gHiiHandle);\r
   InputErrorMessage = GetToken (STRING_TOKEN (INPUT_ERROR_MESSAGE), gHiiHandle);\r
 \r
@@ -1027,40 +1176,69 @@ UpdateStatusBar (
     break;\r
 \r
   case NV_UPDATE_REQUIRED:\r
-    if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) != FORMSET_CLASS_FRONT_PAGE) {\r
-      if (State) {\r
+    //\r
+    // Global setting support. Show configuration change on every form.\r
+    //\r
+    if (State) {\r
+      gResetRequired    = (BOOLEAN) (gResetRequired | ((Flags & EFI_IFR_FLAG_RESET_REQUIRED) == EFI_IFR_FLAG_RESET_REQUIRED));\r
+\r
+      if (Selection != NULL && Selection->Statement != NULL) {\r
+        Question = Selection->Statement;\r
+        if (Question->Storage != NULL || Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) {\r
+          //\r
+          // Update only for Question value that need to be saved into Storage.\r
+          //\r
+          Selection->Form->NvUpdateRequired = TRUE;\r
+        }\r
+      }\r
+      \r
+      if (Selection == NULL || IsNvUpdateRequired (Selection->FormSet)) {\r
         gST->ConOut->SetAttribute (gST->ConOut, INFO_TEXT);\r
         PrintStringAt (\r
           gScreenDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth,\r
           gScreenDimensions.BottomRow - 1,\r
           NvUpdateMessage\r
           );\r
-        gResetRequired    = (BOOLEAN) (gResetRequired | ((Flags & EFI_IFR_FLAG_RESET_REQUIRED) == EFI_IFR_FLAG_RESET_REQUIRED));\r
-\r
-        gNvUpdateRequired = TRUE;\r
-      } else {\r
-        gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextHighlightColor));\r
-        for (Index = 0; Index < (GetStringWidth (NvUpdateMessage) - 2) / 2; Index++) {\r
-          PrintAt (\r
-            (gScreenDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + Index),\r
-            gScreenDimensions.BottomRow - 1,\r
-            L"  "\r
-            );\r
-        }\r
-\r
-        gNvUpdateRequired = FALSE;\r
+      }\r
+    } else {\r
+      gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextHighlightColor));\r
+      for (Index = 0; Index < (GetStringWidth (NvUpdateMessage) - 2) / 2; Index++) {\r
+        PrintAt (\r
+          (gScreenDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + Index),\r
+          gScreenDimensions.BottomRow - 1,\r
+          L"  "\r
+          );\r
       }\r
     }\r
     break;\r
 \r
   case REFRESH_STATUS_BAR:\r
     if (mInputError) {\r
-      UpdateStatusBar (INPUT_ERROR, Flags, TRUE);\r
+      UpdateStatusBar (Selection, INPUT_ERROR, Flags, TRUE);\r
     }\r
 \r
-    if (gNvUpdateRequired) {\r
-      UpdateStatusBar (NV_UPDATE_REQUIRED, Flags, TRUE);\r
+    switch (gBrowserSettingScope) {\r
+    case SystemLevel:\r
+      //\r
+      // Check the maintain list to see whether there is any change.\r
+      //\r
+      Link = GetFirstNode (&gBrowserFormSetList);\r
+      while (!IsNull (&gBrowserFormSetList, Link)) {\r
+        LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);\r
+        if (IsNvUpdateRequired(LocalFormSet)) {\r
+          UpdateStatusBar (NULL, NV_UPDATE_REQUIRED, Flags, TRUE);\r
+          break;\r
+        }\r
+        Link = GetNextNode (&gBrowserFormSetList, Link);\r
+      }\r
+      break;\r
+    case FormSetLevel:\r
+    case FormLevel:\r
+      UpdateStatusBar (Selection, NV_UPDATE_REQUIRED, Flags, TRUE);\r
+    default:\r
+      break;\r
     }\r
+\r
     break;\r
 \r
   default:\r
@@ -1231,16 +1409,12 @@ GetLineByWidth (
 \r
   @param  Selection              The user's selection.\r
   @param  MenuOption             The MenuOption to be checked.\r
-  @param  OptionalString         The option string.\r
-  @param  SkipValue              The number of lins to skip.\r
 \r
 **/\r
 VOID\r
 UpdateOptionSkipLines (\r
   IN UI_MENU_SELECTION            *Selection,\r
-  IN UI_MENU_OPTION               *MenuOption,\r
-  OUT CHAR16                       **OptionalString,\r
-  IN UINTN                        SkipValue\r
+  IN UI_MENU_OPTION               *MenuOption\r
   )\r
 {\r
   UINTN   Index;\r
@@ -1251,9 +1425,7 @@ UpdateOptionSkipLines (
   CHAR16  *OptionString;\r
 \r
   Row           = 0;\r
-  OptionString  = *OptionalString;\r
-  OutputString  = NULL;\r
-\r
+  OptionString  = NULL;\r
   ProcessOptions (Selection, MenuOption, FALSE, &OptionString);\r
 \r
   if (OptionString != NULL) {\r
@@ -1266,31 +1438,28 @@ UpdateOptionSkipLines (
       // If there is more string to process print on the next row and increment the Skip value\r
       //\r
       if (StrLen (&OptionString[Index]) != 0) {\r
-        if (SkipValue == 0) {\r
-          Row++;\r
-          //\r
-          // Since the Number of lines for this menu entry may or may not be reflected accurately\r
-          // since the prompt might be 1 lines and option might be many, and vice versa, we need to do\r
-          // some testing to ensure we are keeping this in-sync.\r
-          //\r
-          // If the difference in rows is greater than or equal to the skip value, increase the skip value\r
-          //\r
-          if ((Row - OriginalRow) >= MenuOption->Skip) {\r
-            MenuOption->Skip++;\r
-          }\r
+        Row++;\r
+        //\r
+        // Since the Number of lines for this menu entry may or may not be reflected accurately\r
+        // since the prompt might be 1 lines and option might be many, and vice versa, we need to do\r
+        // some testing to ensure we are keeping this in-sync.\r
+        //\r
+        // If the difference in rows is greater than or equal to the skip value, increase the skip value\r
+        //\r
+        if ((Row - OriginalRow) >= MenuOption->Skip) {\r
+          MenuOption->Skip++;\r
         }\r
       }\r
 \r
       FreePool (OutputString);\r
-      if (SkipValue != 0) {\r
-        SkipValue--;\r
-      }\r
     }\r
 \r
     Row = OriginalRow;\r
   }\r
 \r
-  *OptionalString = OptionString;\r
+  if (OptionString != NULL) {\r
+    FreePool (OptionString);\r
+  }\r
 }\r
 \r
 \r
@@ -1338,7 +1507,6 @@ ValueIsScroll (
   )\r
 {\r
   LIST_ENTRY      *Temp;\r
-  UI_MENU_OPTION  *MenuOption;\r
 \r
   Temp = Direction ? CurrentPos->BackLink : CurrentPos->ForwardLink;\r
 \r
@@ -1346,14 +1514,7 @@ ValueIsScroll (
     return TRUE;\r
   }\r
 \r
-  for (; Temp != &gMenuOption; Temp = Direction ? Temp->BackLink : Temp->ForwardLink) {\r
-    MenuOption = MENU_OPTION_FROM_LINK (Temp);\r
-    if (IsSelectable (MenuOption)) {\r
-      return FALSE;\r
-    }\r
-  }\r
-\r
-  return TRUE;\r
+  return FALSE;\r
 }\r
 \r
 \r
@@ -1362,60 +1523,70 @@ ValueIsScroll (
 \r
   This is an internal function.\r
 \r
+  @param  Selection              Menu selection.\r
   @param  GoUp                   The navigation direction. TRUE: up, FALSE: down.\r
   @param  CurrentPosition        Current position.\r
+  @param  GapToTop               Gap position to top or bottom.\r
 \r
   @return The row distance from current MenuOption to next selectable MenuOption.\r
 \r
 **/\r
 INTN\r
 MoveToNextStatement (\r
+  IN     UI_MENU_SELECTION         *Selection,\r
   IN     BOOLEAN                   GoUp,\r
-  IN OUT LIST_ENTRY                **CurrentPosition\r
+  IN OUT LIST_ENTRY                **CurrentPosition,\r
+  IN     UINTN                     GapToTop\r
   )\r
 {\r
   INTN             Distance;\r
   LIST_ENTRY       *Pos;\r
-  BOOLEAN          HitEnd;\r
   UI_MENU_OPTION   *NextMenuOption;\r
+  UI_MENU_OPTION   *PreMenuOption;\r
 \r
-  Distance = 0;\r
-  Pos      = *CurrentPosition;\r
-  HitEnd   = FALSE;\r
+  Distance      = 0;\r
+  Pos           = *CurrentPosition;\r
+  PreMenuOption = MENU_OPTION_FROM_LINK (Pos);\r
 \r
   while (TRUE) {\r
     NextMenuOption = MENU_OPTION_FROM_LINK (Pos);\r
+    if (NextMenuOption->Row == 0) {\r
+      UpdateOptionSkipLines (Selection, NextMenuOption);\r
+    }\r
+    \r
+    if (GoUp && (PreMenuOption != NextMenuOption)) {\r
+      //\r
+      // Current Position doesn't need to be caculated when go up.\r
+      // Caculate distanct at first when go up\r
+      //\r
+      if ((UINTN) Distance + NextMenuOption->Skip > GapToTop) {\r
+        NextMenuOption = PreMenuOption;\r
+        break;\r
+      }\r
+      Distance += NextMenuOption->Skip;\r
+    }\r
     if (IsSelectable (NextMenuOption)) {\r
       break;\r
     }\r
     if ((GoUp ? Pos->BackLink : Pos->ForwardLink) == &gMenuOption) {\r
-      HitEnd = TRUE;\r
+      //\r
+      // Arrive at top.\r
+      //\r
+      Distance = -1;\r
       break;\r
     }\r
-    Distance += NextMenuOption->Skip;\r
-    Pos = (GoUp ? Pos->BackLink : Pos->ForwardLink);\r
-  }\r
-\r
-  if (HitEnd) {\r
-    //\r
-    // If we hit end there is still no statement can be focused,\r
-    // we go backwards to find the statement can be focused.\r
-    //\r
-    Distance = 0;\r
-    Pos = *CurrentPosition;\r
-\r
-    while (TRUE) {\r
-      NextMenuOption = MENU_OPTION_FROM_LINK (Pos);\r
-      if (IsSelectable (NextMenuOption)) {\r
-        break;\r
-      }\r
-      if ((!GoUp ? Pos->BackLink : Pos->ForwardLink) == &gMenuOption) {\r
-        ASSERT (FALSE);\r
+    if (!GoUp) {\r
+      //\r
+      // Caculate distanct at later when go down\r
+      //\r
+      if ((UINTN) Distance + NextMenuOption->Skip > GapToTop) {\r
+        NextMenuOption = PreMenuOption;\r
         break;\r
       }\r
-      Distance -= NextMenuOption->Skip;\r
-      Pos = (!GoUp ? Pos->BackLink : Pos->ForwardLink);\r
+      Distance += NextMenuOption->Skip;\r
     }\r
+    PreMenuOption = NextMenuOption;\r
+    Pos = (GoUp ? Pos->BackLink : Pos->ForwardLink);\r
   }\r
 \r
   *CurrentPosition = &NextMenuOption->Link;\r
@@ -1595,45 +1766,340 @@ DevicePathToHiiHandle (
 }\r
 \r
 /**\r
-  Display menu and wait for user to select one menu option, then return it.\r
-  If AutoBoot is enabled, then if user doesn't select any option,\r
-  after period of time, it will automatically return the first menu option.\r
+  Find HII Handle in the HII database associated with given form set guid.\r
 \r
-  @param  Selection              Menu selection.\r
+  If FormSetGuid is NULL, then ASSERT.\r
 \r
-  @retval EFI_SUCESSS            This function always return successfully for now.\r
+  @param  ComparingGuid          FormSet Guid associated with the HII package list\r
+                                 handle.\r
+\r
+  @retval Handle                 HII package list Handle associated with the Device\r
+                                        Path.\r
+  @retval NULL                   Hii Package list handle is not found.\r
+\r
+**/\r
+EFI_HII_HANDLE\r
+FormSetGuidToHiiHandle (\r
+  EFI_GUID     *ComparingGuid\r
+  )\r
+{\r
+  EFI_HII_HANDLE               *HiiHandles;\r
+  UINTN                        Index;\r
+  EFI_HII_PACKAGE_LIST_HEADER  *HiiPackageList;\r
+  UINTN                        BufferSize;\r
+  UINT32                       Offset;\r
+  UINT32                       Offset2;\r
+  UINT32                       PackageListLength;\r
+  EFI_HII_PACKAGE_HEADER       PackageHeader;\r
+  UINT8                        *Package;\r
+  UINT8                        *OpCodeData;\r
+  EFI_STATUS                   Status;\r
+  EFI_HII_HANDLE               HiiHandle;\r
+\r
+  ASSERT (ComparingGuid != NULL);\r
+\r
+  HiiHandle  = NULL;\r
+  //\r
+  // Get all the Hii handles\r
+  //\r
+  HiiHandles = HiiGetHiiHandles (NULL);\r
+  ASSERT (HiiHandles != NULL);\r
+\r
+  //\r
+  // Search for formset of each class type\r
+  //\r
+  for (Index = 0; HiiHandles[Index] != NULL; Index++) {\r
+    BufferSize = 0;\r
+    HiiPackageList = NULL;\r
+    Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, HiiHandles[Index], &BufferSize, HiiPackageList);\r
+    if (Status == EFI_BUFFER_TOO_SMALL) {\r
+      HiiPackageList = AllocatePool (BufferSize);\r
+      ASSERT (HiiPackageList != NULL);\r
+\r
+      Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, HiiHandles[Index], &BufferSize, HiiPackageList);\r
+    }\r
+    if (EFI_ERROR (Status) || HiiPackageList == NULL) {\r
+      return NULL;\r
+    }\r
+\r
+    //\r
+    // Get Form package from this HII package List\r
+    //\r
+    Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);\r
+    Offset2 = 0;\r
+    CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32)); \r
+\r
+    while (Offset < PackageListLength) {\r
+      Package = ((UINT8 *) HiiPackageList) + Offset;\r
+      CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));\r
+\r
+      if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {\r
+        //\r
+        // Search FormSet in this Form Package\r
+        //\r
+        Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);\r
+        while (Offset2 < PackageHeader.Length) {\r
+          OpCodeData = Package + Offset2;\r
+\r
+          if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {\r
+            //\r
+            // Try to compare against formset GUID\r
+            //\r
+            if (CompareGuid (ComparingGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) {\r
+              HiiHandle = HiiHandles[Index];\r
+              break;\r
+            }\r
+          }\r
+\r
+          Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;\r
+        }\r
+      }\r
+      if (HiiHandle != NULL) {\r
+        break;\r
+      }\r
+      Offset += PackageHeader.Length;\r
+    }\r
+    \r
+    FreePool (HiiPackageList);\r
+       if (HiiHandle != NULL) {\r
+               break;\r
+       }\r
+  }\r
+\r
+  FreePool (HiiHandles);\r
+\r
+  return HiiHandle;\r
+}\r
 \r
+/**\r
+  Process the goto op code, update the info in the selection structure.\r
+\r
+  @param Statement    The statement belong to goto op code.\r
+  @param Selection    The selection info.\r
+  @param Repaint      Whether need to repaint the menu.\r
+  @param NewLine      Whether need to create new line.\r
+\r
+  @retval EFI_SUCCESS    The menu process successfully.\r
+  @return Other value if the process failed.\r
 **/\r
 EFI_STATUS\r
-UiDisplayMenu (\r
-  IN OUT UI_MENU_SELECTION           *Selection\r
+ProcessGotoOpCode (\r
+  IN OUT   FORM_BROWSER_STATEMENT      *Statement,\r
+  IN OUT   UI_MENU_SELECTION           *Selection,\r
+  OUT      BOOLEAN                     *Repaint,\r
+  OUT      BOOLEAN                     *NewLine\r
   )\r
 {\r
-  INTN                            SkipValue;\r
-  INTN                            Difference;\r
-  INTN                            OldSkipValue;\r
-  UINTN                           DistanceValue;\r
-  UINTN                           Row;\r
-  UINTN                           Col;\r
-  UINTN                           Temp;\r
+  CHAR16                          *StringPtr;\r
+  UINTN                           StringLen;\r
+  UINTN                           BufferSize;\r
+  EFI_DEVICE_PATH_PROTOCOL        *DevicePath;\r
+  CHAR16                          TemStr[2];\r
+  UINT8                           *DevicePathBuffer;\r
+  UINTN                           Index;\r
+  UINT8                           DigitUint8;\r
+  FORM_BROWSER_FORM               *RefForm;\r
+  EFI_INPUT_KEY                   Key;\r
+  EFI_STATUS                      Status;\r
+  UI_MENU_LIST                    *MenuList;\r
+  BOOLEAN                         UpdateFormInfo;\r
+  \r
+  Status = EFI_SUCCESS;\r
+  UpdateFormInfo = TRUE;\r
+  StringPtr = NULL;\r
+  StringLen = 0;\r
+\r
+  //\r
+  // Prepare the device path check, get the device path info first.\r
+  //\r
+  if (Statement->HiiValue.Value.ref.DevicePath != 0) {\r
+    StringPtr = GetToken (Statement->HiiValue.Value.ref.DevicePath, Selection->FormSet->HiiHandle);\r
+    if (StringPtr != NULL) {\r
+      StringLen = StrLen (StringPtr);\r
+    }\r
+  }\r
+\r
+  //\r
+  // Check whether the device path string is a valid string.\r
+  //\r
+  if (Statement->HiiValue.Value.ref.DevicePath != 0 && StringPtr != NULL && StringLen != 0) {\r
+    if (Selection->Form->ModalForm) {\r
+      return Status;\r
+    }\r
+    //\r
+    // Goto another Hii Package list\r
+    //\r
+    Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
+    BufferSize = StrLen (StringPtr) / 2;\r
+    DevicePath = AllocatePool (BufferSize);\r
+    ASSERT (DevicePath != NULL);\r
+\r
+    //\r
+    // Convert from Device Path String to DevicePath Buffer in the reverse order.\r
+    //\r
+    DevicePathBuffer = (UINT8 *) DevicePath;\r
+    for (Index = 0; StringPtr[Index] != L'\0'; Index ++) {\r
+      TemStr[0] = StringPtr[Index];\r
+      DigitUint8 = (UINT8) StrHexToUint64 (TemStr);\r
+      if (DigitUint8 == 0 && TemStr[0] != L'0') {\r
+        //\r
+        // Invalid Hex Char as the tail.\r
+        //\r
+        break;\r
+      }\r
+      if ((Index & 1) == 0) {\r
+        DevicePathBuffer [Index/2] = DigitUint8;\r
+      } else {\r
+        DevicePathBuffer [Index/2] = (UINT8) ((DevicePathBuffer [Index/2] << 4) + DigitUint8);\r
+      }\r
+    }\r
+    FreePool (StringPtr);\r
+\r
+    Selection->Handle = DevicePathToHiiHandle (DevicePath);\r
+    FreePool (DevicePath);\r
+\r
+    if (Selection->Handle == NULL) {\r
+      //\r
+      // If target Hii Handle not found, exit\r
+      //\r
+      Selection->Action = UI_ACTION_EXIT;\r
+      Selection->Statement = NULL;\r
+      return Status;\r
+    }\r
+\r
+    CopyMem (&Selection->FormSetGuid,&Statement->HiiValue.Value.ref.FormSetGuid, sizeof (EFI_GUID));\r
+    Selection->FormId = Statement->HiiValue.Value.ref.FormId;\r
+    Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;\r
+  } else if (!CompareGuid (&Statement->HiiValue.Value.ref.FormSetGuid, &gZeroGuid)) {\r
+    if (Selection->Form->ModalForm) {\r
+      return Status;\r
+    }  \r
+    //\r
+    // Goto another Formset, check for uncommitted data\r
+    //\r
+    Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
+    \r
+    Selection->Handle = FormSetGuidToHiiHandle(&Statement->HiiValue.Value.ref.FormSetGuid);\r
+    if (Selection->Handle == NULL) {\r
+      //\r
+      // If target Hii Handle not found, exit\r
+      //\r
+      Selection->Action = UI_ACTION_EXIT;\r
+      Selection->Statement = NULL;\r
+      return Status;\r
+    } \r
+\r
+    CopyMem (&Selection->FormSetGuid, &Statement->HiiValue.Value.ref.FormSetGuid, sizeof (EFI_GUID));\r
+    Selection->FormId = Statement->HiiValue.Value.ref.FormId;\r
+    Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;\r
+  } else if (Statement->HiiValue.Value.ref.FormId != 0) {\r
+    //\r
+    // Check whether target From is suppressed.\r
+    //\r
+    RefForm = IdToForm (Selection->FormSet, Statement->HiiValue.Value.ref.FormId);\r
+\r
+    if ((RefForm != NULL) && (RefForm->SuppressExpression != NULL)) {\r
+      Status = EvaluateExpression (Selection->FormSet, RefForm, RefForm->SuppressExpression);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+\r
+      if (RefForm->SuppressExpression->Result.Value.b) {\r
+        //\r
+        // Form is suppressed. \r
+        //\r
+        do {\r
+          CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gFormSuppress, gPressEnter, gEmptyString);\r
+        } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+        if (Repaint != NULL) {\r
+          *Repaint = TRUE;\r
+        }\r
+        return Status;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Goto another form inside this formset,\r
+    //\r
+    Selection->Action = UI_ACTION_REFRESH_FORM;\r
+\r
+    Selection->FormId = Statement->HiiValue.Value.ref.FormId;\r
+    Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;\r
+  } else if (Statement->HiiValue.Value.ref.QuestionId != 0) {\r
+    //\r
+    // Goto another Question\r
+    //\r
+    Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;\r
+\r
+    if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {\r
+      Selection->Action = UI_ACTION_REFRESH_FORM;\r
+    } else {\r
+      if (Repaint != NULL) {\r
+        *Repaint = TRUE;\r
+      }\r
+      if (NewLine != NULL) {\r
+        *NewLine = TRUE;\r
+      }\r
+    }\r
+    UpdateFormInfo = FALSE;\r
+  } else {\r
+    if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {\r
+      Selection->Action = UI_ACTION_REFRESH_FORM;\r
+    }\r
+    UpdateFormInfo = FALSE;\r
+  }\r
+\r
+  if (UpdateFormInfo) {\r
+    //\r
+    // Link current form so that we can always go back when someone hits the ESC\r
+    //\r
+    MenuList = UiFindMenuList (&Selection->FormSetGuid, Selection->FormId);\r
+    if (MenuList == NULL && Selection->CurrentMenu != NULL) {\r
+      MenuList = UiAddMenuList (Selection->CurrentMenu, Selection->Handle, &Selection->FormSetGuid, Selection->FormId);\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Display menu and wait for user to select one menu option, then return it.\r
+  If AutoBoot is enabled, then if user doesn't select any option,\r
+  after period of time, it will automatically return the first menu option.\r
+\r
+  @param  Selection              Menu selection.\r
+\r
+  @retval EFI_SUCESSS            This function always return successfully for now.\r
+\r
+**/\r
+EFI_STATUS\r
+UiDisplayMenu (\r
+  IN OUT UI_MENU_SELECTION           *Selection\r
+  )\r
+{\r
+  INTN                            SkipValue;\r
+  INTN                            Difference;\r
+  INTN                            OldSkipValue;\r
+  UINTN                           DistanceValue;\r
+  UINTN                           Row;\r
+  UINTN                           Col;\r
+  UINTN                           Temp;\r
   UINTN                           Temp2;\r
   UINTN                           TopRow;\r
   UINTN                           BottomRow;\r
   UINTN                           OriginalRow;\r
   UINTN                           Index;\r
-  UINT32                          Count;\r
   UINT16                          Width;\r
   CHAR16                          *StringPtr;\r
   CHAR16                          *OptionString;\r
   CHAR16                          *OutputString;\r
   CHAR16                          *FormattedString;\r
-  CHAR16                          YesResponse;\r
-  CHAR16                          NoResponse;\r
   BOOLEAN                         NewLine;\r
   BOOLEAN                         Repaint;\r
   BOOLEAN                         SavedValue;\r
   BOOLEAN                         UpArrow;\r
   BOOLEAN                         DownArrow;\r
+  BOOLEAN                         InitializedFlag;\r
   EFI_STATUS                      Status;\r
   EFI_INPUT_KEY                   Key;\r
   LIST_ENTRY                      *Link;\r
@@ -1647,18 +2113,14 @@ UiDisplayMenu (
   UI_CONTROL_FLAG                 ControlFlag;\r
   EFI_SCREEN_DESCRIPTOR           LocalScreen;\r
   MENU_REFRESH_ENTRY              *MenuRefreshEntry;\r
+  MENU_REFRESH_ENTRY              *MenuUpdateEntry;  \r
   UI_SCREEN_OPERATION             ScreenOperation;\r
   UINT8                           MinRefreshInterval;\r
-  UINTN                           BufferSize;\r
   UINT16                          DefaultId;\r
-  EFI_DEVICE_PATH_PROTOCOL        *DevicePath;\r
   FORM_BROWSER_STATEMENT          *Statement;\r
-  CHAR16                          TemStr[2];\r
-  UINT8                           *DevicePathBuffer;\r
-  UINT8                           DigitUint8;\r
   UI_MENU_LIST                    *CurrentMenu;\r
-  UI_MENU_LIST                    *MenuList;\r
-  FORM_BROWSER_FORM               *RefForm;\r
+  UINTN                           ModalSkipColumn;\r
+  BROWSER_HOT_KEY                 *HotKey;\r
 \r
   CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));\r
 \r
@@ -1680,7 +2142,8 @@ UiDisplayMenu (
   NextMenuOption      = NULL;\r
   PreviousMenuOption  = NULL;\r
   SavedMenuOption     = NULL;\r
-  RefForm             = NULL;\r
+  HotKey              = NULL;\r
+  ModalSkipColumn     = (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 6;\r
 \r
   ZeroMem (&Key, sizeof (EFI_INPUT_KEY));\r
 \r
@@ -1692,8 +2155,13 @@ UiDisplayMenu (
     Row     = LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
   }\r
 \r
-  Col = LocalScreen.LeftColumn + LEFT_SKIPPED_COLUMNS;\r
-  BottomRow = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT - SCROLL_ARROW_HEIGHT - 1;\r
+  if (Selection->Form->ModalForm) {\r
+    Col = LocalScreen.LeftColumn + LEFT_SKIPPED_COLUMNS + ModalSkipColumn;\r
+  } else {\r
+    Col = LocalScreen.LeftColumn + LEFT_SKIPPED_COLUMNS;\r
+  }\r
+\r
+  BottomRow = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight - SCROLL_ARROW_HEIGHT - 1;\r
 \r
   Selection->TopRow = TopRow;\r
   Selection->BottomRow = BottomRow;\r
@@ -1713,24 +2181,27 @@ UiDisplayMenu (
     //\r
     // Current menu not found, add it to the menu tree\r
     //\r
-    CurrentMenu = UiAddMenuList (NULL, &Selection->FormSetGuid, Selection->FormId);\r
+    CurrentMenu = UiAddMenuList (NULL, Selection->Handle, &Selection->FormSetGuid, Selection->FormId);\r
   }\r
   ASSERT (CurrentMenu != NULL);\r
+  Selection->CurrentMenu = CurrentMenu;\r
 \r
   if (Selection->QuestionId == 0) {\r
     //\r
     // Highlight not specified, fetch it from cached menu\r
     //\r
     Selection->QuestionId = CurrentMenu->QuestionId;\r
+    Selection->Sequence   = CurrentMenu->Sequence;\r
   }\r
 \r
   //\r
-  // Get user's selection\r
+  // Init option as the current user's selection\r
   //\r
+  InitializedFlag = TRUE;\r
   NewPos = gMenuOption.ForwardLink;\r
 \r
   gST->ConOut->EnableCursor (gST->ConOut, FALSE);\r
-  UpdateStatusBar (REFRESH_STATUS_BAR, (UINT8) 0, TRUE);\r
+  UpdateStatusBar (Selection, REFRESH_STATUS_BAR, (UINT8) 0, TRUE);\r
 \r
   ControlFlag = CfInitialization;\r
   Selection->Action = UI_ACTION_NONE;\r
@@ -1766,14 +2237,23 @@ UiDisplayMenu (
         Temp            = (UINTN) SkipValue;\r
         Temp2           = (UINTN) SkipValue;\r
 \r
-        ClearLines (\r
-          LocalScreen.LeftColumn,\r
-          LocalScreen.RightColumn,\r
-          TopRow - SCROLL_ARROW_HEIGHT,\r
-          BottomRow + SCROLL_ARROW_HEIGHT,\r
-          PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND\r
-          );\r
-\r
+        if (Selection->Form->ModalForm) {\r
+          ClearLines (\r
+            LocalScreen.LeftColumn + ModalSkipColumn,\r
+            LocalScreen.LeftColumn + ModalSkipColumn + gPromptBlockWidth + gOptionBlockWidth,\r
+            TopRow - SCROLL_ARROW_HEIGHT,\r
+            BottomRow + SCROLL_ARROW_HEIGHT,\r
+            PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND\r
+            );   \r
+        } else {\r
+          ClearLines (\r
+            LocalScreen.LeftColumn,\r
+            LocalScreen.RightColumn,\r
+            TopRow - SCROLL_ARROW_HEIGHT,\r
+            BottomRow + SCROLL_ARROW_HEIGHT,\r
+            PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND\r
+            );\r
+        }\r
         UiFreeRefreshList ();\r
         MinRefreshInterval = 0;\r
 \r
@@ -1781,7 +2261,11 @@ UiDisplayMenu (
           MenuOption          = MENU_OPTION_FROM_LINK (Link);\r
           MenuOption->Row     = Row;\r
           MenuOption->Col     = Col;\r
-          MenuOption->OptCol  = gPromptBlockWidth + 1 + LocalScreen.LeftColumn;\r
+          if (Selection->Form->ModalForm) {\r
+            MenuOption->OptCol  = gPromptBlockWidth + 1 + LocalScreen.LeftColumn + ModalSkipColumn;\r
+          } else {\r
+            MenuOption->OptCol  = gPromptBlockWidth + 1 + LocalScreen.LeftColumn;\r
+          }\r
 \r
           Statement = MenuOption->ThisTag;\r
           if (Statement->InSubtitle) {\r
@@ -1799,8 +2283,7 @@ UiDisplayMenu (
           Width       = GetWidth (Statement, MenuOption->Handle);\r
           OriginalRow = Row;\r
 \r
-          if (Statement->Operand == EFI_IFR_REF_OP && \r
-            MenuOption->Col >= 2) {\r
+          if (Statement->Operand == EFI_IFR_REF_OP && MenuOption->Col >= 2) {\r
             //\r
             // Print Arrow for Goto button.\r
             //\r
@@ -1847,68 +2330,7 @@ UiDisplayMenu (
 \r
           if (OptionString != NULL) {\r
             if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) {\r
-              //\r
-              // If leading spaces on OptionString - remove the spaces\r
-              //\r
-              for (Index = 0; OptionString[Index] == L' '; Index++) {\r
-                MenuOption->OptCol++;\r
-              }\r
-\r
-              for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {\r
-                OptionString[Count] = OptionString[Index];\r
-                Count++;\r
-              }\r
-\r
-              OptionString[Count] = CHAR_NULL;\r
-            }\r
-\r
-            //\r
-            // If Question request refresh, register the op-code\r
-            //\r
-            if (Statement->RefreshInterval != 0) {\r
-              //\r
-              // Menu will be refreshed at minimal interval of all Questions\r
-              // which have refresh request\r
-              //\r
-              if (MinRefreshInterval == 0 || Statement->RefreshInterval < MinRefreshInterval) {\r
-                MinRefreshInterval = Statement->RefreshInterval;\r
-              }\r
-\r
-              if (gMenuRefreshHead == NULL) {\r
-                MenuRefreshEntry = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));\r
-                ASSERT (MenuRefreshEntry != NULL);\r
-                MenuRefreshEntry->MenuOption        = MenuOption;\r
-                MenuRefreshEntry->Selection         = Selection;\r
-                MenuRefreshEntry->CurrentColumn     = MenuOption->OptCol;\r
-                MenuRefreshEntry->CurrentRow        = MenuOption->Row;\r
-                if (MenuOption->GrayOut) {\r
-                  MenuRefreshEntry->CurrentAttribute = FIELD_TEXT_GRAYED | FIELD_BACKGROUND;\r
-                } else {               \r
-                  MenuRefreshEntry->CurrentAttribute = PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND;\r
-                }\r
-                gMenuRefreshHead                    = MenuRefreshEntry;\r
-              } else {\r
-                //\r
-                // Advance to the last entry\r
-                //\r
-                for (MenuRefreshEntry = gMenuRefreshHead;\r
-                     MenuRefreshEntry->Next != NULL;\r
-                     MenuRefreshEntry = MenuRefreshEntry->Next\r
-                    )\r
-                  ;\r
-                MenuRefreshEntry->Next = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));\r
-                ASSERT (MenuRefreshEntry->Next != NULL);\r
-                MenuRefreshEntry                    = MenuRefreshEntry->Next;\r
-                MenuRefreshEntry->MenuOption        = MenuOption;\r
-                MenuRefreshEntry->Selection         = Selection;\r
-                MenuRefreshEntry->CurrentColumn     = MenuOption->OptCol;\r
-                MenuRefreshEntry->CurrentRow        = MenuOption->Row;\r
-                if (MenuOption->GrayOut) {\r
-                  MenuRefreshEntry->CurrentAttribute = FIELD_TEXT_GRAYED | FIELD_BACKGROUND;\r
-                } else {               \r
-                  MenuRefreshEntry->CurrentAttribute = PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND;\r
-                }\r
-              }\r
+              ProcessStringForDateTime(MenuOption, OptionString, TRUE);\r
             }\r
 \r
             Width       = (UINT16) gOptionBlockWidth;\r
@@ -1948,6 +2370,71 @@ UiDisplayMenu (
 \r
             FreePool (OptionString);\r
           }\r
+\r
+          //\r
+          // If Question has refresh guid, register the op-code.\r
+          //\r
+          if (!CompareGuid (&Statement->RefreshGuid, &gZeroGuid)) {\r
+            if (gMenuEventGuidRefreshHead == NULL) {\r
+              MenuUpdateEntry = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));\r
+              gMenuEventGuidRefreshHead = MenuUpdateEntry;\r
+            } else {\r
+              MenuUpdateEntry = gMenuEventGuidRefreshHead;\r
+              while (MenuUpdateEntry->Next != NULL) {\r
+                MenuUpdateEntry = MenuUpdateEntry->Next; \r
+              }\r
+              MenuUpdateEntry->Next = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));\r
+              MenuUpdateEntry = MenuUpdateEntry->Next; \r
+            }\r
+            ASSERT (MenuUpdateEntry != NULL);\r
+            Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL, TPL_NOTIFY, RefreshQuestionNotify, MenuUpdateEntry, &Statement->RefreshGuid, &MenuUpdateEntry->Event);\r
+            ASSERT (!EFI_ERROR (Status));\r
+            MenuUpdateEntry->MenuOption        = MenuOption;\r
+            MenuUpdateEntry->Selection         = Selection;\r
+            MenuUpdateEntry->CurrentColumn     = MenuOption->OptCol;\r
+            MenuUpdateEntry->CurrentRow        = MenuOption->Row;\r
+            if (MenuOption->GrayOut) {\r
+              MenuUpdateEntry->CurrentAttribute = FIELD_TEXT_GRAYED | FIELD_BACKGROUND;\r
+            } else {\r
+              MenuUpdateEntry->CurrentAttribute = PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND;\r
+            }\r
+          }\r
+          \r
+          //\r
+          // If Question request refresh, register the op-code\r
+          //\r
+          if (Statement->RefreshInterval != 0) {\r
+            //\r
+            // Menu will be refreshed at minimal interval of all Questions\r
+            // which have refresh request\r
+            //\r
+            if (MinRefreshInterval == 0 || Statement->RefreshInterval < MinRefreshInterval) {\r
+              MinRefreshInterval = Statement->RefreshInterval;\r
+            }\r
+            \r
+            if (gMenuRefreshHead == NULL) {\r
+              MenuRefreshEntry = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));\r
+              gMenuRefreshHead = MenuRefreshEntry;\r
+            } else {\r
+              MenuRefreshEntry = gMenuRefreshHead;\r
+              while (MenuRefreshEntry->Next != NULL) {\r
+                MenuRefreshEntry = MenuRefreshEntry->Next; \r
+              }\r
+              MenuRefreshEntry->Next = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));\r
+              MenuRefreshEntry = MenuRefreshEntry->Next;\r
+            }\r
+            ASSERT (MenuRefreshEntry != NULL);            \r
+            MenuRefreshEntry->MenuOption        = MenuOption;\r
+            MenuRefreshEntry->Selection         = Selection;\r
+            MenuRefreshEntry->CurrentColumn     = MenuOption->OptCol;\r
+            MenuRefreshEntry->CurrentRow        = MenuOption->Row;\r
+            if (MenuOption->GrayOut) {\r
+              MenuRefreshEntry->CurrentAttribute = FIELD_TEXT_GRAYED | FIELD_BACKGROUND;\r
+            } else {               \r
+              MenuRefreshEntry->CurrentAttribute = PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND;\r
+            }\r
+          }\r
+          \r
           //\r
           // If this is a text op with secondary text information\r
           //\r
@@ -2048,6 +2535,10 @@ UiDisplayMenu (
       // NewPos:     Current menu option that need to hilight\r
       //\r
       ControlFlag = CfUpdateHelpString;\r
+      if (InitializedFlag) {\r
+        InitializedFlag = FALSE;\r
+        MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - TopRow);\r
+      }\r
 \r
       //\r
       // Repaint flag is normally reset when finish processing CfUpdateHelpString. Temporarily\r
@@ -2060,7 +2551,9 @@ UiDisplayMenu (
         NewPos = gMenuOption.ForwardLink;\r
         SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
 \r
-        while (SavedMenuOption->ThisTag->QuestionId != Selection->QuestionId && NewPos->ForwardLink != &gMenuOption) {\r
+        while ((SavedMenuOption->ThisTag->QuestionId != Selection->QuestionId ||\r
+                SavedMenuOption->Sequence != Selection->Sequence) &&\r
+                NewPos->ForwardLink != &gMenuOption) {\r
           NewPos     = NewPos->ForwardLink;\r
           SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
         }\r
@@ -2073,20 +2566,49 @@ UiDisplayMenu (
           for (Index = TopRow; Index <= BottomRow && Link != NewPos;) {\r
             SavedMenuOption = MENU_OPTION_FROM_LINK (Link);\r
             Index += SavedMenuOption->Skip;\r
+            if (Link == TopOfScreen) {\r
+              Index -= OldSkipValue;\r
+            }\r
             Link = Link->ForwardLink;\r
           }\r
+          if (NewPos == Link) {\r
+            SavedMenuOption = MENU_OPTION_FROM_LINK (Link);\r
+          }\r
 \r
-          if (Link != NewPos || Index > BottomRow) {\r
+          if (Link != NewPos || Index > BottomRow || (Link == NewPos && SavedMenuOption->Row + SavedMenuOption->Skip - 1 > BottomRow)) {\r
+            //\r
+            // Find the MenuOption which has the skip value for Date/Time opcode. \r
+            //\r
+            AdjustDateAndTimePosition(FALSE, &NewPos);\r
             //\r
             // NewPos is not in the current page, simply scroll page so that NewPos is in the end of the page\r
             //\r
+            SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
+            //\r
+            // SavedMenuOption->Row == 0 means the menu not show yet.\r
+            //\r
+            if (SavedMenuOption->Row == 0) {\r
+              UpdateOptionSkipLines (Selection, SavedMenuOption);\r
+            }\r
+            \r
             Link    = NewPos;\r
-            for (Index = TopRow; Index <= BottomRow; ) {\r
+            for (Index = TopRow + SavedMenuOption->Skip; Index <= BottomRow + 1; ) {            \r
               Link = Link->BackLink;\r
               SavedMenuOption = MENU_OPTION_FROM_LINK (Link);\r
+              if (SavedMenuOption->Row == 0) {\r
+                UpdateOptionSkipLines (Selection, SavedMenuOption);\r
+              }\r
               Index     += SavedMenuOption->Skip;\r
             }\r
-            TopOfScreen     = Link->ForwardLink;\r
+            \r
+            SkipValue = Index - BottomRow - 1;\r
+            if (SkipValue > 0 && SkipValue < (INTN) SavedMenuOption->Skip) {\r
+              TopOfScreen     = Link;\r
+              OldSkipValue    = SkipValue;\r
+            } else {\r
+              SkipValue       = 0;\r
+              TopOfScreen     = Link->ForwardLink;\r
+            }\r
 \r
             Repaint = TRUE;\r
             NewLine = TRUE;\r
@@ -2115,18 +2637,7 @@ UiDisplayMenu (
             if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) ||\r
                 (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)\r
                ) {\r
-              //\r
-              // If leading spaces on OptionString - remove the spaces\r
-              //\r
-              for (Index = 0; OptionString[Index] == L' '; Index++)\r
-                ;\r
-\r
-              for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {\r
-                OptionString[Count] = OptionString[Index];\r
-                Count++;\r
-              }\r
-\r
-              OptionString[Count] = CHAR_NULL;\r
+              ProcessStringForDateTime(MenuOption, OptionString, FALSE);\r
             }\r
 \r
             Width               = (UINT16) gOptionBlockWidth;\r
@@ -2181,26 +2692,22 @@ UiDisplayMenu (
         }\r
 \r
         //\r
-        // This is only possible if we entered this page and the first menu option is\r
-        // a "non-menu" item.  In that case, force it UiDown\r
+        // This is the current selected statement\r
         //\r
         MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
+        Statement = MenuOption->ThisTag;\r
+        Selection->Statement = Statement;\r
         if (!IsSelectable (MenuOption)) {\r
-          ASSERT (ScreenOperation == UiNoOperation);\r
-          ScreenOperation = UiDown;\r
-          ControlFlag     = CfScreenOperation;\r
+          Repaint = SavedValue;\r
+          UpdateKeyHelp (Selection, MenuOption, FALSE);\r
           break;\r
         }\r
 \r
-        //\r
-        // This is the current selected statement\r
-        //\r
-        Statement = MenuOption->ThisTag;\r
-        Selection->Statement = Statement;\r
         //\r
         // Record highlight for current menu\r
         //\r
         CurrentMenu->QuestionId = Statement->QuestionId;\r
+        CurrentMenu->Sequence   = MenuOption->Sequence;\r
 \r
         //\r
         // Set reverse attribute\r
@@ -2229,18 +2736,7 @@ UiDisplayMenu (
         ProcessOptions (Selection, MenuOption, FALSE, &OptionString);\r
         if (OptionString != NULL) {\r
           if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) {\r
-            //\r
-            // If leading spaces on OptionString - remove the spaces\r
-            //\r
-            for (Index = 0; OptionString[Index] == L' '; Index++)\r
-              ;\r
-\r
-            for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {\r
-              OptionString[Count] = OptionString[Index];\r
-              Count++;\r
-            }\r
-\r
-            OptionString[Count] = CHAR_NULL;\r
+            ProcessStringForDateTime(MenuOption, OptionString, FALSE);\r
           }\r
           Width               = (UINT16) gOptionBlockWidth;\r
 \r
@@ -2304,13 +2800,16 @@ UiDisplayMenu (
 \r
     case CfUpdateHelpString:\r
       ControlFlag = CfPrepareToReadKey;\r
+      if (Selection->Form->ModalForm) {\r
+        break;\r
+      }\r
 \r
-        if (Repaint || NewLine) {\r
+      if (Repaint || NewLine) {\r
         //\r
         // Don't print anything if it is a NULL help token\r
         //\r
         ASSERT(MenuOption != NULL);\r
-        if (MenuOption->ThisTag->Help == 0) {\r
+        if (MenuOption->ThisTag->Help == 0 || !IsSelectable (MenuOption)) {\r
           StringPtr = L"\0";\r
         } else {\r
           StringPtr = GetToken (MenuOption->ThisTag->Help, MenuOption->Handle);\r
@@ -2361,8 +2860,9 @@ UiDisplayMenu (
         //\r
         // IFR is updated in Callback of refresh opcode, re-parse it\r
         //\r
+        ControlFlag = CfCheckSelection;\r
         Selection->Statement = NULL;\r
-        return EFI_SUCCESS;\r
+        break;\r
       }\r
 \r
       Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
@@ -2376,6 +2876,11 @@ UiDisplayMenu (
 \r
       switch (Key.UnicodeChar) {\r
       case CHAR_CARRIAGE_RETURN:\r
+        if(MenuOption->GrayOut || MenuOption->ReadOnly) {\r
+          ControlFlag = CfReadKey;\r
+          break;\r
+        }\r
+\r
         ScreenOperation = UiSelect;\r
         gDirection      = 0;\r
         break;\r
@@ -2390,7 +2895,7 @@ UiDisplayMenu (
         // If the screen has no menu items, and the user didn't select UiReset\r
         // ignore the selection and go back to reading keys.\r
         //\r
-        if(IsListEmpty (&gMenuOption)) {\r
+        if(IsListEmpty (&gMenuOption) || MenuOption->GrayOut || MenuOption->ReadOnly) {\r
           ControlFlag = CfReadKey;\r
           break;\r
         }\r
@@ -2443,31 +2948,35 @@ UiDisplayMenu (
           }\r
           \r
           ASSERT(MenuOption != NULL);\r
-          if (MenuOption->ThisTag->Operand == EFI_IFR_CHECKBOX_OP && !MenuOption->GrayOut) {\r
+          if (MenuOption->ThisTag->Operand == EFI_IFR_CHECKBOX_OP && !MenuOption->GrayOut && !MenuOption->ReadOnly) {\r
             ScreenOperation = UiSelect;\r
           }\r
         }\r
         break;\r
 \r
       case CHAR_NULL:\r
-        if (((Key.ScanCode == SCAN_F9) && ((gFunctionKeySetting & FUNCTION_NINE) != FUNCTION_NINE)) ||\r
-            ((Key.ScanCode == SCAN_F10) && ((gFunctionKeySetting & FUNCTION_TEN) != FUNCTION_TEN))\r
-            ) {\r
+        for (Index = 0; Index < mScanCodeNumber; Index++) {\r
+          if (Key.ScanCode == gScanCodeToOperation[Index].ScanCode) {\r
+            ScreenOperation = gScanCodeToOperation[Index].ScreenOperation;\r
+            break;\r
+          }\r
+        }\r
+        \r
+        if (Selection->Form->ModalForm && (Key.ScanCode == SCAN_ESC || Index == mScanCodeNumber)) {\r
           //\r
-          // If the function key has been disabled, just ignore the key.\r
+          // ModalForm has no ESC key and Hot Key.\r
           //\r
-        } else {\r
-          for (Index = 0; Index < sizeof (gScanCodeToOperation) / sizeof (gScanCodeToOperation[0]); Index++) {\r
-            if (Key.ScanCode == gScanCodeToOperation[Index].ScanCode) {\r
-              if (Key.ScanCode == SCAN_F9) {\r
-                //\r
-                // Reset to standard default\r
-                //\r
-                DefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;\r
-              }\r
-              ScreenOperation = gScanCodeToOperation[Index].ScreenOperation;\r
-              break;\r
-            }\r
+          ControlFlag = CfReadKey;\r
+        } else if (Index == mScanCodeNumber) {\r
+          //\r
+          // Check whether Key matches the registered hot key.\r
+          //\r
+          HotKey = NULL;\r
+          if ((gBrowserSettingScope == SystemLevel) || (gFunctionKeySetting != NONE_FUNCTION_KEY_SETTING)) {\r
+            HotKey = GetHotKeyFromRegisterList (&Key);\r
+          }\r
+          if (HotKey != NULL) {\r
+            ScreenOperation = UiHotKey;\r
           }\r
         }\r
         break;\r
@@ -2484,20 +2993,6 @@ UiDisplayMenu (
           ControlFlag = CfReadKey;\r
           break;\r
         }\r
-        //\r
-        // if there is nothing logical to place a cursor on, just move on to wait for a key.\r
-        //\r
-        for (Link = gMenuOption.ForwardLink; Link != &gMenuOption; Link = Link->ForwardLink) {\r
-          NextMenuOption = MENU_OPTION_FROM_LINK (Link);\r
-          if (IsSelectable (NextMenuOption)) {\r
-            break;\r
-          }\r
-        }\r
-\r
-        if (Link == &gMenuOption) {\r
-          ControlFlag = CfPrepareToReadKey;\r
-          break;\r
-        }\r
       }\r
 \r
       for (Index = 0;\r
@@ -2527,131 +3022,14 @@ UiDisplayMenu (
 \r
       switch (Statement->Operand) {\r
       case EFI_IFR_REF_OP:\r
-        if (Statement->RefDevicePath != 0) {\r
-          //\r
-          // Goto another Hii Package list\r
-          //\r
-          Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
+        ProcessGotoOpCode(Statement, Selection, &Repaint, &NewLine);\r
+        break;\r
 \r
-          StringPtr = GetToken (Statement->RefDevicePath, Selection->FormSet->HiiHandle);\r
-          if (StringPtr == NULL) {\r
-            //\r
-            // No device path string not found, exit\r
-            //\r
-            Selection->Action = UI_ACTION_EXIT;\r
-            Selection->Statement = NULL;\r
-            break;\r
-          }\r
-          BufferSize = StrLen (StringPtr) / 2;\r
-          DevicePath = AllocatePool (BufferSize);\r
-          ASSERT (DevicePath != NULL);\r
-\r
-          //\r
-          // Convert from Device Path String to DevicePath Buffer in the reverse order.\r
-          //\r
-          DevicePathBuffer = (UINT8 *) DevicePath;\r
-          for (Index = 0; StringPtr[Index] != L'\0'; Index ++) {\r
-            TemStr[0] = StringPtr[Index];\r
-            DigitUint8 = (UINT8) StrHexToUint64 (TemStr);\r
-            if (DigitUint8 == 0 && TemStr[0] != L'0') {\r
-              //\r
-              // Invalid Hex Char as the tail.\r
-              //\r
-              break;\r
-            }\r
-            if ((Index & 1) == 0) {\r
-              DevicePathBuffer [Index/2] = DigitUint8;\r
-            } else {\r
-              DevicePathBuffer [Index/2] = (UINT8) ((DevicePathBuffer [Index/2] << 4) + DigitUint8);\r
-            }\r
-          }\r
-\r
-          Selection->Handle = DevicePathToHiiHandle (DevicePath);\r
-          if (Selection->Handle == NULL) {\r
-            //\r
-            // If target Hii Handle not found, exit\r
-            //\r
-            Selection->Action = UI_ACTION_EXIT;\r
-            Selection->Statement = NULL;\r
-            break;\r
-          }\r
-\r
-          FreePool (StringPtr);\r
-          FreePool (DevicePath);\r
-\r
-          CopyMem (&Selection->FormSetGuid, &Statement->RefFormSetId, sizeof (EFI_GUID));\r
-          Selection->FormId = Statement->RefFormId;\r
-          Selection->QuestionId = Statement->RefQuestionId;\r
-        } else if (!CompareGuid (&Statement->RefFormSetId, &gZeroGuid)) {\r
-          //\r
-          // Goto another Formset, check for uncommitted data\r
-          //\r
-          Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
-\r
-          CopyMem (&Selection->FormSetGuid, &Statement->RefFormSetId, sizeof (EFI_GUID));\r
-          Selection->FormId = Statement->RefFormId;\r
-          Selection->QuestionId = Statement->RefQuestionId;\r
-        } else if (Statement->RefFormId != 0) {\r
-          //\r
-          // Check whether target From is suppressed.\r
-          //\r
-          RefForm = IdToForm (Selection->FormSet, Statement->RefFormId);\r
-\r
-          if ((RefForm != NULL) && (RefForm->SuppressExpression != NULL)) {\r
-            Status = EvaluateExpression (Selection->FormSet, RefForm, RefForm->SuppressExpression);\r
-            if (EFI_ERROR (Status)) {\r
-              return Status;\r
-            }\r
-\r
-            if (RefForm->SuppressExpression->Result.Value.b) {\r
-              //\r
-              // Form is suppressed. \r
-              //\r
-              do {\r
-                CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gFormSuppress, gPressEnter, gEmptyString);\r
-              } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
-\r
-              Repaint = TRUE;\r
-              break;\r
-            }\r
-          }\r
-\r
-          //\r
-          // Goto another form inside this formset,\r
-          //\r
-          Selection->Action = UI_ACTION_REFRESH_FORM;\r
-\r
-          //\r
-          // Link current form so that we can always go back when someone hits the ESC\r
-          //\r
-          MenuList = UiFindMenuList (&Selection->FormSetGuid, Statement->RefFormId);\r
-          if (MenuList == NULL) {\r
-            MenuList = UiAddMenuList (CurrentMenu, &Selection->FormSetGuid, Statement->RefFormId);\r
-          }\r
-\r
-          Selection->FormId = Statement->RefFormId;\r
-          Selection->QuestionId = Statement->RefQuestionId;\r
-        } else if (Statement->RefQuestionId != 0) {\r
-          //\r
-          // Goto another Question\r
-          //\r
-          Selection->QuestionId = Statement->RefQuestionId;\r
-\r
-          if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {\r
-            Selection->Action = UI_ACTION_REFRESH_FORM;\r
-          } else {\r
-            Repaint = TRUE;\r
-            NewLine = TRUE;\r
-            break;\r
-          }\r
-        }\r
-        break;\r
-\r
-      case EFI_IFR_ACTION_OP:\r
-        //\r
-        // Process the Config string <ConfigResp>\r
-        //\r
-        Status = ProcessQuestionConfig (Selection, Statement);\r
+      case EFI_IFR_ACTION_OP:\r
+        //\r
+        // Process the Config string <ConfigResp>\r
+        //\r
+        Status = ProcessQuestionConfig (Selection, Statement);\r
 \r
         if (EFI_ERROR (Status)) {\r
           break;\r
@@ -2698,84 +3076,8 @@ UiDisplayMenu (
       // We come here when someone press ESC\r
       //\r
       ControlFlag = CfCheckSelection;\r
-\r
-      if (CurrentMenu->Parent != NULL) {\r
-        //\r
-        // we have a parent, so go to the parent menu\r
-        //\r
-        if (CompareGuid (&CurrentMenu->FormSetGuid, &CurrentMenu->Parent->FormSetGuid)) {\r
-          //\r
-          // The parent menu and current menu are in the same formset\r
-          //\r
-          Selection->Action = UI_ACTION_REFRESH_FORM;\r
-        } else {\r
-          Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
-        }\r
-        Selection->Statement = NULL;\r
-\r
-        Selection->FormId = CurrentMenu->Parent->FormId;\r
-        Selection->QuestionId = CurrentMenu->Parent->QuestionId;\r
-\r
-        //\r
-        // Clear highlight record for this menu\r
-        //\r
-        CurrentMenu->QuestionId = 0;\r
-        break;\r
-      }\r
-\r
-      if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) == FORMSET_CLASS_FRONT_PAGE) {\r
-        //\r
-        // We never exit FrontPage, so skip the ESC\r
-        //\r
-        Selection->Action = UI_ACTION_NONE;\r
-        break;\r
-      }\r
-\r
-      //\r
-      // We are going to leave current FormSet, so check uncommited data in this FormSet\r
-      //\r
-      if (gNvUpdateRequired) {\r
-        Status      = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
-\r
-        YesResponse = gYesResponse[0];\r
-        NoResponse  = gNoResponse[0];\r
-\r
-        //\r
-        // If NV flag is up, prompt user\r
-        //\r
-        do {\r
-          CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gSaveChanges, gAreYouSure, gEmptyString);\r
-        } while\r
-        (\r
-          (Key.ScanCode != SCAN_ESC) &&\r
-          ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (NoResponse | UPPER_LOWER_CASE_OFFSET)) &&\r
-          ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (YesResponse | UPPER_LOWER_CASE_OFFSET))\r
-        );\r
-\r
-        if (Key.ScanCode == SCAN_ESC) {\r
-          //\r
-          // User hits the ESC key\r
-          //\r
-          Repaint = TRUE;\r
-          NewLine = TRUE;\r
-\r
-          Selection->Action = UI_ACTION_NONE;\r
-          break;\r
-        }\r
-\r
-        //\r
-        // If the user hits the YesResponse key\r
-        //\r
-        if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (YesResponse | UPPER_LOWER_CASE_OFFSET)) {\r
-          Status = SubmitForm (Selection->FormSet, Selection->Form);\r
-        }\r
-      }\r
-\r
-      Selection->Action = UI_ACTION_EXIT;\r
-      Selection->Statement = NULL;\r
-      CurrentMenu->QuestionId = 0;\r
-\r
-      return EFI_SUCCESS;\r
+      FindNextMenu (Selection, &Repaint, &NewLine);\r
+      break;\r
 \r
     case CfUiLeft:\r
       ControlFlag = CfCheckSelection;\r
@@ -2808,47 +3110,50 @@ UiDisplayMenu (
     case CfUiUp:\r
       ControlFlag = CfCheckSelection;\r
 \r
-      SavedListEntry = TopOfScreen;\r
+      SavedListEntry = NewPos;\r
 \r
       ASSERT(NewPos != NULL);\r
+      //\r
+      // Adjust Date/Time position before we advance forward.\r
+      //\r
+      AdjustDateAndTimePosition (TRUE, &NewPos);\r
       if (NewPos->BackLink != &gMenuOption) {\r
-        NewLine = TRUE;\r
-        //\r
-        // Adjust Date/Time position before we advance forward.\r
-        //\r
-        AdjustDateAndTimePosition (TRUE, &NewPos);\r
-\r
-        //\r
-        // Caution that we have already rewind to the top, don't go backward in this situation.\r
-        //\r
-        if (NewPos->BackLink != &gMenuOption) {\r
-          NewPos = NewPos->BackLink;\r
-        }\r
+        MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
+        ASSERT (MenuOption != NULL);\r
+        NewLine    = TRUE;\r
+        NewPos     = NewPos->BackLink;\r
 \r
-        Difference = MoveToNextStatement (TRUE, &NewPos);\r
         PreviousMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
+        if (PreviousMenuOption->Row == 0) {\r
+          UpdateOptionSkipLines (Selection, PreviousMenuOption);\r
+        }\r
         DistanceValue = PreviousMenuOption->Skip;\r
-\r
-        //\r
-        // Since the behavior of hitting the up arrow on a Date/Time op-code is intended\r
-        // to be one that back to the previous set of op-codes, we need to advance to the sencond\r
-        // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate\r
-        // checking can be done.\r
-        //\r
-        DistanceValue += AdjustDateAndTimePosition (TRUE, &NewPos);\r
-        \r
-        ASSERT (MenuOption != NULL);\r
+        Difference    = 0;\r
+        if (MenuOption->Row >= DistanceValue + TopRow) {\r
+          Difference = MoveToNextStatement (Selection, TRUE, &NewPos, MenuOption->Row - TopRow - DistanceValue);\r
+        }\r
+        NextMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
+       \r
         if (Difference < 0) {\r
           //\r
-          // We want to goto previous MenuOption, but finally we go down.\r
-          // it means that we hit the begining MenuOption that can be focused\r
-          // so we simply scroll to the top\r
+          // We hit the begining MenuOption that can be focused\r
+          // so we simply scroll to the top.\r
           //\r
-          if (SavedListEntry != gMenuOption.ForwardLink) {\r
+          if (TopOfScreen != gMenuOption.ForwardLink) {\r
             TopOfScreen = gMenuOption.ForwardLink;\r
             Repaint     = TRUE;\r
+          } else {\r
+            //\r
+            // Scroll up to the last page when we have arrived at top page.\r
+            //\r
+            NewPos          = &gMenuOption;\r
+            TopOfScreen     = &gMenuOption;\r
+            MenuOption      = MENU_OPTION_FROM_LINK (SavedListEntry);\r
+            ScreenOperation = UiPageUp;\r
+            ControlFlag     = CfScreenOperation;\r
+            break;\r
           }\r
-        } else if ((INTN) MenuOption->Row - (INTN) DistanceValue - Difference < (INTN) TopRow) {\r
+        } else if (MenuOption->Row < TopRow + DistanceValue + Difference) {\r
           //\r
           // Previous focus MenuOption is above the TopOfScreen, so we need to scroll\r
           //\r
@@ -2856,27 +3161,30 @@ UiDisplayMenu (
           Repaint     = TRUE;\r
           SkipValue = 0;\r
           OldSkipValue = 0;\r
+        } else if (!IsSelectable (NextMenuOption)) {\r
+          //\r
+          // Continue to go up until scroll to next page or the selectable option is found.\r
+          //\r
+          ScreenOperation = UiUp;\r
+          ControlFlag     = CfScreenOperation;\r
         }\r
 \r
         //\r
         // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.\r
         //\r
         AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
-\r
-        UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE);\r
+        AdjustDateAndTimePosition (TRUE, &NewPos);\r
+        MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
+        UpdateStatusBar (Selection, INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE);\r
       } else {\r
-        SavedMenuOption = MenuOption;\r
-        MenuOption      = MENU_OPTION_FROM_LINK (NewPos);\r
-        if (!IsSelectable (MenuOption)) {\r
-          //\r
-          // If we are at the end of the list and sitting on a text op, we need to more forward\r
-          //\r
-          ScreenOperation = UiDown;\r
-          ControlFlag     = CfScreenOperation;\r
-          break;\r
-        }\r
-\r
-        MenuOption = SavedMenuOption;\r
+        //\r
+        // Scroll up to the last page.\r
+        //\r
+        NewPos          = &gMenuOption;\r
+        TopOfScreen     = &gMenuOption;\r
+        MenuOption      = MENU_OPTION_FROM_LINK (SavedListEntry);\r
+        ScreenOperation = UiPageUp;\r
+        ControlFlag     = CfScreenOperation;\r
       }\r
       break;\r
 \r
@@ -2893,38 +3201,62 @@ UiDisplayMenu (
       NewLine   = TRUE;\r
       Repaint   = TRUE;\r
       Link      = TopOfScreen;\r
-      PreviousMenuOption = MENU_OPTION_FROM_LINK (Link);\r
-      Index = BottomRow;\r
+      Index     = BottomRow;\r
       while ((Index >= TopRow) && (Link->BackLink != &gMenuOption)) {\r
-        Index = Index - PreviousMenuOption->Skip;\r
         Link = Link->BackLink;\r
         PreviousMenuOption = MENU_OPTION_FROM_LINK (Link);\r
+        if (PreviousMenuOption->Row == 0) {\r
+          UpdateOptionSkipLines (Selection, PreviousMenuOption);\r
+        }        \r
+        if (Index < PreviousMenuOption->Skip) {\r
+          Index = 0;\r
+          break;\r
+        }\r
+        Index = Index - PreviousMenuOption->Skip;\r
       }\r
+      \r
+      if ((Link->BackLink == &gMenuOption) && (Index >= TopRow)) {\r
+        if (TopOfScreen == &gMenuOption) {\r
+          TopOfScreen = gMenuOption.ForwardLink;\r
+          NewPos      = gMenuOption.BackLink;\r
+          MoveToNextStatement (Selection, TRUE, &NewPos, BottomRow - TopRow);\r
+          Repaint = FALSE;\r
+        } else if (TopOfScreen != Link) {\r
+          TopOfScreen = Link;\r
+          NewPos      = Link;\r
+          MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - TopRow);\r
+        } else {\r
+          //\r
+          // Finally we know that NewPos is the last MenuOption can be focused.\r
+          //\r
+          Repaint = FALSE;\r
+          NewPos  = Link;\r
+          MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - TopRow);\r
+        }\r
+      } else {\r
+        if (Index + 1 < TopRow) {\r
+          //\r
+          // Back up the previous option.\r
+          //\r
+          Link = Link->ForwardLink;\r
+        }\r
 \r
-      TopOfScreen = Link;\r
-      Difference = MoveToNextStatement (TRUE, &Link);\r
-      if (Difference > 0) {\r
         //\r
-        // The focus MenuOption is above the TopOfScreen\r
+        // Move to the option in Next page.\r
         //\r
-        TopOfScreen = Link;\r
-      } else if (Difference < 0) {\r
+        if (TopOfScreen == &gMenuOption) {\r
+          NewPos = gMenuOption.BackLink;\r
+          MoveToNextStatement (Selection, TRUE, &NewPos, BottomRow - TopRow);\r
+        } else {\r
+          NewPos = Link;\r
+          MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - TopRow);\r
+        }\r
+\r
         //\r
-        // This happens when there is no MenuOption can be focused from\r
-        // Current MenuOption to the first MenuOption\r
+        // There are more MenuOption needing scrolling up.\r
         //\r
-        TopOfScreen = gMenuOption.ForwardLink;\r
-      }\r
-      Index += Difference;\r
-      if (Index < TopRow) {\r
-        MenuOption = NULL;\r
-      }\r
-\r
-      if (NewPos == Link) {\r
-        Repaint = FALSE;\r
-        NewLine = FALSE;\r
-      } else {\r
-        NewPos = Link;\r
+        TopOfScreen = Link;\r
+        MenuOption  = NULL;\r
       }\r
 \r
       //\r
@@ -2956,28 +3288,35 @@ UiDisplayMenu (
         NextMenuOption = MENU_OPTION_FROM_LINK (Link);\r
       }\r
 \r
-      Index += MoveToNextStatement (FALSE, &Link);\r
-      if (Index > BottomRow) {\r
+      if ((Link->ForwardLink == &gMenuOption) && (Index <= BottomRow)) {\r
+        //\r
+        // Finally we know that NewPos is the last MenuOption can be focused.\r
+        //\r
+        Repaint = FALSE;\r
+        MoveToNextStatement (Selection, TRUE, &Link, Index - TopRow);\r
+      } else {\r
+        if (Index - 1 > BottomRow) {\r
+          //\r
+          // Back up the previous option.\r
+          //\r
+          Link = Link->BackLink;\r
+        }\r
         //\r
-        // There are more MenuOption needing scrolling\r
+        // There are more MenuOption needing scrolling down.\r
         //\r
         TopOfScreen = Link;\r
         MenuOption = NULL;\r
-      }\r
-      if (NewPos == Link && Index <= BottomRow) {\r
         //\r
-        // Finally we know that NewPos is the last MenuOption can be focused.\r
+        // Move to the option in Next page.\r
         //\r
-        NewLine = FALSE;\r
-        Repaint = FALSE;\r
-      } else {\r
-        NewPos  = Link;\r
+        MoveToNextStatement (Selection, FALSE, &Link, BottomRow - TopRow);\r
       }\r
 \r
       //\r
       // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.\r
       // Don't do this when we are already in the last page.\r
       //\r
+      NewPos  = Link;\r
       AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
       AdjustDateAndTimePosition (TRUE, &NewPos);\r
       break;\r
@@ -2993,21 +3332,49 @@ UiDisplayMenu (
       // the Date/Time op-code.\r
       //\r
       SavedListEntry = NewPos;\r
-      DistanceValue  = AdjustDateAndTimePosition (FALSE, &NewPos);\r
+      AdjustDateAndTimePosition (FALSE, &NewPos);\r
 \r
       if (NewPos->ForwardLink != &gMenuOption) {\r
         MenuOption      = MENU_OPTION_FROM_LINK (NewPos);\r
         NewLine         = TRUE;\r
         NewPos          = NewPos->ForwardLink;\r
 \r
-        DistanceValue  += MoveToNextStatement (FALSE, &NewPos);\r
+        Difference      = 0;\r
+        if (BottomRow >= MenuOption->Row + MenuOption->Skip) {\r
+          Difference    = MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - MenuOption->Row - MenuOption->Skip);\r
+          //\r
+          // We hit the end of MenuOption that can be focused\r
+          // so we simply scroll to the first page.\r
+          //\r
+          if (Difference < 0) {\r
+            //\r
+            // Scroll to the first page.\r
+            //\r
+            if (TopOfScreen != gMenuOption.ForwardLink) {\r
+              TopOfScreen = gMenuOption.ForwardLink;\r
+              Repaint     = TRUE;\r
+              MenuOption  = NULL;\r
+            } else {\r
+              MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
+            }\r
+            NewPos        = gMenuOption.ForwardLink;\r
+            MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - TopRow);\r
+    \r
+            //\r
+            // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.\r
+            //\r
+            AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
+            AdjustDateAndTimePosition (TRUE, &NewPos);\r
+            break;\r
+          }\r
+        }\r
         NextMenuOption  = MENU_OPTION_FROM_LINK (NewPos);\r
 \r
         //\r
         // An option might be multi-line, so we need to reflect that data in the overall skip value\r
         //\r
-        UpdateOptionSkipLines (Selection, NextMenuOption, &OptionString, (UINTN) SkipValue);\r
-        DistanceValue  += NextMenuOption->Skip;\r
+        UpdateOptionSkipLines (Selection, NextMenuOption);\r
+        DistanceValue  = Difference + NextMenuOption->Skip;\r
 \r
         Temp = MenuOption->Row + MenuOption->Skip + DistanceValue - 1;\r
         if ((MenuOption->Row + MenuOption->Skip == BottomRow + 1) &&\r
@@ -3098,73 +3465,155 @@ UiDisplayMenu (
 \r
           Repaint       = TRUE;\r
           OldSkipValue  = SkipValue;\r
+        } else if (!IsSelectable (NextMenuOption)) {\r
+          //\r
+          // Continue to go down until scroll to next page or the selectable option is found.\r
+          //\r
+          ScreenOperation = UiDown;\r
+          ControlFlag     = CfScreenOperation;\r
         }\r
 \r
         MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
 \r
-        UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE);\r
+        UpdateStatusBar (Selection, INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE);\r
 \r
       } else {\r
-        SavedMenuOption = MenuOption;\r
-        MenuOption      = MENU_OPTION_FROM_LINK (NewPos);\r
-        if (!IsSelectable (MenuOption)) {\r
-          //\r
-          // If we are at the end of the list and sitting on a text op, we need to more forward\r
-          //\r
-          ScreenOperation = UiUp;\r
-          ControlFlag     = CfScreenOperation;\r
-          break;\r
-        }\r
-\r
-        MenuOption = SavedMenuOption;\r
         //\r
-        // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.\r
+        // Scroll to the first page.\r
         //\r
-        AdjustDateAndTimePosition (TRUE, &NewPos);\r
+        if (TopOfScreen != gMenuOption.ForwardLink) {\r
+          TopOfScreen = gMenuOption.ForwardLink;\r
+          Repaint     = TRUE;\r
+          MenuOption  = NULL;\r
+        } else {\r
+          MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
+        }\r
+        NewLine       = TRUE;\r
+        NewPos        = gMenuOption.ForwardLink;\r
+        MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - TopRow);\r
       }\r
+\r
+      //\r
+      // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.\r
+      //\r
+      AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
+      AdjustDateAndTimePosition (TRUE, &NewPos);\r
       break;\r
 \r
-    case CfUiSave:\r
+    case CfUiHotKey:\r
       ControlFlag = CfCheckSelection;\r
-\r
+      \r
+      Status = EFI_SUCCESS;\r
       //\r
-      // Submit the form\r
+      // Discard changes. After it, no NV flag is showed.\r
       //\r
-      Status = SubmitForm (Selection->FormSet, Selection->Form);\r
-\r
-      if (!EFI_ERROR (Status)) {\r
-        ASSERT(MenuOption != NULL);\r
-        UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE);\r
-        UpdateStatusBar (NV_UPDATE_REQUIRED, MenuOption->ThisTag->QuestionFlags, FALSE);\r
-      } else {\r
-        do {\r
-          CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gSaveFailed, gPressEnter, gEmptyString);\r
-        } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+      if ((HotKey->Action & BROWSER_ACTION_DISCARD) == BROWSER_ACTION_DISCARD) {\r
+        Status = DiscardForm (Selection->FormSet, Selection->Form, gBrowserSettingScope);\r
+        if (!EFI_ERROR (Status)) {\r
+          Selection->Action = UI_ACTION_REFRESH_FORM;\r
+          Selection->Statement = NULL;\r
+          gResetRequired = FALSE;\r
+        } else {\r
+          do {\r
+            CreateDialog (4, TRUE, 0, NULL, &Key, HotKey->HelpString, gDiscardFailed, gPressEnter, gEmptyString);\r
+          } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+          //\r
+          // Still show current page.\r
+          //\r
+          Selection->Action = UI_ACTION_NONE;\r
+          Repaint = TRUE;\r
+          NewLine = TRUE;\r
+          break;\r
+        }\r
+      }\r
 \r
-        Repaint = TRUE;\r
-        NewLine = TRUE;\r
+      //\r
+      // Reterieve default setting. After it. NV flag will be showed.\r
+      //\r
+      if ((HotKey->Action & BROWSER_ACTION_DEFAULT) == BROWSER_ACTION_DEFAULT) {\r
+        Status = ExtractDefault (Selection->FormSet, Selection->Form, HotKey->DefaultId, gBrowserSettingScope);\r
+        if (!EFI_ERROR (Status)) {\r
+          Selection->Action = UI_ACTION_REFRESH_FORM;\r
+          Selection->Statement = NULL;\r
+          gResetRequired = TRUE;\r
+        } else {\r
+          do {\r
+            CreateDialog (4, TRUE, 0, NULL, &Key, HotKey->HelpString, gDefaultFailed, gPressEnter, gEmptyString);\r
+          } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+          //\r
+          // Still show current page.\r
+          //\r
+          Selection->Action = UI_ACTION_NONE;\r
+          Repaint = TRUE;\r
+          NewLine = TRUE;\r
+          break;\r
+        }\r
       }\r
-      break;\r
 \r
-    case CfUiDefault:\r
-      ControlFlag = CfCheckSelection;\r
-      if (!Selection->FormEditable) {\r
+      //\r
+      // Save changes. After it, no NV flag is showed.\r
+      //\r
+      if ((HotKey->Action & BROWSER_ACTION_SUBMIT) == BROWSER_ACTION_SUBMIT) {\r
+        Status = SubmitForm (Selection->FormSet, Selection->Form, gBrowserSettingScope);\r
+        if (!EFI_ERROR (Status)) {\r
+          ASSERT(MenuOption != NULL);\r
+          UpdateStatusBar (Selection, INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE);\r
+          UpdateStatusBar (Selection, NV_UPDATE_REQUIRED, MenuOption->ThisTag->QuestionFlags, FALSE);\r
+        } else {\r
+          do {\r
+            CreateDialog (4, TRUE, 0, NULL, &Key, HotKey->HelpString, gSaveFailed, gPressEnter, gEmptyString);\r
+          } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+          //\r
+          // Still show current page.\r
+          //\r
+          Selection->Action = UI_ACTION_NONE;\r
+          Repaint = TRUE;\r
+          NewLine = TRUE;\r
+          break;\r
+        }\r
+      }\r
+      \r
+      //\r
+      // Set Reset required Flag\r
+      //\r
+      if ((HotKey->Action & BROWSER_ACTION_RESET) == BROWSER_ACTION_RESET) {\r
+        gResetRequired = TRUE;\r
+      }\r
+      \r
+      //\r
+      // Exit Action\r
+      //\r
+      if ((HotKey->Action & BROWSER_ACTION_EXIT) == BROWSER_ACTION_EXIT) {\r
         //\r
-        // This Form is not editable, ignore the F9 (reset to default)\r
+        // Form Exit without saving, Similar to ESC Key.\r
+        // FormSet Exit without saving, Exit SendForm.\r
+        // System Exit without saving, CallExitHandler and Exit SendForm.\r
         //\r
-        break;\r
+        DiscardForm (Selection->FormSet, Selection->Form, gBrowserSettingScope);\r
+        if (gBrowserSettingScope == FormLevel) {\r
+          ControlFlag = CfUiReset;\r
+        } else if (gBrowserSettingScope == FormSetLevel) {\r
+          Selection->Action = UI_ACTION_EXIT;\r
+        } else if (gBrowserSettingScope == SystemLevel) {\r
+          if (ExitHandlerFunction != NULL) {\r
+            ExitHandlerFunction ();\r
+          }\r
+          Selection->Action = UI_ACTION_EXIT;\r
+        }\r
+        Selection->Statement = NULL;\r
       }\r
+      break;\r
 \r
-      Status = ExtractFormDefault (Selection->FormSet, Selection->Form, DefaultId);\r
+    case CfUiDefault:\r
+      ControlFlag = CfCheckSelection;\r
+      //\r
+      // Reset to default value for all forms in the whole system.\r
+      //\r
+      Status = ExtractDefault (Selection->FormSet, NULL, DefaultId, FormSetLevel);\r
 \r
       if (!EFI_ERROR (Status)) {\r
         Selection->Action = UI_ACTION_REFRESH_FORM;\r
         Selection->Statement = NULL;\r
-\r
-        //\r
-        // Show NV update flag on status bar\r
-        //\r
-        gNvUpdateRequired = TRUE;\r
         gResetRequired = TRUE;\r
       }\r
       break;\r