]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/SetupBrowserDxe/Ui.c
Enhance EDKII Browser to support flexible HotKey setting.
[mirror_edk2.git] / MdeModulePkg / Universal / SetupBrowserDxe / Ui.c
index d5f3b58b25839512955127de3dc9e8b86396c279..c2340ab80ade30fd0fc64ff7ad814e0dbffb3257 100644 (file)
@@ -50,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
@@ -94,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
@@ -105,6 +91,10 @@ SCREEN_OPERATION_T0_CONTROL_FLAG  gScreenOperationToControlFlag[] = {
   {\r
     UiPageDown,\r
     CfUiPageDown\r
+  }, \r
+  {\r
+    UiHotKey,\r
+    CfUiHotKey\r
   }\r
 };\r
 \r
@@ -402,6 +392,7 @@ RefreshQuestion (
   @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
@@ -1056,7 +1047,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
@@ -1081,32 +1075,38 @@ 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
-        if (Selection != NULL) {\r
-          Selection->Form->NvUpdateRequired = TRUE;\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
-        if (Selection != NULL) {\r
-          Selection->Form->NvUpdateRequired = FALSE;\r
-        }\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
@@ -1116,9 +1116,28 @@ UpdateStatusBar (
       UpdateStatusBar (Selection, INPUT_ERROR, Flags, TRUE);\r
     }\r
 \r
-    if (IsNvUpdateRequired(Selection->FormSet)) {\r
-      UpdateStatusBar (NULL, 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
@@ -1648,6 +1667,175 @@ DevicePathToHiiHandle (
   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
+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
+  CHAR16                          *StringPtr;\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
+  \r
+  Status = EFI_SUCCESS;\r
+\r
+  if (Statement->HiiValue.Value.ref.DevicePath != 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
+\r
+    StringPtr = GetToken (Statement->HiiValue.Value.ref.DevicePath, 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
+      return Status;\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
+      return Status;\r
+    }\r
+\r
+    FreePool (StringPtr);\r
+    FreePool (DevicePath);\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
+    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
+    //\r
+    // Link current form so that we can always go back when someone hits the ESC\r
+    //\r
+    MenuList = UiFindMenuList (&Selection->FormSetGuid, Statement->HiiValue.Value.ref.FormId);\r
+    if (MenuList == NULL && Selection->CurrentMenu != NULL) {\r
+      MenuList = UiAddMenuList (Selection->CurrentMenu, &Selection->FormSetGuid, Statement->HiiValue.Value.ref.FormId);\r
+    }\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
+  } else {\r
+    if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {\r
+      Selection->Action = UI_ACTION_REFRESH_FORM;\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
@@ -1703,17 +1891,11 @@ UiDisplayMenu (
   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
@@ -1735,7 +1917,7 @@ 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
@@ -1754,7 +1936,7 @@ UiDisplayMenu (
     Col = LocalScreen.LeftColumn + LEFT_SKIPPED_COLUMNS;\r
   }\r
 \r
-  BottomRow = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT - SCROLL_ARROW_HEIGHT - 1;\r
+  BottomRow = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight - SCROLL_ARROW_HEIGHT - 1;\r
 \r
   Selection->TopRow = TopRow;\r
   Selection->BottomRow = BottomRow;\r
@@ -1784,6 +1966,7 @@ UiDisplayMenu (
     // Highlight not specified, fetch it from cached menu\r
     //\r
     Selection->QuestionId = CurrentMenu->QuestionId;\r
+    Selection->Sequence   = CurrentMenu->Sequence;\r
   }\r
 \r
   //\r
@@ -1937,83 +2120,6 @@ UiDisplayMenu (
               OptionString[Count] = CHAR_NULL;\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
-              }\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
-                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
-            }\r
-\r
             Width       = (UINT16) gOptionBlockWidth;\r
             OriginalRow = Row;\r
 \r
@@ -2051,6 +2157,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
@@ -2167,7 +2338,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
@@ -2303,6 +2476,7 @@ UiDisplayMenu (
         // Record highlight for current menu\r
         //\r
         CurrentMenu->QuestionId = Statement->QuestionId;\r
+        CurrentMenu->Sequence   = MenuOption->Sequence;\r
 \r
         //\r
         // Set reverse attribute\r
@@ -2466,8 +2640,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
@@ -2555,30 +2730,28 @@ UiDisplayMenu (
         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 (Selection->Form->ModalForm && \r
-              (Key.ScanCode == SCAN_F9 || Key.ScanCode == SCAN_F10 || Key.ScanCode == SCAN_ESC)) {\r
-              ControlFlag = CfReadKey;\r
-              break;\r
-            }\r
-\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
@@ -2624,130 +2797,7 @@ UiDisplayMenu (
 \r
       switch (Statement->Operand) {\r
       case EFI_IFR_REF_OP:\r
-        if (Statement->RefDevicePath != 0) {\r
-          if (Selection->Form->ModalForm) {\r
-            break;\r
-          }\r
-          //\r
-          // Goto another Hii Package list\r
-          //\r
-          Selection->Action = UI_ACTION_REFRESH_FORMSET;\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
-          if (Selection->Form->ModalForm) {\r
-            break;\r
-          }\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
+        ProcessGotoOpCode(Statement, Selection, &Repaint, &NewLine);\r
         break;\r
 \r
       case EFI_IFR_ACTION_OP:\r
@@ -2801,9 +2851,7 @@ UiDisplayMenu (
       // We come here when someone press ESC\r
       //\r
       ControlFlag = CfCheckSelection;\r
-      if (FindNextMenu (Selection, &Repaint, &NewLine)) {\r
-        return EFI_SUCCESS;\r
-      } \r
+      FindNextMenu (Selection, &Repaint, &NewLine);\r
       break;\r
 \r
     case CfUiLeft:\r
@@ -2846,6 +2894,7 @@ UiDisplayMenu (
       AdjustDateAndTimePosition (TRUE, &NewPos);\r
       if (NewPos->BackLink != &gMenuOption) {\r
         MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
+        ASSERT (MenuOption != NULL);\r
         NewLine    = TRUE;\r
         NewPos     = NewPos->BackLink;\r
 \r
@@ -2857,7 +2906,6 @@ UiDisplayMenu (
         }\r
         NextMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
        \r
-        ASSERT (MenuOption != NULL);\r
         if (Difference < 0) {\r
           //\r
           // We hit the begining MenuOption that can be focused\r
@@ -3221,47 +3269,120 @@ UiDisplayMenu (
       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, FALSE);\r
-\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, 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
-        UpdateNvInfoInForm(Selection->FormSet, TRUE);\r
         gResetRequired = TRUE;\r
       }\r
       break;\r