From 48a9d5f7781e430c54cfc2964243580c56384310 Mon Sep 17 00:00:00 2001 From: lgao4 Date: Tue, 13 Sep 2011 09:32:54 +0000 Subject: [PATCH] Enhance EDKII Browser to support flexible HotKey setting. Signed-off-by: lgao4 Reviewed-by: ydong10 git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12336 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Include/Protocol/FormBrowserEx.h | 147 ++++ MdeModulePkg/MdeModulePkg.dec | 5 + .../Universal/SetupBrowserDxe/IfrParse.c | 3 +- .../Universal/SetupBrowserDxe/InputHandler.c | 2 +- .../Universal/SetupBrowserDxe/Presentation.c | 211 ++++- .../Universal/SetupBrowserDxe/Setup.c | 826 +++++++++++++++--- .../Universal/SetupBrowserDxe/Setup.h | 187 +++- .../SetupBrowserDxe/SetupBrowserDxe.inf | 1 + .../SetupBrowserDxe/SetupBrowserStr.uni | Bin 12148 -> 13732 bytes MdeModulePkg/Universal/SetupBrowserDxe/Ui.c | 268 ++++-- MdeModulePkg/Universal/SetupBrowserDxe/Ui.h | 5 +- 11 files changed, 1389 insertions(+), 266 deletions(-) create mode 100644 MdeModulePkg/Include/Protocol/FormBrowserEx.h diff --git a/MdeModulePkg/Include/Protocol/FormBrowserEx.h b/MdeModulePkg/Include/Protocol/FormBrowserEx.h new file mode 100644 index 0000000000..a42039871d --- /dev/null +++ b/MdeModulePkg/Include/Protocol/FormBrowserEx.h @@ -0,0 +1,147 @@ +/** @file + Extension Form Browser Protocol provides the services that can be used to + register the different hot keys for the standard Browser actions described in UEFI specification. + +Copyright (c) 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials are licensed and made available under +the terms and conditions of the BSD License that accompanies this distribution. +The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __FORM_BROWSER_EXTENSION_H__ +#define __FORM_BROWSER_EXTENSION_H__ + +#define FORM_BROWSER_EXTENSION_PROTOCOL_GUID \ + { 0x1f73b18d, 0x4630, 0x43c1, { 0xa1, 0xde, 0x6f, 0x80, 0x85, 0x5d, 0x7d, 0xa4 } } + +typedef struct _EFI_FORM_BROWSER_EXTENSION_PROTOCOL EFI_FORM_BROWSER_EXTENSION_PROTOCOL; + +// +// Return value of EXIT_REMINDER() that describes whether the changed data is saved or discarded. +// +#define BROWSER_NO_CHANGES 0 +#define BROWSER_SAVE_CHANGES 1 +#define BROWSER_DISCARD_CHANGES 2 + +// +// Browser actions. They can be cominbed together. +// If more than one actions are specified, the action with low bit will be executed first. +// +#define BROWSER_ACTION_UNREGISTER 0 +#define BROWSER_ACTION_DISCARD BIT0 +#define BROWSER_ACTION_DEFAULT BIT1 +#define BROWSER_ACTION_SUBMIT BIT2 +#define BROWSER_ACTION_RESET BIT3 +#define BROWSER_ACTION_EXIT BIT4 + +// +// Scope for Browser action. It may be Form, FormSet or System level. +// +typedef enum { + FormLevel, + FormSetLevel, + SystemLevel, + MaxLevel +} BROWSER_SETTING_SCOPE; + +/** + Configure what scope the hot key will impact. + All hot keys have the same scope. The mixed hot keys with the different level are not supported. + If no scope is set, the default scope will be FormSet level. + After all registered hot keys are removed, previous Scope can reset to another level. + + @param[in] Scope Scope level to be set. + + @retval EFI_SUCCESS Scope is set correctly. + @retval EFI_INVALID_PARAMETER Scope is not the valid value specified in BROWSER_SETTING_SCOPE. + @retval EFI_UNSPPORTED Scope level is different from current one that the registered hot keys have. + +**/ +typedef +EFI_STATUS +(EFIAPI *SET_SCOPE) ( + IN BROWSER_SETTING_SCOPE Scope + ); + +/** + Register the hot key with its browser action, or unregistered the hot key. + If the action value is zero, the hot key will be unregistered if it has been registered. + If the same hot key has been registered, the new action and help string will override the previous ones. + + @param[in] KeyData A pointer to a buffer that describes the keystroke + information for the hot key. Its type is EFI_INPUT_KEY to + be supported by all ConsoleIn devices. + @param[in] Action Action value that describes what action will be trigged when the hot key is pressed. + @param[in] DefaultId Specifies the type of defaults to retrieve, which is only for DEFAULT action. + @param[in] HelpString Help string that describes the hot key information. + Its value may be NULL for the unregistered hot key. + + @retval EFI_SUCCESS Hot key is registered or unregistered. + @retval EFI_INVALID_PARAMETER KeyData is NULL. +**/ +typedef +EFI_STATUS +(EFIAPI *REGISTER_HOT_KEY) ( + IN EFI_INPUT_KEY *KeyData, + IN UINT32 Action, + IN UINT16 DefaultId, + IN EFI_STRING HelpString OPTIONAL + ); + +/** + This handler is responsbile for the left things on normal boot after all UI forms are closed. + For example, it can continue to boot the first boot option. + + It will be used only when EXIT action is trigged as system level. +**/ +typedef +VOID +(EFIAPI *EXIT_HANDLER) ( + VOID + ); + +/** + Register Exit handler function. + When more than one handler function is registered, the latter one will override the previous one. + When NULL handler is specified, the previous Exit handler will be unregistered. + + @param[in] Handler Pointer to handler function. + +**/ +typedef +VOID +(EFIAPI *REGISTER_EXIT_HANDLER) ( + IN EXIT_HANDLER Handler + ); + +/** + Create reminder to let user to choose save or discard the changed browser data. + Caller can use it to actively check the changed browser data. + + @retval BROWSER_NO_CHANGES No browser data is changed. + @retval BROWSER_SAVE_CHANGES The changed browser data is saved. + @retval BROWSER_DISCARD_CHANGES The changed browser data is discard. + +**/ +typedef +UINT32 +(EFIAPI *SAVE_REMINDER)( + VOID + ); + +struct _EFI_FORM_BROWSER_EXTENSION_PROTOCOL { + SET_SCOPE SetScope; + REGISTER_HOT_KEY RegisterHotKey; + REGISTER_EXIT_HANDLER RegiserExitHandler; + SAVE_REMINDER SaveReminder; +}; + +extern EFI_GUID gEfiFormBrowserExProtocolGuid; + +#endif + diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec index 8837cac700..4c6d6b166e 100644 --- a/MdeModulePkg/MdeModulePkg.dec +++ b/MdeModulePkg/MdeModulePkg.dec @@ -202,6 +202,9 @@ gEfiBootScriptExecutorVariableGuid = { 0x3079818c, 0x46d4, 0x4a73, { 0xae, 0xf3, 0xe3, 0xe4, 0x6c, 0xf1, 0xee, 0xdb }} gEfiBootScriptExecutorContextGuid = { 0x79cb58c4, 0xac51, 0x442f, { 0xaf, 0xd7, 0x98, 0xe4, 0x7d, 0x2e, 0x99, 0x8 }} + ## Include/Guid/UsbKeyBoardLayout.h + gUsbKeyboardLayoutPackageGuid = { 0xc0f3b43, 0x44de, 0x4907, { 0xb4, 0x78, 0x22, 0x5f, 0x6f, 0x62, 0x89, 0xdc }} + gUsbKeyboardLayoutKeyGuid = { 0x3a4d7a7c, 0x18a, 0x4b42, { 0x81, 0xb3, 0xdc, 0x10, 0xe3, 0xb5, 0x91, 0xbd }} [Ppis] ## Include/Ppi/AtaController.h gPeiAtaControllerPpiGuid = { 0xa45e60d1, 0xc719, 0x44aa, { 0xb0, 0x7a, 0xaa, 0x77, 0x7f, 0x85, 0x90, 0x6d }} @@ -285,6 +288,8 @@ ## Include/Protocol/LockBox.h gEfiLockBoxProtocolGuid = { 0xbd445d79, 0xb7ad, 0x4f04, { 0x9a, 0xd8, 0x29, 0xbd, 0x20, 0x40, 0xeb, 0x3c }} + gEfiFormBrowserExProtocolGuid = { 0x1f73b18d, 0x4630, 0x43c1, { 0xa1, 0xde, 0x6f, 0x80, 0x85, 0x5d, 0x7d, 0xa4 } } + [PcdsFeatureFlag] ## Indicate whether platform can support update capsule across a system reset gEfiMdeModulePkgTokenSpaceGuid.PcdSupportUpdateCapsuleReset|FALSE|BOOLEAN|0x0001001d diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c b/MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c index d8fb8c963e..50ae87d92e 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c +++ b/MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c @@ -992,6 +992,7 @@ ParseOpCodes ( InitializeListHead (&FormSet->StorageListHead); InitializeListHead (&FormSet->DefaultStoreListHead); InitializeListHead (&FormSet->FormListHead); + InitializeListHead (&FormSet->ExpressionListHead); ResetCurrentExpressionStack (); ResetMapExpressionListStack (); @@ -1332,8 +1333,6 @@ ParseOpCodes ( FormSet->NumberOfClassGuid = (UINT8) (((EFI_IFR_FORM_SET *) OpCodeData)->Flags & 0x3); CopyMem (FormSet->ClassGuid, OpCodeData + sizeof (EFI_IFR_FORM_SET), FormSet->NumberOfClassGuid * sizeof (EFI_GUID)); } - - InitializeListHead (&FormSet->ExpressionListHead); break; case EFI_IFR_FORM_OP: diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/InputHandler.c b/MdeModulePkg/Universal/SetupBrowserDxe/InputHandler.c index 1e4d20237c..c42a18e3b0 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/InputHandler.c +++ b/MdeModulePkg/Universal/SetupBrowserDxe/InputHandler.c @@ -1060,7 +1060,7 @@ GetSelectionInputPopUp ( Start = (DimensionsWidth - PopUpWidth - POPUP_FRAME_WIDTH) / 2 + gScreenDimensions.LeftColumn; End = Start + PopUpWidth + POPUP_FRAME_WIDTH; Top = gScreenDimensions.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT; - Bottom = gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT - 1; + Bottom = gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight - 1; MenuLinesInView = Bottom - Top - 1; if (MenuLinesInView >= PopUpMenuLines) { diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c b/MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c index 863097d005..bff79570db 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c @@ -300,7 +300,7 @@ DisplayPageFrame ( ClearLines ( LocalScreen.LeftColumn, LocalScreen.RightColumn, - LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT, + LocalScreen.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight, LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 1, KEYHELP_TEXT | KEYHELP_BACKGROUND ); @@ -348,14 +348,14 @@ DisplayPageFrame ( // +------------------------------------------------------------------------------+ // Character = BOXDRAW_DOWN_RIGHT; - PrintCharAt (LocalScreen.LeftColumn, LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT, Character); + PrintCharAt (LocalScreen.LeftColumn, LocalScreen.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight, Character); PrintString (Buffer); Character = BOXDRAW_DOWN_LEFT; PrintChar (Character); Character = BOXDRAW_VERTICAL; - for (Row = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT + 1; + for (Row = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight + 1; Row <= LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 2; Row++ ) { @@ -583,13 +583,10 @@ InitializeBrowserStrings ( VOID ) { - gFunctionNineString = GetToken (STRING_TOKEN (FUNCTION_NINE_STRING), gHiiHandle); - gFunctionTenString = GetToken (STRING_TOKEN (FUNCTION_TEN_STRING), gHiiHandle); gEnterString = GetToken (STRING_TOKEN (ENTER_STRING), gHiiHandle); gEnterCommitString = GetToken (STRING_TOKEN (ENTER_COMMIT_STRING), gHiiHandle); gEnterEscapeString = GetToken (STRING_TOKEN (ENTER_ESCAPE_STRING), gHiiHandle); gEscapeString = GetToken (STRING_TOKEN (ESCAPE_STRING), gHiiHandle); - gSaveFailed = GetToken (STRING_TOKEN (SAVE_FAILED), gHiiHandle); gMoveHighlight = GetToken (STRING_TOKEN (MOVE_HIGHLIGHT), gHiiHandle); gMakeSelection = GetToken (STRING_TOKEN (MAKE_SELECTION), gHiiHandle); gDecNumericInput = GetToken (STRING_TOKEN (DEC_NUMERIC_INPUT), gHiiHandle); @@ -626,8 +623,6 @@ FreeBrowserStrings ( VOID ) { - FreePool (gFunctionNineString); - FreePool (gFunctionTenString); FreePool (gEnterString); FreePool (gEnterCommitString); FreePool (gEnterEscapeString); @@ -658,6 +653,64 @@ FreeBrowserStrings ( return ; } +/** + Show all registered HotKey help strings on bottom Rows. + +**/ +VOID +PrintHotKeyHelpString ( + VOID + ) +{ + UINTN CurrentCol; + UINTN CurrentRow; + UINTN BottomRowOfHotKeyHelp; + UINTN ColumnWidth; + UINTN Index; + EFI_SCREEN_DESCRIPTOR LocalScreen; + LIST_ENTRY *Link; + BROWSER_HOT_KEY *HotKey; + + CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); + ColumnWidth = (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3; + BottomRowOfHotKeyHelp = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 3; + + // + // Calculate total number of Register HotKeys. + // + Index = 0; + Link = GetFirstNode (&gBrowserHotKeyList); + while (!IsNull (&gBrowserHotKeyList, Link)) { + HotKey = BROWSER_HOT_KEY_FROM_LINK (Link); + // + // Help string can't exceed ColumnWidth. One Row will show three Help information. + // + if (StrLen (HotKey->HelpString) > ColumnWidth) { + HotKey->HelpString[ColumnWidth] = L'\0'; + } + // + // Calculate help information Column and Row. + // + if ((Index % 3) != 2) { + CurrentCol = LocalScreen.LeftColumn + (2 - Index % 3) * ColumnWidth; + } else { + CurrentCol = LocalScreen.LeftColumn + 2; + } + CurrentRow = BottomRowOfHotKeyHelp - Index / 3; + // + // Print HotKey help string on bottom Row. + // + PrintStringAt (CurrentCol, CurrentRow, HotKey->HelpString); + + // + // Get Next Hot Key. + // + Link = GetNextNode (&gBrowserHotKeyList, Link); + Index ++; + } + + return; +} /** Update key's help imformation. @@ -693,13 +746,13 @@ UpdateKeyHelp ( CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); SecCol = LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3; - ThdCol = LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) * 2 / 3; + ThdCol = LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3 * 2; StartColumnOfHelp = LocalScreen.LeftColumn + 2; LeftColumnOfHelp = LocalScreen.LeftColumn + 1; RightColumnOfHelp = LocalScreen.RightColumn - 2; - TopRowOfHelp = LocalScreen.BottomRow - 4; - BottomRowOfHelp = LocalScreen.BottomRow - 3; + TopRowOfHelp = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight + 1; + BottomRowOfHelp = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 2; Statement = MenuOption->ThisTag; switch (Statement->Operand) { @@ -711,11 +764,15 @@ UpdateKeyHelp ( ClearLines (LeftColumnOfHelp, RightColumnOfHelp, TopRowOfHelp, BottomRowOfHelp, KEYHELP_TEXT | KEYHELP_BACKGROUND); if (!Selected) { + // + // On system setting, HotKey will show on every form. + // + if (gBrowserSettingScope == SystemLevel || + (Selection->FormEditable && gFunctionKeySetting != NONE_FUNCTION_KEY_SETTING)) { + PrintHotKeyHelpString (); + } + if ((gClassOfVfr & FORMSET_CLASS_PLATFORM_SETUP) == FORMSET_CLASS_PLATFORM_SETUP) { - if (Selection->FormEditable) { - PrintStringAt (SecCol, TopRowOfHelp, gFunctionNineString); - PrintStringAt (ThdCol, TopRowOfHelp, gFunctionTenString); - } PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString); } @@ -770,11 +827,14 @@ UpdateKeyHelp ( case EFI_IFR_CHECKBOX_OP: ClearLines (LeftColumnOfHelp, RightColumnOfHelp, TopRowOfHelp, BottomRowOfHelp, KEYHELP_TEXT | KEYHELP_BACKGROUND); + // + // On system setting, HotKey will show on every form. + // + if (gBrowserSettingScope == SystemLevel || + (Selection->FormEditable && gFunctionKeySetting != NONE_FUNCTION_KEY_SETTING)) { + PrintHotKeyHelpString (); + } if ((gClassOfVfr & FORMSET_CLASS_PLATFORM_SETUP) == FORMSET_CLASS_PLATFORM_SETUP) { - if (Selection->FormEditable) { - PrintStringAt (SecCol, TopRowOfHelp, gFunctionNineString); - PrintStringAt (ThdCol, TopRowOfHelp, gFunctionTenString); - } PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString); } @@ -792,11 +852,14 @@ UpdateKeyHelp ( ClearLines (LeftColumnOfHelp, RightColumnOfHelp, TopRowOfHelp, BottomRowOfHelp, KEYHELP_TEXT | KEYHELP_BACKGROUND); if (!Selected) { + // + // On system setting, HotKey will show on every form. + // + if (gBrowserSettingScope == SystemLevel || + (Selection->FormEditable && gFunctionKeySetting != NONE_FUNCTION_KEY_SETTING)) { + PrintHotKeyHelpString (); + } if ((gClassOfVfr & FORMSET_CLASS_PLATFORM_SETUP) == FORMSET_CLASS_PLATFORM_SETUP) { - if (Selection->FormEditable) { - PrintStringAt (SecCol, TopRowOfHelp, gFunctionNineString); - PrintStringAt (ThdCol, TopRowOfHelp, gFunctionTenString); - } PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString); } @@ -946,6 +1009,55 @@ FindNextMenu ( CurrentMenu = Selection->CurrentMenu; if (CurrentMenu != NULL && CurrentMenu->Parent != NULL) { + // + // Form Level Check whether the data is changed. + // + if (gBrowserSettingScope == FormLevel && Selection->Form->NvUpdateRequired) { + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + + YesResponse = gYesResponse[0]; + NoResponse = gNoResponse[0]; + + // + // If NV flag is up, prompt user + // + do { + CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gSaveChanges, gAreYouSure, gEmptyString); + } while + ( + (Key.ScanCode != SCAN_ESC) && + ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (NoResponse | UPPER_LOWER_CASE_OFFSET)) && + ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (YesResponse | UPPER_LOWER_CASE_OFFSET)) + ); + + if (Key.ScanCode == SCAN_ESC) { + // + // User hits the ESC key, Ingore. + // + if (Repaint != NULL) { + *Repaint = TRUE; + } + if (NewLine != NULL) { + *NewLine = TRUE; + } + + Selection->Action = UI_ACTION_NONE; + return FALSE; + } + + if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (YesResponse | UPPER_LOWER_CASE_OFFSET)) { + // + // If the user hits the YesResponse key + // + Status = SubmitForm (Selection->FormSet, Selection->Form, FormLevel); + } else { + // + // If the user hits the NoResponse key + // + Status = DiscardForm (Selection->FormSet, Selection->Form, FormLevel); + } + } + // // we have a parent, so go to the parent menu // @@ -980,7 +1092,7 @@ FindNextMenu ( // // We are going to leave current FormSet, so check uncommited data in this FormSet // - if (IsNvUpdateRequired(Selection->FormSet)) { + if (gBrowserSettingScope != SystemLevel && IsNvUpdateRequired(Selection->FormSet)) { Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); YesResponse = gYesResponse[0]; @@ -1014,11 +1126,16 @@ FindNextMenu ( return FALSE; } - // - // If the user hits the YesResponse key - // if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (YesResponse | UPPER_LOWER_CASE_OFFSET)) { - Status = SubmitForm (Selection->FormSet, Selection->Form, FALSE); + // + // If the user hits the YesResponse key + // + Status = SubmitForm (Selection->FormSet, Selection->Form, FormSetLevel); + } else { + // + // If the user hits the NoResponse key + // + Status = DiscardForm (Selection->FormSet, Selection->Form, FormSetLevel); } } @@ -1060,14 +1177,14 @@ ProcessCallBackFunction ( EFI_IFR_TYPE_VALUE *TypeValue; FORM_BROWSER_STATEMENT *Statement; BOOLEAN SubmitFormIsRequired; - BOOLEAN SingleForm; BOOLEAN DiscardFormIsRequired; BOOLEAN NeedExit; LIST_ENTRY *Link; + BROWSER_SETTING_SCOPE SettingLevel; ConfigAccess = Selection->FormSet->ConfigAccess; SubmitFormIsRequired = FALSE; - SingleForm = FALSE; + SettingLevel = FormSetLevel; DiscardFormIsRequired = FALSE; NeedExit = FALSE; Status = EFI_SUCCESS; @@ -1139,24 +1256,24 @@ ProcessCallBackFunction ( case EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT: SubmitFormIsRequired = TRUE; - SingleForm = TRUE; + SettingLevel = FormLevel; NeedExit = TRUE; break; case EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT: DiscardFormIsRequired = TRUE; - SingleForm = TRUE; + SettingLevel = FormLevel; NeedExit = TRUE; break; case EFI_BROWSER_ACTION_REQUEST_FORM_APPLY: SubmitFormIsRequired = TRUE; - SingleForm = TRUE; + SettingLevel = FormLevel; break; case EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD: DiscardFormIsRequired = TRUE; - SingleForm = TRUE; + SettingLevel = FormLevel; break; default: @@ -1179,11 +1296,11 @@ ProcessCallBackFunction ( } if (SubmitFormIsRequired && !SkipSaveOrDiscard) { - SubmitForm (Selection->FormSet, Selection->Form, SingleForm); + SubmitForm (Selection->FormSet, Selection->Form, SettingLevel); } if (DiscardFormIsRequired && !SkipSaveOrDiscard) { - DiscardForm (Selection->FormSet, Selection->Form, SingleForm); + DiscardForm (Selection->FormSet, Selection->Form, SettingLevel); } if (NeedExit) { @@ -1216,12 +1333,9 @@ SetupBrowser ( EFI_HANDLE NotifyHandle; FORM_BROWSER_STATEMENT *Statement; EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; - FORM_BROWSER_FORMSET *FormSet; EFI_INPUT_KEY Key; gMenuRefreshHead = NULL; - gResetRequired = FALSE; - FormSet = Selection->FormSet; ConfigAccess = Selection->FormSet->ConfigAccess; // @@ -1247,6 +1361,17 @@ SetupBrowser ( goto Done; } + // + // Update gOldFormSet on maintain back up FormSet list. + // And, make gOldFormSet point to current FormSet. + // + if (gOldFormSet != NULL) { + RemoveEntryList (&gOldFormSet->Link); + DestroyFormSet (gOldFormSet); + } + gOldFormSet = Selection->FormSet; + InsertTailList (&gBrowserFormSetList, &gOldFormSet->Link); + do { // // Initialize Selection->Form @@ -1442,14 +1567,6 @@ SetupBrowser ( } } while (Selection->Action == UI_ACTION_REFRESH_FORM); - // - // Record the old formset - // - if (gOldFormSet != NULL) { - DestroyFormSet (gOldFormSet); - } - gOldFormSet = FormSet; - Done: // // Reset current form information to the initial setting when error happens or form exit. diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c index 0b526d0a02..88f965059f 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c @@ -20,6 +20,12 @@ SETUP_DRIVER_PRIVATE_DATA mPrivateData = { { SendForm, BrowserCallback + }, + { + SetScope, + RegisterHotKey, + RegiserExitHandler, + SaveReminder } }; @@ -29,6 +35,8 @@ EFI_HII_CONFIG_ROUTING_PROTOCOL *mHiiConfigRouting; UINTN gBrowserContextCount = 0; LIST_ENTRY gBrowserContextList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserContextList); +LIST_ENTRY gBrowserFormSetList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserFormSetList); +LIST_ENTRY gBrowserHotKeyList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserHotKeyList); BANNER_DATA *gBannerData; EFI_HII_HANDLE gFrontPageHandle; @@ -38,17 +46,21 @@ BOOLEAN gResetRequired; EFI_HII_HANDLE gHiiHandle; UINT16 gDirection; EFI_SCREEN_DESCRIPTOR gScreenDimensions; +BROWSER_SETTING_SCOPE gBrowserSettingScope = FormSetLevel; +BOOLEAN mBrowserScopeFirstSet = TRUE; +EXIT_HANDLER ExitHandlerFunction = NULL; +UINTN gFooterHeight; // // Browser Global Strings // -CHAR16 *gFunctionNineString; -CHAR16 *gFunctionTenString; +CHAR16 *gSaveFailed; +CHAR16 *gDiscardFailed; +CHAR16 *gDefaultFailed; CHAR16 *gEnterString; CHAR16 *gEnterCommitString; CHAR16 *gEnterEscapeString; CHAR16 *gEscapeString; -CHAR16 *gSaveFailed; CHAR16 *gMoveHighlight; CHAR16 *gMakeSelection; CHAR16 *gDecNumericInput; @@ -84,7 +96,7 @@ EFI_GUID gSetupBrowserGuid = { 0xab368524, 0xb60c, 0x495b, {0xa0, 0x9, 0x12, 0xe8, 0x5b, 0x1a, 0xea, 0x32} }; -FORM_BROWSER_FORMSET *gOldFormSet; +FORM_BROWSER_FORMSET *gOldFormSet = NULL; FUNCTIION_KEY_SETTING gFunctionKeySettingTable[] = { // @@ -214,12 +226,28 @@ SendForm ( UI_MENU_SELECTION *Selection; UINTN Index; FORM_BROWSER_FORMSET *FormSet; + LIST_ENTRY *Link; + + // + // Calculate total number of Register HotKeys. + // + Index = 0; + Link = GetFirstNode (&gBrowserHotKeyList); + while (!IsNull (&gBrowserHotKeyList, Link)) { + Link = GetNextNode (&gBrowserHotKeyList, Link); + Index ++; + } + // + // Show three HotKeys help information on one ROW. + // + gFooterHeight = FOOTER_HEIGHT + (Index / 3); // // Save globals used by SendForm() // SaveBrowserContext (); + gResetRequired = FALSE; Status = EFI_SUCCESS; ZeroMem (&gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); @@ -254,7 +282,7 @@ SendForm ( SCROLL_ARROW_HEIGHT * 2 + FRONT_PAGE_HEADER_HEIGHT + - FOOTER_HEIGHT + + gFooterHeight + 1 ) ) { @@ -275,7 +303,7 @@ SendForm ( // InitializeBrowserStrings (); - gFunctionKeySetting = DEFAULT_FUNCTION_KEY_SETTING; + gFunctionKeySetting = ENABLE_FUNCTION_KEY_SETTING; // // Ensure we are in Text mode @@ -290,9 +318,14 @@ SendForm ( if (FormSetGuid != NULL) { CopyMem (&Selection->FormSetGuid, FormSetGuid, sizeof (EFI_GUID)); Selection->FormId = FormId; + } else { + CopyMem (&Selection->FormSetGuid, &gEfiHiiPlatformSetupFormsetGuid, sizeof (EFI_GUID)); } - gOldFormSet = NULL; + // + // Try to find pre FormSet in the maintain backup list. + // + gOldFormSet = GetFormSetFromHiiHandle (Selection->Handle); do { FormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET)); @@ -324,7 +357,13 @@ SendForm ( } while (Selection->Action == UI_ACTION_REFRESH_FORMSET); if (gOldFormSet != NULL) { - DestroyFormSet (gOldFormSet); + // + // If no data is changed, don't need to save current FormSet into the maintain list. + // + if (!IsNvUpdateRequired (gOldFormSet)) { + RemoveEntryList (&gOldFormSet->Link); + DestroyFormSet (gOldFormSet); + } gOldFormSet = NULL; } @@ -517,6 +556,65 @@ BrowserCallback ( return EFI_SUCCESS; } +/** + Notify function will remove the formset in the maintain list + once this formset is removed. + + Functions which are registered to receive notification of + database events have this prototype. The actual event is encoded + in NotifyType. The following table describes how PackageType, + PackageGuid, Handle, and Package are used for each of the + notification types. + + @param PackageType Package type of the notification. + + @param PackageGuid If PackageType is + EFI_HII_PACKAGE_TYPE_GUID, then this is + the pointer to the GUID from the Guid + field of EFI_HII_PACKAGE_GUID_HEADER. + Otherwise, it must be NULL. + + @param Package Points to the package referred to by the + notification Handle The handle of the package + list which contains the specified package. + + @param Handle The HII handle. + + @param NotifyType The type of change concerning the + database. See + EFI_HII_DATABASE_NOTIFY_TYPE. + +**/ +EFI_STATUS +EFIAPI +FormsetRemoveNotify ( + IN UINT8 PackageType, + IN CONST EFI_GUID *PackageGuid, + IN CONST EFI_HII_PACKAGE_HEADER *Package, + IN EFI_HII_HANDLE Handle, + IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType + ) +{ + FORM_BROWSER_FORMSET *FormSet; + + // + // Ignore the update for current using formset, which is handled by another notify function. + // + if (IsHiiHandleInBrowserContext (Handle)) { + return EFI_SUCCESS; + } + + // + // Remove the backup FormSet data when the Form Package is removed. + // + FormSet = GetFormSetFromHiiHandle (Handle); + if (FormSet != NULL) { + RemoveEntryList (&FormSet->Link); + DestroyFormSet (FormSet); + } + + return EFI_SUCCESS; +} /** Initialize Setup Browser driver. @@ -536,6 +634,9 @@ InitializeSetup ( ) { EFI_STATUS Status; + EFI_HANDLE NotifyHandle; + EFI_INPUT_KEY DefaultHotKey; + EFI_STRING HelpString; // // Locate required Hii relative protocols @@ -577,6 +678,13 @@ InitializeSetup ( // gBannerData = AllocateZeroPool (sizeof (BANNER_DATA)); ASSERT (gBannerData != NULL); + + // + // Initialize generic help strings. + // + gSaveFailed = GetToken (STRING_TOKEN (SAVE_FAILED), gHiiHandle); + gDiscardFailed = GetToken (STRING_TOKEN (DISCARD_FAILED), gHiiHandle); + gDefaultFailed = GetToken (STRING_TOKEN (DEFAULT_FAILED), gHiiHandle); // // Install FormBrowser2 protocol @@ -590,6 +698,47 @@ InitializeSetup ( ); ASSERT_EFI_ERROR (Status); + // + // Install default HotKey F10 for Save + // + DefaultHotKey.UnicodeChar = CHAR_NULL; + HelpString = GetToken (STRING_TOKEN (FUNCTION_TEN_STRING), gHiiHandle); + DefaultHotKey.ScanCode = SCAN_F10; + RegisterHotKey (&DefaultHotKey, BROWSER_ACTION_SUBMIT, 0, HelpString); + FreePool (HelpString); + // + // Install default HotKey F9 for Reset To Defaults + // + DefaultHotKey.ScanCode = SCAN_F9; + HelpString = GetToken (STRING_TOKEN (FUNCTION_NINE_STRING), gHiiHandle); + RegisterHotKey (&DefaultHotKey, BROWSER_ACTION_DEFAULT, EFI_HII_DEFAULT_CLASS_STANDARD, HelpString); + FreePool (HelpString); + + // + // Install FormBrowserEx protocol + // + mPrivateData.Handle = NULL; + Status = gBS->InstallProtocolInterface ( + &mPrivateData.Handle, + &gEfiFormBrowserExProtocolGuid, + EFI_NATIVE_INTERFACE, + &mPrivateData.FormBrowserEx + ); + ASSERT_EFI_ERROR (Status); + + // + // Register notify for Form package remove + // + Status = mHiiDatabase->RegisterPackageNotify ( + mHiiDatabase, + EFI_HII_PACKAGE_FORMS, + NULL, + FormsetRemoveNotify, + EFI_HII_DATABASE_NOTIFY_REMOVE_PACK, + &NotifyHandle + ); + ASSERT_EFI_ERROR (Status); + return Status; } @@ -1932,78 +2081,104 @@ SynchronizeStorageForForm ( /** - Discard data for form level or formset level. + Discard data based on the input setting scope (Form, FormSet or System). @param FormSet FormSet data structure. @param Form Form data structure. - @param SingleForm Only discard single form or formset. + @param SettingScope Setting Scope for Discard action. @retval EFI_SUCCESS The function completed successfully. + @retval EFI_UNSUPPORTED Unsupport SettingScope. **/ EFI_STATUS DiscardForm ( IN FORM_BROWSER_FORMSET *FormSet, IN FORM_BROWSER_FORM *Form, - IN BOOLEAN SingleForm + IN BROWSER_SETTING_SCOPE SettingScope ) { - LIST_ENTRY *Link; - FORMSET_STORAGE *Storage; + LIST_ENTRY *Link; + FORMSET_STORAGE *Storage; FORM_BROWSER_CONFIG_REQUEST *ConfigInfo; + FORM_BROWSER_FORMSET *LocalFormSet; - if (SingleForm) { - if (Form->NvUpdateRequired) { - ConfigInfo = NULL; - Link = GetFirstNode (&Form->ConfigRequestHead); - while (!IsNull (&Form->ConfigRequestHead, Link)) { - ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link); - Link = GetNextNode (&Form->ConfigRequestHead, Link); - - if (ConfigInfo->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { - continue; - } + // + // Check the supported setting level. + // + if (SettingScope >= MaxLevel) { + return EFI_UNSUPPORTED; + } - // - // Skip if there is no RequestElement - // - if (ConfigInfo->ElementCount == 0) { - continue; - } + if (SettingScope == FormLevel && Form->NvUpdateRequired) { + ConfigInfo = NULL; + Link = GetFirstNode (&Form->ConfigRequestHead); + while (!IsNull (&Form->ConfigRequestHead, Link)) { + ConfigInfo = FORM_BROWSER_CONFIG_REQUEST_FROM_LINK (Link); + Link = GetNextNode (&Form->ConfigRequestHead, Link); - // - // Prepare - // - SynchronizeStorageForForm(FormSet, ConfigInfo, FALSE); + if (ConfigInfo->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { + continue; + } + + // + // Skip if there is no RequestElement + // + if (ConfigInfo->ElementCount == 0) { + continue; } - Form->NvUpdateRequired = FALSE; + // + // Prepare + // + SynchronizeStorageForForm(FormSet, ConfigInfo, FALSE); } - } else { - if (IsNvUpdateRequired(FormSet)) { + + Form->NvUpdateRequired = FALSE; + } else if (SettingScope == FormSetLevel && IsNvUpdateRequired(FormSet)) { + // + // Discard Buffer storage or Name/Value storage + // + Link = GetFirstNode (&FormSet->StorageListHead); + while (!IsNull (&FormSet->StorageListHead, Link)) { + Storage = FORMSET_STORAGE_FROM_LINK (Link); + Link = GetNextNode (&FormSet->StorageListHead, Link); + + if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { + continue; + } + // - // Discard Buffer storage or Name/Value storage + // Skip if there is no RequestElement // - Link = GetFirstNode (&FormSet->StorageListHead); - while (!IsNull (&FormSet->StorageListHead, Link)) { - Storage = FORMSET_STORAGE_FROM_LINK (Link); - Link = GetNextNode (&FormSet->StorageListHead, Link); + if (Storage->ElementCount == 0) { + continue; + } - if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { - continue; - } + SynchronizeStorage(Storage, FALSE); + } + UpdateNvInfoInForm (FormSet, FALSE); + } else if (SettingScope == SystemLevel) { + // + // System Level Discard. + // + + // + // Discard changed value for each FormSet in the maintain list. + // + Link = GetFirstNode (&gBrowserFormSetList); + while (!IsNull (&gBrowserFormSetList, Link)) { + LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link); + DiscardForm (LocalFormSet, NULL, FormSetLevel); + Link = GetNextNode (&gBrowserFormSetList, Link); + if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) { // - // Skip if there is no RequestElement + // Remove maintain backup list after discard except for the current using FormSet. // - if (Storage->ElementCount == 0) { - continue; - } - - SynchronizeStorage(Storage, FALSE); + RemoveEntryList (&LocalFormSet->Link); + DestroyFormSet (LocalFormSet); } - - UpdateNvInfoInForm(FormSet, FALSE); } } @@ -2011,20 +2186,21 @@ DiscardForm ( } /** - Submit data for form level or formset level. + Submit data based on the input Setting level (Form, FormSet or System). @param FormSet FormSet data structure. @param Form Form data structure. - @param SingleForm whether submit for the single form or all form set. + @param SettingScope Setting Scope for Submit action. @retval EFI_SUCCESS The function completed successfully. + @retval EFI_UNSUPPORTED Unsupport SettingScope. **/ EFI_STATUS SubmitForm ( IN FORM_BROWSER_FORMSET *FormSet, IN FORM_BROWSER_FORM *Form, - IN BOOLEAN SingleForm + IN BROWSER_SETTING_SCOPE SettingScope ) { EFI_STATUS Status; @@ -2033,22 +2209,31 @@ SubmitForm ( EFI_STRING Progress; FORMSET_STORAGE *Storage; UINTN BufferSize; - UINT8 *TmpBuf; + UINT8 *TmpBuf; + FORM_BROWSER_FORMSET *LocalFormSet; FORM_BROWSER_CONFIG_REQUEST *ConfigInfo; + // + // Check the supported setting level. + // + if (SettingScope >= MaxLevel) { + return EFI_UNSUPPORTED; + } + // // Validate the Form by NoSubmit check // - if (SingleForm) { + Status = EFI_SUCCESS; + if (SettingScope == FormLevel) { Status = NoSubmitCheck (FormSet, Form); - } else { + } else if (SettingScope == FormSetLevel) { Status = NoSubmitCheck (FormSet, NULL); } if (EFI_ERROR (Status)) { return Status; } - if (SingleForm) { + if (SettingScope == FormLevel && Form->NvUpdateRequired) { ConfigInfo = NULL; Link = GetFirstNode (&Form->ConfigRequestHead); while (!IsNull (&Form->ConfigRequestHead, Link)) { @@ -2153,7 +2338,7 @@ SubmitForm ( // 4. Update the NV flag. // Form->NvUpdateRequired = FALSE; - } else { + } else if (SettingScope == FormSetLevel && IsNvUpdateRequired(FormSet)) { // // Submit Buffer storage or Name/Value storage // @@ -2254,7 +2439,28 @@ SubmitForm ( // // 4. Update the NV flag. // - UpdateNvInfoInForm(FormSet, FALSE); + UpdateNvInfoInForm (FormSet, FALSE); + } else if (SettingScope == SystemLevel) { + // + // System Level Save. + // + + // + // Save changed value for each FormSet in the maintain list. + // + Link = GetFirstNode (&gBrowserFormSetList); + while (!IsNull (&gBrowserFormSetList, Link)) { + LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link); + SubmitForm (LocalFormSet, NULL, FormSetLevel); + Link = GetNextNode (&gBrowserFormSetList, Link); + if (!IsHiiHandleInBrowserContext (LocalFormSet->HiiHandle)) { + // + // Remove maintain backup list after save except for the current using FormSet. + // + RemoveEntryList (&LocalFormSet->Link); + DestroyFormSet (LocalFormSet); + } + } } return EFI_SUCCESS; @@ -2515,7 +2721,7 @@ GetQuestionDefault ( EFI_BROWSER_ACTION_REQUEST ActionRequest; INTN Action; - Status = EFI_SUCCESS; + Status = EFI_NOT_FOUND; StrValue = NULL; // @@ -2658,6 +2864,7 @@ GetQuestionDefault ( // // For Questions without default // + Status = EFI_NOT_FOUND; switch (Question->Operand) { case EFI_IFR_NUMERIC_OP: // @@ -2665,6 +2872,7 @@ GetQuestionDefault ( // if ((HiiValue->Value.u64 < Question->Minimum) || (HiiValue->Value.u64 > Question->Maximum)) { HiiValue->Value.u64 = Question->Minimum; + Status = EFI_SUCCESS; } break; @@ -2677,6 +2885,7 @@ GetQuestionDefault ( if (!IsNull (&Question->OptionListHead, Link)) { Option = QUESTION_OPTION_FROM_LINK (Link); CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE)); + Status = EFI_SUCCESS; } } break; @@ -2688,6 +2897,7 @@ GetQuestionDefault ( Index = 0; Link = GetFirstNode (&Question->OptionListHead); while (!IsNull (&Question->OptionListHead, Link)) { + Status = EFI_SUCCESS; Option = QUESTION_OPTION_FROM_LINK (Link); SetArrayData (Question->BufferValue, Question->ValueType, Index, Option->Value.Value.u64); @@ -2702,7 +2912,6 @@ GetQuestionDefault ( break; default: - Status = EFI_NOT_FOUND; break; } @@ -2711,38 +2920,52 @@ GetQuestionDefault ( /** - Reset Questions in a Formset to their default value. + Reset Questions to their default value in a Form, Formset or System. @param FormSet FormSet data structure. + @param Form Form data structure. @param DefaultId The Class of the default. + @param SettingScope Setting Scope for Default action. @retval EFI_SUCCESS The function completed successfully. + @retval EFI_UNSUPPORTED Unsupport SettingScope. **/ EFI_STATUS -ExtractFormSetDefault ( +ExtractDefault ( IN FORM_BROWSER_FORMSET *FormSet, - IN UINT16 DefaultId + IN FORM_BROWSER_FORM *Form, + IN UINT16 DefaultId, + IN BROWSER_SETTING_SCOPE SettingScope ) { EFI_STATUS Status; LIST_ENTRY *FormLink; - LIST_ENTRY *StatementLink; + LIST_ENTRY *Link; FORM_BROWSER_STATEMENT *Question; - FORM_BROWSER_FORM *Form; + FORM_BROWSER_FORMSET *BackUpFormSet; + FORM_BROWSER_FORMSET *LocalFormSet; + EFI_HII_HANDLE *HiiHandles; + UINTN Index; + EFI_GUID ZeroGuid; + UINTN BackUpClassOfVfr; - FormLink = GetFirstNode (&FormSet->FormListHead); - while (!IsNull (&FormSet->FormListHead, FormLink)) { - Form = FORM_BROWSER_FORM_FROM_LINK (FormLink); - + // + // Check the supported setting level. + // + if (SettingScope >= MaxLevel) { + return EFI_UNSUPPORTED; + } + + if (SettingScope == FormLevel) { // // Extract Form default // - StatementLink = GetFirstNode (&Form->StatementListHead); - while (!IsNull (&Form->StatementListHead, StatementLink)) { - Question = FORM_BROWSER_STATEMENT_FROM_LINK (StatementLink); - StatementLink = GetNextNode (&Form->StatementListHead, StatementLink); - + Link = GetFirstNode (&Form->StatementListHead); + while (!IsNull (&Form->StatementListHead, Link)) { + Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); + Link = GetNextNode (&Form->StatementListHead, Link); + // // If Question is disabled, don't reset it to default // @@ -2752,7 +2975,7 @@ ExtractFormSetDefault ( continue; } } - + // // Reset Question to its default value // @@ -2760,16 +2983,91 @@ ExtractFormSetDefault ( if (EFI_ERROR (Status)) { continue; } - + // // Synchronize Buffer storage's Edit buffer // if ((Question->Storage != NULL) && (Question->Storage->Type != EFI_HII_VARSTORE_EFI_VARIABLE)) { SetQuestionValue (FormSet, Form, Question, TRUE); + // + // Update Form NV flag. + // + Form->NvUpdateRequired = TRUE; + } + } + } else if (SettingScope == FormSetLevel) { + FormLink = GetFirstNode (&FormSet->FormListHead); + while (!IsNull (&FormSet->FormListHead, FormLink)) { + Form = FORM_BROWSER_FORM_FROM_LINK (FormLink); + ExtractDefault (FormSet, Form, DefaultId, FormLevel); + FormLink = GetNextNode (&FormSet->FormListHead, FormLink); + } + } else if (SettingScope == SystemLevel) { + // + // Open all FormSet by locate HII packages. + // Initiliaze the maintain FormSet to store default data as back up data. + // + BackUpClassOfVfr = gClassOfVfr; + BackUpFormSet = gOldFormSet; + gOldFormSet = NULL; + + // + // Get all the Hii handles + // + HiiHandles = HiiGetHiiHandles (NULL); + ASSERT (HiiHandles != NULL); + + // + // Search for formset of each class type + // + for (Index = 0; HiiHandles[Index] != NULL; Index++) { + // + // Check HiiHandles[Index] does exist in global maintain list. + // + if (GetFormSetFromHiiHandle (HiiHandles[Index]) != NULL) { + continue; } + + // + // Initilize FormSet Setting + // + LocalFormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET)); + ASSERT (LocalFormSet != NULL); + ZeroMem (&ZeroGuid, sizeof (ZeroGuid)); + Status = InitializeFormSet (HiiHandles[Index], &ZeroGuid, LocalFormSet); + if (EFI_ERROR (Status) || IsListEmpty (&LocalFormSet->FormListHead)) { + DestroyFormSet (LocalFormSet); + continue; + } + Status = InitializeCurrentSetting (LocalFormSet); + if (EFI_ERROR (Status)) { + DestroyFormSet (LocalFormSet); + continue; + } + + // + // Add FormSet into the maintain list. + // + InsertTailList (&gBrowserFormSetList, &LocalFormSet->Link); + } + + // + // Free resources, and restore gOldFormSet and gClassOfVfr + // + FreePool (HiiHandles); + gOldFormSet = BackUpFormSet; + gClassOfVfr = BackUpClassOfVfr; + + // + // Set Default Value for each FormSet in the maintain list. + // + Link = GetFirstNode (&gBrowserFormSetList); + while (!IsNull (&gBrowserFormSetList, Link)) { + LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link); + ExtractDefault (LocalFormSet, NULL, DefaultId, FormSetLevel); + Link = GetNextNode (&gBrowserFormSetList, Link); } - FormLink = GetNextNode (&FormSet->FormListHead, FormLink); } return EFI_SUCCESS; @@ -3052,10 +3350,8 @@ InitializeCurrentSetting ( // // Extract default from IFR binary // - Status = ExtractFormSetDefault (FormSet, EFI_HII_DEFAULT_CLASS_STANDARD); - if (EFI_ERROR (Status)) { - return Status; - } + ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel); + UpdateNvInfoInForm (FormSet, FALSE); // // Request current settings from Configuration Driver @@ -3180,8 +3476,8 @@ GetIfrBinaryData ( // // if FormSetGuid is NULL or zero GUID, return first Setup FormSet in the package list // - if (FormSetGuid == NULL || CompareGuid (FormSetGuid, &gZeroGuid)) { - ComparingGuid = &gEfiHiiPlatformSetupFormsetGuid; + if (FormSetGuid == NULL) { + ComparingGuid = &gZeroGuid; } else { ComparingGuid = FormSetGuid; } @@ -3227,7 +3523,8 @@ GetIfrBinaryData ( // // Try to compare against formset GUID // - if (CompareGuid (ComparingGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) { + if (CompareGuid (FormSetGuid, &gZeroGuid) || + CompareGuid (ComparingGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) { break; } @@ -3274,7 +3571,7 @@ GetIfrBinaryData ( return EFI_NOT_FOUND; } - if (ClassGuidMatch && (FormSetGuid != NULL)) { + if (FormSetGuid != NULL) { // // Return the FormSet GUID // @@ -3330,6 +3627,7 @@ InitializeFormSet ( return Status; } + FormSet->Signature = FORM_BROWSER_FORMSET_SIGNATURE; FormSet->HiiHandle = Handle; CopyMem (&FormSet->Guid, FormSetGuid, sizeof (EFI_GUID)); @@ -3382,6 +3680,7 @@ InitializeFormSet ( if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) == FORMSET_CLASS_FRONT_PAGE) { gFrontPageHandle = FormSet->HiiHandle; + gFunctionKeySetting = NONE_FUNCTION_KEY_SETTING; } // @@ -3393,20 +3692,10 @@ InitializeFormSet ( // Update the function key setting. // gFunctionKeySetting = gFunctionKeySettingTable[Index].KeySetting; - // - // Function key prompt can not be displayed if the function key has been disabled. - // - if ((gFunctionKeySetting & FUNCTION_NINE) != FUNCTION_NINE) { - gFunctionNineString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle); - } - - if ((gFunctionKeySetting & FUNCTION_TEN) != FUNCTION_TEN) { - gFunctionTenString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle); - } } } - return Status; + return EFI_SUCCESS; } @@ -3444,13 +3733,10 @@ SaveBrowserContext ( Context->FunctionKeySetting = gFunctionKeySetting; Context->ResetRequired = gResetRequired; Context->Direction = gDirection; - Context->FunctionNineString = gFunctionNineString; - Context->FunctionTenString = gFunctionTenString; Context->EnterString = gEnterString; Context->EnterCommitString = gEnterCommitString; Context->EnterEscapeString = gEnterEscapeString; Context->EscapeString = gEscapeString; - Context->SaveFailed = gSaveFailed; Context->MoveHighlight = gMoveHighlight; Context->MakeSelection = gMakeSelection; Context->DecNumericInput = gDecNumericInput; @@ -3524,13 +3810,10 @@ RestoreBrowserContext ( gFunctionKeySetting = Context->FunctionKeySetting; gResetRequired = Context->ResetRequired; gDirection = Context->Direction; - gFunctionNineString = Context->FunctionNineString; - gFunctionTenString = Context->FunctionTenString; gEnterString = Context->EnterString; gEnterCommitString = Context->EnterCommitString; gEnterEscapeString = Context->EnterEscapeString; gEscapeString = Context->EscapeString; - gSaveFailed = Context->SaveFailed; gMoveHighlight = Context->MoveHighlight; gMakeSelection = Context->MakeSelection; gDecNumericInput = Context->DecNumericInput; @@ -3569,3 +3852,334 @@ RestoreBrowserContext ( RemoveEntryList (&Context->Link); gBS->FreePool (Context); } + +/** + Find the matched FormSet context in the backup maintain list based on HiiHandle. + + @param Handle The Hii Handle. + + @return the found FormSet context. If no found, NULL will return. + +**/ +FORM_BROWSER_FORMSET * +GetFormSetFromHiiHandle ( + EFI_HII_HANDLE Handle + ) +{ + LIST_ENTRY *Link; + FORM_BROWSER_FORMSET *FormSet; + + Link = GetFirstNode (&gBrowserFormSetList); + while (!IsNull (&gBrowserFormSetList, Link)) { + FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link); + if (FormSet->HiiHandle == Handle) { + return FormSet; + } + Link = GetNextNode (&gBrowserFormSetList, Link); + } + + return NULL; +} + +/** + Check whether the input HII handle is the FormSet that is being used. + + @param Handle The Hii Handle. + + @retval TRUE HII handle is being used. + @retval FALSE HII handle is not being used. + +**/ +BOOLEAN +IsHiiHandleInBrowserContext ( + EFI_HII_HANDLE Handle + ) +{ + LIST_ENTRY *Link; + BROWSER_CONTEXT *Context; + + // + // HiiHandle is Current FormSet. + // + if ((gOldFormSet != NULL) && (gOldFormSet->HiiHandle == Handle)) { + return TRUE; + } + + // + // Check whether HiiHandle is in BrowserContext. + // + Link = GetFirstNode (&gBrowserContextList); + while (!IsNull (&gBrowserContextList, Link)) { + Context = BROWSER_CONTEXT_FROM_LINK (Link); + if (Context->OldFormSet->HiiHandle == Handle) { + // + // HiiHandle is in BrowserContext + // + return TRUE; + } + Link = GetNextNode (&gBrowserContextList, Link); + } + + return FALSE; +} + +/** + Find the registered HotKey based on KeyData. + + @param[in] KeyData A pointer to a buffer that describes the keystroke + information for the hot key. + + @return The registered HotKey context. If no found, NULL will return. +**/ +BROWSER_HOT_KEY * +GetHotKeyFromRegisterList ( + IN EFI_INPUT_KEY *KeyData + ) +{ + LIST_ENTRY *Link; + BROWSER_HOT_KEY *HotKey; + + Link = GetFirstNode (&gBrowserHotKeyList); + while (!IsNull (&gBrowserHotKeyList, Link)) { + HotKey = BROWSER_HOT_KEY_FROM_LINK (Link); + if (HotKey->KeyData->ScanCode == KeyData->ScanCode) { + return HotKey; + } + Link = GetNextNode (&gBrowserHotKeyList, Link); + } + + return NULL; +} + +/** + Configure what scope the hot key will impact. + All hot keys have the same scope. The mixed hot keys with the different level are not supported. + If no scope is set, the default scope will be FormSet level. + After all registered hot keys are removed, previous Scope can reset to another level. + + @param[in] Scope Scope level to be set. + + @retval EFI_SUCCESS Scope is set correctly. + @retval EFI_INVALID_PARAMETER Scope is not the valid value specified in BROWSER_SETTING_SCOPE. + @retval EFI_UNSPPORTED Scope level is different from current one that the registered hot keys have. + +**/ +EFI_STATUS +EFIAPI +SetScope ( + IN BROWSER_SETTING_SCOPE Scope + ) +{ + if (Scope >= MaxLevel) { + return EFI_INVALID_PARAMETER; + } + + // + // When no hot key registered in system or on the first setting, + // Scope can be set. + // + if (mBrowserScopeFirstSet || IsListEmpty (&gBrowserHotKeyList)) { + gBrowserSettingScope = Scope; + mBrowserScopeFirstSet = FALSE; + } else if (Scope != gBrowserSettingScope) { + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + +/** + Register the hot key with its browser action, or unregistered the hot key. + Only support hot key that is not printable character (control key, function key, etc.). + If the action value is zero, the hot key will be unregistered if it has been registered. + If the same hot key has been registered, the new action and help string will override the previous ones. + + @param[in] KeyData A pointer to a buffer that describes the keystroke + information for the hot key. Its type is EFI_INPUT_KEY to + be supported by all ConsoleIn devices. + @param[in] Action Action value that describes what action will be trigged when the hot key is pressed. + @param[in] DefaultId Specifies the type of defaults to retrieve, which is only for DEFAULT action. + @param[in] HelpString Help string that describes the hot key information. + Its value may be NULL for the unregistered hot key. + + @retval EFI_SUCCESS Hot key is registered or unregistered. + @retval EFI_INVALID_PARAMETER KeyData is NULL or HelpString is NULL on register. + @retval EFI_NOT_FOUND KeyData is not found to be unregistered. + @retval EFI_UNSUPPORTED Key represents a printable character. It is conflicted with Browser. +**/ +EFI_STATUS +EFIAPI +RegisterHotKey ( + IN EFI_INPUT_KEY *KeyData, + IN UINT32 Action, + IN UINT16 DefaultId, + IN EFI_STRING HelpString OPTIONAL + ) +{ + BROWSER_HOT_KEY *HotKey; + + // + // Check input parameters. + // + if (KeyData == NULL || KeyData->UnicodeChar != CHAR_NULL || + (Action != BROWSER_ACTION_UNREGISTER && HelpString == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // + // Check whether the input KeyData is in BrowserHotKeyList. + // + HotKey = GetHotKeyFromRegisterList (KeyData); + + // + // Unregister HotKey + // + if (Action == BROWSER_ACTION_UNREGISTER) { + if (HotKey != NULL) { + // + // The registered HotKey is found. + // Remove it from List, and free its resource. + // + RemoveEntryList (&HotKey->Link); + FreePool (HotKey->KeyData); + FreePool (HotKey->HelpString); + return EFI_SUCCESS; + } else { + // + // The registered HotKey is not found. + // + return EFI_NOT_FOUND; + } + } + + // + // Register HotKey into List. + // + if (HotKey == NULL) { + // + // Create new Key, and add it into List. + // + HotKey = AllocateZeroPool (sizeof (BROWSER_HOT_KEY)); + ASSERT (HotKey != NULL); + HotKey->Signature = BROWSER_HOT_KEY_SIGNATURE; + HotKey->KeyData = AllocateCopyPool (sizeof (EFI_INPUT_KEY), KeyData); + InsertTailList (&gBrowserHotKeyList, &HotKey->Link); + } + + // + // Fill HotKey information. + // + HotKey->Action = Action; + HotKey->DefaultId = DefaultId; + if (HotKey->HelpString != NULL) { + FreePool (HotKey->HelpString); + } + HotKey->HelpString = AllocateCopyPool (StrSize (HelpString), HelpString); + + return EFI_SUCCESS; +} + +/** + Register Exit handler function. + When more than one handler function is registered, the latter one will override the previous one. + When NULL handler is specified, the previous Exit handler will be unregistered. + + @param[in] Handler Pointer to handler function. + +**/ +VOID +EFIAPI +RegiserExitHandler ( + IN EXIT_HANDLER Handler + ) +{ + ExitHandlerFunction = Handler; + return; +} + +/** + Create reminder to let user to choose save or discard the changed browser data. + Caller can use it to actively check the changed browser data. + + @retval BROWSER_NO_CHANGES No browser data is changed. + @retval BROWSER_SAVE_CHANGES The changed browser data is saved. + @retval BROWSER_DISCARD_CHANGES The changed browser data is discard. + +**/ +UINT32 +EFIAPI +SaveReminder ( + VOID + ) +{ + LIST_ENTRY *Link; + FORM_BROWSER_FORMSET *FormSet; + BOOLEAN IsDataChanged; + UINT32 DataSavedAction; + CHAR16 *YesResponse; + CHAR16 *NoResponse; + CHAR16 *EmptyString; + CHAR16 *ChangeReminderString; + CHAR16 *SaveConfirmString; + EFI_INPUT_KEY Key; + EFI_STATUS Status; + + DataSavedAction = BROWSER_NO_CHANGES; + IsDataChanged = FALSE; + Link = GetFirstNode (&gBrowserFormSetList); + while (!IsNull (&gBrowserFormSetList, Link)) { + FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link); + if (IsNvUpdateRequired (FormSet)) { + IsDataChanged = TRUE; + break; + } + Link = GetNextNode (&gBrowserFormSetList, Link); + } + + // + // No data is changed. No save is required. + // + if (!IsDataChanged) { + return DataSavedAction; + } + + // + // If data is changed, prompt user + // + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + + YesResponse = GetToken (STRING_TOKEN (ARE_YOU_SURE_YES), gHiiHandle); + ASSERT (YesResponse != NULL); + NoResponse = GetToken (STRING_TOKEN (ARE_YOU_SURE_NO), gHiiHandle); + ASSERT (NoResponse != NULL); + EmptyString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle); + ChangeReminderString = GetToken (STRING_TOKEN (CHANGE_REMINDER), gHiiHandle); + SaveConfirmString = GetToken (STRING_TOKEN (SAVE_CONFIRM), gHiiHandle); + + do { + CreateDialog (4, TRUE, 0, NULL, &Key, EmptyString, ChangeReminderString, SaveConfirmString, EmptyString); + } while + (((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (NoResponse[0] | UPPER_LOWER_CASE_OFFSET)) && + ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (YesResponse[0] | UPPER_LOWER_CASE_OFFSET)) + ); + + // + // If the user hits the YesResponse key + // + if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (YesResponse[0] | UPPER_LOWER_CASE_OFFSET)) { + SubmitForm (NULL, NULL, SystemLevel); + DataSavedAction = BROWSER_SAVE_CHANGES; + } else { + DiscardForm (NULL, NULL, SystemLevel); + DataSavedAction = BROWSER_DISCARD_CHANGES; + gResetRequired = FALSE; + } + + FreePool (YesResponse); + FreePool (NoResponse); + FreePool (EmptyString); + FreePool (SaveConfirmString); + FreePool (ChangeReminderString); + + return DataSavedAction; +} diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h index 27a1ad1c3c..8f71e7cc38 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h @@ -22,6 +22,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include #include +#include #include #include #include @@ -74,10 +75,7 @@ extern UINT8 SetupBrowserStrings[]; // Definition for function key setting // #define NONE_FUNCTION_KEY_SETTING 0 -#define DEFAULT_FUNCTION_KEY_SETTING (FUNCTION_NINE | FUNCTION_TEN) - -#define FUNCTION_NINE (1 << 2) -#define FUNCTION_TEN (1 << 3) +#define ENABLE_FUNCTION_KEY_SETTING 1 typedef struct { EFI_GUID FormSetGuid; @@ -164,7 +162,9 @@ typedef struct { // // Produced protocol // - EFI_FORM_BROWSER2_PROTOCOL FormBrowser2; + EFI_FORM_BROWSER2_PROTOCOL FormBrowser2; + + EFI_FORM_BROWSER_EXTENSION_PROTOCOL FormBrowserEx; } SETUP_DRIVER_PRIVATE_DATA; @@ -448,8 +448,12 @@ typedef struct { #define FORMSET_DEFAULTSTORE_FROM_LINK(a) CR (a, FORMSET_DEFAULTSTORE, Link, FORMSET_DEFAULTSTORE_SIGNATURE) +#define FORM_BROWSER_FORMSET_SIGNATURE SIGNATURE_32 ('F', 'B', 'F', 'S') + typedef struct { - EFI_HII_HANDLE HiiHandle; + UINTN Signature; + LIST_ENTRY Link; + EFI_HII_HANDLE HiiHandle; // unique id for formset. EFI_HANDLE DriverHandle; EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; EFI_DEVICE_PATH_PROTOCOL *DevicePath; @@ -475,6 +479,8 @@ typedef struct { LIST_ENTRY ExpressionListHead; // List of Expressions (FORM_EXPRESSION) } FORM_BROWSER_FORMSET; +#define FORM_BROWSER_FORMSET_FROM_LINK(a) CR (a, FORM_BROWSER_FORMSET, Link, FORM_BROWSER_FORMSET_SIGNATURE) + #define BROWSER_CONTEXT_SIGNATURE SIGNATURE_32 ('B', 'C', 'T', 'X') typedef struct { @@ -490,13 +496,10 @@ typedef struct { BOOLEAN ResetRequired; UINT16 Direction; EFI_SCREEN_DESCRIPTOR ScreenDimensions; - CHAR16 *FunctionNineString; - CHAR16 *FunctionTenString; CHAR16 *EnterString; CHAR16 *EnterCommitString; CHAR16 *EnterEscapeString; CHAR16 *EscapeString; - CHAR16 *SaveFailed; CHAR16 *MoveHighlight; CHAR16 *MakeSelection; CHAR16 *DecNumericInput; @@ -534,6 +537,20 @@ typedef struct { #define BROWSER_CONTEXT_FROM_LINK(a) CR (a, BROWSER_CONTEXT, Link, BROWSER_CONTEXT_SIGNATURE) +#define BROWSER_HOT_KEY_SIGNATURE SIGNATURE_32 ('B', 'H', 'K', 'S') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + EFI_INPUT_KEY *KeyData; + IN UINT32 Action; + IN UINT16 DefaultId; + IN EFI_STRING HelpString; +} BROWSER_HOT_KEY; + +#define BROWSER_HOT_KEY_FROM_LINK(a) CR (a, BROWSER_HOT_KEY, Link, BROWSER_HOT_KEY_SIGNATURE) + extern EFI_HII_DATABASE_PROTOCOL *mHiiDatabase; extern EFI_HII_STRING_PROTOCOL *mHiiString; extern EFI_HII_CONFIG_ROUTING_PROTOCOL *mHiiConfigRouting; @@ -548,12 +565,17 @@ extern UINT16 gDirection; extern EFI_SCREEN_DESCRIPTOR gScreenDimensions; extern FORM_BROWSER_FORMSET *gOldFormSet; +extern LIST_ENTRY gBrowserFormSetList; +extern LIST_ENTRY gBrowserHotKeyList; +extern BROWSER_SETTING_SCOPE gBrowserSettingScope; +extern EXIT_HANDLER ExitHandlerFunction; +extern UINTN gFooterHeight; // // Browser Global Strings // -extern CHAR16 *gFunctionNineString; -extern CHAR16 *gFunctionTenString; +extern CHAR16 *gDiscardFailed; +extern CHAR16 *gDefaultFailed; extern CHAR16 *gEnterString; extern CHAR16 *gEnterCommitString; extern CHAR16 *gEnterEscapeString; @@ -924,38 +946,41 @@ ValidateQuestion ( IN UINTN Type ); + /** - Discard data for form level or formset level. + Discard data based on the input setting scope (Form, FormSet or System). @param FormSet FormSet data structure. @param Form Form data structure. - @param SingleForm whether submit single form or formset. + @param SettingScope Setting Scope for Discard action. @retval EFI_SUCCESS The function completed successfully. + @retval EFI_UNSUPPORTED Unsupport SettingScope. **/ EFI_STATUS DiscardForm ( IN FORM_BROWSER_FORMSET *FormSet, IN FORM_BROWSER_FORM *Form, - IN BOOLEAN SingleForm + IN BROWSER_SETTING_SCOPE SettingScope ); /** - Submit data for form level or formset level. + Submit data based on the input Setting level (Form, FormSet or System). @param FormSet FormSet data structure. @param Form Form data structure. - @param SingleForm whether submit single form or formset. + @param SettingScope Setting Scope for Submit action. @retval EFI_SUCCESS The function completed successfully. + @retval EFI_UNSUPPORTED Unsupport SettingScope. **/ EFI_STATUS SubmitForm ( IN FORM_BROWSER_FORMSET *FormSet, IN FORM_BROWSER_FORM *Form, - IN BOOLEAN SingleForm + IN BROWSER_SETTING_SCOPE SettingScope ); /** @@ -1011,18 +1036,23 @@ InitializeFormSet ( ); /** - Reset Questions in a Formset to their default value. + Reset Questions to their default value in a Form, Formset or System. @param FormSet FormSet data structure. + @param Form Form data structure. @param DefaultId The Class of the default. + @param SettingScope Setting Scope for Default action. @retval EFI_SUCCESS The function completed successfully. + @retval EFI_UNSUPPORTED Unsupport SettingScope. **/ EFI_STATUS -ExtractFormSetDefault ( +ExtractDefault ( IN FORM_BROWSER_FORMSET *FormSet, - IN UINT16 DefaultId + IN FORM_BROWSER_FORM *Form, + IN UINT16 DefaultId, + IN BROWSER_SETTING_SCOPE SettingScope ); /** @@ -1300,4 +1330,121 @@ ProcessCallBackFunction ( IN EFI_BROWSER_ACTION Action, IN BOOLEAN SkipSaveOrDiscard ); + +/** + Find the matched FormSet context in the backup maintain list based on HiiHandle. + + @param Handle The Hii Handle. + + @return the found FormSet context. If no found, NULL will return. + +**/ +FORM_BROWSER_FORMSET * +GetFormSetFromHiiHandle ( + EFI_HII_HANDLE Handle + ); + +/** + Check whether the input HII handle is the FormSet that is being used. + + @param Handle The Hii Handle. + + @retval TRUE HII handle is being used. + @retval FALSE HII handle is not being used. + +**/ +BOOLEAN +IsHiiHandleInBrowserContext ( + EFI_HII_HANDLE Handle + ); + +/** + Configure what scope the hot key will impact. + All hot keys have the same scope. The mixed hot keys with the different level are not supported. + If no scope is set, the default scope will be FormSet level. + After all registered hot keys are removed, previous Scope can reset to another level. + + @param[in] Scope Scope level to be set. + + @retval EFI_SUCCESS Scope is set correctly. + @retval EFI_INVALID_PARAMETER Scope is not the valid value specified in BROWSER_SETTING_SCOPE. + @retval EFI_UNSPPORTED Scope level is different from current one that the registered hot keys have. + +**/ +EFI_STATUS +EFIAPI +SetScope ( + IN BROWSER_SETTING_SCOPE Scope + ); + +/** + Register the hot key with its browser action, or unregistered the hot key. + Only support hot key that is not printable character (control key, function key, etc.). + If the action value is zero, the hot key will be unregistered if it has been registered. + If the same hot key has been registered, the new action and help string will override the previous ones. + + @param[in] KeyData A pointer to a buffer that describes the keystroke + information for the hot key. Its type is EFI_INPUT_KEY to + be supported by all ConsoleIn devices. + @param[in] Action Action value that describes what action will be trigged when the hot key is pressed. + @param[in] DefaultId Specifies the type of defaults to retrieve, which is only for DEFAULT action. + @param[in] HelpString Help string that describes the hot key information. + Its value may be NULL for the unregistered hot key. + + @retval EFI_SUCCESS Hot key is registered or unregistered. + @retval EFI_INVALID_PARAMETER KeyData is NULL. + @retval EFI_NOT_FOUND KeyData is not found to be unregistered. + @retval EFI_UNSUPPORTED Key represents a printable character. It is conflicted with Browser. +**/ +EFI_STATUS +EFIAPI +RegisterHotKey ( + IN EFI_INPUT_KEY *KeyData, + IN UINT32 Action, + IN UINT16 DefaultId, + IN EFI_STRING HelpString OPTIONAL + ); + +/** + Register Exit handler function. + When more than one handler function is registered, the latter one will override the previous one. + When NULL handler is specified, the previous Exit handler will be unregistered. + + @param[in] Handler Pointer to handler function. + +**/ +VOID +EFIAPI +RegiserExitHandler ( + IN EXIT_HANDLER Handler + ); + +/** + Create reminder to let user to choose save or discard the changed browser data. + Caller can use it to actively check the changed browser data. + + @retval BROWSER_NO_CHANGES No browser data is changed. + @retval BROWSER_SAVE_CHANGES The changed browser data is saved. + @retval BROWSER_DISCARD_CHANGES The changed browser data is discard. + +**/ +UINT32 +EFIAPI +SaveReminder ( + VOID + ); + +/** + Find the registered HotKey based on KeyData. + + @param[in] KeyData A pointer to a buffer that describes the keystroke + information for the hot key. + + @return The registered HotKey context. If no found, NULL will return. +**/ +BROWSER_HOT_KEY * +GetHotKeyFromRegisterList ( + IN EFI_INPUT_KEY *KeyData + ); + #endif diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf b/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf index 0cba75189e..6c7820c664 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf +++ b/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf @@ -69,6 +69,7 @@ gEfiHiiConfigAccessProtocolGuid ## CONSUMES gEfiHiiStringProtocolGuid ## CONSUMES gEfiFormBrowser2ProtocolGuid ## PRODUCES + gEfiFormBrowserExProtocolGuid ## PRODUCES gEfiHiiConfigRoutingProtocolGuid ## CONSUMES gEfiHiiDatabaseProtocolGuid ## CONSUMES gEfiUnicodeCollation2ProtocolGuid ## CONSUMES diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserStr.uni b/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserStr.uni index b09269141b567c4a56e23aada61167bb5377d8cc..fdecbe85a16b7e20981c79250f6322fb40c4b13e 100644 GIT binary patch delta 349 zcmewowCkskeYZ9rJ zA!T!*vNF%)6Kn#K&I}$5jtqVb?hLLB@eDyg(wD&#$ak51QC@Yj0I$kq9!)Rae4xb& zK#TH$mfKHWC|-$0^dOt~*dXs^w zcwK<9!3@qodxL=X+~hF?+GD}#0`yif&`XJv`6X*7oA8PN)j>sowx>XKx&qC1WC&&O lVF-cgoGix1$FBf1F%{@KP~ZRq1nfqj86Y_!G&u$(1^|6WQ3L=0 delta 28 gcmZ3I{UvV0B_(D*hOo&C#Vf(|K{oNtTaStatement != NULL) { + Question = Selection->Statement; + if (Question->Storage != NULL || Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) { + // + // Update only for Question value that need to be saved into Storage. + // + Selection->Form->NvUpdateRequired = TRUE; + } + } + + if (Selection == NULL || IsNvUpdateRequired (Selection->FormSet)) { gST->ConOut->SetAttribute (gST->ConOut, INFO_TEXT); PrintStringAt ( gScreenDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth, gScreenDimensions.BottomRow - 1, NvUpdateMessage ); - gResetRequired = (BOOLEAN) (gResetRequired | ((Flags & EFI_IFR_FLAG_RESET_REQUIRED) == EFI_IFR_FLAG_RESET_REQUIRED)); - - if (Selection != NULL) { - Selection->Form->NvUpdateRequired = TRUE; - } - } else { - gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextHighlightColor)); - for (Index = 0; Index < (GetStringWidth (NvUpdateMessage) - 2) / 2; Index++) { - PrintAt ( - (gScreenDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + Index), - gScreenDimensions.BottomRow - 1, - L" " - ); - } - - if (Selection != NULL) { - Selection->Form->NvUpdateRequired = FALSE; - } + } + } else { + gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextHighlightColor)); + for (Index = 0; Index < (GetStringWidth (NvUpdateMessage) - 2) / 2; Index++) { + PrintAt ( + (gScreenDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + Index), + gScreenDimensions.BottomRow - 1, + L" " + ); } } break; @@ -1117,9 +1116,28 @@ UpdateStatusBar ( UpdateStatusBar (Selection, INPUT_ERROR, Flags, TRUE); } - if (IsNvUpdateRequired(Selection->FormSet)) { - UpdateStatusBar (NULL, NV_UPDATE_REQUIRED, Flags, TRUE); + switch (gBrowserSettingScope) { + case SystemLevel: + // + // Check the maintain list to see whether there is any change. + // + Link = GetFirstNode (&gBrowserFormSetList); + while (!IsNull (&gBrowserFormSetList, Link)) { + LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link); + if (IsNvUpdateRequired(LocalFormSet)) { + UpdateStatusBar (NULL, NV_UPDATE_REQUIRED, Flags, TRUE); + break; + } + Link = GetNextNode (&gBrowserFormSetList, Link); + } + break; + case FormSetLevel: + case FormLevel: + UpdateStatusBar (Selection, NV_UPDATE_REQUIRED, Flags, TRUE); + default: + break; } + break; default: @@ -1877,6 +1895,7 @@ UiDisplayMenu ( FORM_BROWSER_STATEMENT *Statement; UI_MENU_LIST *CurrentMenu; UINTN ModalSkipColumn; + BROWSER_HOT_KEY *HotKey; CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); @@ -1898,6 +1917,7 @@ UiDisplayMenu ( NextMenuOption = NULL; PreviousMenuOption = NULL; SavedMenuOption = NULL; + HotKey = NULL; ModalSkipColumn = (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 6; ZeroMem (&Key, sizeof (EFI_INPUT_KEY)); @@ -1916,7 +1936,7 @@ UiDisplayMenu ( Col = LocalScreen.LeftColumn + LEFT_SKIPPED_COLUMNS; } - BottomRow = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT - SCROLL_ARROW_HEIGHT - 1; + BottomRow = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight - SCROLL_ARROW_HEIGHT - 1; Selection->TopRow = TopRow; Selection->BottomRow = BottomRow; @@ -2620,8 +2640,9 @@ UiDisplayMenu ( // // IFR is updated in Callback of refresh opcode, re-parse it // + ControlFlag = CfCheckSelection; Selection->Statement = NULL; - return EFI_SUCCESS; + break; } Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); @@ -2709,30 +2730,28 @@ UiDisplayMenu ( break; case CHAR_NULL: - if (((Key.ScanCode == SCAN_F9) && ((gFunctionKeySetting & FUNCTION_NINE) != FUNCTION_NINE)) || - ((Key.ScanCode == SCAN_F10) && ((gFunctionKeySetting & FUNCTION_TEN) != FUNCTION_TEN)) - ) { + for (Index = 0; Index < mScanCodeNumber; Index++) { + if (Key.ScanCode == gScanCodeToOperation[Index].ScanCode) { + ScreenOperation = gScanCodeToOperation[Index].ScreenOperation; + break; + } + } + + if (Selection->Form->ModalForm && (Key.ScanCode == SCAN_ESC || Index == mScanCodeNumber)) { // - // If the function key has been disabled, just ignore the key. + // ModalForm has no ESC key and Hot Key. // - } else { - for (Index = 0; Index < sizeof (gScanCodeToOperation) / sizeof (gScanCodeToOperation[0]); Index++) { - if (Selection->Form->ModalForm && - (Key.ScanCode == SCAN_F9 || Key.ScanCode == SCAN_F10 || Key.ScanCode == SCAN_ESC)) { - ControlFlag = CfReadKey; - break; - } - - if (Key.ScanCode == gScanCodeToOperation[Index].ScanCode) { - if (Key.ScanCode == SCAN_F9) { - // - // Reset to standard default - // - DefaultId = EFI_HII_DEFAULT_CLASS_STANDARD; - } - ScreenOperation = gScanCodeToOperation[Index].ScreenOperation; - break; - } + ControlFlag = CfReadKey; + } else if (Index == mScanCodeNumber) { + // + // Check whether Key matches the registered hot key. + // + HotKey = NULL; + if ((gBrowserSettingScope == SystemLevel) || (gFunctionKeySetting != NONE_FUNCTION_KEY_SETTING)) { + HotKey = GetHotKeyFromRegisterList (&Key); + } + if (HotKey != NULL) { + ScreenOperation = UiHotKey; } } break; @@ -2832,9 +2851,7 @@ UiDisplayMenu ( // We come here when someone press ESC // ControlFlag = CfCheckSelection; - if (FindNextMenu (Selection, &Repaint, &NewLine)) { - return EFI_SUCCESS; - } + FindNextMenu (Selection, &Repaint, &NewLine); break; case CfUiLeft: @@ -3252,43 +3269,120 @@ UiDisplayMenu ( AdjustDateAndTimePosition (TRUE, &NewPos); break; - case CfUiSave: + case CfUiHotKey: ControlFlag = CfCheckSelection; - + + Status = EFI_SUCCESS; // - // Submit the form + // Discard changes. After it, no NV flag is showed. // - Status = SubmitForm (Selection->FormSet, Selection->Form, FALSE); + if ((HotKey->Action & BROWSER_ACTION_DISCARD) == BROWSER_ACTION_DISCARD) { + Status = DiscardForm (Selection->FormSet, Selection->Form, gBrowserSettingScope); + if (!EFI_ERROR (Status)) { + Selection->Action = UI_ACTION_REFRESH_FORM; + Selection->Statement = NULL; + gResetRequired = FALSE; + } else { + do { + CreateDialog (4, TRUE, 0, NULL, &Key, HotKey->HelpString, gDiscardFailed, gPressEnter, gEmptyString); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + // + // Still show current page. + // + Selection->Action = UI_ACTION_NONE; + Repaint = TRUE; + NewLine = TRUE; + break; + } + } - if (!EFI_ERROR (Status)) { - ASSERT(MenuOption != NULL); - UpdateStatusBar (Selection, INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE); - UpdateStatusBar (Selection, NV_UPDATE_REQUIRED, MenuOption->ThisTag->QuestionFlags, FALSE); - } else { - do { - CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gSaveFailed, gPressEnter, gEmptyString); - } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + // + // Reterieve default setting. After it. NV flag will be showed. + // + if ((HotKey->Action & BROWSER_ACTION_DEFAULT) == BROWSER_ACTION_DEFAULT) { + Status = ExtractDefault (Selection->FormSet, Selection->Form, HotKey->DefaultId, gBrowserSettingScope); + if (!EFI_ERROR (Status)) { + Selection->Action = UI_ACTION_REFRESH_FORM; + Selection->Statement = NULL; + gResetRequired = TRUE; + } else { + do { + CreateDialog (4, TRUE, 0, NULL, &Key, HotKey->HelpString, gDefaultFailed, gPressEnter, gEmptyString); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + // + // Still show current page. + // + Selection->Action = UI_ACTION_NONE; + Repaint = TRUE; + NewLine = TRUE; + break; + } + } - Repaint = TRUE; - NewLine = TRUE; + // + // Save changes. After it, no NV flag is showed. + // + if ((HotKey->Action & BROWSER_ACTION_SUBMIT) == BROWSER_ACTION_SUBMIT) { + Status = SubmitForm (Selection->FormSet, Selection->Form, gBrowserSettingScope); + if (!EFI_ERROR (Status)) { + ASSERT(MenuOption != NULL); + UpdateStatusBar (Selection, INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE); + UpdateStatusBar (Selection, NV_UPDATE_REQUIRED, MenuOption->ThisTag->QuestionFlags, FALSE); + } else { + do { + CreateDialog (4, TRUE, 0, NULL, &Key, HotKey->HelpString, gSaveFailed, gPressEnter, gEmptyString); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + // + // Still show current page. + // + Selection->Action = UI_ACTION_NONE; + Repaint = TRUE; + NewLine = TRUE; + break; + } + } + + // + // Set Reset required Flag + // + if ((HotKey->Action & BROWSER_ACTION_RESET) == BROWSER_ACTION_RESET) { + gResetRequired = TRUE; + } + + // + // Exit Action + // + if ((HotKey->Action & BROWSER_ACTION_EXIT) == BROWSER_ACTION_EXIT) { + // + // Form Exit without saving, Similar to ESC Key. + // FormSet Exit without saving, Exit SendForm. + // System Exit without saving, CallExitHandler and Exit SendForm. + // + DiscardForm (Selection->FormSet, Selection->Form, gBrowserSettingScope); + if (gBrowserSettingScope == FormLevel) { + ControlFlag = CfUiReset; + } else if (gBrowserSettingScope == FormSetLevel) { + Selection->Action = UI_ACTION_EXIT; + } else if (gBrowserSettingScope == SystemLevel) { + if (ExitHandlerFunction != NULL) { + ExitHandlerFunction (); + } + Selection->Action = UI_ACTION_EXIT; + } + Selection->Statement = NULL; } break; case CfUiDefault: ControlFlag = CfCheckSelection; // - // Reset to default values for the whole formset + // Reset to default value for all forms in the whole system. // - Status = ExtractFormSetDefault (Selection->FormSet, DefaultId); + Status = ExtractDefault (Selection->FormSet, NULL, DefaultId, FormSetLevel); if (!EFI_ERROR (Status)) { Selection->Action = UI_ACTION_REFRESH_FORM; Selection->Statement = NULL; - - // - // Show NV update flag on status bar - // - UpdateNvInfoInForm(Selection->FormSet, TRUE); gResetRequired = TRUE; } break; diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Ui.h b/MdeModulePkg/Universal/SetupBrowserDxe/Ui.h index cec7dcd0c1..df5a22fe71 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/Ui.h +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Ui.h @@ -33,17 +33,16 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. typedef enum { UiNoOperation, - UiDefault, UiSelect, UiUp, UiDown, UiLeft, UiRight, UiReset, - UiSave, UiPrevious, UiPageUp, UiPageDown, + UiHotKey, UiMaxOperation } UI_SCREEN_OPERATION; @@ -64,10 +63,10 @@ typedef enum { CfUiPageUp, CfUiPageDown, CfUiDown, - CfUiSave, CfUiDefault, CfUiNoOperation, CfExit, + CfUiHotKey, CfMaxControlFlag } UI_CONTROL_FLAG; -- 2.39.2