diff --git a/Changelog.md b/Changelog.md index 312b24789d5..b29bf76ebb0 100644 --- a/Changelog.md +++ b/Changelog.md @@ -3,7 +3,7 @@ OpenCore Changelog #### v0.5.9 - Added full HiDPI support in OpenCanopy -- Improved font rendering by using CoreText +- Improved OpenCanopy font rendering by using CoreText - Fixed light and custom background font rendering - Added `Boot####` options support in boot entry listing - Removed `HideSelf` by pattern recognising `BOOTx64.efi` @@ -18,6 +18,7 @@ OpenCore Changelog - Fixed `ReconnectOnResChange` reconnecting even without res change - Fixed OpenCanopy showing internal icons for external drives - Fixed OpenCanopy launching Shell with text over it +- Added partial hotkey support to OpenCanopy (e.g. Ctrl+Enter) #### v0.5.8 - Fixed invalid CPU object reference in SSDT-PLUG diff --git a/Include/Library/OcBootManagementLib.h b/Include/Library/OcBootManagementLib.h index a23751260e7..8202ff666ec 100755 --- a/Include/Library/OcBootManagementLib.h +++ b/Include/Library/OcBootManagementLib.h @@ -916,15 +916,33 @@ OcLoadPickerHotKeys ( #define OC_INPUT_BOTTOM -10 ///< Move to bottom #define OC_INPUT_MORE -11 ///< Show more entries (press space) #define OC_INPUT_VOICE_OVER -12 ///< Toggle VoiceOver (press CMD+F5) +#define OC_INPUT_INTERNAL -13 ///< Accepted internal hotkey (e.g. Apple) #define OC_INPUT_FUNCTIONAL(x) (-20 - (x)) ///< Functional hotkeys /** Obtains key index from user input. + @param[in,out] Context Picker context. + @param[in] KeyMap Apple Key Map Aggregator protocol. + @param[out] SetDefault Set boot option as default, optional. + + @returns key index [0, OC_INPUT_MAX) or OC_INPUT_* value. + @returns OC_INPUT_TIMEOUT when no key is pressed. + @returns OC_INPUT_INVALID when unknown key is pressed. +**/ +INTN +OcGetAppleKeyIndex ( + IN OUT OC_PICKER_CONTEXT *Context, + IN APPLE_KEY_MAP_AGGREGATOR_PROTOCOL *KeyMap, + OUT BOOLEAN *SetDefault OPTIONAL + ); + +/** + Waits for key index from user input. + @param[in,out] Context Picker context. @param[in] KeyMap Apple Key Map Aggregator protocol. @param[in] Timeout Timeout to wait for in milliseconds. - @param[in] PollHotkeys Poll key combinations. @param[out] SetDefault Set boot option as default, optional. @returns key index [0, OC_INPUT_MAX) or OC_INPUT_* value. @@ -934,7 +952,6 @@ OcWaitForAppleKeyIndex ( IN OUT OC_PICKER_CONTEXT *Context, IN APPLE_KEY_MAP_AGGREGATOR_PROTOCOL *KeyMap, IN UINTN Timeout, - IN BOOLEAN PollHotkeys, OUT BOOLEAN *SetDefault OPTIONAL ); diff --git a/Library/OcBootManagementLib/HotKeySupport.c b/Library/OcBootManagementLib/HotKeySupport.c index 76b508b5a6f..6f04932da8a 100644 --- a/Library/OcBootManagementLib/HotKeySupport.c +++ b/Library/OcBootManagementLib/HotKeySupport.c @@ -121,11 +121,9 @@ OcLoadPickerHotKeys ( } INTN -OcWaitForAppleKeyIndex ( +OcGetAppleKeyIndex ( IN OUT OC_PICKER_CONTEXT *Context, IN APPLE_KEY_MAP_AGGREGATOR_PROTOCOL *KeyMap, - IN UINTN Timeout, - IN BOOLEAN PollHotkeys, OUT BOOLEAN *SetDefault OPTIONAL ) { @@ -146,259 +144,293 @@ OcWaitForAppleKeyIndex ( BOOLEAN WantsZeroSlide; BOOLEAN WantsDefault; UINT32 CsrActiveConfig; - UINT64 CurrTime; - UINT64 EndTime; UINTN CsrActiveConfigSize; - // - // These hotkeys are normally parsed by boot.efi, and they work just fine - // when ShowPicker is disabled. On some BSPs, however, they may fail badly - // when ShowPicker is enabled, and for this reason we support these hotkeys - // within picker itself. - // - - CurrTime = GetTimeInNanoSecond (GetPerformanceCounter ()); - EndTime = CurrTime + Timeout * 1000000ULL; + NumKeys = ARRAY_SIZE (Keys); + Status = KeyMap->GetKeyStrokes ( + KeyMap, + &Modifiers, + &NumKeys, + Keys + ); - if (SetDefault != NULL) { - *SetDefault = FALSE; + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_WARN, "OCB: GetKeyStrokes - %r\n", Status)); + return OC_INPUT_INVALID; } - while (Timeout == 0 || CurrTime == 0 || CurrTime < EndTime) { - NumKeys = ARRAY_SIZE (Keys); - Status = KeyMap->GetKeyStrokes ( - KeyMap, - &Modifiers, - &NumKeys, - Keys - ); - - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_ERROR, "OCB: GetKeyStrokes - %r\n", Status)); - return OC_INPUT_INVALID; + // + // Handle key combinations. + // + if (Context->PollAppleHotKeys) { + HasCommand = (Modifiers & (APPLE_MODIFIER_LEFT_COMMAND | APPLE_MODIFIER_RIGHT_COMMAND)) != 0; + HasShift = (Modifiers & (APPLE_MODIFIER_LEFT_SHIFT | APPLE_MODIFIER_RIGHT_SHIFT)) != 0; + HasKeyC = OcKeyMapHasKey (Keys, NumKeys, AppleHidUsbKbUsageKeyC); + HasKeyK = OcKeyMapHasKey (Keys, NumKeys, AppleHidUsbKbUsageKeyK); + HasKeyS = OcKeyMapHasKey (Keys, NumKeys, AppleHidUsbKbUsageKeyS); + HasKeyV = OcKeyMapHasKey (Keys, NumKeys, AppleHidUsbKbUsageKeyV); + // + // Checking for PAD minus is our extension to support more keyboards. + // + HasKeyMinus = OcKeyMapHasKey (Keys, NumKeys, AppleHidUsbKbUsageKeyMinus) + || OcKeyMapHasKey (Keys, NumKeys, AppleHidUsbKbUsageKeyPadMinus); + + // + // Shift is always valid and enables Safe Mode. + // + if (HasShift) { + if (OcGetArgumentFromCmd (Context->AppleBootArgs, "-x", L_STR_LEN ("-x")) == NULL) { + DEBUG ((DEBUG_INFO, "OCB: Shift means -x\n")); + OcAppendArgumentToCmd (Context, Context->AppleBootArgs, "-x", L_STR_LEN ("-x")); + } + return OC_INPUT_INTERNAL; } - CurrTime = GetTimeInNanoSecond (GetPerformanceCounter ()); + // + // CMD+V is always valid and enables Verbose Mode. + // + if (HasCommand && HasKeyV) { + if (OcGetArgumentFromCmd (Context->AppleBootArgs, "-v", L_STR_LEN ("-v")) == NULL) { + DEBUG ((DEBUG_INFO, "OCB: CMD+V means -v\n")); + OcAppendArgumentToCmd (Context, Context->AppleBootArgs, "-v", L_STR_LEN ("-v")); + } + return OC_INPUT_INTERNAL; + } // - // Handle key combinations. + // CMD+C+MINUS is always valid and disables compatibility check. // - if (PollHotkeys) { - HasCommand = (Modifiers & (APPLE_MODIFIER_LEFT_COMMAND | APPLE_MODIFIER_RIGHT_COMMAND)) != 0; - HasShift = (Modifiers & (APPLE_MODIFIER_LEFT_SHIFT | APPLE_MODIFIER_RIGHT_SHIFT)) != 0; - HasKeyC = OcKeyMapHasKey (Keys, NumKeys, AppleHidUsbKbUsageKeyC); - HasKeyK = OcKeyMapHasKey (Keys, NumKeys, AppleHidUsbKbUsageKeyK); - HasKeyS = OcKeyMapHasKey (Keys, NumKeys, AppleHidUsbKbUsageKeyS); - HasKeyV = OcKeyMapHasKey (Keys, NumKeys, AppleHidUsbKbUsageKeyV); - // - // Checking for PAD minus is our extension to support more keyboards. - // - HasKeyMinus = OcKeyMapHasKey (Keys, NumKeys, AppleHidUsbKbUsageKeyMinus) - || OcKeyMapHasKey (Keys, NumKeys, AppleHidUsbKbUsageKeyPadMinus); - - // - // Shift is always valid and enables Safe Mode. - // - if (HasShift) { - if (OcGetArgumentFromCmd (Context->AppleBootArgs, "-x", L_STR_LEN ("-x")) == NULL) { - DEBUG ((DEBUG_INFO, "OCB: Shift means -x\n")); - OcAppendArgumentToCmd (Context, Context->AppleBootArgs, "-x", L_STR_LEN ("-x")); - } - continue; + if (HasCommand && HasKeyC && HasKeyMinus) { + if (OcGetArgumentFromCmd (Context->AppleBootArgs, "-no_compat_check", L_STR_LEN ("-no_compat_check")) == NULL) { + DEBUG ((DEBUG_INFO, "OCB: CMD+C+MINUS means -no_compat_check\n")); + OcAppendArgumentToCmd (Context, Context->AppleBootArgs, "-no_compat_check", L_STR_LEN ("-no_compat_check")); } + return OC_INPUT_INTERNAL; + } - // - // CMD+V is always valid and enables Verbose Mode. - // - if (HasCommand && HasKeyV) { - if (OcGetArgumentFromCmd (Context->AppleBootArgs, "-v", L_STR_LEN ("-v")) == NULL) { - DEBUG ((DEBUG_INFO, "OCB: CMD+V means -v\n")); - OcAppendArgumentToCmd (Context, Context->AppleBootArgs, "-v", L_STR_LEN ("-v")); - } - continue; + // + // CMD+K is always valid for new macOS and means force boot to release kernel. + // + if (HasCommand && HasKeyK) { + if (AsciiStrStr (Context->AppleBootArgs, "kcsuffix=release") == NULL) { + DEBUG ((DEBUG_INFO, "OCB: CMD+K means kcsuffix=release\n")); + OcAppendArgumentToCmd (Context, Context->AppleBootArgs, "kcsuffix=release", L_STR_LEN ("kcsuffix=release")); } + return OC_INPUT_INTERNAL; + } - // - // CMD+C+MINUS is always valid and disables compatibility check. - // - if (HasCommand && HasKeyC && HasKeyMinus) { - if (OcGetArgumentFromCmd (Context->AppleBootArgs, "-no_compat_check", L_STR_LEN ("-no_compat_check")) == NULL) { - DEBUG ((DEBUG_INFO, "OCB: CMD+C+MINUS means -no_compat_check\n")); - OcAppendArgumentToCmd (Context, Context->AppleBootArgs, "-no_compat_check", L_STR_LEN ("-no_compat_check")); - } - continue; + // + // boot.efi also checks for CMD+X, but I have no idea what it is for. + // + + // + // boot.efi requires unrestricted NVRAM just for CMD+S+MINUS, and CMD+S + // does not work at all on T2 macs. For CMD+S we simulate T2 behaviour with + // DisableSingleUser Booter quirk if necessary. + // Ref: https://support.apple.com/HT201573 + // + if (HasCommand && HasKeyS) { + WantsZeroSlide = HasKeyMinus; + + if (WantsZeroSlide) { + CsrActiveConfig = 0; + CsrActiveConfigSize = sizeof (CsrActiveConfig); + Status = gRT->GetVariable ( + L"csr-active-config", + &gAppleBootVariableGuid, + NULL, + &CsrActiveConfigSize, + &CsrActiveConfig + ); + // + // FIXME: CMD+S+Minus behaves as CMD+S when "slide=0" is not supported + // by the SIP configuration. This might be an oversight, but is + // consistent with the boot.efi implementation. + // + WantsZeroSlide = !EFI_ERROR (Status) && (CsrActiveConfig & CSR_ALLOW_UNRESTRICTED_NVRAM) != 0; } - // - // CMD+K is always valid for new macOS and means force boot to release kernel. - // - if (HasCommand && HasKeyK) { - if (AsciiStrStr (Context->AppleBootArgs, "kcsuffix=release") == NULL) { - DEBUG ((DEBUG_INFO, "OCB: CMD+K means kcsuffix=release\n")); - OcAppendArgumentToCmd (Context, Context->AppleBootArgs, "kcsuffix=release", L_STR_LEN ("kcsuffix=release")); + if (WantsZeroSlide) { + if (AsciiStrStr (Context->AppleBootArgs, "slide=0") == NULL) { + DEBUG ((DEBUG_INFO, "OCB: CMD+S+MINUS means slide=0\n")); + OcAppendArgumentToCmd (Context, Context->AppleBootArgs, "slide=0", L_STR_LEN ("slide=0")); } - continue; + } else if (OcGetArgumentFromCmd (Context->AppleBootArgs, "-s", L_STR_LEN ("-s")) == NULL) { + DEBUG ((DEBUG_INFO, "OCB: CMD+S means -s\n")); + OcAppendArgumentToCmd (Context, Context->AppleBootArgs, "-s", L_STR_LEN ("-s")); } + return OC_INPUT_INTERNAL; + } + } - // - // boot.efi also checks for CMD+X, but I have no idea what it is for. - // - - // - // boot.efi requires unrestricted NVRAM just for CMD+S+MINUS, and CMD+S - // does not work at all on T2 macs. For CMD+S we simulate T2 behaviour with - // DisableSingleUser Booter quirk if necessary. - // Ref: https://support.apple.com/HT201573 - // - if (HasCommand && HasKeyS) { - WantsZeroSlide = HasKeyMinus; - - if (WantsZeroSlide) { - CsrActiveConfig = 0; - CsrActiveConfigSize = sizeof (CsrActiveConfig); - Status = gRT->GetVariable ( - L"csr-active-config", - &gAppleBootVariableGuid, - NULL, - &CsrActiveConfigSize, - &CsrActiveConfig - ); - // - // FIXME: CMD+S+Minus behaves as CMD+S when "slide=0" is not supported - // by the SIP configuration. This might be an oversight, but is - // consistent with the boot.efi implementation. - // - WantsZeroSlide = !EFI_ERROR (Status) && (CsrActiveConfig & CSR_ALLOW_UNRESTRICTED_NVRAM) != 0; - } + // + // Handle VoiceOver. + // + if ((Modifiers & (APPLE_MODIFIER_LEFT_COMMAND | APPLE_MODIFIER_RIGHT_COMMAND)) != 0 + && OcKeyMapHasKey (Keys, NumKeys, AppleHidUsbKbUsageKeyF5)) { + OcKeyMapFlush (KeyMap, 0, TRUE); + return OC_INPUT_VOICE_OVER; + } - if (WantsZeroSlide) { - if (AsciiStrStr (Context->AppleBootArgs, "slide=0") == NULL) { - DEBUG ((DEBUG_INFO, "OCB: CMD+S+MINUS means slide=0\n")); - OcAppendArgumentToCmd (Context, Context->AppleBootArgs, "slide=0", L_STR_LEN ("slide=0")); - } - } else if (OcGetArgumentFromCmd (Context->AppleBootArgs, "-s", L_STR_LEN ("-s")) == NULL) { - DEBUG ((DEBUG_INFO, "OCB: CMD+S means -s\n")); - OcAppendArgumentToCmd (Context, Context->AppleBootArgs, "-s", L_STR_LEN ("-s")); - } - continue; + // + // Handle reload menu. + // + if (OcKeyMapHasKey (Keys, NumKeys, AppleHidUsbKbUsageKeyEscape) + || OcKeyMapHasKey (Keys, NumKeys, AppleHidUsbKbUsageKeyZero)) { + OcKeyMapFlush (KeyMap, 0, TRUE); + return OC_INPUT_ABORTED; + } + + if (OcKeyMapHasKey (Keys, NumKeys, AppleHidUsbKbUsageKeySpaceBar)) { + OcKeyMapFlush (KeyMap, 0, TRUE); + return OC_INPUT_MORE; + } + + // + // Default update is desired for Ctrl+Index and Ctrl+Enter. + // + WantsDefault = Modifiers != 0 && (Modifiers & ~(APPLE_MODIFIER_LEFT_CONTROL | APPLE_MODIFIER_RIGHT_CONTROL)) == 0; + + // + // Check exact match on index strokes. + // + if ((Modifiers == 0 || WantsDefault) && NumKeys == 1) { + if (Keys[0] == AppleHidUsbKbUsageKeyEnter + || Keys[0] == AppleHidUsbKbUsageKeyReturn + || Keys[0] == AppleHidUsbKbUsageKeyPadEnter) { + if (WantsDefault && SetDefault != NULL) { + *SetDefault = TRUE; } + OcKeyMapFlush (KeyMap, Keys[0], TRUE); + return OC_INPUT_CONTINUE; } - // - // Handle VoiceOver. - // - if ((Modifiers & (APPLE_MODIFIER_LEFT_COMMAND | APPLE_MODIFIER_RIGHT_COMMAND)) != 0 - && OcKeyMapHasKey (Keys, NumKeys, AppleHidUsbKbUsageKeyF5)) { - OcKeyMapFlush (KeyMap, 0, TRUE); - return OC_INPUT_VOICE_OVER; + if (Keys[0] == AppleHidUsbKbUsageKeyUpArrow) { + OcKeyMapFlush (KeyMap, Keys[0], TRUE); + return OC_INPUT_UP; } - // - // Handle reload menu. - // - if (OcKeyMapHasKey (Keys, NumKeys, AppleHidUsbKbUsageKeyEscape) - || OcKeyMapHasKey (Keys, NumKeys, AppleHidUsbKbUsageKeyZero)) { - OcKeyMapFlush (KeyMap, 0, TRUE); - return OC_INPUT_ABORTED; + if (Keys[0] == AppleHidUsbKbUsageKeyDownArrow) { + OcKeyMapFlush (KeyMap, Keys[0], TRUE); + return OC_INPUT_DOWN; } - if (OcKeyMapHasKey (Keys, NumKeys, AppleHidUsbKbUsageKeySpaceBar)) { - OcKeyMapFlush (KeyMap, 0, TRUE); - return OC_INPUT_MORE; + if (Keys[0] == AppleHidUsbKbUsageKeyLeftArrow) { + OcKeyMapFlush (KeyMap, Keys[0], TRUE); + return OC_INPUT_LEFT; } - // - // Default update is desired for Ctrl+Index and Ctrl+Enter. - // - WantsDefault = Modifiers != 0 && (Modifiers & ~(APPLE_MODIFIER_LEFT_CONTROL | APPLE_MODIFIER_RIGHT_CONTROL)) == 0; + if (Keys[0] == AppleHidUsbKbUsageKeyRightArrow) { + OcKeyMapFlush (KeyMap, Keys[0], TRUE); + return OC_INPUT_RIGHT; + } - // - // Check exact match on index strokes. - // - if ((Modifiers == 0 || WantsDefault) && NumKeys == 1) { - if (Keys[0] == AppleHidUsbKbUsageKeyEnter - || Keys[0] == AppleHidUsbKbUsageKeyReturn - || Keys[0] == AppleHidUsbKbUsageKeyPadEnter) { + if (Keys[0] == AppleHidUsbKbUsageKeyPgUp + || Keys[0] == AppleHidUsbKbUsageKeyHome) { + OcKeyMapFlush (KeyMap, Keys[0], TRUE); + return OC_INPUT_TOP; + } + + if (Keys[0] == AppleHidUsbKbUsageKeyPgDn + || Keys[0] == AppleHidUsbKbUsageKeyEnd) { + OcKeyMapFlush (KeyMap, Keys[0], TRUE); + return OC_INPUT_BOTTOM; + } + + STATIC_ASSERT (AppleHidUsbKbUsageKeyF1 + 11 == AppleHidUsbKbUsageKeyF12, "Unexpected encoding"); + if (Keys[0] >= AppleHidUsbKbUsageKeyF1 && Keys[0] <= AppleHidUsbKbUsageKeyF12) { + OcKeyMapFlush (KeyMap, Keys[0], TRUE); + return OC_INPUT_FUNCTIONAL (Keys[0] - AppleHidUsbKbUsageKeyF1 + 1); + } + + STATIC_ASSERT (AppleHidUsbKbUsageKeyF13 + 11 == AppleHidUsbKbUsageKeyF24, "Unexpected encoding"); + if (Keys[0] >= AppleHidUsbKbUsageKeyF13 && Keys[0] <= AppleHidUsbKbUsageKeyF24) { + OcKeyMapFlush (KeyMap, Keys[0], TRUE); + return OC_INPUT_FUNCTIONAL (Keys[0] - AppleHidUsbKbUsageKeyF13 + 13); + } + + STATIC_ASSERT (AppleHidUsbKbUsageKeyOne + 8 == AppleHidUsbKbUsageKeyNine, "Unexpected encoding"); + for (KeyCode = AppleHidUsbKbUsageKeyOne; KeyCode <= AppleHidUsbKbUsageKeyNine; ++KeyCode) { + if (OcKeyMapHasKey (Keys, NumKeys, KeyCode)) { if (WantsDefault && SetDefault != NULL) { *SetDefault = TRUE; } OcKeyMapFlush (KeyMap, Keys[0], TRUE); - return OC_INPUT_CONTINUE; + return (INTN) (KeyCode - AppleHidUsbKbUsageKeyOne); } + } - if (Keys[0] == AppleHidUsbKbUsageKeyUpArrow) { + STATIC_ASSERT (AppleHidUsbKbUsageKeyA + 25 == AppleHidUsbKbUsageKeyZ, "Unexpected encoding"); + for (KeyCode = AppleHidUsbKbUsageKeyA; KeyCode <= AppleHidUsbKbUsageKeyZ; ++KeyCode) { + if (OcKeyMapHasKey (Keys, NumKeys, KeyCode)) { + if (WantsDefault && SetDefault != NULL) { + *SetDefault = TRUE; + } OcKeyMapFlush (KeyMap, Keys[0], TRUE); - return OC_INPUT_UP; + return (INTN) (KeyCode - AppleHidUsbKbUsageKeyA + 9); } + } + } - if (Keys[0] == AppleHidUsbKbUsageKeyDownArrow) { - OcKeyMapFlush (KeyMap, Keys[0], TRUE); - return OC_INPUT_DOWN; - } + if (NumKeys > 0) { + return OC_INPUT_INVALID; + } - if (Keys[0] == AppleHidUsbKbUsageKeyLeftArrow) { - OcKeyMapFlush (KeyMap, Keys[0], TRUE); - return OC_INPUT_LEFT; - } + return OC_INPUT_TIMEOUT; +} - if (Keys[0] == AppleHidUsbKbUsageKeyRightArrow) { - OcKeyMapFlush (KeyMap, Keys[0], TRUE); - return OC_INPUT_RIGHT; - } +INTN +OcWaitForAppleKeyIndex ( + IN OUT OC_PICKER_CONTEXT *Context, + IN APPLE_KEY_MAP_AGGREGATOR_PROTOCOL *KeyMap, + IN UINTN Timeout, + OUT BOOLEAN *SetDefault OPTIONAL + ) +{ + INTN ResultingKey; + UINT64 CurrTime; + UINT64 EndTime; - if (Keys[0] == AppleHidUsbKbUsageKeyPgUp - || Keys[0] == AppleHidUsbKbUsageKeyHome) { - OcKeyMapFlush (KeyMap, Keys[0], TRUE); - return OC_INPUT_TOP; - } + // + // These hotkeys are normally parsed by boot.efi, and they work just fine + // when ShowPicker is disabled. On some BSPs, however, they may fail badly + // when ShowPicker is enabled, and for this reason we support these hotkeys + // within picker itself. + // - if (Keys[0] == AppleHidUsbKbUsageKeyPgDn - || Keys[0] == AppleHidUsbKbUsageKeyEnd) { - OcKeyMapFlush (KeyMap, Keys[0], TRUE); - return OC_INPUT_BOTTOM; - } + CurrTime = GetTimeInNanoSecond (GetPerformanceCounter ()); + EndTime = CurrTime + Timeout * 1000000ULL; - STATIC_ASSERT (AppleHidUsbKbUsageKeyF1 + 11 == AppleHidUsbKbUsageKeyF12, "Unexpected encoding"); - if (Keys[0] >= AppleHidUsbKbUsageKeyF1 && Keys[0] <= AppleHidUsbKbUsageKeyF12) { - OcKeyMapFlush (KeyMap, Keys[0], TRUE); - return OC_INPUT_FUNCTIONAL (Keys[0] - AppleHidUsbKbUsageKeyF1 + 1); - } + if (SetDefault != NULL) { + *SetDefault = FALSE; + } - STATIC_ASSERT (AppleHidUsbKbUsageKeyF13 + 11 == AppleHidUsbKbUsageKeyF24, "Unexpected encoding"); - if (Keys[0] >= AppleHidUsbKbUsageKeyF13 && Keys[0] <= AppleHidUsbKbUsageKeyF24) { - OcKeyMapFlush (KeyMap, Keys[0], TRUE); - return OC_INPUT_FUNCTIONAL (Keys[0] - AppleHidUsbKbUsageKeyF13 + 13); - } + while (Timeout == 0 || CurrTime == 0 || CurrTime < EndTime) { + CurrTime = GetTimeInNanoSecond (GetPerformanceCounter ()); - STATIC_ASSERT (AppleHidUsbKbUsageKeyOne + 8 == AppleHidUsbKbUsageKeyNine, "Unexpected encoding"); - for (KeyCode = AppleHidUsbKbUsageKeyOne; KeyCode <= AppleHidUsbKbUsageKeyNine; ++KeyCode) { - if (OcKeyMapHasKey (Keys, NumKeys, KeyCode)) { - if (WantsDefault && SetDefault != NULL) { - *SetDefault = TRUE; - } - OcKeyMapFlush (KeyMap, Keys[0], TRUE); - return (INTN) (KeyCode - AppleHidUsbKbUsageKeyOne); - } - } + ResultingKey = OcGetAppleKeyIndex (Context, KeyMap, SetDefault); - STATIC_ASSERT (AppleHidUsbKbUsageKeyA + 25 == AppleHidUsbKbUsageKeyZ, "Unexpected encoding"); - for (KeyCode = AppleHidUsbKbUsageKeyA; KeyCode <= AppleHidUsbKbUsageKeyZ; ++KeyCode) { - if (OcKeyMapHasKey (Keys, NumKeys, KeyCode)) { - if (WantsDefault && SetDefault != NULL) { - *SetDefault = TRUE; - } - OcKeyMapFlush (KeyMap, Keys[0], TRUE); - return (INTN) (KeyCode - AppleHidUsbKbUsageKeyA + 9); - } - } + // + // Requested for another iteration, handled Apple hotkey. + // + if (ResultingKey == OC_INPUT_INTERNAL) { + continue; } + // // Abort the timeout when unrecognised keys are pressed. // - if (Timeout != 0 && NumKeys != 0) { + if (Timeout != 0 && ResultingKey == OC_INPUT_INVALID) { return OC_INPUT_INVALID; } + // + // Found key, return it. + // + if (ResultingKey != OC_INPUT_INVALID && ResultingKey != OC_INPUT_TIMEOUT) { + return ResultingKey; + } + MicroSecondDelay (10); } diff --git a/Library/OcBootManagementLib/OcBootManagementLib.c b/Library/OcBootManagementLib/OcBootManagementLib.c index 9bf22b2e381..0c69f1dc3dd 100644 --- a/Library/OcBootManagementLib/OcBootManagementLib.c +++ b/Library/OcBootManagementLib/OcBootManagementLib.c @@ -225,7 +225,6 @@ OcShowSimpleBootMenu ( BootContext->PickerContext, KeyMap, PlayChosen ? OC_VOICE_OVER_IDLE_TIMEOUT_MS : TimeOutSeconds * 1000, - BootContext->PickerContext->PollAppleHotKeys, &SetDefault ); diff --git a/Platform/OpenCanopy/GuiIo.h b/Platform/OpenCanopy/GuiIo.h index dd3fa9c1077..e5ee8bc28b5 100644 --- a/Platform/OpenCanopy/GuiIo.h +++ b/Platform/OpenCanopy/GuiIo.h @@ -8,6 +8,7 @@ #ifndef GUI_IO_H #define GUI_IO_H +#include #include #include "OpenCanopy.h" @@ -65,10 +66,11 @@ GuiPointerReset ( GUI_POINTER_CONTEXT * GuiPointerConstruct ( - IN UINT32 DefaultX, - IN UINT32 DefaultY, - IN UINT32 Width, - IN UINT32 Height + IN OC_PICKER_CONTEXT *PickerContext, + IN UINT32 DefaultX, + IN UINT32 DefaultY, + IN UINT32 Width, + IN UINT32 Height ); VOID @@ -78,7 +80,7 @@ GuiPointerDestruct ( GUI_KEY_CONTEXT * GuiKeyConstruct ( - VOID + IN OC_PICKER_CONTEXT *PickerContext ); VOID @@ -91,7 +93,8 @@ EFI_STATUS EFIAPI GuiKeyRead ( IN OUT GUI_KEY_CONTEXT *Context, - OUT EFI_INPUT_KEY *Key + OUT INTN *KeyIndex, + OUT BOOLEAN *Modifier ); VOID diff --git a/Platform/OpenCanopy/Input/InputSimAbsPtr.c b/Platform/OpenCanopy/Input/InputSimAbsPtr.c index 038520c35b4..3f1e519e382 100644 --- a/Platform/OpenCanopy/Input/InputSimAbsPtr.c +++ b/Platform/OpenCanopy/Input/InputSimAbsPtr.c @@ -451,10 +451,11 @@ GuiPointerGetState ( GUI_POINTER_CONTEXT * GuiPointerConstruct ( - IN UINT32 DefaultX, - IN UINT32 DefaultY, - IN UINT32 Width, - IN UINT32 Height + IN OC_PICKER_CONTEXT *PickerContext, + IN UINT32 DefaultX, + IN UINT32 DefaultY, + IN UINT32 Width, + IN UINT32 Height ) { // TODO: alloc on the fly? diff --git a/Platform/OpenCanopy/Input/InputSimTextIn.c b/Platform/OpenCanopy/Input/InputSimTextIn.c index f4b2da2fc3f..935a79075e5 100644 --- a/Platform/OpenCanopy/Input/InputSimTextIn.c +++ b/Platform/OpenCanopy/Input/InputSimTextIn.c @@ -7,39 +7,69 @@ #include -#include +#include #include +#include +#include #include #include "../GuiIo.h" struct GUI_KEY_CONTEXT_ { - EFI_SIMPLE_TEXT_INPUT_PROTOCOL TextIn; + APPLE_KEY_MAP_AGGREGATOR_PROTOCOL *KeyMap; + OC_PICKER_CONTEXT *Context; }; GUI_KEY_CONTEXT * GuiKeyConstruct ( - VOID + IN OC_PICKER_CONTEXT *PickerContext ) { - ASSERT (gST->ConIn != NULL); - return (GUI_KEY_CONTEXT *)gST->ConIn; + STATIC GUI_KEY_CONTEXT mContext; + mContext.KeyMap = OcAppleKeyMapInstallProtocols (FALSE); + mContext.Context = PickerContext; + if (mContext.KeyMap == NULL) { + DEBUG ((DEBUG_WARN, "OCUI: Missing AppleKeyMapAggregator\n")); + return NULL; + } + + return &mContext; } EFI_STATUS EFIAPI GuiKeyRead ( IN OUT GUI_KEY_CONTEXT *Context, - OUT EFI_INPUT_KEY *Key + OUT INTN *KeyIndex, + OUT BOOLEAN *Modifier ) { - EFI_SIMPLE_TEXT_INPUT_PROTOCOL *TextIn; ASSERT (Context != NULL); - TextIn = &Context->TextIn; - return TextIn->ReadKeyStroke (TextIn, Key); + *Modifier = FALSE; + *KeyIndex = OcGetAppleKeyIndex ( + Context->Context, + Context->KeyMap, + Modifier + ); + + // + // No key was pressed. + // + if (*KeyIndex == OC_INPUT_TIMEOUT) { + return EFI_NOT_FOUND; + } + + // + // Internal key was pressed and handled. + // + if (*KeyIndex == OC_INPUT_INTERNAL) { + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; } VOID @@ -48,14 +78,10 @@ GuiKeyReset ( IN OUT GUI_KEY_CONTEXT *Context ) { - EFI_STATUS Status; - EFI_INPUT_KEY Key; - ASSERT (Context != NULL); - - do { - Status = GuiKeyRead (Context, &Key); - } while (!EFI_ERROR (Status)); + // + // Flush console here? + // } VOID @@ -64,4 +90,5 @@ GuiKeyDestruct ( ) { ASSERT (Context != NULL); + ZeroMem (Context, sizeof (*Context)); } diff --git a/Platform/OpenCanopy/OcBootstrap.c b/Platform/OpenCanopy/OcBootstrap.c index dbc97bffdc7..4a1118978be 100644 --- a/Platform/OpenCanopy/OcBootstrap.c +++ b/Platform/OpenCanopy/OcBootstrap.c @@ -54,6 +54,7 @@ OcShowMenuByOc ( mGuiContext.Refresh = FALSE; Status = GuiLibConstruct ( + BootContext->PickerContext, mGuiContext.CursorDefaultX, mGuiContext.CursorDefaultY ); diff --git a/Platform/OpenCanopy/OpenCanopy.c b/Platform/OpenCanopy/OpenCanopy.c index 3ddd9cc3827..6353be6fc85 100644 --- a/Platform/OpenCanopy/OpenCanopy.c +++ b/Platform/OpenCanopy/OpenCanopy.c @@ -956,8 +956,9 @@ GuiRedrawAndFlushScreen ( EFI_STATUS GuiLibConstruct ( - IN UINT32 CursorDefaultX, - IN UINT32 CursorDefaultY + IN OC_PICKER_CONTEXT *PickerContet, + IN UINT32 CursorDefaultX, + IN UINT32 CursorDefaultY ) { CONST EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *OutputInfo; @@ -975,16 +976,17 @@ GuiLibConstruct ( CursorDefaultY = MIN (CursorDefaultY, OutputInfo->VerticalResolution - 1); mPointerContext = GuiPointerConstruct ( - CursorDefaultX, - CursorDefaultY, - OutputInfo->HorizontalResolution, - OutputInfo->VerticalResolution - ); + PickerContet, + CursorDefaultX, + CursorDefaultY, + OutputInfo->HorizontalResolution, + OutputInfo->VerticalResolution + ); if (mPointerContext == NULL) { DEBUG ((DEBUG_WARN, "OCUI: Failed to initialise pointer\n")); } - mKeyContext = GuiKeyConstruct (); + mKeyContext = GuiKeyConstruct (PickerContet); if (mKeyContext == NULL) { DEBUG ((DEBUG_WARN, "OCUI: Failed to initialise key input\n")); } @@ -1128,7 +1130,8 @@ GuiDrawLoop ( EFI_STATUS Status; BOOLEAN Result; - EFI_INPUT_KEY InputKey; + INTN InputKey; + BOOLEAN Modifier; GUI_POINTER_STATE PointerState; GUI_OBJ *HoldObject; INT64 HoldObjBaseX; @@ -1203,7 +1206,7 @@ GuiDrawLoop ( // // Process key events. Only allow one key at a time for now. // - Status = GuiKeyRead (mKeyContext, &InputKey); + Status = GuiKeyRead (mKeyContext, &InputKey, &Modifier); if (!EFI_ERROR (Status)) { ASSERT (DrawContext->Screen->KeyEvent != NULL); DrawContext->Screen->KeyEvent ( @@ -1212,7 +1215,8 @@ GuiDrawLoop ( DrawContext->GuiContext, 0, 0, - &InputKey + InputKey, + Modifier ); // // If detected key press then disable menu timeout diff --git a/Platform/OpenCanopy/OpenCanopy.h b/Platform/OpenCanopy/OpenCanopy.h index f3c8ae7d4ab..f09d006b29f 100644 --- a/Platform/OpenCanopy/OpenCanopy.h +++ b/Platform/OpenCanopy/OpenCanopy.h @@ -8,6 +8,7 @@ #ifndef OPEN_CANOPY_H #define OPEN_CANOPY_H +#include #include #include @@ -58,7 +59,8 @@ VOID IN VOID *Context OPTIONAL, IN INT64 BaseX, IN INT64 BaseY, - IN CONST EFI_INPUT_KEY *Key + IN INTN Key, + IN BOOLEAN Modifier ); typedef @@ -259,8 +261,9 @@ GuiClearScreen ( EFI_STATUS GuiLibConstruct ( - IN UINT32 CursorDefaultX, - IN UINT32 CursorDefaultY + IN OC_PICKER_CONTEXT *PickerContet, + IN UINT32 CursorDefaultX, + IN UINT32 CursorDefaultY ); VOID diff --git a/Platform/OpenCanopy/OpenCanopy.inf b/Platform/OpenCanopy/OpenCanopy.inf index e3e986a046f..cc5808f1b6e 100644 --- a/Platform/OpenCanopy/OpenCanopy.inf +++ b/Platform/OpenCanopy/OpenCanopy.inf @@ -68,6 +68,7 @@ DebugLib FrameBufferBltLib MemoryAllocationLib + OcAppleKeyMapLib OcBootManagementLib OcCompressionLib OcGuardLib diff --git a/Platform/OpenCanopy/Views/BootPicker.c b/Platform/OpenCanopy/Views/BootPicker.c index 7b030d77349..44e8c3e75f7 100644 --- a/Platform/OpenCanopy/Views/BootPicker.c +++ b/Platform/OpenCanopy/Views/BootPicker.c @@ -134,12 +134,13 @@ InternalBootPickerViewKeyEvent ( IN VOID *Context OPTIONAL, IN INT64 BaseX, IN INT64 BaseY, - IN CONST EFI_INPUT_KEY *Key + IN INTN Key, + IN BOOLEAN Modifier ) { ASSERT (This != NULL); ASSERT (DrawContext != NULL); - ASSERT (Key != NULL); + // // Consider moving between multiple panes with UP/DOWN and store the current // view within the object - for now, hardcoding this is enough. @@ -151,7 +152,8 @@ InternalBootPickerViewKeyEvent ( Context, BaseX + mBootPicker.Hdr.Obj.OffsetX, BaseY + mBootPicker.Hdr.Obj.OffsetY, - Key + Key, + Modifier ); } @@ -239,7 +241,8 @@ InternalBootPickerKeyEvent ( IN VOID *Context OPTIONAL, IN INT64 BaseX, IN INT64 BaseY, - IN CONST EFI_INPUT_KEY *Key + IN INTN Key, + IN BOOLEAN Modifier ) { GUI_VOLUME_PICKER *Picker; @@ -250,13 +253,12 @@ InternalBootPickerKeyEvent ( ASSERT (This != NULL); ASSERT (DrawContext != NULL); - ASSERT (Key != NULL); Picker = BASE_CR (This, GUI_VOLUME_PICKER, Hdr.Obj); PrevEntry = Picker->SelectedEntry; ASSERT (PrevEntry != NULL); - if (Key->ScanCode == SCAN_RIGHT) { + if (Key == OC_INPUT_RIGHT) { NextLink = GetNextNode ( &Picker->Hdr.Obj.Children, &PrevEntry->Hdr.Link @@ -271,7 +273,7 @@ InternalBootPickerKeyEvent ( NextEntry = BASE_CR (NextLink, GUI_VOLUME_ENTRY, Hdr.Link); InternalBootPickerChangeEntry (Picker, DrawContext, BaseX, BaseY, NextEntry); } - } else if (Key->ScanCode == SCAN_LEFT) { + } else if (Key == OC_INPUT_LEFT) { NextLink = GetPreviousNode ( &Picker->Hdr.Obj.Children, &PrevEntry->Hdr.Link @@ -283,10 +285,11 @@ InternalBootPickerKeyEvent ( NextEntry = BASE_CR (NextLink, GUI_VOLUME_ENTRY, Hdr.Link); InternalBootPickerChangeEntry (Picker, DrawContext, BaseX, BaseY, NextEntry); } - } else if (Key->UnicodeChar == CHAR_CARRIAGE_RETURN) { + } else if (Key == OC_INPUT_CONTINUE) { ASSERT (Context != NULL); ASSERT (Picker->SelectedEntry != NULL); GuiContext = (BOOT_PICKER_GUI_CONTEXT *)Context; + Picker->SelectedEntry->Context->SetDefault = Modifier; GuiContext->BootEntry = Picker->SelectedEntry->Context; } else if (mBootPickerOpacity != 0xFF) { // @@ -295,11 +298,11 @@ InternalBootPickerKeyEvent ( return; } - if (Key->UnicodeChar == L' ') { + if (Key == OC_INPUT_MORE) { GuiContext = (BOOT_PICKER_GUI_CONTEXT *)Context; GuiContext->HideAuxiliary = FALSE; GuiContext->Refresh = TRUE; - } else if (Key->ScanCode == SCAN_ESC) { + } else if (Key == OC_INPUT_ABORTED) { GuiContext = (BOOT_PICKER_GUI_CONTEXT *)Context; GuiContext->Refresh = TRUE; } diff --git a/Platform/OpenCanopy/Views/BootPicker.h b/Platform/OpenCanopy/Views/BootPicker.h index a13210277c5..87a4224fa42 100644 --- a/Platform/OpenCanopy/Views/BootPicker.h +++ b/Platform/OpenCanopy/Views/BootPicker.h @@ -8,6 +8,8 @@ #ifndef BOOT_PICKER_H #define BOOT_PICKER_H +#include "../OpenCanopy.h" + typedef struct { GUI_OBJ_CHILD Hdr; CONST GUI_IMAGE *ClickImage; @@ -18,7 +20,7 @@ typedef struct { GUI_OBJ_CHILD Hdr; GUI_IMAGE EntryIcon; GUI_IMAGE Label; - VOID *Context; + OC_BOOT_ENTRY *Context; BOOLEAN CustomIcon; } GUI_VOLUME_ENTRY;