+\r
+/**\r
+ Find the matched FormSet context in the backup maintain list based on HiiHandle.\r
+ \r
+ @param Handle The Hii Handle.\r
+ \r
+ @return the found FormSet context. If no found, NULL will return.\r
+\r
+**/\r
+FORM_BROWSER_FORMSET * \r
+GetFormSetFromHiiHandle (\r
+ EFI_HII_HANDLE Handle\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ FORM_BROWSER_FORMSET *FormSet;\r
+\r
+ Link = GetFirstNode (&gBrowserFormSetList);\r
+ while (!IsNull (&gBrowserFormSetList, Link)) {\r
+ FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);\r
+ Link = GetNextNode (&gBrowserFormSetList, Link);\r
+ if (!ValidateFormSet(FormSet)) {\r
+ continue;\r
+ }\r
+ if (FormSet->HiiHandle == Handle) {\r
+ return FormSet;\r
+ }\r
+ }\r
+ \r
+ return NULL;\r
+}\r
+\r
+/**\r
+ Check whether the input HII handle is the FormSet that is being used.\r
+ \r
+ @param Handle The Hii Handle.\r
+ \r
+ @retval TRUE HII handle is being used.\r
+ @retval FALSE HII handle is not being used.\r
+\r
+**/\r
+BOOLEAN\r
+IsHiiHandleInBrowserContext (\r
+ EFI_HII_HANDLE Handle\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ BROWSER_CONTEXT *Context;\r
+\r
+ //\r
+ // HiiHandle is Current FormSet.\r
+ //\r
+ if ((gOldFormSet != NULL) && (gOldFormSet->HiiHandle == Handle)) {\r
+ return TRUE;\r
+ }\r
+\r
+ //\r
+ // Check whether HiiHandle is in BrowserContext.\r
+ //\r
+ Link = GetFirstNode (&gBrowserContextList);\r
+ while (!IsNull (&gBrowserContextList, Link)) {\r
+ Context = BROWSER_CONTEXT_FROM_LINK (Link);\r
+ if (Context->OldFormSet->HiiHandle == Handle) {\r
+ //\r
+ // HiiHandle is in BrowserContext\r
+ //\r
+ return TRUE;\r
+ }\r
+ Link = GetNextNode (&gBrowserContextList, Link);\r
+ }\r
+ \r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ Find the registered HotKey based on KeyData.\r
+ \r
+ @param[in] KeyData A pointer to a buffer that describes the keystroke\r
+ information for the hot key.\r
+\r
+ @return The registered HotKey context. If no found, NULL will return.\r
+**/\r
+BROWSER_HOT_KEY *\r
+GetHotKeyFromRegisterList (\r
+ IN EFI_INPUT_KEY *KeyData\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ BROWSER_HOT_KEY *HotKey;\r
+\r
+ Link = GetFirstNode (&gBrowserHotKeyList);\r
+ while (!IsNull (&gBrowserHotKeyList, Link)) {\r
+ HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);\r
+ if (HotKey->KeyData->ScanCode == KeyData->ScanCode) {\r
+ return HotKey;\r
+ }\r
+ Link = GetNextNode (&gBrowserHotKeyList, Link);\r
+ }\r
+ \r
+ return NULL;\r
+}\r
+\r
+/**\r
+ Configure what scope the hot key will impact.\r
+ All hot keys have the same scope. The mixed hot keys with the different level are not supported.\r
+ If no scope is set, the default scope will be FormSet level.\r
+ After all registered hot keys are removed, previous Scope can reset to another level.\r
+ \r
+ @param[in] Scope Scope level to be set. \r
+ \r
+ @retval EFI_SUCCESS Scope is set correctly.\r
+ @retval EFI_INVALID_PARAMETER Scope is not the valid value specified in BROWSER_SETTING_SCOPE. \r
+ @retval EFI_UNSPPORTED Scope level is different from current one that the registered hot keys have.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SetScope (\r
+ IN BROWSER_SETTING_SCOPE Scope\r
+ )\r
+{\r
+ if (Scope >= MaxLevel) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ \r
+ //\r
+ // When no hot key registered in system or on the first setting,\r
+ // Scope can be set.\r
+ //\r
+ if (mBrowserScopeFirstSet || IsListEmpty (&gBrowserHotKeyList)) {\r
+ gBrowserSettingScope = Scope;\r
+ mBrowserScopeFirstSet = FALSE;\r
+ } else if (Scope != gBrowserSettingScope) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Register the hot key with its browser action, or unregistered the hot key.\r
+ Only support hot key that is not printable character (control key, function key, etc.).\r
+ If the action value is zero, the hot key will be unregistered if it has been registered.\r
+ If the same hot key has been registered, the new action and help string will override the previous ones.\r
+ \r
+ @param[in] KeyData A pointer to a buffer that describes the keystroke\r
+ information for the hot key. Its type is EFI_INPUT_KEY to \r
+ be supported by all ConsoleIn devices.\r
+ @param[in] Action Action value that describes what action will be trigged when the hot key is pressed. \r
+ @param[in] DefaultId Specifies the type of defaults to retrieve, which is only for DEFAULT action.\r
+ @param[in] HelpString Help string that describes the hot key information.\r
+ Its value may be NULL for the unregistered hot key.\r
+ \r
+ @retval EFI_SUCCESS Hot key is registered or unregistered.\r
+ @retval EFI_INVALID_PARAMETER KeyData is NULL or HelpString is NULL on register.\r
+ @retval EFI_NOT_FOUND KeyData is not found to be unregistered.\r
+ @retval EFI_UNSUPPORTED Key represents a printable character. It is conflicted with Browser.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RegisterHotKey (\r
+ IN EFI_INPUT_KEY *KeyData,\r
+ IN UINT32 Action,\r
+ IN UINT16 DefaultId,\r
+ IN EFI_STRING HelpString OPTIONAL\r
+ )\r
+{\r
+ BROWSER_HOT_KEY *HotKey;\r
+\r
+ //\r
+ // Check input parameters.\r
+ //\r
+ if (KeyData == NULL || KeyData->UnicodeChar != CHAR_NULL || \r
+ (Action != BROWSER_ACTION_UNREGISTER && HelpString == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Check whether the input KeyData is in BrowserHotKeyList.\r
+ //\r
+ HotKey = GetHotKeyFromRegisterList (KeyData);\r
+ \r
+ //\r
+ // Unregister HotKey\r
+ //\r
+ if (Action == BROWSER_ACTION_UNREGISTER) {\r
+ if (HotKey != NULL) {\r
+ //\r
+ // The registered HotKey is found. \r
+ // Remove it from List, and free its resource.\r
+ //\r
+ RemoveEntryList (&HotKey->Link);\r
+ FreePool (HotKey->KeyData);\r
+ FreePool (HotKey->HelpString);\r
+ return EFI_SUCCESS;\r
+ } else {\r
+ //\r
+ // The registered HotKey is not found. \r
+ //\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ }\r
+ \r
+ //\r
+ // Register HotKey into List.\r
+ //\r
+ if (HotKey == NULL) {\r
+ //\r
+ // Create new Key, and add it into List.\r
+ //\r
+ HotKey = AllocateZeroPool (sizeof (BROWSER_HOT_KEY));\r
+ ASSERT (HotKey != NULL);\r
+ HotKey->Signature = BROWSER_HOT_KEY_SIGNATURE;\r
+ HotKey->KeyData = AllocateCopyPool (sizeof (EFI_INPUT_KEY), KeyData);\r
+ InsertTailList (&gBrowserHotKeyList, &HotKey->Link);\r
+ }\r
+\r
+ //\r
+ // Fill HotKey information.\r
+ //\r
+ HotKey->Action = Action;\r
+ HotKey->DefaultId = DefaultId;\r
+ if (HotKey->HelpString != NULL) {\r
+ FreePool (HotKey->HelpString);\r
+ }\r
+ HotKey->HelpString = AllocateCopyPool (StrSize (HelpString), HelpString);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Register Exit handler function. \r
+ When more than one handler function is registered, the latter one will override the previous one. \r
+ When NULL handler is specified, the previous Exit handler will be unregistered. \r
+ \r
+ @param[in] Handler Pointer to handler function. \r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+RegiserExitHandler (\r
+ IN EXIT_HANDLER Handler\r
+ )\r
+{\r
+ ExitHandlerFunction = Handler;\r
+ return;\r
+}\r
+\r
+/**\r
+ Create reminder to let user to choose save or discard the changed browser data.\r
+ Caller can use it to actively check the changed browser data.\r
+\r
+ @retval BROWSER_NO_CHANGES No browser data is changed.\r
+ @retval BROWSER_SAVE_CHANGES The changed browser data is saved.\r
+ @retval BROWSER_DISCARD_CHANGES The changed browser data is discard.\r
+\r
+**/\r
+UINT32\r
+EFIAPI\r
+SaveReminder (\r
+ VOID\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ FORM_BROWSER_FORMSET *FormSet;\r
+ BOOLEAN IsDataChanged;\r
+ UINT32 DataSavedAction;\r
+ CHAR16 *YesResponse;\r
+ CHAR16 *NoResponse;\r
+ CHAR16 *EmptyString;\r
+ CHAR16 *ChangeReminderString;\r
+ CHAR16 *SaveConfirmString;\r
+ EFI_INPUT_KEY Key;\r
+\r
+ DataSavedAction = BROWSER_NO_CHANGES;\r
+ IsDataChanged = FALSE;\r
+ Link = GetFirstNode (&gBrowserFormSetList);\r
+ while (!IsNull (&gBrowserFormSetList, Link)) {\r
+ FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);\r
+ Link = GetNextNode (&gBrowserFormSetList, Link);\r
+ if (!ValidateFormSet(FormSet)) {\r
+ continue;\r
+ }\r
+ if (IsNvUpdateRequired (FormSet)) {\r
+ IsDataChanged = TRUE;\r
+ break;\r
+ }\r
+ }\r
+ \r
+ //\r
+ // No data is changed. No save is required. \r
+ //\r
+ if (!IsDataChanged) {\r
+ return DataSavedAction;\r
+ }\r
+ \r
+ //\r
+ // If data is changed, prompt user\r
+ //\r
+ gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
+\r
+ YesResponse = GetToken (STRING_TOKEN (ARE_YOU_SURE_YES), gHiiHandle);\r
+ ASSERT (YesResponse != NULL);\r
+ NoResponse = GetToken (STRING_TOKEN (ARE_YOU_SURE_NO), gHiiHandle);\r
+ ASSERT (NoResponse != NULL);\r
+ EmptyString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle);\r
+ ChangeReminderString = GetToken (STRING_TOKEN (CHANGE_REMINDER), gHiiHandle);\r
+ SaveConfirmString = GetToken (STRING_TOKEN (SAVE_CONFIRM), gHiiHandle);\r
+\r
+ do {\r
+ CreateDialog (4, TRUE, 0, NULL, &Key, EmptyString, ChangeReminderString, SaveConfirmString, EmptyString);\r
+ } while\r
+ (((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (NoResponse[0] | UPPER_LOWER_CASE_OFFSET)) &&\r
+ ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (YesResponse[0] | UPPER_LOWER_CASE_OFFSET))\r
+ );\r
+\r
+ //\r
+ // If the user hits the YesResponse key\r
+ //\r
+ if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (YesResponse[0] | UPPER_LOWER_CASE_OFFSET)) {\r
+ SubmitForm (NULL, NULL, SystemLevel);\r
+ DataSavedAction = BROWSER_SAVE_CHANGES;\r
+ } else {\r
+ DiscardForm (NULL, NULL, SystemLevel);\r
+ DataSavedAction = BROWSER_DISCARD_CHANGES;\r
+ gResetRequired = FALSE;\r
+ }\r
+\r
+ FreePool (YesResponse);\r
+ FreePool (NoResponse);\r
+ FreePool (EmptyString);\r
+ FreePool (SaveConfirmString);\r
+ FreePool (ChangeReminderString);\r
+\r
+ return DataSavedAction;\r
+}\r